json-ld 3.2.4 → 3.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/json/ld/api.rb +807 -771
  4. data/lib/json/ld/compact.rb +304 -304
  5. data/lib/json/ld/conneg.rb +179 -161
  6. data/lib/json/ld/context.rb +2080 -1913
  7. data/lib/json/ld/expand.rb +745 -666
  8. data/lib/json/ld/extensions.rb +14 -13
  9. data/lib/json/ld/flatten.rb +257 -247
  10. data/lib/json/ld/format.rb +202 -194
  11. data/lib/json/ld/frame.rb +525 -502
  12. data/lib/json/ld/from_rdf.rb +223 -204
  13. data/lib/json/ld/html/nokogiri.rb +123 -121
  14. data/lib/json/ld/html/rexml.rb +151 -147
  15. data/lib/json/ld/reader.rb +107 -100
  16. data/lib/json/ld/resource.rb +224 -205
  17. data/lib/json/ld/streaming_reader.rb +574 -507
  18. data/lib/json/ld/streaming_writer.rb +93 -92
  19. data/lib/json/ld/to_rdf.rb +171 -169
  20. data/lib/json/ld/utils.rb +270 -264
  21. data/lib/json/ld/version.rb +24 -14
  22. data/lib/json/ld/writer.rb +334 -311
  23. data/lib/json/ld.rb +103 -96
  24. metadata +55 -198
  25. data/spec/api_spec.rb +0 -132
  26. data/spec/compact_spec.rb +0 -3482
  27. data/spec/conneg_spec.rb +0 -373
  28. data/spec/context_spec.rb +0 -2056
  29. data/spec/expand_spec.rb +0 -4496
  30. data/spec/flatten_spec.rb +0 -1203
  31. data/spec/format_spec.rb +0 -115
  32. data/spec/frame_spec.rb +0 -2541
  33. data/spec/from_rdf_spec.rb +0 -1072
  34. data/spec/matchers.rb +0 -20
  35. data/spec/rdfstar_spec.rb +0 -25
  36. data/spec/reader_spec.rb +0 -883
  37. data/spec/resource_spec.rb +0 -76
  38. data/spec/spec_helper.rb +0 -281
  39. data/spec/streaming_reader_spec.rb +0 -237
  40. data/spec/streaming_writer_spec.rb +0 -145
  41. data/spec/suite_compact_spec.rb +0 -22
  42. data/spec/suite_expand_spec.rb +0 -36
  43. data/spec/suite_flatten_spec.rb +0 -34
  44. data/spec/suite_frame_spec.rb +0 -29
  45. data/spec/suite_from_rdf_spec.rb +0 -22
  46. data/spec/suite_helper.rb +0 -411
  47. data/spec/suite_html_spec.rb +0 -22
  48. data/spec/suite_http_spec.rb +0 -35
  49. data/spec/suite_remote_doc_spec.rb +0 -22
  50. data/spec/suite_to_rdf_spec.rb +0 -30
  51. data/spec/support/extensions.rb +0 -44
  52. data/spec/test-files/test-1-compacted.jsonld +0 -10
  53. data/spec/test-files/test-1-context.jsonld +0 -7
  54. data/spec/test-files/test-1-expanded.jsonld +0 -5
  55. data/spec/test-files/test-1-input.jsonld +0 -10
  56. data/spec/test-files/test-1-rdf.ttl +0 -8
  57. data/spec/test-files/test-2-compacted.jsonld +0 -20
  58. data/spec/test-files/test-2-context.jsonld +0 -7
  59. data/spec/test-files/test-2-expanded.jsonld +0 -16
  60. data/spec/test-files/test-2-input.jsonld +0 -20
  61. data/spec/test-files/test-2-rdf.ttl +0 -14
  62. data/spec/test-files/test-3-compacted.jsonld +0 -11
  63. data/spec/test-files/test-3-context.jsonld +0 -8
  64. data/spec/test-files/test-3-expanded.jsonld +0 -10
  65. data/spec/test-files/test-3-input.jsonld +0 -11
  66. data/spec/test-files/test-3-rdf.ttl +0 -8
  67. data/spec/test-files/test-4-compacted.jsonld +0 -10
  68. data/spec/test-files/test-4-context.jsonld +0 -7
  69. data/spec/test-files/test-4-expanded.jsonld +0 -6
  70. data/spec/test-files/test-4-input.jsonld +0 -10
  71. data/spec/test-files/test-4-rdf.ttl +0 -5
  72. data/spec/test-files/test-5-compacted.jsonld +0 -13
  73. data/spec/test-files/test-5-context.jsonld +0 -7
  74. data/spec/test-files/test-5-expanded.jsonld +0 -9
  75. data/spec/test-files/test-5-input.jsonld +0 -13
  76. data/spec/test-files/test-5-rdf.ttl +0 -7
  77. data/spec/test-files/test-6-compacted.jsonld +0 -10
  78. data/spec/test-files/test-6-context.jsonld +0 -7
  79. data/spec/test-files/test-6-expanded.jsonld +0 -10
  80. data/spec/test-files/test-6-input.jsonld +0 -10
  81. data/spec/test-files/test-6-rdf.ttl +0 -6
  82. data/spec/test-files/test-7-compacted.jsonld +0 -23
  83. data/spec/test-files/test-7-context.jsonld +0 -4
  84. data/spec/test-files/test-7-expanded.jsonld +0 -20
  85. data/spec/test-files/test-7-input.jsonld +0 -23
  86. data/spec/test-files/test-7-rdf.ttl +0 -14
  87. data/spec/test-files/test-8-compacted.jsonld +0 -34
  88. data/spec/test-files/test-8-context.jsonld +0 -11
  89. data/spec/test-files/test-8-expanded.jsonld +0 -24
  90. data/spec/test-files/test-8-frame.jsonld +0 -18
  91. data/spec/test-files/test-8-framed.jsonld +0 -25
  92. data/spec/test-files/test-8-input.jsonld +0 -30
  93. data/spec/test-files/test-8-rdf.ttl +0 -15
  94. data/spec/test-files/test-9-compacted.jsonld +0 -20
  95. data/spec/test-files/test-9-context.jsonld +0 -13
  96. data/spec/test-files/test-9-expanded.jsonld +0 -14
  97. data/spec/test-files/test-9-input.jsonld +0 -12
  98. data/spec/to_rdf_spec.rb +0 -1684
  99. data/spec/writer_spec.rb +0 -427
data/lib/json/ld/frame.rb CHANGED
@@ -1,224 +1,234 @@
1
- # -*- encoding: utf-8 -*-
2
1
  # frozen_string_literal: true
