Module: YAML_LD::Representation

Defined in:
vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb

Overview

Transforms a Psych AST to the JSON-LD (extended) Internal Representation build using Psych.parse, .parse_stream, or parse_file.

FIXME: Aliases

Defined Under Namespace

Classes: IRTree

Class Method Summary collapse

Class Method Details

.as_jsonld_ir(node, **options) ⇒ Object

Transform a Psych::Nodes::Node to the JSON-LD Internal Representation

Parameters:

Options Hash (**options):

  • :extendedYAML (Boolean) — default: false

    Use the expanded internal representation.

Returns:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 110

def as_jsonld_ir(node, **options)
  # Scans scalars for built-in classes
  @ss ||= Psych::ScalarScanner.new(Psych::ClassLoader::Restricted.new([], %i()))

  # Record in-scope anchors to check for circular alias references.
  in_scope_anchors = options[:in_scope_anchors] ||= {}

  case node
  when Psych::Nodes::Stream
    node.children.map {|n| as_jsonld_ir(n, **options)}
  when Psych::Nodes::Document
    as_jsonld_ir(node.children.first, named_nodes: {}, **options)
  when Psych::Nodes::Sequence
    value = []
    if node.anchor
      options = options.merge(in_scope_anchors: in_scope_anchors.merge(node.anchor => true))
      options[:named_nodes][node.anchor] = value
    end
    node.children.each {|n| value << as_jsonld_ir(n, **options)}
    value
  when Psych::Nodes::Mapping
    value = {}
    if node.anchor
      options = options.merge(in_scope_anchors: in_scope_anchors.merge(node.anchor => true))
      options[:named_nodes][node.anchor] = value
    end
    node.children.each_slice(2) do |k, v|
      key = as_jsonld_ir(k)
      raise YAML_LD::Error::MappingKeyError, "mapping key #{k} (#{key.inspect}) not a string" unless key.is_a?(String)
      value[as_jsonld_ir(k)] = as_jsonld_ir(v, **options)
    end
    value
  when ::Psych::Nodes::Scalar
    value = scan_scalar(node, **options)
    if node.anchor
      options = options.merge(in_scope_anchors: in_scope_anchors.merge(node.anchor => true))
      options[:named_nodes][node.anchor] = value
    end
    value
  when ::Psych::Nodes::Alias
   raise JSON::LD::JsonLdError::LoadingDocumentFailed, "anchor for *#{node.anchor} not found" unless options[:named_nodes].key?(node.anchor)
   raise JSON::LD::JsonLdError::LoadingDocumentFailed, "anchor for *#{node.anchor} creates a cycle" if in_scope_anchors.key?(node.anchor)
   options[:named_nodes][node.anchor]
  end
end

.deep_dup(obj) ⇒ Object



93
94
95
96
97
98
99
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 93

def deep_dup(obj)
  case obj
  when Array then obj.map {|e| deep_dup(e)}
  when Hash then obj.inject({}) {|memo, (k,v)| memo.merge(k => deep_dup(v))}
  else obj # No need to de-dup
  end
end

.dump(ir, **options) ⇒ Object

Dump internal representaiton to YAML

Parameters:

  • options[Boolean] (Hash)

    a customizable set of options



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 77

def dump(ir, **options)
  if options[:extendedYAML]
    options = {
      aliases: true,
      permitted_classes: [RDF::Literal]
    }.merge(options)
  else
    # Deep duplicate representation to avoid alias nodes
    ir = deep_dup(ir)
  end
  visitor = Representation::IRTree.create(options)
  visitor << ir
  visitor.tree.yaml
end

.load(yaml, filename: nil, fallback: nil, **options) ⇒ Object

Load a single document from +yaml+.

Parameters:

Returns:



59
60
61
62
63
64
65
66
67
68
69
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 59

def load(yaml, filename: nil, fallback: nil, **options)
  result = if block_given?
    load_stream(yaml, filename: filename, **options) do |node|
      yield node.first
    end
  else
    load_stream(yaml, filename: filename, **options).first
  end

  result || fallback
end

.load_stream(yaml, filename: nil, fallback: [], **options) ⇒ Array<Object>

Load multiple documents given in +yaml+. Returns the parsed documents as a list. If a block is given, each document will be converted to Ruby and passed to the block during parsing

Examples:

load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar']

list = []
load_stream("--- foo\n...\n--- bar\n...") do |ruby|
  list << ruby
end
list # => ['foo', 'bar']

Parameters:

Returns:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 32

def load_stream(yaml, filename: nil, fallback: [], **options)
  result = if block_given?
    Psych.parse_stream(yaml, filename: filename) do |node|
      yield as_jsonld_ir(node, **options)
    end
  else
    as_jsonld_ir(Psych.parse_stream(yaml, filename: filename), **options)
  end

  result.is_a?(Array) && result.empty? ? fallback : result
rescue Psych::SyntaxError => e
  msg = filename ? "file: #{filename} #{e.message}" : e.message
  if yaml.respond_to?(:read)
    msg << "Content:\n" + yaml.tap(:rewind).read
  end
  if e.message.match?(/invalid leading UTF-8 octet/)
    raise YAML_LD::Error::InvalidEncoding, msg
  else
    raise JSON::LD::JsonLdError::LoadingDocumentFailed, msg
  end
end

.scan_scalar(node, **options) ⇒ Object

Scans a scalar value to a JSON-LD IR scalar value. Quoted scalar values are not interpreted.

Parameters:

Options Hash (**options):

  • :extendedYAML (Boolean) — default: false

    Use the expanded internal representation.

Returns:



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/yaml-ld-d851238cc6dc/lib/yaml_ld/representation.rb', line 166

def scan_scalar(node, **options)
  return node.value if node.quoted # No interpretation
  case node.tag
  when "", NilClass
    # Tokenize, but prohibit certain types
    case node.value
      # Don't scan some scalar values to types other than string
    when Psych::ScalarScanner::TIME,
         /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/, # Date
         /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/, # Time to seconds
         /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/ # Time to seconds
      node.value
    else
       @ss.tokenize(node.value)
    end
  when '!str', 'tag:yaml.org,2002:str'
    node.value
  when '!int', 'tag:yaml.org,2002:int'
    Integer(node.value)
  when "!float", "tag:yaml.org,2002:float"
    Float(@ss.tokenize(node.value))
  when "!null", "tag:yaml.org,2002:null"
    nil
  when "!bool", "tag:yaml.org,2002:bool"
    node.value.downcase == 'true'
  when %r(^https://www.w3.org/ns/i18n)
    l_d = node.tag[26..-1]
    l_d = l_d[1..-1] if l_d.start_with?('#')
    l, d = l_d.split('_')
    if !options[:extendedYAML]
      (node.style== Psych::Nodes::Scalar::PLAIN ? @ss.tokenize(node.value) : node.value)
    elsif d.nil?
      # Just use language component
      RDF::Literal(node.value, language: l)
    else
      # Language and direction
      RDF::Literal(node.value, datatype: RDF::URI("https://www.w3.org/ns/i18n##{l_d}"))
    end
  else
    tag = node.tag
    options[:extendedYAML] ?
      RDF::Literal(node.value, datatype: RDF::URI(tag), validate: true) :
      (node.style== Psych::Nodes::Scalar::PLAIN ? @ss.tokenize(node.value) : node.value)
  end
end