Skip to content

Commit

Permalink
Merge pull request #12 from joanvallve/9-default-values-for-custom-cl…
Browse files Browse the repository at this point in the history
…asses

9 default values for custom classes
  • Loading branch information
joanvallve authored May 17, 2024
2 parents c90177f + d8265c8 commit 320a706
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 40 deletions.
11 changes: 9 additions & 2 deletions include/yaml-schema-cpp/yaml_schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ YAML::Node loadSchema(std::string schema_file,
const std::vector<std::string>& folders_schema,
std::stringstream& log,
bool override = true);
void checkSchema(const YAML::Node& node_schema, const std::string& field, const YAML::Node& node_schema_parent);
void checkSchema(const YAML::Node& node_schema,
const std::string& field,
const YAML::Node& node_schema_parent,
const std::vector<std::string>& folders_schema);

bool validateAllSchemas(const std::vector<std::string>& folders_schema, bool verbose, bool override = true);

Expand All @@ -58,7 +61,11 @@ bool hasAnyReservedKey(const YAML::Node& node_schema);
bool isSpecification(const YAML::Node& node_schema);
bool isSequenceSchema(const YAML::Node& node_schema);

void addNodeSchema(YAML::Node& node, const std::string& key, const YAML::Node& value, bool override);
void addNodeSchema(YAML::Node& node,
const std::string& key,
const YAML::Node& value,
bool override,
std::string parent_path = "");

std::string getTypeOfSequence(const YAML::Node& node_schema);

Expand Down
18 changes: 15 additions & 3 deletions include/yaml-schema-cpp/yaml_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,21 @@ namespace filesystem = boost::filesystem;
// 'folders'
// -> input node (is_schema = false): path to file allowed (either relative or absolute). Relative paths will be done
// with respect to the first item specified in folders. No search will be performed.
void flattenNode(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override);
void flattenMap(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override);
void flattenSequence(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override);
void flattenNode(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override);
void flattenMap(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override);
void flattenSequence(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override);