2
+
3
3
  require 'set'
4
4
 
5
- module JSON::LD
6
- module Frame
7
- include Utils
8
-
9
- ##
10
- # Frame input. Input is expected in expanded form, but frame is in compacted form.
11
- #
12
- # @param [Hash{Symbol => Object}] state
13
- # Current framing state
14
- # @param [Array<String>] subjects
15
- # The subjects to filter
16
- # @param [Hash{String => Object}] frame
17
- # @param [String] property (nil)
18
- # The parent property.
19
- # @param [Hash{String => Object}] parent (nil)
20
- # Parent subject or top-level array
21
- # @param [Boolean] ordered (true)
22
- # Ensure output objects have keys ordered properly
23
- # @param [Hash{Symbol => Object}] options ({})
24
- # @raise [JSON::LD::InvalidFrame]
25
- def frame(state, subjects, frame, parent: nil, property: nil, ordered: false, **options)
26
- # Validate the frame
27
- validate_frame(frame)
28
- frame = frame.first if frame.is_a?(Array)
29
-
30
- # Get values for embedOn and explicitOn
31
- flags = {
32
- embed: get_frame_flag(frame, options, :embed),
33
- explicit: get_frame_flag(frame, options, :explicit),
34
- requireAll: get_frame_flag(frame, options, :requireAll),
35
- }
36
-
37
- # Get link for current graph
38
- link = state[:link][state[:graph]] ||= {}
39
-
40
- # Create a set of matched subjects by filtering subjects by checking the map of flattened subjects against frame
41
- # This gives us a hash of objects indexed by @id
42
- matches = filter_subjects(state, subjects, frame, flags)
43
-
44
- # For each id and node from the set of matched subjects ordered by id
45
- matches.keys.opt_sort(ordered: ordered).each do |id|
46
- subject = matches[id]
47
-
48
- # Note: In order to treat each top-level match as a compartmentalized result, clear the unique embedded subjects map when the property is nil, which only occurs at the top-level.
49
- if property.nil?
50
- state[:uniqueEmbeds] = {state[:graph] => {}}
51
- else
52
- state[:uniqueEmbeds][state[:graph]] ||= {}
53
- end
5
+ module JSON
6
+ module LD
7
+ module Frame
8
+ include Utils
9
+
10
+ ##
11
+ # Frame input. Input is expected in expanded form, but frame is in compacted form.
12
+ #
13
+ # @param [Hash{Symbol => Object}] state
14
+ # Current framing state
15
+ # @param [Array<String>] subjects
16
+ # The subjects to filter
17
+ # @param [Hash{String => Object}] frame
18
+ # @param [String] property (nil)
19
+ # The parent property.
20
+ # @param [Hash{String => Object}] parent (nil)
21
+ # Parent subject or top-level array
22
+ # @param [Boolean] ordered (true)
23
+ # Ensure output objects have keys ordered properly
24
+ # @param [Hash{Symbol => Object}] options ({})
25
+ # @raise [JSON::LD::InvalidFrame]
26
+ def frame(state, subjects, frame, parent: nil, property: nil, ordered: false, **options)
27
+ # Validate the frame
28
+ validate_frame(frame)
29
+ frame = frame.first if frame.is_a?(Array)
30
+
31
+ # Get values for embedOn and explicitOn
32
+ flags = {
33
+ embed: get_frame_flag(frame, options, :embed),
34
+ explicit: get_frame_flag(frame, options, :explicit),
35
+ requireAll: get_frame_flag(frame, options, :requireAll)
36
+ }
54
37
 
55
- if flags[:embed] == '@link' && link.key?(id)
56
- # add existing linked subject
57
- add_frame_output(parent, property, link[id])
58
- next
59
- end
38
+ # Get link for current graph
39
+ link = state[:link][state[:graph]] ||= {}
60
40
 
61
- output = {'@id' => id}
62
- link[id] = output
41
+ # Create a set of matched subjects by filtering subjects by checking the map of flattened subjects against frame
42
+ # This gives us a hash of objects indexed by @id
43
+ matches = filter_subjects(state, subjects, frame, flags)
63
44
 
64
- if %w(@first @last).include?(flags[:embed]) && context.processingMode('json-ld-1.1')
65
- raise JSON::LD::JsonLdError::InvalidEmbedValue, "#{flags[:embed]} is not a valid value of @embed in 1.1 mode" if @options[:validate]
66
- warn "[DEPRECATION] #{flags[:embed]} is not a valid value of @embed in 1.1 mode.\n"
67
- end
45
+ # For each id and node from the set of matched subjects ordered by id
46
+ matches.keys.opt_sort(ordered: ordered).each do |id|
47
+ subject = matches[id]
68
48
 
69
- if !state[:embedded] && state[:uniqueEmbeds][state[:graph]].key?(id)
70
- # Skip adding this node object to the top-level, as it was included in another node object
71
- next
72
- elsif state[:embedded] &&
73
- (flags[:embed] == '@never' || creates_circular_reference(subject, state[:graph], state[:subjectStack]))
74
- # if embed is @never or if a circular reference would be created by an embed, the subject cannot be embedded, just add the reference; note that a circular reference won't occur when the embed flag is `@link` as the above check will short-circuit before reaching this point
75
- add_frame_output(parent, property, output)
76
- next
77
- elsif state[:embedded] &&
78
- %w(@first @once).include?(flags[:embed]) &&
79
- state[:uniqueEmbeds][state[:graph]].key?(id)
49
+ # NOTE: In order to treat each top-level match as a compartmentalized result, clear the unique embedded subjects map when the property is nil, which only occurs at the top-level.
50
+ if property.nil?
51
+ state[:uniqueEmbeds] = { state[:graph] => {} }
52
+ else
53
+ state[:uniqueEmbeds][state[:graph]] ||= {}
54
+ end
80
55
 
81
- # if only the first match should be embedded
82
- # Embed unless already embedded
83
- add_frame_output(parent, property, output)
84
- next
85
- elsif flags[:embed] == '@last'
86
- # if only the last match should be embedded
87
- # remove any existing embed
88
- remove_embed(state, id) if state[:uniqueEmbeds][state[:graph]].include?(id)
89
- end
56
+ if flags[:embed] == '@link' && link.key?(id)
57
+ # add existing linked subject
58
+ add_frame_output(parent, property, link[id])
59
+ next
60
+ end
90
61
 
91
- state[:uniqueEmbeds][state[:graph]][id] = {
92
- parent: parent,
93
- property: property
94
- }
62
+ output = { '@id' => id }
63
+ link[id] = output
95
64
 
