Module: Ruby::Rego::Builtins::Yaml

Extended by:
RegistryHelpers
Defined in:
lib/ruby/rego/builtins/yaml.rb,
lib/ruby/rego/builtins/yaml/emitter.rb,
lib/ruby/rego/builtins/yaml/scalar_resolver.rb,
lib/ruby/rego/builtins/yaml/emitter/key_order.rb,
lib/ruby/rego/builtins/yaml/emitter/float_format.rb,
lib/ruby/rego/builtins/yaml/scalar_resolver/tags.rb,
lib/ruby/rego/builtins/yaml/scalar_resolver/numbers.rb,
lib/ruby/rego/builtins/yaml/scalar_resolver/document.rb

Overview

Built-in YAML helpers (yaml.marshal, yaml.unmarshal, yaml.is_valid).

OPA implements these via sigs.k8s.io/yaml, which round-trips through JSON on top of gopkg.in/yaml.v2. To match byte-for-byte: - marshal delegates layout/folding/escaping to Psych (libyaml — the same engine yaml.v2 ports), and supplies the divergent pieces itself: sorted keys, Go float formatting, explicit scalar styles, and null for nil. - unmarshal/is_valid resolve plain scalars with a yaml.v2-compatible resolver (no timestamp resolution — timestamps stay strings, as OPA’s JSON round-trip leaves them), stringify object keys (JSON keys are strings), and treat a non-finite number (Inf/NaN, unrepresentable in JSON) as undefined.

Defined Under Namespace

Modules: Emitter, ScalarResolver

Constant Summary collapse

YAML_FUNCTIONS =
{
  "yaml.marshal" => { arity: 1, handler: :marshal },
  "yaml.unmarshal" => { arity: 1, handler: :unmarshal },
  "yaml.is_valid" => { arity: 1, handler: :is_valid }
}.freeze

Class Method Summary collapse

Methods included from RegistryHelpers

register_configured_functions

Class Method Details

.is_valid(value) ⇒ Ruby::Rego::BooleanValue

A total predicate: a non-string runtime value (or any parse/resolve failure) yields false rather than undefined, matching OPA’s *_is_valid builtins.

Parameters:

Returns:



74
75
76
77
78
79
80
81
# File 'lib/ruby/rego/builtins/yaml.rb', line 74

def self.is_valid(value)
  return BooleanValue.new(false) unless value.is_a?(StringValue)

  ScalarResolver.load(value.value)
  BooleanValue.new(true)
rescue Psych::Exception, ScalarResolver::ResolveError, ArgumentError, SystemStackError
  BooleanValue.new(false)
end

.marshal(value) ⇒ Ruby::Rego::StringValue

Parameters:

Returns:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ruby/rego/builtins/yaml.rb', line 46

def self.marshal(value)
  StringValue.new(Emitter.emit(value.to_ruby))
rescue Emitter::MarshalError, SystemStackError, ArgumentError => e
  # SystemStackError guards deep-recursion overflow; ArgumentError guards an
  # unsortable set element (NaN, whose <=> is nil, raises while ordering the set).
  # Both keep marshal total (undefined) instead of crashing.
  message = e.message
  raise Ruby::Rego::BuiltinArgumentError.new(
    "Cannot marshal value to YAML: #{message}",
    expected: "a YAML-marshalable value",
    actual: message,
    context: "yaml.marshal",
    location: nil
  )
end

.register!Ruby::Rego::Builtins::BuiltinRegistry



36
37
38
39
40
# File 'lib/ruby/rego/builtins/yaml.rb', line 36

def self.register!
  registry = BuiltinRegistry.instance
  register_configured_functions(registry, YAML_FUNCTIONS)
  registry
end

.unmarshal(value) ⇒ Ruby::Rego::Value

Parameters:

Returns:



64
65
66
67
# File 'lib/ruby/rego/builtins/yaml.rb', line 64

def self.unmarshal(value)
  string = string_arg(value, "yaml.unmarshal")
  decoded("yaml.unmarshal") { Value.from_ruby(ScalarResolver.load(string)) }
end