Skip to content

Commit f0733d5

Browse files
shepmastercarols10cents
authored andcommitted
Rewrite the categories TOML format and parser
1 parent 9318605 commit f0733d5

File tree

2 files changed

+62
-70
lines changed

2 files changed

+62
-70
lines changed

src/categories.rs

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,76 @@ use env;
77
use util::errors::{CargoResult, ChainError, internal};
88

99
struct Category {
10-
name: String,
1110
slug: String,
11+
name: String,
1212
description: String,
1313
}
1414

1515
impl Category {
16-
fn concat(&self, child: &Category) -> Category {
17-
Category {
18-
name: format!("{}::{}", self.name, child.name),
19-
slug: format!("{}::{}", self.slug, child.slug),
20-
description: child.description.clone(),
16+
fn from_parent(slug: &str, name: &str, description: &str, parent: Option<&Category>)
17+
-> Category {
18+
match parent {
19+
Some(parent) => {
20+
Category {
21+
slug: format!("{}::{}", parent.slug, slug),
22+
name: format!("{}::{}", parent.name, name),
23+
description: description.into(),
24+
}
25+
}
26+
None => {
27+
Category {
28+
slug: slug.into(),
29+
name: name.into(),
30+
description: description.into(),
31+
}
32+
}
2133
}
2234
}
2335
}
2436

25-
fn concat_parent_and_child(parent: Option<&Category>, child: Category)
26-
-> Category {
27-
parent.map(|p| p.concat(&child)).unwrap_or(child)
28-
}
29-
30-
fn required_string_from_toml(toml: &toml::Table, key: &str)
31-
-> CargoResult<String> {
37+
fn required_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> CargoResult<&'a str> {
3238
toml.get(key)
3339
.and_then(toml::Value::as_str)
34-
.map(str::to_string)
3540
.chain_error(|| {
36-
internal("Expected Category toml attribute to be a String")
41+
internal(format!("Expected category TOML attribute '{}' to be a String", key))
3742
})
3843
}
3944

40-
fn optional_string_from_toml(toml: &toml::Table, key: &str)
41-
-> String {
45+
fn optional_string_from_toml<'a>(toml: &'a toml::Table, key: &str) -> &'a str {
4246
toml.get(key)
4347
.and_then(toml::Value::as_str)
4448
.unwrap_or("")
45-
.to_string()
4649
}
4750

48-
fn category_from_toml(toml: &toml::Value, parent: Option<&Category>)
49-
-> CargoResult<Vec<Category>> {
50-
let toml = toml.as_table().chain_error(|| {
51-
internal("Category isn't a toml Table")
52-
})?;
53-
54-
let category = Category {
55-
slug: required_string_from_toml(&toml, "slug")?,
56-
name: required_string_from_toml(&toml, "name")?,
57-
description: optional_string_from_toml(&toml, "description"),
58-
};
59-
60-
let category = concat_parent_and_child(parent, category);
61-
62-
let mut children: Vec<_> = toml.get("categories")
63-
.and_then(toml::Value::as_slice)
64-
.map(|children| {
65-
children.iter()
66-
.flat_map(|ref child| {
67-
category_from_toml(child, Some(&category))
68-
.expect("Could not create child from toml")
69-
}).collect()
70-
}).unwrap_or(Vec::new());
71-
72-
children.push(category);
73-
74-
Ok(children)
51+
fn categories_from_toml(categories: &toml::Table, parent: Option<&Category>) -> CargoResult<Vec<Category>> {
52+
let mut result = vec![];
53+
54+
for (slug, details) in categories {
55+
let details = details.as_table().chain_error(|| {
56+
internal(format!("category {} was not a TOML table", slug))
57+
})?;
58+
59+
let category = Category::from_parent(
60+
slug,
61+
required_string_from_toml(&details, "name")?,
62+
optional_string_from_toml(&details, "description"),
63+
parent,
64+
);
65+
66+
if let Some(categories) = details.get("categories") {
67+
let categories = categories.as_table().chain_error(|| {
68+
internal(format!("child categories of {} were not a table", slug))
69+
})?;
70+
71+
result.extend(
72+
categories_from_toml(categories, Some(&category))?
73+
);
74+
}
75+
76+
result.push(category)
77+
}
78+
79+
Ok(result)
7580
}
7681

7782
pub fn sync() -> CargoResult<()> {
@@ -84,17 +89,9 @@ pub fn sync() -> CargoResult<()> {
8489
"Could not parse categories.toml"
8590
);
8691

87-
let categories = toml.get("categories")
88-
.expect("No categories key found")
89-
.as_slice()
90-
.expect("Categories isn't a toml::Array");
91-
92-
let categories: Vec<_> = categories
93-
.iter()
94-
.flat_map(|c| {
95-
category_from_toml(c, None)
96-
.expect("Categories from toml failed")
97-
}).collect();
92+
let categories = categories_from_toml(&toml, None).expect(
93+
"Could not convert categories from TOML"
94+
);
9895

9996
for category in categories.iter() {
10097
tx.execute("\

src/categories.toml

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
1-
[[categories]]
2-
slug = "development-tools"
1+
[development-tools]
32
name = "Development Tools"
43
description = "Ways to make developing in Rust better"
54

6-
[[categories.categories]]
7-
slug = "testing"
5+
[development-tools.categories.testing]
86
name = "Testing"
97
description = "Additions to automated testing features"
108

11-
[[categories.categories.categories]]
12-
slug = "mocking"
9+
[development-tools.categories.testing.categories.mocking]
1310
name = "Mocking"
11+
description = "Mocks are not the same as stubs!"
1412

15-
[[categories]]
16-
slug = "libraries"
13+
[libraries]
1714
name = "Libraries"
15+
description = "Libraries are reusable pieces of code"
1816

19-
[[categories.categories]]
20-
slug = "async"
17+
[libraries.categories.async]
2118
name = "Async"
2219
description = "Code that can take time to run but won't block"
2320

24-
[[categories.categories]]
25-
slug = "date-and-time"
21+
[libraries.categories.date-and-time]
2622
name = "Date and Time"
2723
description = "Date and time math"
2824

29-
[[categories]]
30-
slug = "games"
25+
[games]
3126
name = "Games"
3227
description = "Share fun things"

0 commit comments

Comments
 (0)