96
- # push matching subject onto stack to enable circular embed checks
97
- state[:subjectStack] << {subject: subject, graph: state[:graph]}
98
-
99
- # Subject is also the name of a graph
100
- if state[:graphMap].key?(id)
101
- # check frame's "@graph" to see what to do next
102
- # 1. if it doesn't exist and state.graph === "@merged", don't recurse
103
- # 2. if it doesn't exist and state.graph !== "@merged", recurse
104
- # 3. if "@merged" then don't recurse
105
- # 4. if "@default" then don't recurse
106
- # 5. recurse
107
- recurse, subframe = false, nil
108
- if !frame.key?('@graph')
109
- recurse, subframe = (state[:graph] != '@merged'), {}
110
- else
111
- subframe = frame['@graph'].first
112
- recurse = !(id == '@merged' || id == '@default')
113
- subframe = {} unless subframe.is_a?(Hash)
65
+ if %w[@first @last].include?(flags[:embed]) && context.processingMode('json-ld-1.1')
66
+ if @options[:validate]
67
+ raise JSON::LD::JsonLdError::InvalidEmbedValue,
68
+ "#{flags[:embed]} is not a valid value of @embed in 1.1 mode"
69
+ end
70
+
71
+ warn "[DEPRECATION] #{flags[:embed]} is not a valid value of @embed in 1.1 mode.\n"
114
72
  end
115
73
 
116
- if recurse
117
- frame(state.merge(graph: id, embedded: false), state[:graphMap][id].keys, [subframe], parent: output, property: '@graph', **options)
74
+ if !state[:embedded] && state[:uniqueEmbeds][state[:graph]].key?(id)
75
+ # Skip adding this node object to the top-level, as it was included in another node object
76
+ next
77
+ elsif state[:embedded] &&
78
+ (flags[:embed] == '@never' || creates_circular_reference(subject, state[:graph], state[:subjectStack]))
79
+ # if embed is @never or if a circular reference would be created by an embed, the subject cannot be embedded, just add the reference; note that a circular reference won't occur when the embed flag is `@link` as the above check will short-circuit before reaching this point
80
+ add_frame_output(parent, property, output)
81
+ next
82
+ elsif state[:embedded] &&
83
+ %w[@first @once].include?(flags[:embed]) &&
84
+ state[:uniqueEmbeds][state[:graph]].key?(id)
85
+
86
+ # if only the first match should be embedded
87
+ # Embed unless already embedded
88
+ add_frame_output(parent, property, output)
89
+ next
90
+ elsif flags[:embed] == '@last'
91
+ # if only the last match should be embedded
92
+ # remove any existing embed
93
+ remove_embed(state, id) if state[:uniqueEmbeds][state[:graph]].include?(id)
118
94
  end
119
- end
120
95
 
121
- # If frame has `@included`, recurse over its sub-frame
122
- if frame['@included']
123
- frame(state.merge(embedded: false), subjects, frame['@included'], parent: output, property: '@included', **options)
124
- end
96
+ state[:uniqueEmbeds][state[:graph]][id] = {
97
+ parent: parent,
98
+ property: property
99
+ }
100
+
101
+ # push matching subject onto stack to enable circular embed checks
102
+ state[:subjectStack] << { subject: subject, graph: state[:graph] }
103
+
104
+ # Subject is also the name of a graph
105
+ if state[:graphMap].key?(id)
106
+ # check frame's "@graph" to see what to do next
107
+ # 1. if it doesn't exist and state.graph === "@merged", don't recurse
108
+ # 2. if it doesn't exist and state.graph !== "@merged", recurse
109
+ # 3. if "@merged" then don't recurse
110
+ # 4. if "@default" then don't recurse
111
+ # 5. recurse
112
+ recurse = false
113
+ subframe = nil
114
+ if frame.key?('@graph')
115
+ subframe = frame['@graph'].first
116
+ recurse = !['@merged', '@default'].include?(id)
117
+ subframe = {} unless subframe.is_a?(Hash)
118
+ else
119
+ recurse = (state[:graph] != '@merged')
120
+ subframe = {}
121
+ end
125
122
 
126
- # iterate over subject properties in order
127
- subject.keys.opt_sort(ordered: ordered).each do |prop|
128
- objects = subject[prop]
123
+ if recurse
124
+ frame(state.merge(graph: id, embedded: false), state[:graphMap][id].keys, [subframe], parent: output,
125
+ property: '@graph', **options)
126
+ end
127
+ end
129
128
 
130
- # copy keywords to output
131
- if prop.start_with?('@')
132
- output[prop] = objects.dup
133
- next
129
+ # If frame has `@included`, recurse over its sub-frame
130
+ if frame['@included']
131
+ frame(state.merge(embedded: false), subjects, frame['@included'], parent: output, property: '@included',
132
+ **options)
134
133
  end
135
134
 
136
- # explicit is on and property isn't in frame, skip processing
137
- next if flags[:explicit] && !frame.key?(prop)
138
-
139
- # add objects
140
- objects.each do |o|
141
- subframe = Array(frame[prop]).first || create_implicit_frame(flags)
142
-
143
- case
144
- when list?(o)
145
- subframe = frame[prop].first['@list'] if Array(frame[prop]).first.is_a?(Hash)
146
- subframe ||= create_implicit_frame(flags)
147
- # add empty list
148
- list = {'@list' => []}
149
- add_frame_output(output, prop, list)
150
-
151
- src = o['@list']
152
- src.each do |oo|
153
- if node_reference?(oo)
154
- frame(state.merge(embedded: true), [oo['@id']], subframe, parent: list, property: '@list', **options)
155
- else
156
- add_frame_output(list, '@list', oo.dup)
135
+ # iterate over subject properties in order
136
+ subject.keys.opt_sort(ordered: ordered).each do |prop|
137
+ objects = subject[prop]
138
+
139
+ # copy keywords to output
140
+ if prop.start_with?('@')
141
+ output[prop] = objects.dup
142
+ next
143
+ end
144
+
145
+ # explicit is on and property isn't in frame, skip processing
146
+ next if flags[:explicit] && !frame.key?(prop)
147
+
148
+ # add objects
149
+ objects.each do |o|
150
+ subframe = Array(frame[prop]).first || create_implicit_frame(flags)
151
+
152
+ if list?(o)
153
+ subframe = frame[prop].first['@list'] if Array(frame[prop]).first.is_a?(Hash)
154
+ subframe ||= create_implicit_frame(flags)
155
+ # add empty list
156
+ list = { '@list' => [] }
157
+ add_frame_output(output, prop, list)
158
+
159
+ src = o['@list']
160
+ src.each do |oo|
161
+ if node_reference?(oo)
162
+ frame(state.merge(embedded: true), [oo['@id']], subframe, parent: list, property: '@list',
163
+ **options)
164
+ else
165
+ add_frame_output(list, '@list', oo.dup)
166
+ end
157
167
  end
