summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers+gitlab@digital-scurf.org>2023-01-28 10:15:25 +0000
committerDaniel Silverstone <dsilvers+gitlab@digital-scurf.org>2023-01-28 10:15:25 +0000
commite1d63019fdd6f0d24703197b6a6029f26e6f089f (patch)
tree82483e5dad773cbf90884716e66a47629aa487fa
parentfa5765189eef33bed301479410c4a53dc274acf0 (diff)
parent387f0b7675fba94115ead348c358c7d3e7638e4c (diff)
downloadsubplot-e1d63019fdd6f0d24703197b6a6029f26e6f089f.tar.gz
Merge branch 'liw/refactor-metadata' into 'main'
refactor: move YamlMetadata to src/metadata.rs See merge request subplot/subplot!306
-rw-r--r--src/ast.rs172
-rw-r--r--src/doc.rs8
-rw-r--r--src/error.rs2
-rw-r--r--src/lib.rs5
-rw-r--r--src/metadata.rs174
5 files changed, 177 insertions, 184 deletions
diff --git a/src/ast.rs b/src/ast.rs
deleted file mode 100644
index ed163f0..0000000
--- a/src/ast.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-use lazy_static::lazy_static;
-use regex::Regex;
-use serde::Deserialize;
-use serde_yaml::Value;
-use std::collections::{BTreeMap, HashMap};
-use std::path::{Path, PathBuf};
-
-lazy_static! {
- // Pattern that recognises a YAML block at the beginning of a file.
- static ref LEADING_YAML_PATTERN: Regex = Regex::new(r"^(?:\S*\n)*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?P<text>(.*\n)*)$").unwrap();
-
-
- // Pattern that recognises a YAML block at the end of a file.
- static ref TRAILING_YAML_PATTERN: Regex = Regex::new(r"(?P<text>(.*\n)*)\n*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?:\S*\n)*$").unwrap();
-}
-
-/// Errors from Markdown parsing.
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
- #[error(transparent)]
- Regex(#[from] regex::Error),
-
- #[error("Markdown doesn't contain a YAML block for document metadata")]
- NoMetadata,
-
- #[error(transparent)]
- Yaml(#[from] serde_yaml::Error),
-}
-
-/// Document metadata.
-///
-/// This is expressed in the Markdown input file as an embedded YAML
-/// block.
-///
-/// Note that this structure needs to be able to capture any metadata
-/// block we can work with, in any input file. By being strict here we
-/// make it easier to tell the user when a metadata block has, say, a
-/// misspelled field.
-#[derive(Debug, Default, Clone, Deserialize)]
-#[serde(deny_unknown_fields)]
-pub struct YamlMetadata {
- title: String,
- subtitle: Option<String>,
- authors: Option<Vec<String>>,
- date: Option<String>,
- classes: Option<Vec<String>>,
- bibliography: Option<Vec<PathBuf>>,
- markdowns: Vec<PathBuf>,
- bindings: Option<Vec<PathBuf>>,
- documentclass: Option<String>,
- #[serde(default)]
- impls: BTreeMap<String, Vec<PathBuf>>,
- pandoc: Option<HashMap<String, Value>>,
-}
-
-impl YamlMetadata {
- #[cfg(test)]
- fn new(yaml_text: &str) -> Result<Self, Error> {
- let meta: Self = serde_yaml::from_str(yaml_text)?;
- Ok(meta)
- }
-
- /// Name of file with the Markdown for the subplot document.
- pub fn markdown(&self) -> &Path {
- &self.markdowns[0]
- }
-
- /// Title.
- pub fn title(&self) -> &str {
- &self.title
- }
-
- /// Subtitle.
- pub fn subtitle(&self) -> Option<&str> {
- self.subtitle.as_deref()
- }
-
- /// Date.
- pub fn date(&self) -> Option<&str> {
- self.date.as_deref()
- }
-
- /// Authors.
- pub fn authors(&self) -> Option<&[String]> {
- self.authors.as_deref()
- }
-
- /// Names of bindings files.
- pub fn bindings_filenames(&self) -> Option<&[PathBuf]> {
- self.bindings.as_deref()
- }
-
- /// Impls section.
- pub fn impls(&self) -> &BTreeMap<String, Vec<PathBuf>> {
- &self.impls
- }
-
- /// Bibliographies.
- pub fn bibliographies(&self) -> Option<&[PathBuf]> {
- self.bibliography.as_deref()
- }
-
- /// Classes..
- pub fn classes(&self) -> Option<&[String]> {
- self.classes.as_deref()
- }
-
- /// Documentclass.
- pub fn documentclass(&self) -> Option<&str> {
- self.documentclass.as_deref()
- }
-
- /// Pandoc metadata.
- pub fn pandoc(&self) -> Option<&HashMap<String, Value>> {
- if let Some(x) = &self.pandoc {
- Some(x)
- } else {
- None
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::YamlMetadata;
- use std::path::{Path, PathBuf};
-
- #[test]
- fn full_meta() {
- let meta = YamlMetadata::new(
- "\
-title: Foo Bar
-date: today
-classes: [json, text]
-impls:
- python:
- - foo.py
- - bar.py
-bibliography:
-- foo.bib
-- bar.bib
-markdowns:
-- test.md
-bindings:
-- foo.yaml
-- bar.yaml
-",
- )
- .unwrap();
- assert_eq!(meta.title, "Foo Bar");
- assert_eq!(meta.date.unwrap(), "today");
- assert_eq!(meta.classes.unwrap(), &["json", "text"]);
- assert_eq!(
- meta.bibliography.unwrap(),
- &[path("foo.bib"), path("bar.bib")]
- );
- assert_eq!(meta.markdowns, vec![Path::new("test.md")]);
- assert_eq!(
- meta.bindings.unwrap(),
- &[path("foo.yaml"), path("bar.yaml")]
- );
- assert!(!meta.impls.is_empty());
- for (k, v) in meta.impls.iter() {
- assert_eq!(k, "python");
- assert_eq!(v, &[path("foo.py"), path("bar.py")]);
- }
- }
-
- fn path(s: &str) -> PathBuf {
- PathBuf::from(s)
- }
-}
diff --git a/src/doc.rs b/src/doc.rs
index 7a7e64c..a39ab99 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -1,4 +1,3 @@
-use crate::ast;
use crate::bindings::CaptureType;
use crate::generate_test_program;
use crate::get_basedir_from;
@@ -6,12 +5,11 @@ use crate::md::Markdown;
use crate::EmbeddedFile;
use crate::EmbeddedFiles;
use crate::MatchedScenario;
-use crate::Metadata;
use crate::PartialStep;
use crate::Scenario;
use crate::Style;
use crate::SubplotError;
-use crate::YamlMetadata;
+use crate::{Metadata, YamlMetadata};
use crate::{Warning, Warnings};
use std::collections::HashSet;
@@ -106,7 +104,7 @@ impl Document {
basedir: P,
subplot: PathBuf,
markdowns: Vec<PathBuf>,
- yamlmeta: &ast::YamlMetadata,
+ yamlmeta: &YamlMetadata,
mut md: Markdown,
style: Style,
template: Option<&str>,
@@ -422,7 +420,7 @@ impl Document {
fn load_metadata_from_yaml_file(filename: &Path) -> Result<YamlMetadata, SubplotError> {
let yaml = read(filename).map_err(|e| SubplotError::ReadFile(filename.into(), e))?;
trace!("Parsing YAML metadata from {}", filename.display());
- let meta: ast::YamlMetadata = serde_yaml::from_slice(&yaml)
+ let meta: YamlMetadata = serde_yaml::from_slice(&yaml)
.map_err(|e| SubplotError::MetadataFile(filename.into(), e))?;
Ok(meta)
}
diff --git a/src/error.rs b/src/error.rs
index a729bf0..0ac2abf 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -308,7 +308,7 @@ pub enum SubplotError {
/// Abstract syntax tree error.
#[error(transparent)]
- Ast(#[from] crate::ast::Error),
+ Ast(#[from] crate::metadata::Error),
/// UTF8 conversion error.
#[error("failed to parse UTF8 in file {0}")]
diff --git a/src/lib.rs b/src/lib.rs
index 747b375..1ae64d4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,7 @@ mod policy;
pub use policy::get_basedir_from;
mod metadata;
-pub use metadata::Metadata;
+pub use metadata::{Metadata, YamlMetadata};
mod doc;
pub mod md;
@@ -72,6 +72,3 @@ pub use templatespec::TemplateSpec;
mod codegen;
pub use codegen::generate_test_program;
-
-mod ast;
-pub use ast::YamlMetadata;
diff --git a/src/metadata.rs b/src/metadata.rs
index e88c732..b840633 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -1,11 +1,181 @@
-use crate::{Bindings, SubplotError, TemplateSpec, YamlMetadata};
+use crate::{Bindings, SubplotError, TemplateSpec};
+use lazy_static::lazy_static;
use log::trace;
-use std::collections::HashMap;
+use regex::Regex;
+use serde::Deserialize;
+use serde_yaml::Value;
+use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::ops::Deref;
use std::path::{Path, PathBuf};
+lazy_static! {
+ // Pattern that recognises a YAML block at the beginning of a file.
+ static ref LEADING_YAML_PATTERN: Regex = Regex::new(r"^(?:\S*\n)*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?P<text>(.*\n)*)$").unwrap();
+
+
+ // Pattern that recognises a YAML block at the end of a file.
+ static ref TRAILING_YAML_PATTERN: Regex = Regex::new(r"(?P<text>(.*\n)*)\n*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?:\S*\n)*$").unwrap();
+}
+
+/// Errors from Markdown parsing.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error(transparent)]
+ Regex(#[from] regex::Error),
+
+ #[error("Markdown doesn't contain a YAML block for document metadata")]
+ NoMetadata,
+
+ #[error(transparent)]
+ Yaml(#[from] serde_yaml::Error),
+}
+
+/// Document metadata.
+///
+/// This is expressed in the Markdown input file as an embedded YAML
+/// block.
+///
+/// Note that this structure needs to be able to capture any metadata
+/// block we can work with, in any input file. By being strict here we
+/// make it easier to tell the user when a metadata block has, say, a
+/// misspelled field.
+#[derive(Debug, Default, Clone, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct YamlMetadata {
+ title: String,
+ subtitle: Option<String>,
+ authors: Option<Vec<String>>,
+ date: Option<String>,
+ classes: Option<Vec<String>>,
+ bibliography: Option<Vec<PathBuf>>,
+ markdowns: Vec<PathBuf>,
+ bindings: Option<Vec<PathBuf>>,
+ documentclass: Option<String>,
+ #[serde(default)]
+ impls: BTreeMap<String, Vec<PathBuf>>,
+ pandoc: Option<HashMap<String, Value>>,
+}
+
+impl YamlMetadata {
+ #[cfg(test)]
+ fn new(yaml_text: &str) -> Result<Self, Error> {
+ let meta: Self = serde_yaml::from_str(yaml_text)?;
+ Ok(meta)
+ }
+
+ /// Name of file with the Markdown for the subplot document.
+ pub fn markdown(&self) -> &Path {
+ &self.markdowns[0]
+ }
+
+ /// Title.
+ pub fn title(&self) -> &str {
+ &self.title
+ }
+
+ /// Subtitle.
+ pub fn subtitle(&self) -> Option<&str> {
+ self.subtitle.as_deref()
+ }
+
+ /// Date.
+ pub fn date(&self) -> Option<&str> {
+ self.date.as_deref()
+ }
+
+ /// Authors.
+ pub fn authors(&self) -> Option<&[String]> {
+ self.authors.as_deref()
+ }
+
+ /// Names of bindings files.
+ pub fn bindings_filenames(&self) -> Option<&[PathBuf]> {
+ self.bindings.as_deref()
+ }
+
+ /// Impls section.
+ pub fn impls(&self) -> &BTreeMap<String, Vec<PathBuf>> {
+ &self.impls
+ }
+
+ /// Bibliographies.
+ pub fn bibliographies(&self) -> Option<&[PathBuf]> {
+ self.bibliography.as_deref()
+ }
+
+ /// Classes..
+ pub fn classes(&self) -> Option<&[String]> {
+ self.classes.as_deref()
+ }
+
+ /// Documentclass.
+ pub fn documentclass(&self) -> Option<&str> {
+ self.documentclass.as_deref()
+ }
+
+ /// Pandoc metadata.
+ pub fn pandoc(&self) -> Option<&HashMap<String, Value>> {
+ if let Some(x) = &self.pandoc {
+ Some(x)
+ } else {
+ None
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::YamlMetadata;
+ use std::path::{Path, PathBuf};
+
+ #[test]
+ fn full_meta() {
+ let meta = YamlMetadata::new(
+ "\
+title: Foo Bar
+date: today
+classes: [json, text]
+impls:
+ python:
+ - foo.py
+ - bar.py
+bibliography:
+- foo.bib
+- bar.bib
+markdowns:
+- test.md
+bindings:
+- foo.yaml
+- bar.yaml
+",
+ )
+ .unwrap();
+ assert_eq!(meta.title, "Foo Bar");
+ assert_eq!(meta.date.unwrap(), "today");
+ assert_eq!(meta.classes.unwrap(), &["json", "text"]);
+ assert_eq!(
+ meta.bibliography.unwrap(),
+ &[path("foo.bib"), path("bar.bib")]
+ );
+ assert_eq!(meta.markdowns, vec![Path::new("test.md")]);
+ assert_eq!(
+ meta.bindings.unwrap(),
+ &[path("foo.yaml"), path("bar.yaml")]
+ );
+ assert!(!meta.impls.is_empty());
+ for (k, v) in meta.impls.iter() {
+ assert_eq!(k, "python");
+ assert_eq!(v, &[path("foo.py"), path("bar.py")]);
+ }
+ }
+
+ fn path(s: &str) -> PathBuf {
+ PathBuf::from(s)
+ }
+}
+
/// Metadata of a document, as needed by Subplot.
#[derive(Debug)]
pub struct Metadata {