Hide MarkedYaml from the public API

This gives the freedom to changing the YAML parsing implementation without changing the public API.
This commit is contained in:
Oliver Hamlet
2025-03-30 08:38:43 +01:00
parent 74a834e039
commit 422ed8cce3
10 changed files with 133 additions and 140 deletions
+13 -16
View File
@@ -7,10 +7,9 @@ use super::{
MessageContent, emit_message_contents, parse_message_contents_yaml,
validate_message_contents,
},
yaml::{EmitYaml, YamlEmitter},
yaml::{
YamlObjectType, as_string_node, get_required_string_value, get_string_value,
parse_condition,
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, as_string_node,
get_required_string_value, get_string_value, parse_condition,
},
};
@@ -139,10 +138,8 @@ impl std::fmt::Display for Filename {
}
}
impl TryFrom<&MarkedYaml> for File {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for File {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
match &value.data {
YamlData::String(s) => Ok(File {
name: Filename::new(s.clone()),
@@ -249,7 +246,7 @@ mod tests {
fn should_only_set_name_if_decoding_from_scalar() {
let yaml = parse("name1");
let file = File::try_from(&yaml).unwrap();
let file = File::try_from_yaml(&yaml).unwrap();
assert_eq!("name1", file.name().as_str());
assert!(file.display_name().is_none());
@@ -261,21 +258,21 @@ mod tests {
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(File::try_from(&yaml).is_err());
assert!(File::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_name_is_missing() {
let yaml = parse("{display: display1}");
assert!(File::try_from(&yaml).is_err());
assert!(File::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_an_invalid_condition() {
let yaml = parse("{name: name1, condition: invalid}");
assert!(File::try_from(&yaml).is_err());
assert!(File::try_from_yaml(&yaml).is_err());
}
#[test]
@@ -284,7 +281,7 @@ mod tests {
"{name: name1, display: display1, condition: 'file(\"Foo.esp\")', detail: 'details'}",
);
let file = File::try_from(&yaml).unwrap();
let file = File::try_from_yaml(&yaml).unwrap();
assert_eq!("name1", file.name().as_str());
assert_eq!("display1", file.display_name().unwrap());
@@ -296,7 +293,7 @@ mod tests {
fn should_leave_optional_fields_empty_if_not_present() {
let yaml = parse("{name: name1}");
let file = File::try_from(&yaml).unwrap();
let file = File::try_from_yaml(&yaml).unwrap();
assert_eq!("name1", file.name().as_str());
assert!(file.display_name().is_none());
@@ -310,7 +307,7 @@ mod tests {
"{name: name1, detail: [{text: english, lang: en}, {text: french, lang: fr}]}",
);
let file = File::try_from(&yaml).unwrap();
let file = File::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[
@@ -325,7 +322,7 @@ mod tests {
fn should_not_error_if_one_detail_is_given_and_it_is_not_english() {
let yaml = parse("name: name1\ndetail:\n - lang: fr\n text: content1");
let file = File::try_from(&yaml).unwrap();
let file = File::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[MessageContent::new("content1".into()).with_language("fr".into())],
@@ -339,7 +336,7 @@ mod tests {
"name: name1\ndetail:\n - lang: de\n text: content1\n - lang: fr\n text: content2",
);
assert!(File::try_from(&yaml).is_err());
assert!(File::try_from_yaml(&yaml).is_err());
}
}
+14 -14
View File
@@ -1,9 +1,11 @@
use saphyr::MarkedYaml;
use super::error::ParseMetadataError;
use super::yaml::{EmitYaml, YamlEmitter};
use super::yaml::{
YamlObjectType, get_as_hash, get_required_string_value, get_string_value, get_strings_vec_value,
use super::{
error::ParseMetadataError,
yaml::{
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, get_as_hash, get_required_string_value,
get_string_value, get_strings_vec_value,
},
};
/// Represents a group to which plugin metadata objects can belong.
@@ -82,10 +84,8 @@ impl std::default::Default for Group {
}
}
impl TryFrom<&MarkedYaml> for Group {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for Group {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
let hash = get_as_hash(value, YamlObjectType::Group)?;
let name =
@@ -143,32 +143,32 @@ mod tests {
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(Group::try_from(&yaml).is_err());
assert!(Group::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_name_is_missing() {
let yaml = parse("{description: text}");
assert!(Group::try_from(&yaml).is_err());
assert!(Group::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_after_is_not_an_array_of_strings() {
let yaml = parse("{name: group1, after: other_group}");
assert!(Group::try_from(&yaml).is_err());
assert!(Group::try_from_yaml(&yaml).is_err());
let yaml = parse("{name: group1, after: [0, 1]}");
assert!(Group::try_from(&yaml).is_err());
assert!(Group::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_set_all_given_fields() {
let yaml = parse("{name: group1, description: text, after: [ other_group ]}");
let group = Group::try_from(&yaml).unwrap();
let group = Group::try_from_yaml(&yaml).unwrap();
assert_eq!("group1", group.name());
assert_eq!("text", group.description().unwrap());
@@ -179,7 +179,7 @@ mod tests {
fn should_leave_optional_fields_empty_if_not_present() {
let yaml = parse("{name: group1}");
let group = Group::try_from(&yaml).unwrap();
let group = Group::try_from_yaml(&yaml).unwrap();
assert_eq!("group1", group.name());
assert!(group.description().is_none());
+13 -17
View File
@@ -1,11 +1,9 @@
use saphyr::{MarkedYaml, YamlData};
use super::error::ExpectedType;
use super::error::ParseMetadataError;
use super::yaml::EmitYaml;
use super::yaml::YamlEmitter;
use super::yaml::{YamlObjectType, get_required_string_value};
use super::{
error::{ExpectedType, ParseMetadataError},
yaml::{EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, get_required_string_value},
};
/// Represents a URL at which the parent plugin can be found.
#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
@@ -48,10 +46,8 @@ impl Location {
}
}
impl TryFrom<&MarkedYaml> for Location {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for Location {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
match &value.data {
YamlData::String(s) => Ok(Location {
url: s.clone(),
@@ -120,7 +116,7 @@ mod tests {
fn should_only_set_name_if_decoding_from_scalar() {
let yaml = parse("https://www.example.com");
let location = Location::try_from(&yaml).unwrap();
let location = Location::try_from_yaml(&yaml).unwrap();
assert_eq!("https://www.example.com", location.url());
assert!(location.name().is_none());
@@ -130,42 +126,42 @@ mod tests {
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(Location::try_from(&yaml).is_err());
assert!(Location::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_link_is_missing() {
let yaml = parse("{name: example}");
assert!(Location::try_from(&yaml).is_err());
assert!(Location::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_link_is_not_a_string() {
let yaml = parse("{link: [https://www.example.com], name: example}");
assert!(Location::try_from(&yaml).is_err());
assert!(Location::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_name_is_not_a_string() {
let yaml = parse("{link: https://www.example.com, name: [example]}");
assert!(Location::try_from(&yaml).is_err());
assert!(Location::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_name_is_missing() {
let yaml = parse("{link: https://www.example.com}");
assert!(Location::try_from(&yaml).is_err());
assert!(Location::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_set_all_fields() {
let yaml = parse("{link: https://www.example.com, name: example}");
let location = Location::try_from(&yaml).unwrap();
let location = Location::try_from_yaml(&yaml).unwrap();
assert_eq!("https://www.example.com", location.url());
assert_eq!("example", location.name().unwrap());
+29 -34
View File
@@ -10,10 +10,9 @@ use super::{
ExpectedType, MetadataParsingErrorReason, MultilingualMessageContentsError,
ParseMetadataError,
},
yaml::{EmitYaml, YamlEmitter},
yaml::{
YamlObjectType, as_string_node, get_as_hash, get_required_string_value,
get_strings_vec_value, parse_condition,
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, as_string_node, get_as_hash,
get_required_string_value, get_strings_vec_value, parse_condition,
},
};
@@ -239,10 +238,8 @@ pub(crate) fn validate_message_contents(
Ok(())
}
impl TryFrom<&MarkedYaml> for MessageContent {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for MessageContent {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
let hash = get_as_hash(value, YamlObjectType::MessageContent)?;
let text =
@@ -269,7 +266,7 @@ pub(crate) fn parse_message_contents_yaml(
}
YamlData::Array(a) => a
.iter()
.map(MessageContent::try_from)
.map(MessageContent::try_from_yaml)
.collect::<Result<Vec<MessageContent>, _>>()?,
_ => {
return Err(ParseMetadataError::unexpected_value_type(
@@ -293,10 +290,8 @@ pub(crate) fn parse_message_contents_yaml(
}
}
impl TryFrom<&MarkedYaml> for Message {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for Message {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
let hash = get_as_hash(value, YamlObjectType::Message)?;
let message_type =
@@ -554,21 +549,21 @@ mod tests {
fn should_error_if_given_a_scalar() {
let yaml = parse("content");
assert!(MessageContent::try_from(&yaml).is_err());
assert!(MessageContent::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(MessageContent::try_from(&yaml).is_err());
assert!(MessageContent::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_set_all_given_fields() {
let yaml = parse("{text: content, lang: fr}");
let content = MessageContent::try_from(&yaml).unwrap();
let content = MessageContent::try_from_yaml(&yaml).unwrap();
assert_eq!("content", content.text());
assert_eq!("fr", content.language());
@@ -603,35 +598,35 @@ mod tests {
fn should_error_if_given_a_scalar() {
let yaml = parse("content");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_content_is_missing() {
let yaml = parse("{type: say}");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_an_invalid_condition() {
let yaml = parse("{type: say, content: text, condition: invalid}");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_set_all_given_fields() {
let yaml = parse("{type: say, content: text, condition: 'file(\"Foo.esp\")'}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Say, message.message_type());
assert_eq!(&[MessageContent::new("text".into())], message.content());
@@ -642,7 +637,7 @@ mod tests {
fn should_leave_optional_fields_empty_if_not_present() {
let yaml = parse("{type: say, content: text}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Say, message.message_type());
assert_eq!(&[MessageContent::new("text".into())], message.content());
@@ -653,17 +648,17 @@ mod tests {
fn should_set_say_warn_and_error_message_types() {
let yaml = parse("{type: say, content: text}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Say, message.message_type());
let yaml = parse("{type: warn, content: text}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Warn, message.message_type());
let yaml = parse("{type: error, content: text}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Error, message.message_type());
}
@@ -671,7 +666,7 @@ mod tests {
fn should_use_say_if_message_type_is_unrecognised() {
let yaml = parse("{type: info, content: text}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(MessageType::Say, message.message_type());
}
@@ -681,7 +676,7 @@ mod tests {
"{type: say, content: [{text: english, lang: en}, {text: french, lang: fr}]}",
);
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[
@@ -696,7 +691,7 @@ mod tests {
fn should_not_error_if_one_content_object_is_given_and_it_is_not_english() {
let yaml = parse("type: say\ncontent:\n - lang: fr\n text: content1");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[MessageContent::new("content1".into()).with_language("fr".into())],
@@ -710,14 +705,14 @@ mod tests {
"type: say\ncontent:\n - lang: de\n text: content1\n - lang: fr\n text: content2",
);
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_apply_substitutions_when_there_is_only_one_content_string() {
let yaml = parse("type: say\ncontent: con{0}tent1\nsubs:\n - sub1");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!("consub1tent1", message.content()[0].text());
}
@@ -728,7 +723,7 @@ mod tests {
"type: say\ncontent:\n - lang: en\n text: content1 {0}\n - lang: fr\n text: content2 {0}\nsubs:\n - sub",
);
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!("content1 sub", message.content()[0].text());
assert_eq!("content2 sub", message.content()[1].text());
@@ -738,21 +733,21 @@ mod tests {
fn should_error_if_the_message_has_more_substitutions_than_expected() {
let yaml = parse("{type: say, content: 'content1', subs: [sub1]}");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_the_content_string_expects_more_substitutions_than_exist() {
let yaml = parse("{type: say, content: '{0} {1}', subs: [sub1]}");
assert!(Message::try_from(&yaml).is_err());
assert!(Message::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_ignore_substution_syntax_if_no_substitutions_exist() {
let yaml = parse("{type: say, content: 'content {0}'}");
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!("content {0}", message.content()[0].text());
}
@@ -763,7 +758,7 @@ mod tests {
"{type: say, content: 'content %1% %2% %3% %4% %5% %6% %7% %8% %9% %10% %11%', subs: [a, b, c, d, e, f, g, h, i, j, k]}",
);
let message = Message::try_from(&yaml).unwrap();
let message = Message::try_from_yaml(&yaml).unwrap();
assert_eq!("content a b c d e f g h i j k", message.content()[0].text());
}
+4 -4
View File
@@ -16,7 +16,7 @@ use super::{
group::Group,
message::Message,
plugin_metadata::PluginMetadata,
yaml::{EmitYaml, YamlEmitter, YamlObjectType, get_as_slice, process_merge_keys},
yaml::{EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, get_as_slice, process_merge_keys},
};
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -119,7 +119,7 @@ impl MetadataDocument {
let mut plugins: HashMap<Filename, PluginMetadata> = HashMap::new();
let mut regex_plugins: Vec<PluginMetadata> = Vec::new();
for plugin_yaml in get_as_slice(&doc, "plugins", YamlObjectType::MetadataDocument)? {
let plugin = PluginMetadata::try_from(plugin_yaml)?;
let plugin = PluginMetadata::try_from_yaml(plugin_yaml)?;
if plugin.is_regex_plugin() {
regex_plugins.push(plugin);
} else {
@@ -137,7 +137,7 @@ impl MetadataDocument {
let messages = get_as_slice(&doc, "globals", YamlObjectType::MetadataDocument)?
.iter()
.map(Message::try_from)
.map(Message::try_from_yaml)
.collect::<Result<Vec<_>, _>>()?;
let mut bash_tags = Vec::new();
@@ -171,7 +171,7 @@ impl MetadataDocument {
let mut group_names = HashSet::new();
let mut groups = Vec::new();
for group_yaml in get_as_slice(&doc, "groups", YamlObjectType::MetadataDocument)? {
let group = Group::try_from(group_yaml)?;
let group = Group::try_from_yaml(group_yaml)?;
let name = group.name().to_string();
if group_names.contains(&name) {
+21 -21
View File
@@ -6,8 +6,10 @@ use super::{
MessageContent, emit_message_contents, parse_message_contents_yaml,
validate_message_contents,
},
yaml::{EmitYaml, YamlEmitter},
yaml::{YamlObjectType, as_string_node, get_as_hash, get_required_string_value, get_u32_value},
yaml::{
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, as_string_node, get_as_hash,
get_required_string_value, get_u32_value,
},
};
/// Represents data identifying the plugin under which it is stored as dirty or
@@ -134,10 +136,8 @@ impl PluginCleaningData {
}
}
impl TryFrom<&MarkedYaml> for PluginCleaningData {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for PluginCleaningData {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
let hash = get_as_hash(value, YamlObjectType::PluginCleaningData)?;
let crc = match get_u32_value(hash, "crc", YamlObjectType::PluginCleaningData)? {
@@ -224,58 +224,58 @@ mod tests {
fn should_error_if_given_a_scalar() {
let yaml = parse("0x12345678");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_crc_is_missing() {
let yaml = parse("{util: cleaner}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_util_is_missing() {
let yaml = parse("{crc: 0x12345678}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_a_count_is_not_a_number() {
let yaml = parse("{crc: 0x12345678, util: cleaner, itm: true}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
let yaml = parse("{crc: 0x12345678, util: cleaner, udr: true}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
let yaml = parse("{crc: 0x12345678, util: cleaner, nav: true}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_a_count_does_not_fit_in_a_u32() {
let yaml = parse("{crc: 0x12345678, util: cleaner, itm: -1}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
let yaml = parse("{crc: 0x12345678, util: cleaner, udr: -2}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
let yaml = parse("{crc: 0x12345678, util: cleaner, nav: -3}");
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
#[test]
@@ -283,7 +283,7 @@ mod tests {
let yaml =
parse("{crc: 0x12345678, util: cleaner, detail: info, itm: 2, udr: 10, nav: 30}");
let data = PluginCleaningData::try_from(&yaml).unwrap();
let data = PluginCleaningData::try_from_yaml(&yaml).unwrap();
assert_eq!(0x12345678, data.crc());
assert_eq!("cleaner", data.cleaning_utility());
@@ -297,7 +297,7 @@ mod tests {
fn should_leave_optional_fields_at_defaults_if_not_present() {
let yaml = parse("{crc: 0x12345678, util: cleaner}");
let data = PluginCleaningData::try_from(&yaml).unwrap();
let data = PluginCleaningData::try_from_yaml(&yaml).unwrap();
assert_eq!(0x12345678, data.crc());
assert_eq!("cleaner", data.cleaning_utility());
@@ -313,7 +313,7 @@ mod tests {
"{crc: 0x12345678, util: cleaner, detail: [{text: english, lang: en}, {text: french, lang: fr}]}",
);
let data = PluginCleaningData::try_from(&yaml).unwrap();
let data = PluginCleaningData::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[
@@ -329,7 +329,7 @@ mod tests {
let yaml =
parse("crc: 0x12345678\nutil: cleaner\ndetail:\n - lang: fr\n text: content1");
let data = PluginCleaningData::try_from(&yaml).unwrap();
let data = PluginCleaningData::try_from_yaml(&yaml).unwrap();
assert_eq!(
&[MessageContent::new("content1".into()).with_language("fr".into())],
@@ -343,7 +343,7 @@ mod tests {
"crc: 0x12345678\nutil: cleaner\ndetail:\n - lang: de\n text: content1\n - lang: fr\n text: content2",
);
assert!(PluginCleaningData::try_from(&yaml).is_err());
assert!(PluginCleaningData::try_from_yaml(&yaml).is_err());
}
}
+13 -15
View File
@@ -12,9 +12,9 @@ use super::{
message::Message,
plugin_cleaning_data::PluginCleaningData,
tag::Tag,
yaml::{EmitYaml, YamlEmitter},
yaml::{
YamlObjectType, get_as_hash, get_as_slice, get_required_string_value, get_string_value,
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, get_as_hash, get_as_slice,
get_required_string_value, get_string_value,
},
};
@@ -349,10 +349,8 @@ fn replace_capturing_groups(regex_string: &str) -> Cow<'_, str> {
}
}
impl TryFrom<&MarkedYaml> for PluginMetadata {
type Error = ParseMetadataError;
fn try_from(value: &MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for PluginMetadata {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
let hash = get_as_hash(value, YamlObjectType::PluginMetadata)?;
let name = get_required_string_value(
@@ -397,13 +395,13 @@ impl TryFrom<&MarkedYaml> for PluginMetadata {
}
}
fn get_vec<'a, T: TryFrom<&'a MarkedYaml, Error = impl Into<ParseMetadataError>>>(
hash: &'a saphyr::AnnotatedHash<MarkedYaml>,
fn get_vec<T: TryFromYaml>(
hash: &saphyr::AnnotatedHash<MarkedYaml>,
key: &'static str,
) -> Result<Vec<T>, ParseMetadataError> {
let mut vec = get_as_slice(hash, key, YamlObjectType::PluginMetadata)?
.iter()
.map(|e| T::try_from(e).map_err(Into::into))
.map(|e| T::try_from_yaml(e))
.collect::<Result<Vec<T>, _>>()?;
vec.shrink_to_fit();
@@ -872,14 +870,14 @@ mod tests {
fn should_error_if_given_a_scalar() {
let yaml = parse("name1");
assert!(PluginMetadata::try_from(&yaml).is_err());
assert!(PluginMetadata::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(PluginMetadata::try_from(&yaml).is_err());
assert!(PluginMetadata::try_from_yaml(&yaml).is_err());
}
#[test]
@@ -908,7 +906,7 @@ mod tests {
- 'https://www.example.com'",
);
let plugin = PluginMetadata::try_from(&yaml).unwrap();
let plugin = PluginMetadata::try_from_yaml(&yaml).unwrap();
assert_eq!(BLANK_ESP, plugin.name());
assert_eq!(&[File::new(BLANK_ESM.into())], plugin.load_after_files());
@@ -955,7 +953,7 @@ mod tests {
util: 'utility'",
);
let plugin = PluginMetadata::try_from(&yaml).unwrap();
let plugin = PluginMetadata::try_from_yaml(&yaml).unwrap();
assert_eq!("Blank\\.esp", plugin.name());
assert_eq!(
@@ -972,14 +970,14 @@ mod tests {
fn should_error_if_regex_name_is_invalid() {
let yaml = parse("{name: 'RagnvaldBook(Farengar(+Ragnvald)?)?\\.esp'}");
assert!(PluginMetadata::try_from(&yaml).is_err());
assert!(PluginMetadata::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_a_field_that_should_be_an_array_is_not() {
let yaml = parse("{name: 'Blank.esp', after: Blank.esm}");
assert!(PluginMetadata::try_from(&yaml).is_err());
assert!(PluginMetadata::try_from_yaml(&yaml).is_err());
}
}
+17 -17
View File
@@ -1,10 +1,12 @@
use saphyr::YamlData;
use saphyr::{MarkedYaml, YamlData};
use super::error::ExpectedType;
use super::error::ParseMetadataError;
use super::yaml::EmitYaml;
use super::yaml::YamlEmitter;
use super::yaml::{YamlObjectType, get_required_string_value, parse_condition};
use super::{
error::{ExpectedType, ParseMetadataError},
yaml::{
EmitYaml, TryFromYaml, YamlEmitter, YamlObjectType, get_required_string_value,
parse_condition,
},
};
/// Represents whether a Bash Tag suggestion is for addition or removal.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
@@ -62,10 +64,8 @@ impl Tag {
}
}
impl TryFrom<&saphyr::MarkedYaml> for Tag {
type Error = ParseMetadataError;
fn try_from(value: &saphyr::MarkedYaml) -> Result<Self, Self::Error> {
impl TryFromYaml for Tag {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError> {
match &value.data {
YamlData::String(s) => {
let (name, suggestion) = name_and_suggestion(s);
@@ -146,7 +146,7 @@ mod tests {
fn should_only_set_name_and_suggestion_if_decoding_from_scalar() {
let yaml = parse("Relev");
let tag = Tag::try_from(&yaml).unwrap();
let tag = Tag::try_from_yaml(&yaml).unwrap();
assert_eq!("Relev", tag.name());
assert!(tag.is_addition());
@@ -157,7 +157,7 @@ mod tests {
fn should_only_set_name_and_suggestion_if_decoding_from_scalar_with_leading_hyphen() {
let yaml = parse("-Relev");
let tag = Tag::try_from(&yaml).unwrap();
let tag = Tag::try_from_yaml(&yaml).unwrap();
assert_eq!("Relev", tag.name());
assert!(!tag.is_addition());
@@ -168,28 +168,28 @@ mod tests {
fn should_error_if_given_a_list() {
let yaml = parse("[0, 1, 2]");
assert!(Tag::try_from(&yaml).is_err());
assert!(Tag::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_name_is_missing() {
let yaml = parse("{condition: 'file(\"Foo.esp\")'}");
assert!(Tag::try_from(&yaml).is_err());
assert!(Tag::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_error_if_given_an_invalid_condition() {
let yaml = parse("{name: Relev, condition: invalid}");
assert!(Tag::try_from(&yaml).is_err());
assert!(Tag::try_from_yaml(&yaml).is_err());
}
#[test]
fn should_set_all_fields() {
let yaml = parse("{name: Relev, condition: 'file(\"Foo.esp\")'}");
let tag = Tag::try_from(&yaml).unwrap();
let tag = Tag::try_from_yaml(&yaml).unwrap();
assert_eq!("Relev", tag.name());
assert!(tag.is_addition());
@@ -200,7 +200,7 @@ mod tests {
fn should_leave_optional_fields_empty_if_not_present() {
let yaml = parse("{name: Relev}");
let tag = Tag::try_from(&yaml).unwrap();
let tag = Tag::try_from_yaml(&yaml).unwrap();
assert_eq!("Relev", tag.name());
assert!(tag.is_addition());
+3 -2
View File
@@ -5,6 +5,7 @@ mod parse;
pub use emit::{EmitYaml, YamlEmitter};
pub use merge::process_merge_keys;
pub use parse::{
YamlObjectType, as_string_node, get_as_hash, get_as_slice, get_required_string_value,
get_string_value, get_strings_vec_value, get_u32_value, parse_condition, to_yaml,
TryFromYaml, YamlObjectType, as_string_node, get_as_hash, get_as_slice,
get_required_string_value, get_string_value, get_strings_vec_value, get_u32_value,
parse_condition, to_yaml,
};
+6
View File
@@ -192,3 +192,9 @@ pub fn parse_condition(
None => Ok(None),
}
}
/// This is effectively TryFrom<&MarkedYaml>, but implementing it doesn't make
/// MarkedYaml part of the crate's public API.
pub trait TryFromYaml: Sized {
fn try_from_yaml(value: &MarkedYaml) -> Result<Self, ParseMetadataError>;
}