168
+ elsif node_reference?(o)
169
+ # recurse into subject reference
170
+ frame(state.merge(embedded: true), [o['@id']], subframe, parent: output, property: prop, **options)
171
+ elsif value_match?(subframe, o)
172
+ # Include values if they match
173
+ add_frame_output(output, prop, o.dup)
158
174
  end
159
- when node_reference?(o)
160
- # recurse into subject reference
161
- frame(state.merge(embedded: true), [o['@id']], subframe, parent: output, property: prop, **options)
162
- when value_match?(subframe, o)
163
- # Include values if they match
164
- add_frame_output(output, prop, o.dup)
165
175
  end
166
176
  end
167
- end
168
177
 
169
- # handle defaults in order
170
- frame.keys.opt_sort(ordered: ordered).each do |prop|
171
- if prop == '@type' && frame[prop].first.is_a?(Hash) && frame[prop].first.keys == %w(@default)
172
- # Treat this as a default
173
- elsif prop.start_with?('@')
174
- next
175
- end
178
+ # handle defaults in order
179
+ frame.keys.opt_sort(ordered: ordered).each do |prop|
180
+ if prop == '@type' && frame[prop].first.is_a?(Hash) && frame[prop].first.keys == %w[@default]
181
+ # Treat this as a default
182
+ elsif prop.start_with?('@')
183
+ next
184
+ end
176
185
 
177
- # if omit default is off, then include default values for properties that appear in the next frame but are not in the matching subject
178
- n = frame[prop].first || {}
179
- omit_default_on = get_frame_flag(n, options, :omitDefault)
180
- if !omit_default_on && !output[prop]
181
- preserve = as_array(n.fetch('@default', '@null').dup)
182
- output[prop] = [{'@preserve' => preserve}]
186
+ # if omit default is off, then include default values for properties that appear in the next frame but are not in the matching subject
187
+ n = frame[prop].first || {}
188
+ omit_default_on = get_frame_flag(n, options, :omitDefault)
189
+ if !omit_default_on && !output[prop]
190
+ preserve = as_array(n.fetch('@default', '@null').dup)
191
+ output[prop] = [{ '@preserve' => preserve }]
192
+ end
183
193
  end
184
- end
185
194
 
186
- # If frame has @reverse, embed identified nodes having this subject as a value of the associated property.
187
- frame.fetch('@reverse', {}).each do |reverse_prop, subframe|
188
- state[:subjects].each do |r_id, node|
189
- if Array(node[reverse_prop]).any? {|v| v['@id'] == id}
195
+ # If frame has @reverse, embed identified nodes having this subject as a value of the associated property.
196
+ frame.fetch('@reverse', {}).each do |reverse_prop, subframe|
197
+ state[:subjects].each do |r_id, node|
198
+ next unless Array(node[reverse_prop]).any? { |v| v['@id'] == id }
199
+
190
200
  # Node has property referencing this subject
191
201
  # recurse into reference
192
202
  (output['@reverse'] ||= {})[reverse_prop] ||= []
193
- frame(state.merge(embedded: true), [r_id], subframe, parent: output['@reverse'][reverse_prop], property: property, **options)
203
+ frame(state.merge(embedded: true), [r_id], subframe, parent: output['@reverse'][reverse_prop],
204
+ property: property, **options)
194
205
  end
195
206
  end
196
- end
197
207
 
198
- # add output to parent
199
- add_frame_output(parent, property, output)
208
+ # add output to parent
209
+ add_frame_output(parent, property, output)
200
210
 
201
- # pop matching subject from circular ref-checking stack
202
- state[:subjectStack].pop()
211
+ # pop matching subject from circular ref-checking stack
212
+ state[:subjectStack].pop
213
+ end
214
+ # end
203
215
  end
204
- #end
205
- end
206
216
 
207
- ##
208
- # Recursively find and count blankNode identifiers.
209
- # @return [Hash{String => Integer}]
210
- def count_blank_node_identifiers(input)
211
- {}.tap do |results|
212
- count_blank_node_identifiers_internal(input, results)
217
+ ##
218
+ # Recursively find and count blankNode identifiers.
219
+ # @return [Hash{String => Integer}]
220
+ def count_blank_node_identifiers(input)
221
+ {}.tap do |results|
222
+ count_blank_node_identifiers_internal(input, results)
223
+ end
213
224
  end
214
- end
215
225
 
216
- def count_blank_node_identifiers_internal(input, results)
217
- case input
226
+ def count_blank_node_identifiers_internal(input, results)
227
+ case input
218
228
  when Array
219
- input.each {|o| count_blank_node_identifiers_internal(o, results)}
229
+ input.each { |o| count_blank_node_identifiers_internal(o, results) }
220
230
  when Hash
221
- input.each do |k, v|
231
+ input.each do |_k, v|
222
232
  count_blank_node_identifiers_internal(v, results)
223
233
  end
224
234
  when String
@@ -226,377 +236,390 @@ module JSON::LD
226
236
  results[input] ||= 0
227
237
  results[input] += 1
228
238
  end
239
+ end
229
240
  end
230
- end
231
241
 
232
- ##
233
- # Prune BNode identifiers recursively
234
- #
235
- # @param [Array, Hash] input
236
- # @param [Array<String>] bnodes_to_clear
237
- # @return [Array, Hash]
238
- def prune_bnodes(input, bnodes_to_clear)
239
- result = case input
240
- when Array
241
- # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
242
- input.map {|o| prune_bnodes(o, bnodes_to_clear)}.compact
243
- when Hash
244
- output = Hash.new
245
- input.each do |key, value|
246
- if context.expand_iri(key) == '@id' && bnodes_to_clear.include?(value)
247
- # Don't add this to output, as it is pruned as being superfluous
248
- else
249
- output[key] = prune_bnodes(value, bnodes_to_clear)
242
+ ##
243
+ # Prune BNode identifiers recursively
244
+ #
245
+ # @param [Array, Hash] input
246
+ # @param [Array<String>] bnodes_to_clear
247
+ # @return [Array, Hash]
248
+ def prune_bnodes(input, bnodes_to_clear)
249
+ case input
250
+ when Array
251
+ # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
252
+ input.map { |o| prune_bnodes(o, bnodes_to_clear) }.compact
253
+ when Hash
254
+ output = {}
255
+ input.each do |key, value|
256
+ if context.expand_iri(key) == '@id' && bnodes_to_clear.include?(value)
257
+ # Don't add this to output, as it is pruned as being superfluous
258
+ else
259
+ output[key] = prune_bnodes(value, bnodes_to_clear)
260
+ end
250
261
  end
