@@ -2,12 +2,16 @@ | |||||
name = "gutenberg" | name = "gutenberg" | ||||
version = "0.1.0" | version = "0.1.0" | ||||
dependencies = [ | dependencies = [ | ||||
"clap 2.19.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", | "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | "error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", | "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"serde_derive 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"tera 0.4.1 (git+https://github.com/Keats/tera.git?branch=v0.5)", | "tera 0.4.1 (git+https://github.com/Keats/tera.git?branch=v0.5)", | ||||
"toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | "walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -66,7 +70,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
[[package]] | [[package]] | ||||
name = "clap" | name = "clap" | ||||
version = "2.19.1" | |||||
version = "2.19.2" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
dependencies = [ | dependencies = [ | ||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", | "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -95,7 +99,7 @@ dependencies = [ | |||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", | "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", | "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -219,6 +223,11 @@ name = "quine-mc_cluskey" | |||||
version = "0.2.4" | version = "0.2.4" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
[[package]] | |||||
name = "quote" | |||||
version = "0.3.10" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
[[package]] | [[package]] | ||||
name = "regex" | name = "regex" | ||||
version = "0.1.80" | version = "0.1.80" | ||||
@@ -243,7 +252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
[[package]] | [[package]] | ||||
name = "rustc-serialize" | name = "rustc-serialize" | ||||
version = "0.3.21" | |||||
version = "0.3.22" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
[[package]] | [[package]] | ||||
@@ -259,9 +268,35 @@ name = "serde" | |||||
version = "0.8.19" | version = "0.8.19" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
[[package]] | |||||
name = "serde_codegen" | |||||
version = "0.8.19" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
dependencies = [ | |||||
"quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"serde_codegen_internals 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"syn 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | |||||
[[package]] | |||||
name = "serde_codegen_internals" | |||||
version = "0.11.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
dependencies = [ | |||||
"syn 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | |||||
[[package]] | |||||
name = "serde_derive" | |||||
version = "0.8.19" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
dependencies = [ | |||||
"serde_codegen 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "serde_json" | name = "serde_json" | ||||
version = "0.8.3" | |||||
version = "0.8.4" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
dependencies = [ | dependencies = [ | ||||
"dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -283,10 +318,19 @@ name = "strsim" | |||||
version = "0.5.2" | version = "0.5.2" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
[[package]] | |||||
name = "syn" | |||||
version = "0.10.3" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
dependencies = [ | |||||
"quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "tera" | name = "tera" | ||||
version = "0.4.1" | version = "0.4.1" | ||||
source = "git+https://github.com/Keats/tera.git?branch=v0.5#85b6fb3723469cb9ec06e63aa80f48348d4ece73" | |||||
source = "git+https://github.com/Keats/tera.git?branch=v0.5#6fc3c61fc58c010abc26f3272badea1b9bc13963" | |||||
dependencies = [ | dependencies = [ | ||||
"error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | "error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -295,7 +339,7 @@ dependencies = [ | |||||
"pest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | "pest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", | "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"serde_json 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | "slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | "url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
] | ] | ||||
@@ -332,7 +376,7 @@ name = "toml" | |||||
version = "0.1.30" | version = "0.1.30" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
dependencies = [ | dependencies = [ | ||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | ] | ||||
[[package]] | [[package]] | ||||
@@ -366,6 +410,11 @@ name = "unicode-width" | |||||
version = "0.1.3" | version = "0.1.3" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
[[package]] | |||||
name = "unicode-xid" | |||||
version = "0.0.3" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
[[package]] | [[package]] | ||||
name = "unidecode" | name = "unidecode" | ||||
version = "0.2.0" | version = "0.2.0" | ||||
@@ -417,7 +466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" | "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" | ||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" | ||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" | "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" | ||||
"checksum clap 2.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "956cee0b2427dd9e71129a509d1ef17a7f5df9f8253924074d7a5d79bc61851e" | |||||
"checksum clap 2.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "305ad043f009db535a110200541d4567b63e172b1fe030313fbb92565da7ed24" | |||||
"checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32" | "checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32" | ||||
"checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a" | "checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a" | ||||
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" | "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" | ||||
@@ -439,15 +488,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
"checksum pest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6666c81a6359af7a9dbc48f596d6f318a9dbaefdec248581ab836dc0c1f082" | "checksum pest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6666c81a6359af7a9dbc48f596d6f318a9dbaefdec248581ab836dc0c1f082" | ||||
"checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" | "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" | ||||
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" | "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" | ||||
"checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be" | |||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" | "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" | ||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" | "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" | ||||
"checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc" | "checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc" | ||||
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818" | |||||
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" | |||||
"checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f" | "checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f" | ||||
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5" | "checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5" | ||||
"checksum serde_json 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1cb6b19e74d9f65b9d03343730b643d729a446b29376785cd65efdff4675e2fc" | |||||
"checksum serde_codegen 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ce29a6ae259579707650ec292199b5fed2c0b8e2a4bdc994452d24d1bcf2242a" | |||||
"checksum serde_codegen_internals 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "59933a62554548c690d2673c5164f0c4a46be7c5731edfd94b0ecb1048940732" | |||||
"checksum serde_derive 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b541549c4207d3602c9abcc3e31252e91751674264eb85c103bb20197054b4" | |||||
"checksum serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7d3c184d35801fb8b32b46a7d58d57dbcc150b0eb2b46a1eb79645e8ecfd5b" | |||||
"checksum slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f5ff4b43cb07b86c5f9236c92714a22cdf9e5a27a7d85e398e2c9403328cb8" | "checksum slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f5ff4b43cb07b86c5f9236c92714a22cdf9e5a27a7d85e398e2c9403328cb8" | ||||
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" | "checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" | ||||
"checksum syn 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94e7d81ecd16d39f16193af05b8d5a0111b9d8d2f3f78f31760f327a247da777" | |||||
"checksum tera 0.4.1 (git+https://github.com/Keats/tera.git?branch=v0.5)" = "<none>" | "checksum tera 0.4.1 (git+https://github.com/Keats/tera.git?branch=v0.5)" = "<none>" | ||||
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0" | "checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0" | ||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" | "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" | ||||
@@ -458,6 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" | "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" | ||||
"checksum unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3bc443ded17b11305ffffe6b37e2076f328a5a8cb6aa877b1b98f77699e98b5" | "checksum unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3bc443ded17b11305ffffe6b37e2076f328a5a8cb6aa877b1b98f77699e98b5" | ||||
"checksum unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6722facc10989f63ee0e20a83cd4e1714a9ae11529403ac7e0afd069abc39e" | "checksum unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6722facc10989f63ee0e20a83cd4e1714a9ae11529403ac7e0afd069abc39e" | ||||
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" | |||||
"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2" | "checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2" | ||||
"checksum url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "48ccf7bd87a81b769cf84ad556e034541fb90e1cd6d4bc375c822ed9500cd9d7" | "checksum url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "48ccf7bd87a81b769cf84ad556e034541fb90e1cd6d4bc375c822ed9500cd9d7" | ||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" | "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" | ||||
@@ -16,6 +16,10 @@ walkdir = "1" | |||||
pulldown-cmark = "0" | pulldown-cmark = "0" | ||||
regex = "0.1" | regex = "0.1" | ||||
lazy_static = "0.2" | lazy_static = "0.2" | ||||
glob = "0.2" | |||||
serde = "0.8" | |||||
serde_json = "0.8" | |||||
serde_derive = "0.8" | |||||
tera = { git = "https://github.com/Keats/tera.git", branch = "v0.5" } | tera = { git = "https://github.com/Keats/tera.git", branch = "v0.5" } | ||||
clippy = {version = "~0.0.103", optional = true} | clippy = {version = "~0.0.103", optional = true} | ||||
@@ -0,0 +1,35 @@ | |||||
# Gutenberg | |||||
## Design | |||||
Can be used for blogs or general static pages | |||||
Commands: | |||||
- new: start a new project -> creates the structure + default config.toml | |||||
- build: reads all the .md files and build the site with template | |||||
- serve: starts a server and watches/reload the site on change | |||||
All pages go into the `content` folder. Subfolder represents a list of content, ie | |||||
```bash | |||||
├── content | |||||
│  ├── posts | |||||
│  │  └── intro.md | |||||
│  └── some.md | |||||
``` | |||||
`some.md` will be accessible at `mywebsite.com/some` and there will be other pages: | |||||
- `mywebsite.com/posts` that will list all the pages contained in the `posts` folder | |||||
- `mywebsite.com/posts/intro` | |||||
### Building the site | |||||
Get all .md files in content, remove the `content/` prefix to their path | |||||
Split the file between front matter and content | |||||
Parse the front matter | |||||
markdown -> HTML for the content | |||||
TO THINK OF: create list pages for folders, can be done while globbing I guess? | |||||
Render templates |
@@ -1,12 +1,28 @@ | |||||
use glob::glob; | |||||
use tera::Tera; | |||||
use config:: Config; | use config:: Config; | ||||
use errors::{Result}; | |||||
use tera::Tera; | |||||
use errors::{Result, ResultExt}; | |||||
use page::Page; | |||||
pub fn build(config: Config) -> Result<()> { | pub fn build(config: Config) -> Result<()> { | ||||
let tera = Tera::new("layouts/**/*").chain_err(|| "Error parsing templates")?; | |||||
let mut pages: Vec<Page> = vec![]; | |||||
// hardcoded pattern so can't error | |||||
for entry in glob("content/**/*.md").unwrap().filter_map(|e| e.ok()) { | |||||
let path = entry.as_path(); | |||||
// Remove the content string from name | |||||
let filepath = path.to_string_lossy().replace("content/", ""); | |||||
pages.push(Page::from_file(&filepath)?); | |||||
} | |||||
for page in pages { | |||||
let html = page.render_html(&tera, &config) | |||||
.chain_err(|| format!("Failed to render '{}'", page.filepath))?; | |||||
} | |||||
Ok(()) | Ok(()) | ||||
} | } |
@@ -3,7 +3,7 @@ use std::io::prelude::*; | |||||
use std::fs::{create_dir, File}; | use std::fs::{create_dir, File}; | ||||
use std::path::Path; | use std::path::Path; | ||||
use errors::{Result, ErrorKind}; | |||||
use errors::Result; | |||||
const CONFIG: &'static str = r#" | const CONFIG: &'static str = r#" | ||||
@@ -5,13 +5,14 @@ use std::path::Path; | |||||
use toml::Parser; | use toml::Parser; | ||||
use errors::{Result, ErrorKind}; | |||||
use errors::{Result, ErrorKind, ResultExt}; | |||||
#[derive(Debug, PartialEq)] | |||||
#[derive(Debug, PartialEq, Serialize, Deserialize)] | |||||
pub struct Config { | pub struct Config { | ||||
pub title: String, | pub title: String, | ||||
pub base_url: String, | pub base_url: String, | ||||
pub theme: String, | |||||
pub favicon: Option<String>, | pub favicon: Option<String>, | ||||
} | } | ||||
@@ -21,6 +22,7 @@ impl Default for Config { | |||||
Config { | Config { | ||||
title: "".to_string(), | title: "".to_string(), | ||||
base_url: "".to_string(), | base_url: "".to_string(), | ||||
theme: "".to_string(), | |||||
favicon: None, | favicon: None, | ||||
} | } | ||||
@@ -55,12 +57,15 @@ impl Config { | |||||
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { | pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { | ||||
let mut content = String::new(); | let mut content = String::new(); | ||||
File::open(path)?.read_to_string(&mut content)?; | |||||
File::open(path) | |||||
.chain_err(|| "Failed to load config.toml. Are you in the right directory?")? | |||||
.read_to_string(&mut content)?; | |||||
Config::from_str(&content) | Config::from_str(&content) | ||||
} | } | ||||
} | } | ||||
#[cfg(test)] | #[cfg(test)] | ||||
mod tests { | mod tests { | ||||
use super::{Config}; | use super::{Config}; | ||||
@@ -1,14 +1,16 @@ | |||||
use tera; | |||||
error_chain! { | error_chain! { | ||||
links { | |||||
Tera(tera::Error, tera::ErrorKind); | |||||
} | |||||
foreign_links { | foreign_links { | ||||
Io(::std::io::Error); | Io(::std::io::Error); | ||||
} | } | ||||
errors { | errors { | ||||
InvalidFrontMatter(name: String) { | |||||
description("frontmatter is invalid") | |||||
display("Front Matter of file '{}' is missing or is invalid", name) | |||||
} | |||||
InvalidConfig { | InvalidConfig { | ||||
description("invalid config") | description("invalid config") | ||||
display("The config.toml is invalid or is using the wrong type for an argument") | display("The config.toml is invalid or is using the wrong type for an argument") | ||||
@@ -0,0 +1,185 @@ | |||||
use std::collections::BTreeMap; | |||||
use toml::{Parser, Value as TomlValue}; | |||||
use tera::{Value, to_value}; | |||||
use errors::{Result}; | |||||
use page::Page; | |||||
// Converts from one value (Toml) to another (Tera) | |||||
// Used to fill the Page::extra map | |||||
fn toml_to_tera(val: &TomlValue) -> Value { | |||||
match *val { | |||||
TomlValue::String(ref s) | TomlValue::Datetime(ref s) => to_value(s), | |||||
TomlValue::Boolean(ref b) => to_value(b), | |||||
TomlValue::Integer(ref n) => to_value(n), | |||||
TomlValue::Float(ref n) => to_value(n), | |||||
TomlValue::Array(ref arr) => to_value(&arr.into_iter().map(toml_to_tera).collect::<Vec<_>>()), | |||||
TomlValue::Table(ref table) => { | |||||
to_value(&table.into_iter().map(|(k, v)| { | |||||
(k, toml_to_tera(v)) | |||||
}).collect::<BTreeMap<_, _>>()) | |||||
} | |||||
} | |||||
} | |||||
pub fn parse_front_matter(front_matter: &str, page: &mut Page) -> Result<()> { | |||||
if front_matter.trim() == "" { | |||||
bail!("Front matter of file is missing"); | |||||
} | |||||
let mut parser = Parser::new(&front_matter); | |||||
if let Some(value) = parser.parse() { | |||||
for (key, value) in value.iter() { | |||||
match key.as_str() { | |||||
"title" | "slug" | "url" | "category" | "layout" | "description" => match *value { | |||||
TomlValue::String(ref s) => { | |||||
if key == "title" { | |||||
page.title = s.to_string(); | |||||
} else if key == "slug" { | |||||
page.slug = s.to_string(); | |||||
} else if key == "url" { | |||||
page.url = Some(s.to_string()); | |||||
} else if key == "category" { | |||||
page.category = Some(s.to_string()); | |||||
} else if key == "layout" { | |||||
page.layout = Some(s.to_string()); | |||||
} else if key == "description" { | |||||
page.description = Some(s.to_string()); | |||||
} | |||||
} | |||||
_ => bail!("Field {} should be a string", key) | |||||
}, | |||||
"draft" => match *value { | |||||
TomlValue::Boolean(b) => page.is_draft = b, | |||||
_ => bail!("Field {} should be a boolean", key) | |||||
}, | |||||
"date" => match *value { | |||||
TomlValue::Datetime(ref d) => page.date = Some(d.to_string()), | |||||
_ => bail!("Field {} should be a date", key) | |||||
}, | |||||
"tags" => match *value { | |||||
TomlValue::Array(ref a) => { | |||||
for elem in a { | |||||
if key == "tags" { | |||||
match *elem { | |||||
TomlValue::String(ref s) => page.tags.push(s.to_string()), | |||||
_ => bail!("Tag `{}` should be a string") | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
_ => bail!("Field {} should be an array", key) | |||||
}, | |||||
// extra fields | |||||
_ => { | |||||
page.extra.insert(key.to_string(), toml_to_tera(value)); | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
bail!("Errors parsing front matter: {:?}", parser.errors); | |||||
} | |||||
if page.title == "" || page.slug == "" { | |||||
bail!("Front matter is missing required fields (title, slug or both)"); | |||||
} | |||||
Ok(()) | |||||
} | |||||
#[cfg(test)] | |||||
mod tests { | |||||
use super::{parse_front_matter}; | |||||
use tera::to_value; | |||||
use page::Page; | |||||
#[test] | |||||
fn test_can_parse_a_valid_front_matter() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
slug = "hello-world""#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_ok()); | |||||
assert_eq!(page.title, "Hello".to_string()); | |||||
assert_eq!(page.slug, "hello-world".to_string()); | |||||
} | |||||
#[test] | |||||
fn test_can_parse_tags() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
slug = "hello-world" | |||||
tags = ["rust", "html"]"#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_ok()); | |||||
assert_eq!(page.title, "Hello".to_string()); | |||||
assert_eq!(page.slug, "hello-world".to_string()); | |||||
assert_eq!(page.tags, ["rust".to_string(), "html".to_string()]); | |||||
} | |||||
#[test] | |||||
fn test_can_parse_extra_attributes_in_frontmatter() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
slug = "hello-world" | |||||
language = "en" | |||||
authors = ["Bob", "Alice"]"#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_ok()); | |||||
assert_eq!(page.title, "Hello".to_string()); | |||||
assert_eq!(page.slug, "hello-world".to_string()); | |||||
assert_eq!(page.extra.get("language").unwrap(), &to_value("en")); | |||||
assert_eq!( | |||||
page.extra.get("authors").unwrap(), | |||||
&to_value(["Bob".to_string(), "Alice".to_string()]) | |||||
); | |||||
} | |||||
#[test] | |||||
fn test_ignores_pages_with_empty_front_matter() { | |||||
let content = r#" "#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_errors_with_invalid_front_matter() { | |||||
let content = r#"title = 1\n"#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_errors_with_missing_required_value_front_matter() { | |||||
let content = r#"title = """#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_errors_on_non_string_tag() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
slug = "hello-world" | |||||
tags = ["rust", 1]"#; | |||||
let mut page = Page::default(); | |||||
let res = parse_front_matter(content, &mut page); | |||||
assert!(res.is_err()); | |||||
} | |||||
} |
@@ -1,19 +1,24 @@ | |||||
// `error_chain!` can recurse deeply | |||||
#![recursion_limit = "1024"] | |||||
#![feature(proc_macro)] | |||||
#[macro_use] extern crate clap; | #[macro_use] extern crate clap; | ||||
#[macro_use] extern crate error_chain; | #[macro_use] extern crate error_chain; | ||||
#[macro_use] extern crate lazy_static; | #[macro_use] extern crate lazy_static; | ||||
#[macro_use] extern crate serde_derive; | |||||
extern crate toml; | extern crate toml; | ||||
extern crate walkdir; | extern crate walkdir; | ||||
extern crate pulldown_cmark; | extern crate pulldown_cmark; | ||||
extern crate regex; | extern crate regex; | ||||
extern crate tera; | extern crate tera; | ||||
extern crate glob; | |||||
mod config; | mod config; | ||||
mod errors; | mod errors; | ||||
mod cmd; | mod cmd; | ||||
mod page; | mod page; | ||||
mod front_matter; | |||||
use config::Config; | use config::Config; | ||||
@@ -58,13 +63,13 @@ fn main() { | |||||
}, | }, | ||||
}; | }; | ||||
}, | }, | ||||
("build", None) => { | |||||
("build", Some(_)) => { | |||||
match cmd::build(get_config()) { | match cmd::build(get_config()) { | ||||
Ok(()) => { | Ok(()) => { | ||||
println!("Project built"); | println!("Project built"); | ||||
}, | }, | ||||
Err(e) => { | Err(e) => { | ||||
println!("Error: {}", e); | |||||
println!("Error: {}", e.iter().nth(1).unwrap().description()); | |||||
::std::process::exit(1); | ::std::process::exit(1); | ||||
}, | }, | ||||
}; | }; | ||||
@@ -1,76 +1,68 @@ | |||||
/// A page, can be a blog post or a basic page | /// A page, can be a blog post or a basic page | ||||
use std::collections::{HashMap, BTreeMap}; | |||||
use std::collections::HashMap; | |||||
use std::default::Default; | use std::default::Default; | ||||
use std::fs::File; | |||||
use std::io::prelude::*; | |||||
// use pulldown_cmark as cmark; | // use pulldown_cmark as cmark; | ||||
use regex::Regex; | use regex::Regex; | ||||
use toml::{Parser, Value as TomlValue}; | |||||
use tera::{Tera, Value, to_value, Context}; | |||||
use tera::{Tera, Value, Context}; | |||||
use errors::{Result}; | |||||
use errors::ErrorKind::InvalidFrontMatter; | |||||
use errors::{Result, ResultExt}; | |||||
use config::Config; | use config::Config; | ||||
use front_matter::parse_front_matter; | |||||
lazy_static! { | lazy_static! { | ||||
static ref DELIM_RE: Regex = Regex::new(r"\+\+\+\s*\r?\n").unwrap(); | static ref DELIM_RE: Regex = Regex::new(r"\+\+\+\s*\r?\n").unwrap(); | ||||
} | } | ||||
// Converts from one value (Toml) to another (Tera) | |||||
// Used to fill the Page::extra map | |||||
fn toml_to_tera(val: &TomlValue) -> Value { | |||||
match *val { | |||||
TomlValue::String(ref s) | TomlValue::Datetime(ref s) => to_value(s), | |||||
TomlValue::Boolean(ref b) => to_value(b), | |||||
TomlValue::Integer(ref n) => to_value(n), | |||||
TomlValue::Float(ref n) => to_value(n), | |||||
TomlValue::Array(ref arr) => to_value(&arr.into_iter().map(toml_to_tera).collect::<Vec<_>>()), | |||||
TomlValue::Table(ref table) => { | |||||
to_value(&table.into_iter().map(|(k, v)| { | |||||
(k, toml_to_tera(v)) | |||||
}).collect::<BTreeMap<_,_>>()) | |||||
} | |||||
} | |||||
} | |||||
#[derive(Debug, PartialEq, Serialize, Deserialize)] | |||||
pub struct Page { | |||||
// .md filepath, excluding the content/ bit | |||||
pub filepath: String, | |||||
#[derive(Debug, PartialEq)] | |||||
struct Page { | |||||
// <title> of the page | // <title> of the page | ||||
title: String, | |||||
// the url the page appears at (slug form) | |||||
url: String, | |||||
pub title: String, | |||||
// The page slug | |||||
pub slug: String, | |||||
// the actual content of the page | // the actual content of the page | ||||
content: String, | |||||
pub content: String, | |||||
// tags, not to be confused with categories | // tags, not to be confused with categories | ||||
tags: Vec<String>, | |||||
pub tags: Vec<String>, | |||||
// whether this page should be public or not | // whether this page should be public or not | ||||
is_draft: bool, | |||||
pub is_draft: bool, | |||||
// any extra parameter present in the front matter | // any extra parameter present in the front matter | ||||
// it will be passed to the template context | // it will be passed to the template context | ||||
extra: HashMap<String, Value>, | |||||
pub extra: HashMap<String, Value>, | |||||
// the url the page appears at, overrides the slug if set | |||||
pub url: Option<String>, | |||||
// only one category allowed | // only one category allowed | ||||
category: Option<String>, | |||||
pub category: Option<String>, | |||||
// optional date if we want to order pages (ie blog post) | // optional date if we want to order pages (ie blog post) | ||||
date: Option<String>, | |||||
pub date: Option<String>, | |||||
// optional layout, if we want to specify which html to render for that page | // optional layout, if we want to specify which html to render for that page | ||||
layout: Option<String>, | |||||
pub layout: Option<String>, | |||||
// description that appears when linked, e.g. on twitter | // description that appears when linked, e.g. on twitter | ||||
description: Option<String>, | |||||
pub description: Option<String>, | |||||
} | } | ||||
impl Default for Page { | impl Default for Page { | ||||
fn default() -> Page { | fn default() -> Page { | ||||
Page { | Page { | ||||
filepath: "".to_string(), | |||||
title: "".to_string(), | title: "".to_string(), | ||||
url: "".to_string(), | |||||
slug: "".to_string(), | |||||
content: "".to_string(), | content: "".to_string(), | ||||
tags: vec![], | tags: vec![], | ||||
is_draft: false, | is_draft: false, | ||||
extra: HashMap::new(), | extra: HashMap::new(), | ||||
url: None, | |||||
category: None, | category: None, | ||||
date: None, | date: None, | ||||
layout: None, | layout: None, | ||||
@@ -84,119 +76,65 @@ impl Page { | |||||
// Parse a page given the content of the .md file | // Parse a page given the content of the .md file | ||||
// Files without front matter or with invalid front matter are considered | // Files without front matter or with invalid front matter are considered | ||||
// erroneous | // erroneous | ||||
pub fn from_str(filename: &str, content: &str) -> Result<Page> { | |||||
pub fn from_str(filepath: &str, content: &str) -> Result<Page> { | |||||
// 1. separate front matter from content | // 1. separate front matter from content | ||||
if !DELIM_RE.is_match(content) { | if !DELIM_RE.is_match(content) { | ||||
return Err(InvalidFrontMatter(filename.to_string()).into()); | |||||
bail!("Couldn't find front matter in `{}`. Did you forget to add `+++`?", filepath); | |||||
} | } | ||||
// 2. extract the front matter and the content | // 2. extract the front matter and the content | ||||
let splits: Vec<&str> = DELIM_RE.splitn(content, 2).collect(); | let splits: Vec<&str> = DELIM_RE.splitn(content, 2).collect(); | ||||
let front_matter = splits[0]; | let front_matter = splits[0]; | ||||
if front_matter.trim() == "" { | |||||
return Err(InvalidFrontMatter(filename.to_string()).into()); | |||||
} | |||||
let content = splits[1]; | let content = splits[1]; | ||||
// 2. create our page, parse front matter and assign all of that | // 2. create our page, parse front matter and assign all of that | ||||
let mut page = Page::default(); | let mut page = Page::default(); | ||||
page.filepath = filepath.to_string(); | |||||
page.content = content.to_string(); | page.content = content.to_string(); | ||||
parse_front_matter(front_matter, &mut page) | |||||
.chain_err(|| format!("Error when parsing front matter of file `{}`", filepath))?; | |||||
// Keeps track of required fields: title, url | |||||
let mut num_required_fields = 2; | |||||
let mut parser = Parser::new(&front_matter); | |||||
if let Some(value) = parser.parse() { | |||||
for (key, value) in value.iter() { | |||||
if key == "title" { | |||||
page.title = value | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))? | |||||
.to_string(); | |||||
num_required_fields -= 1; | |||||
} else if key == "url" { | |||||
page.url = value | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))? | |||||
.to_string(); | |||||
num_required_fields -= 1; | |||||
} else if key == "draft" { | |||||
page.is_draft = value | |||||
.as_bool() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?; | |||||
} else if key == "category" { | |||||
page.category = Some( | |||||
value | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?.to_string() | |||||
); | |||||
} else if key == "layout" { | |||||
page.layout = Some( | |||||
value | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?.to_string() | |||||
); | |||||
} else if key == "description" { | |||||
page.description = Some( | |||||
value | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?.to_string() | |||||
); | |||||
} else if key == "date" { | |||||
page.date = Some( | |||||
value | |||||
.as_datetime() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?.to_string() | |||||
); | |||||
} else if key == "tags" { | |||||
let toml_tags = value | |||||
.as_slice() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))?; | |||||
Ok(page) | |||||
} | |||||
for tag in toml_tags { | |||||
page.tags.push( | |||||
tag | |||||
.as_str() | |||||
.ok_or(InvalidFrontMatter(filename.to_string()))? | |||||
.to_string() | |||||
); | |||||
} | |||||
} else { | |||||
page.extra.insert(key.to_string(), toml_to_tera(value)); | |||||
} | |||||
} | |||||
pub fn from_file(path: &str) -> Result<Page> { | |||||
let mut content = String::new(); | |||||
File::open(path) | |||||
.chain_err(|| format!("Failed to open '{:?}'", path))? | |||||
.read_to_string(&mut content)?; | |||||
} else { | |||||
// TODO: handle error in parsing TOML | |||||
println!("parse errors: {:?}", parser.errors); | |||||
} | |||||
Page::from_str(path, &content) | |||||
} | |||||
if num_required_fields > 0 { | |||||
println!("Not all required fields"); | |||||
return Err(InvalidFrontMatter(filename.to_string()).into()); | |||||
fn get_layout_name(&self) -> String { | |||||
// TODO: handle themes | |||||
match self.layout { | |||||
Some(ref l) => l.to_string(), | |||||
None => "_default/single.html".to_string() | |||||
} | } | ||||
Ok(page) | |||||
} | } | ||||
// pub fn render_html(&self, tera: &Tera, config: &Config) -> Result<String> { | |||||
// | |||||
// } | |||||
pub fn render_html(&self, tera: &Tera, config: &Config) -> Result<String> { | |||||
let tpl = self.get_layout_name(); | |||||
let mut context = Context::new(); | |||||
context.add("site", config); | |||||
context.add("page", self); | |||||
// println!("{:?}", tera); | |||||
tera.render(&tpl, context).chain_err(|| "") | |||||
} | |||||
} | } | ||||
#[cfg(test)] | #[cfg(test)] | ||||
mod tests { | mod tests { | ||||
use super::{Page}; | use super::{Page}; | ||||
use tera::to_value; | |||||
#[test] | #[test] | ||||
fn test_can_parse_a_valid_page() { | fn test_can_parse_a_valid_page() { | ||||
let content = r#" | let content = r#" | ||||
title = "Hello" | title = "Hello" | ||||
url = "hello-world" | |||||
slug = "hello-world" | |||||
+++ | +++ | ||||
Hello world"#; | Hello world"#; | ||||
let res = Page::from_str("", content); | let res = Page::from_str("", content); | ||||
@@ -204,90 +142,8 @@ Hello world"#; | |||||
let page = res.unwrap(); | let page = res.unwrap(); | ||||
assert_eq!(page.title, "Hello".to_string()); | assert_eq!(page.title, "Hello".to_string()); | ||||
assert_eq!(page.url, "hello-world".to_string()); | |||||
assert_eq!(page.slug, "hello-world".to_string()); | |||||
assert_eq!(page.content, "Hello world".to_string()); | assert_eq!(page.content, "Hello world".to_string()); | ||||
} | } | ||||
#[test] | |||||
fn test_can_parse_tags() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
url = "hello-world" | |||||
tags = ["rust", "html"] | |||||
+++ | |||||
Hello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_ok()); | |||||
let page = res.unwrap(); | |||||
assert_eq!(page.title, "Hello".to_string()); | |||||
assert_eq!(page.url, "hello-world".to_string()); | |||||
assert_eq!(page.content, "Hello world".to_string()); | |||||
assert_eq!(page.tags, ["rust".to_string(), "html".to_string()]); | |||||
} | |||||
#[test] | |||||
fn test_can_parse_extra_attributes_in_frontmatter() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
url = "hello-world" | |||||
language = "en" | |||||
authors = ["Bob", "Alice"] | |||||
+++ | |||||
Hello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_ok()); | |||||
let page = res.unwrap(); | |||||
assert_eq!(page.title, "Hello".to_string()); | |||||
assert_eq!(page.url, "hello-world".to_string()); | |||||
assert_eq!(page.extra.get("language").unwrap(), &to_value("en")); | |||||
assert_eq!( | |||||
page.extra.get("authors").unwrap(), | |||||
&to_value(["Bob".to_string(), "Alice".to_string()]) | |||||
); | |||||
} | |||||
#[test] | |||||
fn test_ignore_pages_with_no_front_matter() { | |||||
let content = r#"Hello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_ignores_pages_with_empty_front_matter() { | |||||
let content = r#"+++\nHello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_ignores_pages_with_invalid_front_matter() { | |||||
let content = r#"title = 1\n+++\nHello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_ignores_pages_with_missing_required_value_front_matter() { | |||||
let content = r#" | |||||
title = "" | |||||
+++ | |||||
Hello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_err()); | |||||
} | |||||
#[test] | |||||
fn test_errors_on_non_string_tag() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
url = "hello-world" | |||||
tags = ["rust", 1] | |||||
+++ | |||||
Hello world"#; | |||||
let res = Page::from_str("", content); | |||||
assert!(res.is_err()); | |||||
} | |||||
} | } |