Class: SpecForge::Normalizer
- Inherits:
-
Object
- Object
- SpecForge::Normalizer
- Extended by:
- Default
- Defined in:
- lib/spec_forge/normalizer.rb,
lib/spec_forge/normalizer/default.rb,
lib/spec_forge/normalizer/structure.rb,
lib/spec_forge/normalizer/validators.rb,
lib/spec_forge/normalizer/transformers.rb
Overview
Validates and transforms input data against structure definitions
The Normalizer system ensures that YAML input conforms to expected structures, applying defaults, type checking, and custom validations. Structure definitions are loaded from YAML files in the normalizers/ directory.
Defined Under Namespace
Modules: Default Classes: Structure, Transformers, Validators
Constant Summary collapse
- LABELS =
Mapping of structure names to their human-readable labels
{ factory_reference: "factory reference", global_context: "global context" }.freeze
Class Attribute Summary collapse
-
.structures ⇒ Hash<Symbol, Hash>
readonly
Collection of structure definitions used for validation.
Class Method Summary collapse
-
.default(name = nil, structure: nil, include_optional: false) ⇒ Hash
Returns the default values for a structure.
-
.load_from_files ⇒ Hash
private
Loads normalizer structure definitions from YAML files.
-
.normalize(input, using:, label: nil) ⇒ Array<Hash, Set>
Normalizes input data against a structure without raising errors.
-
.normalize!(input, using:, label: nil) ⇒ Hash
(also: validate!)
Normalizes input data against a structure with error raising.
-
.raise_errors! { ... } ⇒ Object
private
Raises any errors collected by the block.
Instance Method Summary collapse
-
#initialize(label, input, structure:) ⇒ Normalizer
constructor
Creates a normalizer for normalizing Hash data based on a structure.
-
#normalize ⇒ Array<Hash, Set>
Normalizes the data according to the defined structure.
Constructor Details
#initialize(label, input, structure:) ⇒ Normalizer
Creates a normalizer for normalizing Hash data based on a structure
217 218 219 220 221 |
# File 'lib/spec_forge/normalizer.rb', line 217 def initialize(label, input, structure:) @label = label @input = input @structure = structure end |
Class Attribute Details
.structures ⇒ Hash<Symbol, Hash> (readonly)
Collection of structure definitions used for validation
Contains all the structure definitions loaded from YAML files, indexed by their name. Each structure defines the expected format, types, and validation rules for a specific data structure.
36 37 38 |
# File 'lib/spec_forge/normalizer.rb', line 36 def structures @structures end |
Class Method Details
.default(name = nil, structure: nil, include_optional: false) ⇒ Hash
Returns the default values for a structure
Creates a hash of defaults based on a structure definition. Handles optional values, nested structures, and type-specific default generation.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/spec_forge/normalizer.rb', line 132 def default(name = nil, structure: nil, include_optional: false) structure ||= @structures[name.to_sym] if !structure.is_a?(Hash) = if name.present? "No normalizer structure exists with name #{name.in_quotes}" else "The provided normalizer structure must be a Hash. Got #{structure.inspect}" end raise ArgumentError, end default_from_structure(structure, include_optional:) end |
.load_from_files ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Loads normalizer structure definitions from YAML files
Reads YAML files in the normalizers directory and creates structure definitions for use in validation and normalization.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/spec_forge/normalizer.rb', line 159 def load_from_files base_path = Pathname.new(File.("normalizers", __dir__)) paths = Dir[base_path.join("**/*.yml")].sort @structures = paths.each_with_object({}) do |path, hash| path = Pathname.new(path) # Include the directory name in the path to include normalizers in directories name = path.relative_path_from(base_path).to_s.delete_suffix(".yml").to_sym input = YAML.safe_load_file(path, symbolize_names: true, aliases: true) raise Error, "Normalizer defined at #{path.to_s.in_quotes} is empty" if input.blank? hash[name] = Structure.new(input, label: LABELS[name] || name.to_s.humanize.downcase) end end |
.normalize(input, using:, label: nil) ⇒ Array<Hash, Set>
Normalizes input data against a structure without raising errors
Validates and transforms input data according to a structure definition, collecting any validation errors rather than raising them. This method is the underlying implementation used by normalize! but returns errors instead of raising them.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/spec_forge/normalizer.rb', line 80 def normalize(input, using:, label: nil) # Since normalization is based on a structured hash, :using can be passed a Hash # to skip using a predefined normalizer. if using.is_a?(Hash) structure = using if label.blank? raise ArgumentError, "A label must be provided when using a custom structure" end else structure = @structures[using.to_sym] # We have a predefined structure and structures all have labels label ||= structure.label end # Ensure we have a structure if !structure.is_a?(Hash) structures = @structures.keys.map(&:in_quotes).to_or_sentence raise ArgumentError, "Invalid structure or name. Got #{using}, expected one of #{structures}" end # This is checked down here because it felt like it belonged... # and because of that pesky label raise Error::InvalidTypeError.new(input, Hash, for: label) unless input.is_a?(Hash) new(label, input, structure:).normalize end |
.normalize!(input, using:, label: nil) ⇒ Hash Also known as: validate!
Normalizes input data against a structure with error raising
Same as #normalize but raises an error if validation fails.
58 59 60 |
# File 'lib/spec_forge/normalizer.rb', line 58 def normalize!(input, using:, label: nil) raise_errors! { normalize(input, using:, label:) } end |
.raise_errors! { ... } ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Raises any errors collected by the block
189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/spec_forge/normalizer.rb', line 189 def raise_errors!(&block) errors = Set.new begin output, new_errors = yield errors.merge(new_errors) if new_errors.size > 0 rescue => e errors << e end raise Error::InvalidStructureError.new(errors) if errors.size > 0 output end |