262
+ output
263
+ else
264
+ input
251
265
  end
252
- output
253
- else
254
- input
255
266
  end
256
- result
257
- end
258
267
 
259
- ##
260
- # Replace @preserve keys with the values, also replace @null with null.
261
- #
262
- # @param [Array, Hash] input
263
- # @return [Array, Hash]
264
- def cleanup_preserve(input)
265
- case input
266
- when Array
267
- # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
268
- input.map {|o| cleanup_preserve(o)}
269
- when Hash
270
- if input.key?('@preserve')
271
- # Replace with the content of `@preserve`
272
- cleanup_preserve(input['@preserve'].first)
273
- else
274
- input.inject({}) do |memo, (k,v)|
275
- memo.merge(k => cleanup_preserve(v))
268
+ ##
269
+ # Replace @preserve keys with the values, also replace @null with null.
270
+ #
271
+ # @param [Array, Hash] input
272
+ # @return [Array, Hash]
273
+ def cleanup_preserve(input)
274
+ case input
275
+ when Array
276
+ input.map! { |o| cleanup_preserve(o) }
277
+ when Hash
278
+ if input.key?('@preserve')
279
+ # Replace with the content of `@preserve`
280
+ cleanup_preserve(input['@preserve'].first)
281
+ else
282
+ input.transform_values do |v|
283
+ cleanup_preserve(v)
284
+ end
276
285
  end
286
+ else
287
+ input
277
288
  end
278
- else
279
- input
280
289
  end
281
- end
282
290
 
283
- ##
284
- # Replace `@null` with `null`, removing it from arrays.
285
- #
286
- # @param [Array, Hash] input
287
- # @return [Array, Hash]
288
- def cleanup_null(input)
289
- result = case input
290
- when Array
291
- # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
292
- input.map {|o| cleanup_null(o)}.compact
293
- when Hash
294
- input.inject({}) do |memo, (k,v)|
295
- memo.merge(k => cleanup_null(v))
291
+ ##
292
+ # Replace `@null` with `null`, removing it from arrays.
293
+ #
294
+ # @param [Array, Hash] input
295
+ # @return [Array, Hash]
296
+ def cleanup_null(input)
297
+ case input
298
+ when Array
299
+ # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
300
+ input.map! { |o| cleanup_null(o) }.compact
301
+ when Hash
302
+ input.transform_values do |v|
303
+ cleanup_null(v)
304
+ end
305
+ when '@null'
306
+ # If the value from the key-pair is @null, replace the value with null
307
+ nil
308
+ else
309
+ input
296
310
  end
297
- when '@null'
298
- # If the value from the key-pair is @null, replace the value with null
299
- nil
300
- else
301
- input
302
311
  end
303
- result
304
- end
305
312
 
306
- private
307
-
308
- ##
309
- # Returns a map of all of the subjects that match a parsed frame.
310
- #
311
- # @param [Hash{Symbol => Object}] state
312
- # Current framing state
313
- # @param [Array<String>] subjects
314
- # The subjects to filter
315
- # @param [Hash{String => Object}] frame
316
- # @param [Hash{Symbol => String}] flags the frame flags.
317
- #
318
- # @return all of the matched subjects.
319
- def filter_subjects(state, subjects, frame, flags)
320
- subjects.each_with_object({}) do |id, memo|
321
- subject = state[:graphMap][state[:graph]][id]
322
- memo[id] = subject if filter_subject(subject, frame, state, flags)
313
+ private
314
+
315
+ ##
316
+ # Returns a map of all of the subjects that match a parsed frame.
317
+ #
318
+ # @param [Hash{Symbol => Object}] state
319
+ # Current framing state
320
+ # @param [Array<String>] subjects
321
+ # The subjects to filter
322
+ # @param [Hash{String => Object}] frame
323
+ # @param [Hash{Symbol => String}] flags the frame flags.
324
+ #
325
+ # @return all of the matched subjects.
326
+ def filter_subjects(state, subjects, frame, flags)
327
+ subjects.each_with_object({}) do |id, memo|
328
+ subject = state[:graphMap][state[:graph]][id]
329
+ memo[id] = subject if filter_subject(subject, frame, state, flags)
330
+ end
323
331
  end
324
- end
325
332
 
326
- ##
327
- # Returns true if the given node matches the given frame.
328
- #
329
- # Matches either based on explicit type inclusion where the node has any type listed in the frame. If the frame has empty types defined matches nodes not having a @type. If the frame has a type of {} defined matches nodes having any type defined.
330
- #
331
- # Otherwise, does duck typing, where the node must have any or all of the properties defined in the frame, depending on the `requireAll` flag.
332
- #
333
- # @param [Hash{String => Object}] subject the subject to check.
334
- # @param [Hash{String => Object}] frame the frame to check.
335
- # @param [Hash{Symbol => Object}] state Current framing state
336
- # @param [Hash{Symbol => Object}] flags the frame flags.
337
- #
338
- # @return [Boolean] true if the node matches, false if not.
339
- def filter_subject(subject, frame, state, flags)
340
- # Duck typing, for nodes not having a type, but having @id
341
- wildcard, matches_some = true, false
342
-
343
- frame.each do |k, v|
344
- node_values = subject.fetch(k, [])
345
-
346
- case k
347
- when '@id'
348
- ids = v || []
349
-
350
- # Match on specific @id.
351
- match_this = case ids
352
- when [], [{}]
353
- # Match on no @id or any @id
354
- true
355
- else
356
- # Match on specific @id
357
- ids.include?(subject['@id'])
358
- end
359
- return match_this if !flags[:requireAll]
360
- when '@type'
361
- # No longer a wildcard pattern
362
- wildcard = false
363
-
364
- match_this = case v
365
- when []
366
- # Don't match with any @type
367
- return false if !node_values.empty?
368
- true
369
- when [{}]
370
- # Match with any @type
371
- !node_values.empty?
372
- else
373
- # Treat a map with @default like an empty map
374
- if v.first.is_a?(Hash) && v.first.keys == %w(@default)
333
+ ##
334
+ # Returns true if the given node matches the given frame.
335
+ #
336
+ # Matches either based on explicit type inclusion where the node has any type listed in the frame. If the frame has empty types defined matches nodes not having a @type. If the frame has a type of {} defined matches nodes having any type defined.
337
+ #
338
+ # Otherwise, does duck typing, where the node must have any or all of the properties defined in the frame, depending on the `requireAll` flag.
339
+ #
340
+ # @param [Hash{String => Object}] subject the subject to check.
341
+ # @param [Hash{String => Object}] frame the frame to check.
342
+ # @param [Hash{Symbol => Object}] state Current framing state
343
+ # @param [Hash{Symbol => Object}] flags the frame flags.
344
+ #
345
+ # @return [Boolean] true if the node matches, false if not.
346
+ def filter_subject(subject, frame, state, flags)
347
+ # Duck typing, for nodes not having a type, but having @id
348
+ wildcard = true
349
+ matches_some = false
350
+
351
+ frame.each do |k, v|
352
+ node_values = subject.fetch(k, [])
353
+
354
+ case k
355
+ when '@id'
356
+ ids = v || []
357
+
358
+ # Match on specific @id.
359
+ match_this = case ids
360
+ when [], [{}]
361
+ # Match on no @id or any @id
375
362
  true
