[#2] Database integration complete.
Posts and Authors can now be inserted and retrieved from the database created. It was decided to use a SQLite database for it high read spead and ease of use/maintenance. A build feature was created to seperate how the library is being used. If you are making the database and storing posts, then use the publisher flag. If you are just reading from a database then do not use the publisher flag. This was also set to change the tale contents from a PathBuf to the String of HTML blog data without having to create a whole new data object. An example and a test were made. Test coverage needs to be increased however.
This commit is contained in:
380
Cargo.lock
generated
380
Cargo.lock
generated
@ -2,17 +2,149 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
@ -24,6 +156,65 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
@ -33,6 +224,25 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"getopts",
|
||||
"memchr",
|
||||
"pulldown-cmark-escape",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark-escape"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
@ -42,6 +252,26 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
@ -71,6 +301,18 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
@ -86,6 +328,9 @@ dependencies = [
|
||||
name = "tavern"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"pulldown-cmark",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
@ -129,12 +374,147 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.12"
|
||||
|
||||
11
Cargo.toml
11
Cargo.toml
@ -11,5 +11,16 @@ license = "Apache-2.0"
|
||||
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.41", features = ["serde"] }
|
||||
pulldown-cmark = "0.13.0"
|
||||
rusqlite = "0.37.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
toml = "0.9.5"
|
||||
|
||||
# When switching to PostgreSQL use feature: "sqlx-postgres"
|
||||
#sea-orm = { version = "1.1.14", features = [ "sqlx-sqlite",
|
||||
# "runtime-tokio-native-tls",
|
||||
# "macros" ] }
|
||||
|
||||
[features]
|
||||
publisher = []
|
||||
|
||||
107
examples/generate_database.rs
Normal file
107
examples/generate_database.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
|
||||
use tavern::{Adventurer, Database, Tale, Tavern};
|
||||
|
||||
|
||||
|
||||
fn generate_tavern() -> Tavern
|
||||
{
|
||||
let author: Adventurer =
|
||||
Adventurer { name: String::from("Jason Smith"),
|
||||
handle: String::from("myrddin"),
|
||||
profile:
|
||||
String::from("https://cybermages.tech/about/myrddin"),
|
||||
image:
|
||||
String::from("https://cybermages.tech/about/myrddin/pic"),
|
||||
blurb: String::from("I love code!") };
|
||||
|
||||
let tale: Tale =
|
||||
Tale { title: String::from("Test post"),
|
||||
slug: String::from("test_post"),
|
||||
author: author.handle.clone(),
|
||||
summary: String::from("The Moon is made of cheese!"),
|
||||
tags: vec![String::from("Space"), String::from("Cheese")],
|
||||
publish_date: NaiveDate::from_ymd_opt(2025, 12, 25).unwrap().and_hms_opt(13, 10, 41).unwrap(),
|
||||
content: PathBuf::from("posts/test_post.md") };
|
||||
|
||||
|
||||
// Create a dummy posts directory and file for this example to work
|
||||
if !Path::new("posts").exists()
|
||||
{
|
||||
std::fs::create_dir("posts").unwrap();
|
||||
}
|
||||
std::fs::write("posts/the-rustacean.md",
|
||||
"# Hello, Rust!\n\nThis is a **test** post.").unwrap();
|
||||
|
||||
|
||||
Tavern { title: String::from("Runes & Ramblings"),
|
||||
description: String::from("Join software engineer Jason Smith on his Rust programming journey. Explore program design, tech stacks, and more on this blog from CybeMages, LLC."),
|
||||
tales: vec![tale],
|
||||
authors: vec![author] }
|
||||
}
|
||||
|
||||
|
||||
fn read_from_file<P>(config_file: P) -> Tavern
|
||||
where P: AsRef<Path>
|
||||
{
|
||||
// Read the previously written TOML file
|
||||
let toml_data =
|
||||
std::fs::read_to_string(&config_file).expect("Failed to read TOML file");
|
||||
|
||||
// Deserialize it
|
||||
toml::from_str(&toml_data).expect("Failed to parse TOML")
|
||||
}
|
||||
|
||||
|
||||
fn create_database() -> Result<(), Box<dyn std::error::Error>>
|
||||
{
|
||||
// This part would be the entry point of your CI/CD script
|
||||
// It would load your data and then save it to the database
|
||||
|
||||
// Create a Tavern object
|
||||
let tavern = read_from_file("Tavern.toml");
|
||||
//let tavern = generate_tavern();
|
||||
|
||||
// Open the database and save the Tavern content
|
||||
let db = Database::open(Path::new("tavern.db"))?;
|
||||
|
||||
db.insert_tavern(&tavern.title, &tavern.description)?;
|
||||
println!("Saved site settings: Title='{}', Description='{}'", tavern.title, tavern.description);
|
||||
|
||||
for author in &tavern.authors
|
||||
{
|
||||
db.insert_adventurer(author)?;
|
||||
println!("Saved adventurer: {}", author.name);
|
||||
}
|
||||
|
||||
for tale in &tavern.tales
|
||||
{
|
||||
db.insert_tale(tale)?;
|
||||
println!("Saved tale: {}", tale.title);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main()
|
||||
{
|
||||
match std::env::set_current_dir("/home/myrddin/cybermages/blog/")
|
||||
{
|
||||
Ok(_) =>
|
||||
{
|
||||
println!("Successfully changed working directory.");
|
||||
}
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("Failed to change directory: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
match create_database()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => { eprintln!("Error: {}", e); }
|
||||
}
|
||||
}
|
||||
@ -12,13 +12,16 @@ pub struct Adventurer
|
||||
/// The full name of the adventurer.
|
||||
pub name: String,
|
||||
|
||||
/// A unique handle or username for the adventurer (e.g., used in URLs or mentions).
|
||||
/// A unique handle or username for the adventurer (e.g., used in URLs or
|
||||
/// mentions).
|
||||
pub handle: String,
|
||||
|
||||
/// A link to the adventurer's profile (e.g., personal website, GitHub, etc.).
|
||||
/// A link to the adventurer's profile (e.g., personal website, GitHub,
|
||||
/// etc.).
|
||||
pub profile: String,
|
||||
|
||||
/// A URL or path to an image representing the adventurer (e.g., avatar or portrait).
|
||||
/// A URL or path to an image representing the adventurer (e.g., avatar or
|
||||
/// portrait).
|
||||
pub image: String,
|
||||
|
||||
/// A short descriptive text or tagline about the adventurer.
|
||||
@ -27,6 +30,4 @@ pub struct Adventurer
|
||||
|
||||
|
||||
|
||||
impl Adventurer
|
||||
{
|
||||
}
|
||||
impl Adventurer {}
|
||||
|
||||
83
src/converter.rs
Normal file
83
src/converter.rs
Normal file
@ -0,0 +1,83 @@
|
||||
//use std::io::Write;
|
||||
|
||||
use pulldown_cmark::{html, Parser};
|
||||
|
||||
|
||||
pub enum Converter {}
|
||||
|
||||
|
||||
|
||||
impl Converter
|
||||
{
|
||||
/*
|
||||
/// Public function to handle file-to-file conversion
|
||||
pub fn md_to_html(markdown_path: &std::path::Path,
|
||||
html_path: &std::path::Path)
|
||||
-> std::io::Result<()>
|
||||
{
|
||||
let markdown_content = std::fs::read_to_string(markdown_path)?;
|
||||
let html_output = Self::markdown_to_html(&markdown_content);
|
||||
let mut html_file = std::fs::File::create(html_path)?;
|
||||
|
||||
html_file.write_all(html_output.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
/// Private function to handle the core conversion logic
|
||||
pub fn markdown_to_html(markdown_content: &str) -> String
|
||||
{
|
||||
let parser = Parser::new(markdown_content);
|
||||
let mut html_output = String::new();
|
||||
html::push_html(&mut html_output, parser);
|
||||
html_output
|
||||
}
|
||||
}
|
||||
|
||||
// tests/integration_test.rs
|
||||
// This file would be in your project's `tests` directory.
|
||||
// It tests the public functions of your main program.
|
||||
// You will also need to add `use crate::*` to access the functions.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use super::*; // Import the parent module's items
|
||||
|
||||
#[test]
|
||||
fn test_markdown_conversion_with_files()
|
||||
{
|
||||
let test_dir = Path::new("temp_test_dir");
|
||||
let temp_md_path = test_dir.join("test.md");
|
||||
let temp_html_path = test_dir.join("test.html");
|
||||
|
||||
// Ensure the test directory is clean
|
||||
if test_dir.exists()
|
||||
{
|
||||
fs::remove_dir_all(&test_dir).unwrap();
|
||||
}
|
||||
fs::create_dir(&test_dir).unwrap();
|
||||
|
||||
// Create a temporary Markdown file for the test
|
||||
let markdown_content = "# Hello, World!\n\nThis is a **test**.";
|
||||
let expected_html =
|
||||
"<h1>Hello, World!</h1>\n<p>This is a <strong>test</strong>.</p>\n";
|
||||
|
||||
let mut temp_md_file = fs::File::create(&temp_md_path).unwrap();
|
||||
temp_md_file.write_all(markdown_content.as_bytes()).unwrap();
|
||||
|
||||
// Use the new Converter API
|
||||
Converter::md_to_html(&temp_md_path, &temp_html_path).unwrap();
|
||||
let converted_html = fs::read_to_string(&temp_html_path).unwrap();
|
||||
|
||||
// Assert that the output matches the expected HTML
|
||||
assert_eq!(converted_html.trim(), expected_html.trim());
|
||||
|
||||
// Clean up the temporary directory after the test
|
||||
fs::remove_dir_all(&test_dir).unwrap();
|
||||
}
|
||||
}
|
||||
309
src/database.rs
Normal file
309
src/database.rs
Normal file
@ -0,0 +1,309 @@
|
||||
// The connection strings are:
|
||||
// PostgreSQL - "postgres://root:root@localhost:5432"
|
||||
// SQLite - "sqlite::memory:"
|
||||
// const DATABASE_URL: &str = "sqlite::memory:";
|
||||
// const DB_NAME: &str = "cm_tavern_db";
|
||||
use std::path::Path;
|
||||
|
||||
use rusqlite::{params, Connection, Result};
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
use rusqlite::Statement;
|
||||
|
||||
use crate::adventurer::Adventurer;
|
||||
#[cfg(feature = "publisher")]
|
||||
use crate::converter::Converter;
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
use crate::tale::FrontMatter;
|
||||
use crate::tale::Tale;
|
||||
|
||||
|
||||
|
||||
pub struct Database
|
||||
{
|
||||
connection: Connection
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Database
|
||||
{
|
||||
/// Opens a connection to the SQLite database and creates the necessary
|
||||
/// tables.
|
||||
pub fn open(db_path: &Path) -> Result<Self>
|
||||
{
|
||||
let connection = Connection::open(db_path)?;
|
||||
|
||||
#[cfg(feature = "publisher")]
|
||||
Self::create_tables(&connection)?;
|
||||
|
||||
Ok(Database { connection })
|
||||
}
|
||||
|
||||
/// Creates the 'tales' and 'adventurers' tables if they don't exist.
|
||||
#[cfg(feature = "publisher")]
|
||||
fn create_tables(conn: &Connection) -> Result<()>
|
||||
{
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS adventurers (
|
||||
handle TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
profile TEXT,
|
||||
image TEXT,
|
||||
blurb TEXT
|
||||
)",
|
||||
[]
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS tales (
|
||||
slug TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
author TEXT NOT NULL,
|
||||
summary TEXT,
|
||||
publish_date TEXT NOT NULL,
|
||||
content TEXT
|
||||
)",
|
||||
[]
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE
|
||||
)",
|
||||
[]
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS tale_tags (
|
||||
tale_slug TEXT,
|
||||
tag_id INTEGER,
|
||||
FOREIGN KEY(tale_slug) REFERENCES tales(slug),
|
||||
FOREIGN KEY(tag_id) REFERENCES tags(id),
|
||||
UNIQUE(tale_slug, tag_id)
|
||||
)",
|
||||
[]
|
||||
)?;
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS tavern (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a single tale into the database.
|
||||
#[cfg(feature = "publisher")]
|
||||
pub fn insert_tale(&self, tale: &Tale) -> Result<()>
|
||||
{
|
||||
// Read the markdown content from the file
|
||||
let markdown_content = std::fs::read_to_string(&tale.content)
|
||||
.map_err(|e| rusqlite::Error::ToSqlConversionFailure(e.into()))?;
|
||||
|
||||
// Convert the markdown to HTML
|
||||
let html_content = Converter::markdown_to_html(&markdown_content);
|
||||
|
||||
self.connection.execute(
|
||||
"INSERT OR REPLACE INTO tales (
|
||||
slug, title, author, summary, publish_date, content
|
||||
) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
|
||||
params![
|
||||
tale.front_matter.slug,
|
||||
tale.front_matter.title,
|
||||
tale.front_matter.author,
|
||||
tale.front_matter.summary,
|
||||
tale.front_matter.publish_date.to_string(),
|
||||
html_content
|
||||
]
|
||||
)?;
|
||||
|
||||
// Insert tags and link them to the tale
|
||||
for tag_name in &tale.front_matter.tags
|
||||
{
|
||||
let tag_id = self.insert_and_get_tag_id(tag_name)?;
|
||||
self.connection.execute("INSERT OR IGNORE INTO tale_tags \
|
||||
(tale_slug, tag_id) VALUES (?1, ?2)",
|
||||
params![tale.front_matter.slug, tag_id])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a tag and returns its ID. If the tag already exists, it returns
|
||||
/// the existing ID.
|
||||
#[cfg(feature = "publisher")]
|
||||
fn insert_and_get_tag_id(&self, tag_name: &str) -> Result<i64>
|
||||
{
|
||||
self.connection
|
||||
.execute("INSERT OR IGNORE INTO tags (name) VALUES (?1)",
|
||||
params![tag_name])?;
|
||||
let id: i64 = self.connection
|
||||
.query_row("SELECT id FROM tags WHERE name = ?1",
|
||||
params![tag_name],
|
||||
|row| row.get(0))?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Inserts a single adventurer into the database.
|
||||
#[cfg(feature = "publisher")]
|
||||
pub fn insert_adventurer(&self, adventurer: &Adventurer) -> Result<()>
|
||||
{
|
||||
self.connection.execute(
|
||||
"INSERT OR REPLACE INTO adventurers (
|
||||
handle, name, profile, image, blurb
|
||||
) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
params![
|
||||
adventurer.handle,
|
||||
adventurer.name,
|
||||
adventurer.profile,
|
||||
adventurer.image,
|
||||
adventurer.blurb
|
||||
]
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts the site-wide settings like title and description.
|
||||
#[cfg(feature = "publisher")]
|
||||
pub fn insert_tavern(&self, title: &str, description: &str) -> Result<()> {
|
||||
self.connection.execute_batch(&format!(
|
||||
"BEGIN;
|
||||
INSERT OR REPLACE INTO tavern (key, value) VALUES ('title', '{}');
|
||||
INSERT OR REPLACE INTO tavern (key, value) VALUES ('description', '{}');
|
||||
COMMIT;",
|
||||
title, description
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fetches a vector of lightweight FrontMatter objects from the database.
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
pub fn get_tales_summary(&self, categories: &[String]) -> Result<Vec<FrontMatter>> {
|
||||
let mut query = String::from(
|
||||
"SELECT
|
||||
t.title,
|
||||
t.slug,
|
||||
t.summary,
|
||||
t.author,
|
||||
t.publish_date,
|
||||
GROUP_CONCAT(tg.name, ',') AS tags
|
||||
FROM tales AS t
|
||||
JOIN tale_tags AS tt ON t.slug = tt.tale_slug
|
||||
JOIN tags AS tg ON tt.tag_id = tg.id"
|
||||
);
|
||||
|
||||
// If categories are provided, filter the results
|
||||
if !categories.is_empty() {
|
||||
query.push_str(" WHERE tg.name IN (");
|
||||
// Add a placeholder for each category
|
||||
let placeholders: Vec<_> = (0..categories.len()).map(|_| "?").collect();
|
||||
query.push_str(&placeholders.join(", "));
|
||||
query.push_str(")");
|
||||
}
|
||||
|
||||
// Group by tale to get all tags for each tale
|
||||
query.push_str(" GROUP BY t.slug");
|
||||
|
||||
query.push_str(" ORDER BY t.publish_date DESC");
|
||||
|
||||
let mut stmt: Statement = self.connection.prepare(&query)?;
|
||||
|
||||
let tales_iter = stmt.query_map(rusqlite::params_from_iter(categories), |row| {
|
||||
let date_str: String = row.get(4)?;
|
||||
let tags_str: String = row.get(5)?;
|
||||
let tags: Vec<String> = tags_str.split(',').map(|s| s.to_string()).collect();
|
||||
Ok(FrontMatter {
|
||||
title: row.get(0)?,
|
||||
slug: row.get(1)?,
|
||||
summary: row.get(2)?,
|
||||
author: row.get(3)?,
|
||||
publish_date: chrono::NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S").map_err(|e| rusqlite::Error::ToSqlConversionFailure(e.into()))?,
|
||||
tags,
|
||||
})
|
||||
})?;
|
||||
|
||||
let summaries: Result<Vec<_>, _> = tales_iter.collect();
|
||||
summaries
|
||||
}
|
||||
|
||||
/// Fetches a single tale from the database by its slug.
|
||||
/// This function is only available in the 'reader' build.
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
pub fn get_tale_by_slug(&self, slug: &str) -> Result<Option<Tale>> {
|
||||
let query = String::from(
|
||||
"SELECT
|
||||
t.title,
|
||||
t.slug,
|
||||
t.summary,
|
||||
t.author,
|
||||
t.publish_date,
|
||||
t.content,
|
||||
GROUP_CONCAT(tg.name, ',') AS tags
|
||||
FROM tales AS t
|
||||
LEFT JOIN tale_tags AS tt ON t.slug = tt.tale_slug
|
||||
LEFT JOIN tags AS tg ON tt.tag_id = tg.id
|
||||
WHERE t.slug = ?1
|
||||
GROUP BY t.slug"
|
||||
);
|
||||
|
||||
// Prepare the statement and execute a query for a single row.
|
||||
let result = self.connection.query_row(
|
||||
&query,
|
||||
params![slug],
|
||||
|row| {
|
||||
// Parse the tags string into a vector of strings.
|
||||
let tags_str: Option<String> = row.get(6)?;
|
||||
let tags = tags_str.map(|s| s.split(',').map(|tag| tag.to_string()).collect()).unwrap_or_default();
|
||||
|
||||
// Parse the date string into a NaiveDateTime.
|
||||
let date_str: String = row.get(4)?;
|
||||
let publish_date = chrono::NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%dT%H:%M:%S")
|
||||
.map_err(|e| rusqlite::Error::ToSqlConversionFailure(e.into()))?;
|
||||
|
||||
// Construct the FrontMatter and the full Tale struct.
|
||||
Ok(Tale {
|
||||
front_matter: FrontMatter {
|
||||
title: row.get(0)?,
|
||||
slug: row.get(1)?,
|
||||
summary: row.get(2)?,
|
||||
author: row.get(3)?,
|
||||
publish_date,
|
||||
tags,
|
||||
},
|
||||
content: row.get(5)?,
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
// Handle the result: if no rows were returned, return `None`.
|
||||
match result {
|
||||
Ok(tale) => Ok(Some(tale)),
|
||||
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches a single adventurer from the database by their handle.
|
||||
/// This function is only available in the 'reader' build.
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
pub fn get_adventurer(&self, handle: &str) -> Result<Option<Adventurer>> {
|
||||
let result = self.connection.query_row(
|
||||
"SELECT handle, name, profile, image, blurb FROM adventurers WHERE handle = ?1",
|
||||
params![handle],
|
||||
|row| {
|
||||
Ok(Adventurer {
|
||||
handle: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
profile: row.get(2)?,
|
||||
image: row.get(3)?,
|
||||
blurb: row.get(4)?,
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(adventurer) => Ok(Some(adventurer)),
|
||||
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/lib.rs
10
src/lib.rs
@ -1,15 +1,19 @@
|
||||
//! A blogging system that will allow you to write your blog in Markdown and then display it in HTML using Dioxus.
|
||||
//! A blogging system that will allow you to write your blog in Markdown and
|
||||
//! then display it in HTML using Dioxus.
|
||||
|
||||
mod info;
|
||||
|
||||
mod adventurer;
|
||||
#[cfg(feature = "publisher")]
|
||||
mod converter;
|
||||
mod database;
|
||||
mod tale;
|
||||
mod tavern;
|
||||
|
||||
|
||||
|
||||
pub use crate::info::{get_name, get_version};
|
||||
|
||||
pub use crate::adventurer::Adventurer;
|
||||
pub use crate::database::Database;
|
||||
pub use crate::info::{get_name, get_version};
|
||||
pub use crate::tale::Tale;
|
||||
pub use crate::tavern::Tavern;
|
||||
|
||||
39
src/tale.rs
39
src/tale.rs
@ -1,18 +1,27 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
|
||||
|
||||
|
||||
/// A type alias representing the path to a Markdown file.
|
||||
/// This type is used to point to the location of the content of a `Tale`.
|
||||
#[cfg(feature = "publisher")]
|
||||
pub type Markdown = std::path::PathBuf;
|
||||
|
||||
|
||||
/// Represents a post or story in the application.
|
||||
/// A type alias representing the HTML content of the tale.
|
||||
#[cfg(not(feature = "publisher"))]
|
||||
pub type Markdown = String;
|
||||
|
||||
|
||||
|
||||
/// Metadata describing a tale.
|
||||
///
|
||||
/// A `Tale` contains metadata about the post such as its title, author,
|
||||
/// and tags, along with a path to its Markdown content.
|
||||
/// This includes details such as the title, author, summary, and
|
||||
/// associated tags.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Tale
|
||||
pub struct FrontMatter
|
||||
{
|
||||
/// The title of the tale.
|
||||
pub title: String,
|
||||
@ -26,15 +35,23 @@ pub struct Tale
|
||||
/// A short summary or description of the tale.
|
||||
pub summary: String,
|
||||
|
||||
/// A list of tags associated with the tale for categorization and searching.
|
||||
/// A list of tags associated with the tale for categorization and
|
||||
/// searching.
|
||||
pub tags: Vec<String>,
|
||||
|
||||
/// The Date and Time that must elapse before this tale can be told.
|
||||
pub publish_date: NaiveDateTime
|
||||
}
|
||||
|
||||
|
||||
/// Represents a post or story in the application.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Tale
|
||||
{
|
||||
/// Metadata of the post.
|
||||
#[serde(flatten)]
|
||||
pub front_matter: FrontMatter,
|
||||
|
||||
/// The file path to the Markdown content of the tale.
|
||||
pub content: Markdown
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Tale
|
||||
{
|
||||
}
|
||||
|
||||
@ -7,11 +7,18 @@ use crate::tale::Tale;
|
||||
|
||||
/// Represents the entire blog or collection of content.
|
||||
///
|
||||
/// A `Tavern` contains a list of all tales (posts) and their respective authors.
|
||||
/// It serves as the central structure for organizing and serializing the site's content.
|
||||
/// A `Tavern` contains a list of all tales (posts) and their respective
|
||||
/// authors. It serves as the central structure for organizing and serializing
|
||||
/// the site's content.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Tavern
|
||||
{
|
||||
///
|
||||
pub title: String,
|
||||
|
||||
///
|
||||
pub description: String,
|
||||
|
||||
/// A list of all published tales (posts) in the tavern.
|
||||
pub tales: Vec<Tale>,
|
||||
|
||||
|
||||
@ -1,31 +1,36 @@
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
|
||||
use tavern::{Adventurer, Tale, Tavern};
|
||||
|
||||
|
||||
|
||||
fn generate_tavern() -> Tavern
|
||||
{
|
||||
let author: Adventurer = Adventurer
|
||||
{
|
||||
name: String::from("Jason Smith"),
|
||||
handle: String::from("myrddin"),
|
||||
profile: String::from("https://cybermages.tech/about/myrddin"),
|
||||
image: String::from("https://cybermages.tech/about/myrddin/pic"),
|
||||
blurb: String::from("I love code!")
|
||||
};
|
||||
let author: Adventurer =
|
||||
Adventurer { name: String::from("Jason Smith"),
|
||||
handle: String::from("myrddin"),
|
||||
profile:
|
||||
String::from("https://cybermages.tech/about/myrddin"),
|
||||
image:
|
||||
String::from("https://cybermages.tech/about/myrddin/pic"),
|
||||
blurb: String::from("I love code!") };
|
||||
|
||||
let tale: Tale = Tale
|
||||
{
|
||||
title: String::from("Test post"),
|
||||
slug: String::from("test_post"),
|
||||
author: author.handle.clone(),
|
||||
summary: String::from("The Moon is made of cheese!"),
|
||||
tags: vec![String::from("Space"), String::from("Cheese")],
|
||||
content: std::path::PathBuf::from("posts/test_post.md")
|
||||
};
|
||||
let tale: Tale =
|
||||
Tale { title: String::from("Test post"),
|
||||
slug: String::from("test_post"),
|
||||
author: author.handle.clone(),
|
||||
summary: String::from("The Moon is made of cheese!"),
|
||||
tags: vec![String::from("Space"), String::from("Cheese")],
|
||||
publish_date: NaiveDate::from_ymd_opt(2025, 12, 25).unwrap().and_hms_opt(13, 10, 41).unwrap(),
|
||||
content: std::path::PathBuf::from("posts/test_post.md") };
|
||||
|
||||
Tavern { tales: vec![tale], authors: vec![author]}
|
||||
Tavern { title: String::from("Runes & Ramblings"),
|
||||
description: String::from("Join software engineer Jason Smith on his Rust programming journey. Explore program design, tech stacks, and more on this blog from CybeMages, LLC."),
|
||||
tales: vec![tale],
|
||||
authors: vec![author] }
|
||||
}
|
||||
|
||||
|
||||
fn cleanup_temp_file(path: &std::path::PathBuf)
|
||||
{
|
||||
if path.exists()
|
||||
@ -40,14 +45,14 @@ fn to_file()
|
||||
{
|
||||
let tavern = generate_tavern();
|
||||
|
||||
let toml_string = toml::to_string_pretty(&tavern)
|
||||
.expect("Serialization to TOML should succeed");
|
||||
let toml_string = toml::to_string_pretty(&tavern).expect("Serialization \
|
||||
to TOML should \
|
||||
succeed");
|
||||
|
||||
// Save the TOML to a temporary file.
|
||||
let mut path = std::env::temp_dir();
|
||||
path.push("tavern_test_out.toml");
|
||||
std::fs::write(&path, &toml_string)
|
||||
.expect("Failed to write TOML to file");
|
||||
std::fs::write(&path, &toml_string).expect("Failed to write TOML to file");
|
||||
|
||||
cleanup_temp_file(&path);
|
||||
}
|
||||
@ -57,22 +62,22 @@ fn from_file()
|
||||
{
|
||||
let tavern = generate_tavern();
|
||||
|
||||
let toml_string = toml::to_string_pretty(&tavern)
|
||||
.expect("Serialization to TOML should succeed");
|
||||
let toml_string = toml::to_string_pretty(&tavern).expect("Serialization \
|
||||
to TOML should \
|
||||
succeed");
|
||||
|
||||
// Save the TOML to a temporary file.
|
||||
let mut path = std::env::temp_dir();
|
||||
path.push("tavern_test_in.toml");
|
||||
std::fs::write(&path, &toml_string)
|
||||
.expect("Failed to write TOML to file");
|
||||
std::fs::write(&path, &toml_string).expect("Failed to write TOML to file");
|
||||
|
||||
// Read the previously written TOML file
|
||||
let toml_data = std::fs::read_to_string(&path)
|
||||
.expect("Failed to read TOML file");
|
||||
let toml_data =
|
||||
std::fs::read_to_string(&path).expect("Failed to read TOML file");
|
||||
|
||||
// Deserialize it
|
||||
let tavern: Tavern = toml::from_str(&toml_data)
|
||||
.expect("Failed to parse TOML");
|
||||
let tavern: Tavern =
|
||||
toml::from_str(&toml_data).expect("Failed to parse TOML");
|
||||
|
||||
// Assert some known values to make this a real test
|
||||
let tale = &tavern.tales[0];
|
||||
|
||||
Reference in New Issue
Block a user