json-ld 3.2.3 → 3.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/json/ld/api.rb +807 -764
  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 -1945
  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 +224 -166
  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 -167
  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 +78 -209
  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 -2036
  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 -2498
  33. data/spec/from_rdf_spec.rb +0 -1005
  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 -1551
  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