376
- elsif (v & node_values).empty?
377
- # Match on specific @type
378
- false
379
363
  else
380
- true
364
+ # Match on specific @id
365
+ ids.include?(subject['@id'])
381
366
  end
382
- end
383
- return match_this if !flags[:requireAll]
384
- when /@/
385
- # Skip other keywords
386
- next
387
- else
388
- is_empty = v.empty?
389
- if v = v.first
390
- validate_frame(v)
391
- has_default = v.key?('@default')
392
- end
367
+ return match_this unless flags[:requireAll]
368
+ when '@type'
369
+ # No longer a wildcard pattern
370
+ wildcard = false
393
371
 
394
- # No longer a wildcard pattern if frame has any non-keyword properties
395
- wildcard = false
396
-
397
- # Skip, but allow match if node has no value for property, and frame has a default value
398
- next if node_values.empty? && has_default
399
-
400
- # If frame value is empty, don't match if subject has any value
401
- return false if !node_values.empty? && is_empty
402
-
403
- match_this = case
404
- when v.nil?
405
- # node does not match if values is not empty and the value of property in frame is match none.
406
- return false unless node_values.empty?
407
- true
408
- when v.is_a?(Hash) && (v.keys - FRAMING_KEYWORDS).empty?
409
- # node matches if values is not empty and the value of property in frame is wildcard (frame with properties other than framing keywords)
410
- !node_values.empty?
411
- when value?(v)
412
- # Match on any matching value
413
- node_values.any? {|nv| value_match?(v, nv)}
414
- when node?(v) || node_reference?(v)
415
- node_values.any? do |nv|
416
- node_match?(v, nv, state, flags)
372
+ match_this = case v
373
+ when []
374
+ # Don't match with any @type
375
+ return false unless node_values.empty?
376
+
377
+ true
378
+ when [{}]
379
+ # Match with any @type
380
+ !node_values.empty?
381
+ else
382
+ # Treat a map with @default like an empty map
383
+ if v.first.is_a?(Hash) && v.first.keys == %w[@default]
384
+ true
385
+ else
386
+ !(v & node_values).empty?
387
+ end
417
388
  end
418
- when list?(v)
419
- vv = v['@list'].first
420
- node_values = list?(node_values.first) ?
421
- node_values.first['@list'] :
422
- false
423
- if !node_values
424
- false # Lists match Lists
425
- elsif value?(vv)
389
+ return match_this unless flags[:requireAll]
390
+ when /@/
391
+ # Skip other keywords
392
+ next
393
+ else
394
+ is_empty = v.empty?
395
+ if (v = v.first)
396
+ validate_frame(v)
397
+ has_default = v.key?('@default')
398
+ end
399
+
400
+ # No longer a wildcard pattern if frame has any non-keyword properties
401
+ wildcard = false
402
+
403
+ # Skip, but allow match if node has no value for property, and frame has a default value
404
+ next if node_values.empty? && has_default
405
+
406
+ # If frame value is empty, don't match if subject has any value
407
+ return false if !node_values.empty? && is_empty
408
+
409
+ match_this = case
410
+ when v.nil?
411
+ # node does not match if values is not empty and the value of property in frame is match none.
412
+ return false unless node_values.empty?
413
+
414
+ true
415
+ when v.is_a?(Hash) && (v.keys - FRAMING_KEYWORDS).empty?
416
+ # node matches if values is not empty and the value of property in frame is wildcard (frame with properties other than framing keywords)
417
+ !node_values.empty?
418
+ when value?(v)
426
419
  # Match on any matching value
427
- node_values.any? {|nv| value_match?(vv, nv)}
428
- elsif node?(vv) || node_reference?(vv)
420
+ node_values.any? { |nv| value_match?(v, nv) }
421
+ when node?(v) || node_reference?(v)
429
422
  node_values.any? do |nv|
430
- node_match?(vv, nv, state, flags)
423
+ node_match?(v, nv, state, flags)
424
+ end
425
+ when list?(v)
426
+ vv = v['@list'].first
427
+ node_values = if list?(node_values.first)
428
+ node_values.first['@list']
429
+ else
430
+ false
431
+ end
432
+ if !node_values
433
+ false # Lists match Lists
434
+ elsif value?(vv)
435
+ # Match on any matching value
436
+ node_values.any? { |nv| value_match?(vv, nv) }
437
+ elsif node?(vv) || node_reference?(vv)
438
+ node_values.any? do |nv|
439
+ node_match?(vv, nv, state, flags)
440
+ end
441
+ else
442
+ false
431
443
  end
432
444
  else
433
- false
445
+ false # No matching on non-value or node values
434
446
  end
435
- else
436
- false # No matching on non-value or node values
437
447
  end
438
- end
439
448
 
440
- # All non-defaulted values must match if @requireAll is set
441
- return false if !match_this && flags[:requireAll]
449
+ # All non-defaulted values must match if @requireAll is set
450
+ return false if !match_this && flags[:requireAll]
451
+
452
+ matches_some ||= match_this
453
+ end
442
454
 
443
- matches_some ||= match_this
455
+ # return true if wildcard or subject matches some properties
456
+ wildcard || matches_some
444
457
  end
445
458
 
446
- # return true if wildcard or subject matches some properties
447
- wildcard || matches_some
448
- end
459
+ def validate_frame(frame)
460
+ unless frame.is_a?(Hash) || (frame.is_a?(Array) && frame.first.is_a?(Hash) && frame.length == 1)
461
+ raise JsonLdError::InvalidFrame,
462
+ "Invalid JSON-LD frame syntax; a JSON-LD frame must be an object: #{frame.inspect}"
463
+ end
464
+ frame = frame.first if frame.is_a?(Array)
449
465
 
