Class: YamlWrapper
Class Method Summary collapse
-
.psych_safe_load_uses_keywords? ⇒ Boolean
safe_load's calling convention changed between Psych 3 (bundled with Ruby 3.0) and Psych 4+ (bundled with Ruby 3.1+, and installable on any Ruby >= 3.0): Psych 4+: safe_load(yaml, permitted_classes: [], aliases: false, ...) # keyword args Psych 3: safe_load(yaml, permitted_classes = [], permitted_symbols = [], aliases = false) # positional Psych::VERSION is fixed for the life of the process, and #load/#load_string are called repeatedly over a Ceedling run, so the version check is memoized rather than repeated per call.
Instance Method Summary collapse
- #dump(filepath, structure) ⇒ Object
- #load(filepath) ⇒ Object
- #load_string(source, source_label: '<inline YAML>') ⇒ Object
Class Method Details
.psych_safe_load_uses_keywords? ⇒ Boolean
safe_load's calling convention changed between Psych 3 (bundled with Ruby 3.0) and Psych 4+ (bundled with Ruby 3.1+, and installable on any Ruby >= 3.0):
Psych 4+: safe_load(yaml, permitted_classes: [], aliases: false, ...) # keyword args
Psych 3: safe_load(yaml, permitted_classes = [], permitted_symbols = [], aliases = false) # positional
Psych::VERSION is fixed for the life of the process, and #load/#load_string are called repeatedly over a Ceedling run, so the version check is memoized rather than repeated per call.
32 33 34 35 |
# File 'lib/ceedling/yaml_wrapper.rb', line 32 def self.psych_safe_load_uses_keywords? return @psych_safe_load_uses_keywords if defined?(@psych_safe_load_uses_keywords) @psych_safe_load_uses_keywords = (Gem::Version.new(Psych::VERSION) >= Gem::Version.new("4.0")) end |
Instance Method Details
#dump(filepath, structure) ⇒ Object
91 92 93 94 95 |
# File 'lib/ceedling/yaml_wrapper.rb', line 91 def dump(filepath, structure) File.open(filepath, 'w') do |output| YAML.dump(structure, output) end end |
#load(filepath) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ceedling/yaml_wrapper.rb', line 37 def load(filepath) begin source = File.read(filepath) rescue Errno::ENOENT raise YamlLoadException.new( reason: :not_found, source: filepath, original_error: nil, message: "Could not find YAML file ⏩️ #{filepath}" ) end load_string(source, source_label: filepath) end |
#load_string(source, source_label: '<inline YAML>') ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/ceedling/yaml_wrapper.rb', line 50 def load_string(source, source_label: '<inline YAML>') if self.class.psych_safe_load_uses_keywords? YAML.safe_load(source, permitted_classes: [Symbol], aliases: true, filename: source_label) else YAML.safe_load(source, [Symbol], [], true, source_label) end # The YAML parsed fine syntactically, but it contains a tag/type (e.g. `!ruby/object:...`) # that isn't on safe_load's permitted-class allowlist. This is Psych doing its safety job, # not a content typo -- surfaced separately from :syntax so the user understands the fix is # "remove this Ruby-object tag," not "fix a formatting mistake." rescue Psych::DisallowedClass => e raise YamlLoadException.new( reason: :unsafe, source: source_label, original_error: e, message: "YAML content in #{source_label} uses a Ruby type not permitted by safe YAML loading ⏩️ #{e.}" ) # Catches every other Psych::Exception subclass (Psych::SyntaxError, Psych::BadAlias, # Psych::AnchorNotDefined, etc.) -- i.e. the YAML text itself is malformed: bad syntax, # a dangling alias reference, and similar authoring mistakes the user needs to fix in # the YAML source. Ordered after Psych::DisallowedClass, which is a subclass of # Psych::Exception and needs its own more specific message. rescue Psych::Exception => e raise YamlLoadException.new( reason: :syntax, source: source_label, original_error: e, message: "Malformed YAML content in #{source_label} ⏩️ #{e.}" ) # Not a problem with the YAML content at all -- the installed Psych version rejected one # of the arguments safe_load was called with. self.class.psych_safe_load_uses_keywords? # already picks the right calling convention for the installed Psych, so this should be # unreachable in practice; it exists as a last-resort safety net for an unanticipated # Psych version/interface mismatch, reported distinctly so it isn't mistaken for a user # YAML-authoring error. rescue ArgumentError => e raise YamlLoadException.new( reason: :incompatible, source: source_label, original_error: e, message: "Installed Psych YAML library (#{Psych::VERSION}) does not support a safe-loading feature Ceedling requires ⏩️ #{e.}" ) end |