Skip to content

Commit 6a17d31

Browse files
committed
Add Dot-Dsl solution
1 parent 83614e1 commit 6a17d31

File tree

4 files changed

+303
-0
lines changed

4 files changed

+303
-0
lines changed

dot-dsl/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "dot-dsl"
3+
version = "0.1.0"
4+
5+
[dependencies]
6+
maplit = "1.0.1"

dot-dsl/README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# DOT DSL
2+
3+
Write a Domain Specific Language similar to the Graphviz dot language.
4+
5+
A [Domain Specific Language
6+
(DSL)](https://en.wikipedia.org/wiki/Domain-specific_language) is a
7+
small language optimized for a specific domain.
8+
9+
For example the [DOT language](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) allows
10+
you to write a textual description of a graph which is then transformed into a picture by one of
11+
the [Graphviz](http://graphviz.org/) tools (such as `dot`). A simple graph looks like this:
12+
13+
graph {
14+
graph [bgcolor="yellow"]
15+
a [color="red"]
16+
b [color="blue"]
17+
a -- b [color="green"]
18+
}
19+
20+
Putting this in a file `example.dot` and running `dot example.dot -T png
21+
-o example.png` creates an image `example.png` with red and blue circle
22+
connected by a green line on a yellow background.
23+
24+
Create a DSL similar to the dot language.
25+
26+
## Builder pattern
27+
28+
This exercise expects you to build several structs using `builder pattern`.
29+
In short, this pattern allows you to split the construction function of your struct, that contains a lot of arguments, into
30+
several separate functions. This approuch gives you the means to make compact but highly-flexible struct construction and
31+
configuration.
32+
You can read more about it on the [following page](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html).
33+
34+
35+
## Rust Installation
36+
37+
Refer to the [exercism help page][help-page] for Rust installation and learning
38+
resources.
39+
40+
## Writing the Code
41+
42+
Execute the tests with:
43+
44+
```bash
45+
$ cargo test
46+
```
47+
48+
All but the first test have been ignored. After you get the first test to
49+
pass, open the tests source file which is located in the `tests` directory
50+
and remove the `#[ignore]` flag from the next test and get the tests to pass
51+
again. Each separate test is a function with `#[test]` flag above it.
52+
Continue, until you pass every test.
53+
54+
If you wish to run all tests without editing the tests source file, use:
55+
56+
```bash
57+
$ cargo test -- --ignored
58+
```
59+
60+
To run a specific test, for example `some_test`, you can use:
61+
62+
```bash
63+
$ cargo test some_test
64+
```
65+
66+
If the specific test is ignored use:
67+
68+
```bash
69+
$ cargo test some_test -- --ignored
70+
```
71+
72+
To learn more about Rust tests refer to the [online test documentation][rust-tests]
73+
74+
Make sure to read the [Modules](https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html) chapter if you
75+
haven't already, it will help you with organizing your files.
76+
77+
## Feedback, Issues, Pull Requests
78+
79+
The [exercism/rust](https://github.com/exercism/rust) repository on GitHub is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help!
80+
81+
If you want to know more about Exercism, take a look at the [contribution guide](https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md).
82+
83+
[help-page]: http://exercism.io/languages/rust
84+
[modules]: https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html
85+
[cargo]: https://doc.rust-lang.org/book/second-edition/ch14-00-more-about-cargo.html
86+
[rust-tests]: https://doc.rust-lang.org/book/second-edition/ch11-02-running-tests.html
87+
88+
## Submitting Incomplete Solutions
89+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

dot-dsl/src/lib.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
pub mod graph {
2+
3+
use self::graph_items::edge::Edge;
4+
use self::graph_items::node::Node;
5+
use std::collections::HashMap;
6+
7+
pub mod graph_items {
8+
9+
pub mod edge {
10+
11+
#[derive(Clone, Debug, PartialEq)]
12+
pub struct Edge {
13+
start: String,
14+
end: String,
15+
attrs: Vec<(String, String)>,
16+
}
17+
18+
impl Edge {
19+
pub fn new(start: &str, end: &str) -> Self {
20+
let start = start.to_string();
21+
let end = end.to_string();
22+
let attrs = Vec::new();
23+
Edge { start, end, attrs }
24+
}
25+
pub fn with_attrs(mut self, attrs: &[(&str, &str)]) -> Self {
26+
self.attrs = attrs
27+
.iter()
28+
.map(|attr| (attr.0.to_string(), attr.1.to_string()))
29+
.collect();
30+
self
31+
}
32+
}
33+
}
34+
35+
pub mod node {
36+
37+
#[derive(Clone, Debug, PartialEq)]
38+
pub struct Node {
39+
label: String,
40+
attrs: Vec<(String, String)>,
41+
}
42+
43+
impl Node {
44+
pub fn new(label: &str) -> Self {
45+
let label = label.to_string();
46+
let attrs = Vec::new();
47+
Node { label, attrs }
48+
}
49+
pub fn with_attrs(mut self, attrs: &[(&str, &str)]) -> Self {
50+
self.attrs = attrs
51+
.iter()
52+
.map(|attr| (attr.0.to_string(), attr.1.to_string()))
53+
.collect();
54+
self
55+
}
56+
}
57+
}
58+
}
59+
60+
#[derive(Default)]
61+
pub struct Graph {
62+
pub nodes: Vec<Node>,
63+
pub edges: Vec<Edge>,
64+
pub attrs: HashMap<String, String>,
65+
}
66+
67+
impl Graph {
68+
pub fn new() -> Self {
69+
Graph::default()
70+
}
71+
pub fn with_nodes(mut self, nodes: &[Node]) -> Self {
72+
self.nodes = nodes.to_vec();
73+
self
74+
}
75+
pub fn with_edges(mut self, edges: &[Edge]) -> Self {
76+
self.edges = edges.to_vec();
77+
self
78+
}
79+
pub fn with_attrs(mut self, attrs: &[(&str, &str)]) -> Self {
80+
self.attrs = attrs.iter().fold(HashMap::new(), |mut acc, attr| {
81+
acc.insert((attr.0).to_string(), (attr.1).to_string());
82+
acc
83+
});
84+
self
85+
}
86+
}
87+
}

dot-dsl/tests/dot-dsl.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#[macro_use]
2+
extern crate maplit;
3+
extern crate dot_dsl;
4+
5+
use dot_dsl::graph::graph_items::edge::Edge;
6+
use dot_dsl::graph::graph_items::node::Node;
7+
use dot_dsl::graph::Graph;
8+
9+
#[test]
10+
fn test_empty_graph() {
11+
let graph = Graph::new();
12+
13+
assert!(graph.nodes.is_empty());
14+
15+
assert!(graph.edges.is_empty());
16+
17+
assert!(graph.attrs.is_empty());
18+
}
19+
20+
#[test]
21+
fn test_graph_with_one_node() {
22+
let nodes = vec![Node::new("a")];
23+
24+
let graph = Graph::new().with_nodes(&nodes);
25+
26+
assert!(graph.edges.is_empty());
27+
28+
assert!(graph.attrs.is_empty());
29+
30+
assert_eq!(graph.nodes, vec![Node::new("a")]);
31+
}
32+
33+
#[test]
34+
fn test_graph_with_one_node_with_keywords() {
35+
let nodes = vec![Node::new("a").with_attrs(&[("color", "green")])];
36+
37+
let graph = Graph::new().with_nodes(&nodes);
38+
39+
assert!(graph.edges.is_empty());
40+
41+
assert!(graph.attrs.is_empty());
42+
43+
assert_eq!(
44+
graph.nodes,
45+
vec![Node::new("a").with_attrs(&[("color", "green")])]
46+
);
47+
}
48+
49+
#[test]
50+
fn test_graph_with_one_edge() {
51+
let edges = vec![Edge::new("a", "b")];
52+
53+
let graph = Graph::new().with_edges(&edges);
54+
55+
assert!(graph.nodes.is_empty());
56+
57+
assert!(graph.attrs.is_empty());
58+
59+
assert_eq!(graph.edges, vec![Edge::new("a", "b")]);
60+
}
61+
62+
#[test]
63+
fn test_graph_with_one_attribute() {
64+
let graph = Graph::new().with_attrs(&[("foo", "1")]);
65+
66+
let expected_attrs = hashmap!{
67+
"foo".to_string() => "1".to_string(),
68+
};
69+
70+
assert!(graph.nodes.is_empty());
71+
72+
assert!(graph.edges.is_empty());
73+
74+
assert_eq!(graph.attrs, expected_attrs);
75+
}
76+
77+
#[test]
78+
fn test_graph_with_attributes() {
79+
let nodes = vec![
80+
Node::new("a").with_attrs(&[("color", "green")]),
81+
Node::new("c"),
82+
Node::new("b").with_attrs(&[("label", "Beta!")]),
83+
];
84+
85+
let edges = vec![
86+
Edge::new("b", "c"),
87+
Edge::new("a", "b").with_attrs(&[("color", "blue")]),
88+
];
89+
90+
let attrs = vec![("foo", "1"), ("title", "Testing Attrs"), ("bar", "true")];
91+
92+
let expected_attrs = hashmap! {
93+
"foo".to_string() => "1".to_string(),
94+
"title".to_string() => "Testing Attrs".to_string(),
95+
"bar".to_string() => "true".to_string(),
96+
};
97+
98+
let graph = Graph::new()
99+
.with_nodes(&nodes)
100+
.with_edges(&edges)
101+
.with_attrs(&attrs);
102+
103+
assert_eq!(
104+
graph.nodes,
105+
vec![
106+
Node::new("a").with_attrs(&[("color", "green")]),
107+
Node::new("c"),
108+
Node::new("b").with_attrs(&[("label", "Beta!")]),
109+
]
110+
);
111+
112+
assert_eq!(
113+
graph.edges,
114+
vec![
115+
Edge::new("b", "c"),
116+
Edge::new("a", "b").with_attrs(&[("color", "blue")]),
117+
]
118+
);
119+
120+
assert_eq!(graph.attrs, expected_attrs);
121+
}

0 commit comments

Comments
 (0)