450
- def validate_frame(frame)
451
- raise JsonLdError::InvalidFrame,
452
- "Invalid JSON-LD frame syntax; a JSON-LD frame must be an object: #{frame.inspect}" unless
453
- frame.is_a?(Hash) || (frame.is_a?(Array) && frame.first.is_a?(Hash) && frame.length == 1)
454
- frame = frame.first if frame.is_a?(Array)
455
-
456
- # Check values of @id and @type
457
- raise JsonLdError::InvalidFrame,
458
- "Invalid JSON-LD frame syntax; invalid value of @id: #{frame['@id']}" unless
459
- Array(frame['@id']) == [{}] || Array(frame['@id']).all?{|v| RDF::URI(v).valid?}
460
- raise JsonLdError::InvalidFrame,
461
- "Invalid JSON-LD frame syntax; invalid value of @type: #{frame['@type']}" unless
462
- Array(frame['@type']).all?{|v| v.is_a?(Hash) && (v.keys - %w(@default)).empty? || RDF::URI(v).valid?}
463
- end
466
+ # Check values of @id and @type
467
+ unless Array(frame['@id']) == [{}] || Array(frame['@id']).all? { |v| RDF::URI(v).valid? }
468
+ raise JsonLdError::InvalidFrame,
469
+ "Invalid JSON-LD frame syntax; invalid value of @id: #{frame['@id']}"
470
+ end
471
+ unless Array(frame['@type']).all? do |v|
472
+ (v.is_a?(Hash) && (v.keys - %w[@default]).empty?) || RDF::URI(v).valid?
473
+ end
474
+ raise JsonLdError::InvalidFrame,
475
+ "Invalid JSON-LD frame syntax; invalid value of @type: #{frame['@type']}"
476
+ end
477
+ end
464
478
 
465
- # Checks the current subject stack to see if embedding the given subject would cause a circular reference.
466
- #
467
- # @param subject_to_embed the subject to embed.
468
- # @param graph the graph the subject to embed is in.
469
- # @param subject_stack the current stack of subjects.
470
- #
471
- # @return true if a circular reference would be created, false if not.
472
- def creates_circular_reference(subject_to_embed, graph, subject_stack)
473
- subject_stack[0..-2].any? do |subject|
474
- subject[:graph] == graph && subject[:subject]['@id'] == subject_to_embed['@id']
479
+ # Checks the current subject stack to see if embedding the given subject would cause a circular reference.
480
+ #
481
+ # @param subject_to_embed the subject to embed.
482
+ # @param graph the graph the subject to embed is in.
483
+ # @param subject_stack the current stack of subjects.
484
+ #
485
+ # @return true if a circular reference would be created, false if not.
486
+ def creates_circular_reference(subject_to_embed, graph, subject_stack)
487
+ subject_stack[0..-2].any? do |subject|
488
+ subject[:graph] == graph && subject[:subject]['@id'] == subject_to_embed['@id']
489
+ end
475
490
  end
476
- end
477
491
 
478
- ##
479
- # Gets the frame flag value for the given flag name.
480
- #
481
- # @param frame the frame.
482
- # @param options the framing options.
483
- # @param name the flag name.
484
- #
485
- # @return the flag value.
486
- def get_frame_flag(frame, options, name)
487
- rval = frame.fetch("@#{name}", [options[name]]).first
488
- rval = rval.values.first if value?(rval)
489
- if name == :embed
490
- rval = case rval
491
- when true then '@once'
492
- when false then '@never'
493
- when '@always', '@first', '@last', '@link', '@once', '@never' then rval
494
- else
495
- raise JsonLdError::InvalidEmbedValue,
496
- "Invalid JSON-LD frame syntax; invalid value of @embed: #{rval}"
492
+ ##
493
+ # Gets the frame flag value for the given flag name.
494
+ #
495
+ # @param frame the frame.
496
+ # @param options the framing options.
497
+ # @param name the flag name.
498
+ #
499
+ # @return the flag value.
500
+ def get_frame_flag(frame, options, name)
501
+ rval = frame.fetch("@#{name}", [options[name]]).first
502
+ rval = rval.values.first if value?(rval)
503
+ if name == :embed
504
+ rval = case rval
505
+ when true then '@once'
506
+ when false then '@never'
507
+ when '@always', '@first', '@last', '@link', '@once', '@never' then rval
508
+ else
509
+ raise JsonLdError::InvalidEmbedValue,
510
+ "Invalid JSON-LD frame syntax; invalid value of @embed: #{rval}"
511
+ end
497
512
  end
513
+ rval
498
514
  end
499
- rval
500
- end
501
515
 
502
- ##
503
- # Removes an existing embed.
504
- #
505
- # @param state the current framing state.
506
- # @param id the @id of the embed to remove.
507
- def remove_embed(state, id)
508
- # get existing embed
509
- embeds = state[:uniqueEmbeds][state[:graph]];
510
- embed = embeds[id];
511
- property = embed[:property];
512
-
513
- # create reference to replace embed
514
- subject = {'@id' => id}
515
-
516
- if embed[:parent].is_a?(Array)
517
- # replace subject with reference
518
- embed[:parent].map! do |parent|
519
- compare_values(parent, subject) ? subject : parent
516
+ ##
517
+ # Removes an existing embed.
518
+ #
519
+ # @param state the current framing state.
520
+ # @param id the @id of the embed to remove.
521
+ def remove_embed(state, id)
522
+ # get existing embed
523
+ embeds = state[:uniqueEmbeds][state[:graph]]
524
+ embed = embeds[id]
525
+ property = embed[:property]
526
+
527
+ # create reference to replace embed
528
+ subject = { '@id' => id }
529
+
530
+ if embed[:parent].is_a?(Array)
531
+ # replace subject with reference
532
+ embed[:parent].map! do |parent|
533
+ compare_values(parent, subject) ? subject : parent
534
+ end
535
+ else
536
+ parent = embed[:parent]
537
+ # replace node with reference
538
+ if parent[property].is_a?(Array)
539
+ parent[property].reject! { |v| compare_values(v, subject) }
540
+ parent[property] << subject
541
+ elsif compare_values(parent[property], subject)
542
+ parent[property] = subject
543
+ end
520
544
  end