void writeErrorToLog(std::stringstream& log,
const std::string& _acc_field,
Expand Down
2 changes: 1 addition & 1 deletion src/type_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ bool isNonTrivialType(const std::string& type, const std::vector<std::string>& f
}
catch (const std::exception& e)
{
// non existing file
// non existing schema file
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions src/yaml_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ YAML::Node generateYaml(std::string name_schema, const std::vector<std::string>&
// Flatten yaml nodes (containing "follow") to a single YAML node containing all the information
try
{
flattenNode(node_schema, folders_schema, true, override);
flattenNode(node_schema, path_schema.parent_path().string(), folders_schema, true, override);
}
catch (const std::exception& e)
{
Expand All @@ -118,7 +118,7 @@ YAML::Node generateYaml(std::string name_schema, const std::vector<std::string>&
// Check schema
try
{
checkSchema(node_schema, "", node_schema);
checkSchema(node_schema, "", node_schema, folders_schema);
}
catch (const std::exception& e)
{
Expand Down
105 changes: 92 additions & 13 deletions src/yaml_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ YAML::Node loadSchema(std::string name_schema,
}

// Flatten yaml nodes (containing "follow") to a single YAML node containing all the information
flattenNode(node_schema, folders_schema, true, override);
flattenNode(node_schema, path_schema.parent_path().string(), folders_schema, true, override);

// Check schema
try
{
checkSchema(node_schema, "", node_schema);
checkSchema(node_schema, "", node_schema, folders_schema);
}
catch (const std::exception& e)
{
Expand All @@ -71,7 +71,10 @@ YAML::Node loadSchema(std::string name_schema,
return node_schema;
}

void checkSchema(const YAML::Node& node_schema, const std::string& node_field, const YAML::Node& node_schema_parent)
void checkSchema(const YAML::Node& node_schema,
const std::string& node_field,
const YAML::Node& node_schema_parent,
const std::vector<std::string>& folders_schema)
{
// skip scalars and not defined (empty schemas)
if (node_schema.IsScalar() or node_schema.IsNull()) return;
Expand Down Expand Up @@ -139,9 +142,28 @@ void checkSchema(const YAML::Node& node_schema, const std::string& node_field, c
// check type
auto type =
isSequenceSchema(node_schema) ? getTypeOfSequence(node_schema) : node_schema[TYPE].as<std::string>();
if (not tryNodeAs(node_schema[VALUE], type))
// trivial type
if (isTrivialType(type))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + VALUE + " of wrong type");
if (not tryNodeAs(node_schema[VALUE], type))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + VALUE + " of wrong type");
}
}
// type with schema
else if (isNonTrivialType(type, folders_schema))
{
std::stringstream log;
YAML::Node node_schema_value = node_schema[VALUE];
if (not applySchema(node_schema_value, type, folders_schema, log, ""))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + VALUE +
" value did not pass the schema check with error: " + log.str());
}
}
else
{
throw std::runtime_error("YAML schema: " + node_field + ", " + VALUE + " value unknown type.");
}

// if 'value', 'mandatory' should be false (no sense requiring user to define something already defined)
Expand All @@ -164,9 +186,28 @@ void checkSchema(const YAML::Node& node_schema, const std::string& node_field, c
// check type
auto type =
isSequenceSchema(node_schema) ? getTypeOfSequence(node_schema) : node_schema[TYPE].as<std::string>();
if (not tryNodeAs(node_schema[DEFAULT], type))
// trivial type
if (isTrivialType(type))
{
if (not tryNodeAs(node_schema[DEFAULT], type))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + DEFAULT + " value wrong type");
}
}
// type with schema
else if (isNonTrivialType(type, folders_schema))
{
std::stringstream log;
YAML::Node node_schema_default = node_schema[DEFAULT];
if (not applySchema(node_schema_default, type, folders_schema, log, ""))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + DEFAULT +
" value did not pass the schema check with error: " + log.str());
}
}
else
{
throw std::runtime_error("YAML schema: " + node_field + ", " + DEFAULT + " value wrong type");
throw std::runtime_error("YAML schema: " + node_field + ", " + DEFAULT + " value unknown type.");
}
}
// OPTIONAL sequence 'options'
Expand All @@ -182,10 +223,31 @@ void checkSchema(const YAML::Node& node_schema, const std::string& node_field, c
isSequenceSchema(node_schema) ? getTypeOfSequence(node_schema) : node_schema[TYPE].as<std::string>();
for (auto n_i = 0; n_i < node_schema[OPTIONS].size(); n_i++)
{
if (not tryNodeAs(node_schema[OPTIONS][n_i], type))
// trivial type
if (isTrivialType(type))
{
if (not tryNodeAs(node_schema[OPTIONS][n_i], type))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + OPTIONS + "[" +
std::to_string(n_i) + "] has wrong type (should be " + type + ")");
}
}
// type with schema
else if (isNonTrivialType(type, folders_schema))
{
std::stringstream log;
YAML::Node node_schema_i = node_schema[OPTIONS][n_i];
if (not applySchema(node_schema_i, type, folders_schema, log, ""))
{
throw std::runtime_error("YAML schema: " + node_field + ", " + OPTIONS + "[" +
std::to_string(n_i) +
"] did not pass the schema check with error: " + log.str());
}
}
else
{
throw std::runtime_error("YAML schema: " + node_field + ", " + OPTIONS + "[" +
std::to_string(n_i) + "] has wrong type (should be " + type + ")");
std::to_string(n_i) + "] unknown type.");
}
}
// If default, check it is included in options
Expand Down Expand Up @@ -243,7 +305,8 @@ void checkSchema(const YAML::Node& node_schema, const std::string& node_field, c
// check the children nodes
for (auto node_schema_child : node_schema)
{
checkSchema(node_schema_child.second, node_schema_child.first.as<std::string>(), node_schema);
checkSchema(
node_schema_child.second, node_schema_child.first.as<std::string>(), node_schema, folders_schema);
}
}
}
Expand Down Expand Up @@ -283,7 +346,7 @@ bool validateAllSchemas(const std::vector<std::string>& folders_schema, bool ver
// Flatten yaml nodes (containing "follow") to a single YAML node containing all the information
try
{
flattenNode(node_schema, folders_schema, true, override);
flattenNode(node_schema, entry.path().parent_path().string(), folders_schema, true, override);
}
catch (const std::exception& e)
{
Expand All @@ -298,7 +361,7 @@ bool validateAllSchemas(const std::vector<std::string>& folders_schema, bool ver
// Check schema
try
{
checkSchema(node_schema, "", node_schema);
checkSchema(node_schema, "", node_schema, folders_schema);
}
catch (const std::exception& e)
{
Expand Down Expand Up @@ -559,7 +622,11 @@ bool checkOptions(const YAML::Node& input_node, const YAML::Node& options_node,
return false;
}

void addNodeSchema(YAML::Node& node, const std::string& key, const YAML::Node& value, bool override)
void addNodeSchema(YAML::Node& node,
const std::string& key,
const YAML::Node& value,
bool override,
std::string parent_path)
{
if (node[key])
{
Expand Down Expand Up @@ -593,6 +660,18 @@ void addNodeSchema(YAML::Node& node, const std::string& key, const YAML::Node& v
{
node[key] = value;
}

// relative path input case
if (node[key].Type() == YAML::NodeType::Scalar)
{
std::string value_str = node[key].as<std::string>();
if ((value_str.size() > 1 and value_str.substr(0, 2) == "./") or
(value_str.size() > 2 and value_str.substr(0, 3) == "../"))
{
filesystem::path path_value = filesystem::path(parent_path) / filesystem::path(value.as<std::string>());
node[key] = path_value.string();
}
}
}

bool isSpecification(const YAML::Node& node_schema)
Expand Down
2 changes: 1 addition & 1 deletion src/yaml_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void YamlServer::loadYaml(const std::string& path_input)
node_input_ = YAML::LoadFile(path_input);

// flatten
flattenNode(node_input_, {path_input_.parent_path().string()}, false, override_);
flattenNode(node_input_, path_input_.parent_path().string(), {}, false, override_);
}

void YamlServer::setYaml(const YAML::Node _node_input)
Expand Down
57 changes: 40 additions & 17 deletions src/yaml_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,69 @@ namespace yaml_schema_cpp
{
namespace filesystem = boost::filesystem;

void flattenNode(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override)
void flattenNode(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override)
{
switch (node.Type())
{
case YAML::NodeType::Map:
flattenMap(node, folders, is_schema, override);
flattenMap(node, current_folder, schema_folders, is_schema, override);
break;
case YAML::NodeType::Sequence:
flattenSequence(node, folders, is_schema, override);
flattenSequence(node, current_folder, schema_folders, is_schema, override);
break;
case YAML::NodeType::Scalar:
default:
break;
}
}

void flattenSequence(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override)
void flattenSequence(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override)
{
for (auto node_i : node)
{
flattenNode(node_i, folders, is_schema, override);
flattenNode(node_i, current_folder, schema_folders, is_schema, override);
}
}

void flattenMap(YAML::Node& node, std::vector<std::string> folders, bool is_schema, bool override)
void flattenMap(YAML::Node& node,
std::string current_folder,
std::vector<std::string> schema_folders,
bool is_schema,
bool override)
{
YAML::Node node_aux; // Done using copy to preserve order of follow
for (auto n : node)
{
if (n.first.as<std::string>() == "follow")
{
std::string path_follow_str = n.second.as<std::string>();
filesystem::path path_follow;

if (is_schema)
// follow schema: empty or .schema
bool followed_is_schema = filesystem::extension(path_follow_str).empty() or
filesystem::extension(path_follow_str) == SCHEMA_EXTENSION;
if (followed_is_schema)
{
path_follow = findFileRecursive(path_follow_str, schema_folders);
}
// follow yaml file
else if (filesystem::extension(path_follow_str) == ".yaml")
{
path_follow = findFileRecursive(n.second.as<std::string>(), folders);
const filesystem::path follow_value(path_follow_str);
path_follow = current_folder / follow_value;
}
else
{
const filesystem::path follow_value(n.second.as<std::string>());
path_follow = folders.front() / follow_value;
throw std::runtime_error("In flattenNode: follow '" + path_follow_str +
"' bad extension, should be '.yaml', '.schema' or empty (assumed '.schema')");
}

if (not filesystem::exists(path_follow))
Expand All @@ -65,21 +87,22 @@ void flattenMap(YAML::Node& node, std::vector<std::string> folders, bool is_sche
YAML::Node node_child = YAML::LoadFile(path_follow.string());

// Recursively flatten the "follow" file
if (is_schema)
if (followed_is_schema)
{
flattenNode(node_child, folders, is_schema, override);
flattenNode(node_child, current_folder, schema_folders, followed_is_schema, override);
}
else
{
flattenNode(node_child, {path_follow.parent_path().string()}, is_schema, override);
flattenNode(node_child, path_follow.parent_path().string(), {}, followed_is_schema, override);
}

for (auto nc : node_child)
{
// Case schema
if (is_schema)
if (followed_is_schema)
{
addNodeSchema(node_aux, nc.first.as<std::string>(), nc.second, override);
addNodeSchema(
node_aux, nc.first.as<std::string>(), nc.second, override, path_follow.parent_path().string());
}
// Case input yaml
else
Expand All @@ -91,7 +114,7 @@ void flattenMap(YAML::Node& node, std::vector<std::string> folders, bool is_sche
}
else
{
flattenNode(n.second, folders, is_schema, override);
flattenNode(n.second, current_folder, schema_folders, is_schema, override);

// Case schema
if (is_schema)
Expand All @@ -101,7 +124,7 @@ void flattenMap(YAML::Node& node, std::vector<std::string> folders, bool is_sche
// Case input yaml
else
{
addNodeYaml(node_aux, n.first.as<std::string>(), n.second, override, folders[0]);
addNodeYaml(node_aux, n.first.as<std::string>(), n.second, override, current_folder);
}
}
}
Expand Down
Loading

0 comments on commit 320a706

Please sign in to comment.