521
- else
522
- parent = embed[:parent]
523
- # replace node with reference
524
- if parent[property].is_a?(Array)
525
- parent[property].reject! {|v| compare_values(v, subject)}
526
- parent[property] << subject
527
- elsif compare_values(parent[property], subject)
528
- parent[property] = subject
545
+
546
+ # recursively remove dependent dangling embeds
547
+ def remove_dependents(id, embeds)
548
+ # get embed keys as a separate array to enable deleting keys in map
549
+ embeds.each do |id_dep, e|
550
+ p = e.fetch(:parent, {}) if e.is_a?(Hash)
551
+ next unless p.is_a?(Hash)
552
+
553
+ pid = p.fetch('@id', nil)
554
+ if pid == id
555
+ embeds.delete(id_dep)
556
+ remove_dependents(id_dep, embeds)
557
+ end
558
+ end
559
+ end
560
+
561
+ remove_dependents(id, embeds)
562
+ end
563
+
564
+ ##
565
+ # Adds framing output to the given parent.
566
+ #
567
+ # @param parent the parent to add to.
568
+ # @param property the parent property, null for an array parent.
569
+ # @param output the output to add.
570
+ def add_frame_output(parent, property, output)
571
+ if parent.is_a?(Hash)
572
+ parent[property] ||= []
573
+ parent[property] << output
574
+ else
575
+ parent << output
529
576
  end
530
577
  end
531
578
 
532
- # recursively remove dependent dangling embeds
533
- def remove_dependents(id, embeds)
534
- # get embed keys as a separate array to enable deleting keys in map
535
- embeds.each do |id_dep, e|
536
- p = e.fetch(:parent, {}) if e.is_a?(Hash)
537
- next unless p.is_a?(Hash)
538
- pid = p.fetch('@id', nil)
539
- if pid == id
540
- embeds.delete(id_dep)
541
- remove_dependents(id_dep, embeds)
579
+ # Creates an implicit frame when recursing through subject matches. If a frame doesn't have an explicit frame for a particular property, then a wildcard child frame will be created that uses the same flags that the parent frame used.
580
+ #
581
+ # @param [Hash] flags the current framing flags.
582
+ # @return [Array<Hash>] the implicit frame.
583
+ def create_implicit_frame(flags)
584
+ {}.tap do |memo|
585
+ flags.each_pair do |key, val|
586
+ memo["@#{key}"] = [val]
542
587
  end
543
588
  end
544
589
  end
545
590
 
546
- remove_dependents(id, embeds)
547
- end
591
+ # Node matches if it is a node, and matches the pattern as a frame
592
+ def node_match?(pattern, value, state, flags)
593
+ return false unless value['@id']
548
594
 
549
- ##
550
- # Adds framing output to the given parent.
551
- #
552
- # @param parent the parent to add to.
553
- # @param property the parent property, null for an array parent.
554
- # @param output the output to add.
555
- def add_frame_output(parent, property, output)
556
- if parent.is_a?(Hash)
557
- parent[property] ||= []
558
- parent[property] << output
559
- else
560
- parent << output
595
+ node_object = state[:subjects][value['@id']]
596
+ node_object && filter_subject(node_object, pattern, state, flags)
561
597
  end
562
- end
563
598
 
564
- # Creates an implicit frame when recursing through subject matches. If a frame doesn't have an explicit frame for a particular property, then a wildcard child frame will be created that uses the same flags that the parent frame used.
565
- #
566
- # @param [Hash] flags the current framing flags.
567
- # @return [Array<Hash>] the implicit frame.
568
- def create_implicit_frame(flags)
569
- {}.tap do |memo|
570
- flags.each_pair do |key, val|
571
- memo["@#{key}"] = [val]
599
+ # Value matches if it is a value, and matches the value pattern.
600
+ #
601
+ # * `pattern` is empty
602
+ # * @values are the same, or `pattern[@value]` is a wildcard, and
603
+ # * @types are the same or `value[@type]` is not null and `pattern[@type]` is `{}`, or `value[@type]` is null and `pattern[@type]` is null or `[]`, and
604
+ # * @languages are the same or `value[@language]` is not null and `pattern[@language]` is `{}`, or `value[@language]` is null and `pattern[@language]` is null or `[]`.
605
+ def value_match?(pattern, value)
606
+ v1 = value['@value']
607
+ t1 = value['@type']
608
+ l1 = value['@language']
609
+ v2 = Array(pattern['@value'])
610
+ t2 = Array(pattern['@type'])
611
+ l2 = Array(pattern['@language']).map do |v|
612
+ v.is_a?(String) ? v.downcase : v
572
613
  end
573
- end
574
- end
614
+ return true if (v2 + t2 + l2).empty?
615
+ return false unless v2.include?(v1) || v2 == [{}]
616
+ return false unless t2.include?(t1) || (t1 && t2 == [{}]) || (t1.nil? && (t2 || []).empty?)
617
+ return false unless l2.include?(l1.to_s.downcase) || (l1 && l2 == [{}]) || (l1.nil? && (l2 || []).empty?)
575
618
 
576
- private
577
- # Node matches if it is a node, and matches the pattern as a frame
578
- def node_match?(pattern, value, state, flags)
579
- return false unless value['@id']
580
- node_object = state[:subjects][value['@id']]
581
- node_object && filter_subject(node_object, pattern, state, flags)
582
- end
619
+ true
620
+ end
583
621
 
584
- # Value matches if it is a value, and matches the value pattern.
585
- #
586
- # * `pattern` is empty
587
- # * @values are the same, or `pattern[@value]` is a wildcard, and
588
- # * @types are the same or `value[@type]` is not null and `pattern[@type]` is `{}`, or `value[@type]` is null and `pattern[@type]` is null or `[]`, and
589
- # * @languages are the same or `value[@language]` is not null and `pattern[@language]` is `{}`, or `value[@language]` is null and `pattern[@language]` is null or `[]`.
590
- def value_match?(pattern, value)
591
- v1, t1, l1 = value['@value'], value['@type'], value['@language']
592
- v2, t2, l2 = Array(pattern['@value']), Array(pattern['@type']), Array(pattern['@language']).map {|v| v.is_a?(String) ? v.downcase : v}
593
- return true if (v2 + t2 + l2).empty?
594
- return false unless v2.include?(v1) || v2 == [{}]
595
- return false unless t2.include?(t1) || t1 && t2 == [{}] || t1.nil? && (t2 || []).empty?
596
- return false unless l2.include?(l1.to_s.downcase) || l1 && l2 == [{}] || l1.nil? && (l2 || []).empty?
597
- true
622
+ FRAMING_KEYWORDS = %w[@default @embed @explicit @omitDefault @requireAll].freeze
598
623
  end
599
-
600
- FRAMING_KEYWORDS = %w(@default @embed @explicit @omitDefault @requireAll).freeze
601
624
  end
602
625
  end