json-ld 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9fcb46a6c6bf33bfed92adcc8a751598cec5d6511e0450d38c9920bfdb696ce
4
- data.tar.gz: 6fec905be8d5e0335149da757fef899d6e3fa948e852f74e9c88d0bff45801ae
3
+ metadata.gz: 686aaec1dba1b51a5f37e1d4ebd28395c189c0944022b1b9877c7c5a8500cef3
4
+ data.tar.gz: 5a9f07dd8fc17e3b4b3129b45cbd783e5390b7921da10c62d7d087621e1e123d
5
5
  SHA512:
6
- metadata.gz: 1a7d07de17bc462f2f38fc24ae7c2a04a2c1ffd24d0a431626771259d59ffd6fe4b33b4ea8501add71d710e3c4501897454aada60ff6054fa9a12ef69cf488f3
7
- data.tar.gz: 48da4933e6660ccd7cffe9cdcb08b576d883f1c744a889867b5e8619f9c3908fad00af02a739bc9af5c1abd7495d3cb9517d914ee12f7ac4f48acf94b5b9b637
6
+ metadata.gz: f3bb2f7b57db9b1689e43ceca7fbe497f0c67fffd5c12a8a7b451f07e0acf45be1f45f30d3acfd2e7e5ab1a52b9486954e8af1ebceb40478599b1fa8d9809035
7
+ data.tar.gz: 8acfd478567cec305f2a37e189a7ba11c2bb75463746bc1a114be79b71ea3e84b19632224515b0e2097c2a2a16293f098eb06556d74bb6a2a7e32516ad1476d3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.0
1
+ 3.1.1
@@ -115,7 +115,7 @@ module JSON
115
115
  class CyclicIRIMapping < JsonLdError; @code = "cyclic IRI mapping"; end
116
116
  class InvalidBaseIRI < JsonLdError; @code = "invalid base IRI"; end
117
117
  class InvalidContainerMapping < JsonLdError; @code = "invalid container mapping"; end
118
- class InvalidContextMember < JsonLdError; @code = "invalid context member"; end
118
+ class InvalidContextEntry < JsonLdError; @code = "invalid context entry"; end
119
119
  class InvalidContextNullification < JsonLdError; @code = "invalid context nullification"; end
120
120
  class InvalidDefaultLanguage < JsonLdError; @code = "invalid default language"; end
121
121
  class InvalidIdValue < JsonLdError; @code = "invalid @id value"; end
@@ -35,7 +35,7 @@ module JSON::LD
35
35
 
36
36
  # Options used for open_file
37
37
  OPEN_OPTS = {
38
- headers: {"Accept" => "application/ld+json, text/html;q=0.8, application/json;q=0.5"}
38
+ headers: {"Accept" => "application/ld+json, text/html;q=0.8, application/xhtml+xml;q=0.8, application/json;q=0.5"}
39
39
  }
40
40
 
41
41
  # The following constants are used to reduce object allocations
@@ -229,7 +229,7 @@ module JSON::LD
229
229
  # xxx) Add the given context to the output
230
230
  ctx = self.context.serialize
231
231
  if result.is_a?(Array)
232
- kwgraph = self.context.compact_iri('@graph', vocab: true, quiet: true)
232
+ kwgraph = self.context.compact_iri('@graph', vocab: true)
233
233
  result = result.empty? ? {} : {kwgraph => result}
234
234
  end
235
235
  result = ctx.merge(result) unless ctx.empty?
@@ -295,7 +295,7 @@ module JSON::LD
295
295
  if context && !flattened.empty?
296
296
  # Otherwise, return the result of compacting flattened according the Compaction algorithm passing context ensuring that the compaction result uses the @graph keyword (or its alias) at the top-level, even if the context is empty or if there is only one element to put in the @graph array. This ensures that the returned document has a deterministic structure.
297
297
  compacted = as_array(compact(flattened, ordered: @options[:ordered]))
298
- kwgraph = self.context.compact_iri('@graph', quiet: true)
298
+ kwgraph = self.context.compact_iri('@graph')
299
299
  flattened = self.context.serialize.merge(kwgraph => compacted)
300
300
  end
301
301
  end
@@ -313,11 +313,11 @@ module JSON::LD
313
313
  # @param [String, #read, Hash, Array] frame
314
314
  # The frame to use when re-arranging the data.
315
315
  # @option options (see #initialize)
316
- # @option options ['@always', '@first', '@last', '@link', '@once', '@never'] :embed ('@last')
316
+ # @option options ['@always', '@link', '@once', '@never'] :embed ('@once')
317
317
  # a flag specifying that objects should be directly embedded in the output, instead of being referred to by their IRI.
318
318
  # @option options [Boolean] :explicit (false)
319
319
  # a flag specifying that for properties to be included in the output, they must be explicitly declared in the framing context.
320
- # @option options [Boolean] :requireAll (true)
320
+ # @option options [Boolean] :requireAll (false)
321
321
  # A flag specifying that all properties present in the input frame must either have a default value or be present in the JSON-LD input for the frame to match.
322
322
  # @option options [Boolean] :omitDefault (false)
323
323
  # a flag specifying that properties that are missing from the JSON-LD input should be omitted from the output.
@@ -394,7 +394,7 @@ module JSON::LD
394
394
  # Get framing nodes from expanded input, replacing Blank Node identifiers as necessary
395
395
  create_node_map(value, framing_state[:graphMap], active_graph: '@default')
396
396
 
397
- frame_keys = frame.keys.map {|k| context.expand_iri(k, vocab: true, quiet: true)}
397
+ frame_keys = frame.keys.map {|k| context.expand_iri(k, vocab: true)}
398
398
  if frame_keys.include?('@graph')
399
399
  # If frame contains @graph, it matches the default graph.
400
400
  framing_state[:graph] = '@default'
@@ -436,7 +436,7 @@ module JSON::LD
436
436
  result = if !compacted.is_a?(Array)
437
437
  context.serialize.merge(compacted)
438
438
  else
439
- kwgraph = context.compact_iri('@graph', quiet: true)
439
+ kwgraph = context.compact_iri('@graph')
440
440
  context.serialize.merge({kwgraph => compacted})
441
441
  end
442
442
  log_debug(".frame") {"after compact: #{result.to_json(JSON_STATE) rescue 'malformed json'}"}
@@ -535,7 +535,7 @@ module JSON::LD
535
535
  # @param [Boolean] extractAllScripts
536
536
  # If set to `true`, when extracting JSON-LD script elements from HTML, unless a specific fragment identifier is targeted, extracts all encountered JSON-LD script elements using an array form, if necessary.
537
537
  # @param [String] profile
538
- # When the resulting `contentType` is `text/html`, this option determines the profile to use for selecting a JSON-LD script elements.
538
+ # When the resulting `contentType` is `text/html` or `application/xhtml+xml`, this option determines the profile to use for selecting a JSON-LD script elements.
539
539
  # @param [String] requestProfile
540
540
  # One or more IRIs to use in the request as a profile parameter.
541
541
  # @param [Boolean] validate
@@ -612,7 +612,7 @@ module JSON::LD
612
612
  # Parse any HTML
613
613
  if remote_doc.document.is_a?(String)
614
614
  remote_doc.document = case remote_doc.contentType
615
- when 'text/html'
615
+ when 'text/html', 'application/xhtml+xml'
616
616
  load_html(remote_doc.document,
617
617
  url: remote_doc.documentUrl,
618
618
  extractAllScripts: extractAllScripts,
@@ -628,7 +628,7 @@ module JSON::LD
628
628
 
629
629
  if remote_doc.contentType && validate
630
630
  raise IOError, "url: #{url}, contentType: #{remote_doc.contentType}" unless
631
- remote_doc.contentType.match?(/application\/(.+\+)?json|text\/html/)
631
+ remote_doc.contentType.match?(/application\/(.+\+)?json|text\/html|application\/xhtml\+xml/)
632
632
  end
633
633
  block_given? ? yield(remote_doc) : remote_doc
634
634
  end
@@ -642,7 +642,7 @@ module JSON::LD
642
642
  # @param [Boolean] extractAllScripts
643
643
  # If set to `true`, when extracting JSON-LD script elements from HTML, unless a specific fragment identifier is targeted, extracts all encountered JSON-LD script elements using an array form, if necessary.
644
644
  # @param [String] profile
645
- # When the resulting `contentType` is `text/html`, this option determines the profile to use for selecting a JSON-LD script elements.
645
+ # When the resulting `contentType` is `text/html` or `application/xhtml+xml`, this option determines the profile to use for selecting a JSON-LD script elements.
646
646
  # @param [String] requestProfile
647
647
  # One or more IRIs to use in the request as a profile parameter.
648
648
  # @param [Hash<Symbol => Object>] options
@@ -739,7 +739,7 @@ module JSON::LD
739
739
  elements = if profile
740
740
  es = input.xpath("//script[starts-with(@type, 'application/ld+json;profile=#{profile}')]")
741
741
  # If no profile script, just take a single script without profile
742
- es = [input.at_xpath("//script[starts-with(@type, 'application/ld+json')]")] if es.empty?
742
+ es = [input.at_xpath("//script[starts-with(@type, 'application/ld+json')]")].compact if es.empty?
743
743
  es
744
744
  else
745
745
  input.xpath("//script[starts-with(@type, 'application/ld+json')]")
@@ -5,12 +5,7 @@ module JSON::LD
5
5
  include Utils
6
6
 
7
7
  # The following constant is used to reduce object allocations in #compact below
8
- CONTAINER_MAPPING_ID = %w(@id).freeze
9
- CONTAINER_MAPPING_INDEX = %w(@index).freeze
10
- CONTAINER_MAPPING_LANGUAGE = %w(@language).freeze
11
8
  CONTAINER_MAPPING_LANGUAGE_INDEX_ID_TYPE = Set.new(%w(@language @index @id @type)).freeze
12
- CONTAINER_MAPPING_LIST = %w(@list).freeze
13
- CONTAINER_MAPPING_TYPE = %w(@type).freeze
14
9
  EXPANDED_PROPERTY_DIRECTION_INDEX_LANGUAGE_VALUE = %w(@direction @index @language @value).freeze
15
10
 
16
11
  ##
@@ -71,7 +66,7 @@ module JSON::LD
71
66
  end
72
67
 
73
68
  # If expanded property is @list and we're contained within a list container, recursively compact this item to an array
74
- if list?(element) && context.container(property) == CONTAINER_MAPPING_LIST
69
+ if list?(element) && context.container(property).include?('@list')
75
70
  return compact(element['@list'], property: property, ordered: ordered)
76
71
  end
77
72
 
@@ -110,8 +105,7 @@ module JSON::LD
110
105
  (context.as_array?(kw_alias) &&
111
106
  !value?(element) &&
112
107
  context.processingMode('json-ld-1.1'))
113
- compacted_value = compacted_value.first unless as_array
114
- result[kw_alias] = compacted_value
108
+ add_value(result, kw_alias, compacted_value, property_is_array: as_array)
115
109
  next
116
110
  end
117
111
 
@@ -128,7 +122,7 @@ module JSON::LD
128
122
  end
129
123
 
130
124
  unless compacted_value.empty?
131
- al = context.compact_iri('@reverse', quiet: true)
125
+ al = context.compact_iri('@reverse')
132
126
  #log_debug("") {"remainder: #{al} => #{compacted_value.inspect}"}
133
127
  result[al] = compacted_value
134
128
  end
@@ -146,14 +140,14 @@ module JSON::LD
146
140
  next
147
141
  end
148
142
 
149
- if expanded_property == '@index' && context.container(property) == CONTAINER_MAPPING_INDEX
143
+ if expanded_property == '@index' && context.container(property).include?('@index')
150
144
  #log_debug("@index") {"drop @index"}
151
145
  next
152
146
  end
153
147
 
154
148
  # Otherwise, if expanded property is @direction, @index, @value, or @language:
155
149
  if EXPANDED_PROPERTY_DIRECTION_INDEX_LANGUAGE_VALUE.include?(expanded_property)
156
- al = context.compact_iri(expanded_property, vocab: true, quiet: true)
150
+ al = context.compact_iri(expanded_property, vocab: true)
157
151
  #log_debug(expanded_property) {"#{al} => #{expanded_value.inspect}"}
158
152
  result[al] = expanded_value
159
153
  next
@@ -209,11 +203,11 @@ module JSON::LD
209
203
  # handle @list
210
204
  if list?(expanded_item)
211
205
  compacted_item = as_array(compacted_item)
212
- unless container == CONTAINER_MAPPING_LIST
213
- al = context.compact_iri('@list', vocab: true, quiet: true)
206
+ unless container.include?('@list')
207
+ al = context.compact_iri('@list', vocab: true)
214
208
  compacted_item = {al => compacted_item}
215
209
  if expanded_item.has_key?('@index')
216
- key = context.compact_iri('@index', vocab: true, quiet: true)
210
+ key = context.compact_iri('@index', vocab: true)
217
211
  compacted_item[key] = expanded_item['@index']
218
212
  end
219
213
  else
@@ -231,11 +225,11 @@ module JSON::LD
231
225
  map_object = nest_result[item_active_property] ||= {}
232
226
  # If there is no @id, create a blank node identifier to use as an index
233
227
  map_key = if container.include?('@id') && expanded_item['@id']
234
- context.compact_iri(expanded_item['@id'], quiet: true)
228
+ context.compact_iri(expanded_item['@id'])
235
229
  elsif container.include?('@index') && expanded_item['@index']
236
- context.compact_iri(expanded_item['@index'], quiet: true)
230
+ context.compact_iri(expanded_item['@index'])
237
231
  else
238
- context.compact_iri('@none', vocab: true, quiet: true)
232
+ context.compact_iri('@none', vocab: true)
239
233
  end
240
234
  add_value(map_object, map_key, compacted_item,
241
235
  property_is_array: as_array)
@@ -243,7 +237,7 @@ module JSON::LD
243
237
  # container includes @graph but not @id or @index and value is a simple graph object
244
238
  if compacted_item.is_a?(Array) && compacted_item.length > 1
245
239
  # Mutple objects in the same graph can't be represented directly, as they would be interpreted as two different graphs. Need to wrap in @included.
246
- included_key = context.compact_iri('@included', vocab: true).to_s
240
+ included_key = context.compact_iri('@included', vocab: true)
247
241
  compacted_item = {included_key => compacted_item}
248
242
  end
249
243
  # Drop through, where compacted_item will be added
@@ -251,35 +245,34 @@ module JSON::LD
251
245
  property_is_array: as_array)
252
246
  else
253
247
  # container does not include @graph or otherwise does not match one of the previous cases, redo compacted_item
254
- al = context.compact_iri('@graph', vocab: true, quiet: true)
248
+ al = context.compact_iri('@graph', vocab: true)
255
249
  compacted_item = {al => compacted_item}
256
250
  if expanded_item['@id']
257
- al = context.compact_iri('@id', vocab: true, quiet: true)
258
- compacted_item[al] = context.compact_iri(expanded_item['@id'], vocab: false, quiet: true).to_s
251
+ al = context.compact_iri('@id', vocab: true)
252
+ compacted_item[al] = context.compact_iri(expanded_item['@id'], vocab: false)
259
253
  end
260
254
  if expanded_item.has_key?('@index')
261
- key = context.compact_iri('@index', vocab: true, quiet: true)
255
+ key = context.compact_iri('@index', vocab: true)
262
256
  compacted_item[key] = expanded_item['@index']
263
257
  end
264
258
  add_value(nest_result, item_active_property, compacted_item,
265
259
  property_is_array: as_array)
266
260
  end
267
- elsif container.any? { |key| CONTAINER_MAPPING_LANGUAGE_INDEX_ID_TYPE.include?(key) } && !container.include?('@graph')
261
+ elsif container.intersect?(CONTAINER_MAPPING_LANGUAGE_INDEX_ID_TYPE) && !container.include?('@graph')
268
262
  map_object = nest_result[item_active_property] ||= {}
269
263
  c = container.first
270
- container_key = context.compact_iri(c, vocab: true, quiet: true)
271
- compacted_item = case container
272
- when CONTAINER_MAPPING_ID
264
+ container_key = context.compact_iri(c, vocab: true)
265
+ compacted_item = case
266
+ when container.include?('@id')
273
267
  map_key = compacted_item[container_key]
274
268
  compacted_item.delete(container_key)
275
269
  compacted_item
276
- when CONTAINER_MAPPING_INDEX
270
+ when container.include?('@index')
277
271
  index_key = context.term_definitions[item_active_property].index || '@index'
278
272
  if index_key == '@index'
279
273
  map_key = expanded_item['@index']
280
- compacted_item.delete(container_key) if compacted_item.is_a?(Hash)
281
274
  else
282
- container_key = context.compact_iri(index_key, vocab: true, quiet: true)
275
+ container_key = context.compact_iri(index_key, vocab: true)
283
276
  map_key, *others = Array(compacted_item[container_key])
284
277
  if map_key.is_a?(String)
285
278
  case others.length
@@ -288,15 +281,15 @@ module JSON::LD
288
281
  else compacted_item[container_key] = others
289
282
  end
290
283
  else
291
- map_key = context.compact_iri('@none', vocab: true, quiet: true)
284
+ map_key = context.compact_iri('@none', vocab: true)
292
285
  end
293
286
  end
294
287
  # Note, if compacted_item is a node reference and key is @id-valued, then this could be compacted further.
295
288
  compacted_item
296
- when CONTAINER_MAPPING_LANGUAGE
289
+ when container.include?('@language')
297
290
  map_key = expanded_item['@language']
298
291
  value?(expanded_item) ? expanded_item['@value'] : compacted_item
299
- when CONTAINER_MAPPING_TYPE
292
+ when container.include?('@type')
300
293
  map_key, *types = Array(compacted_item[container_key])
301
294
  case types.length
302
295
  when 0 then compacted_item.delete(container_key)
@@ -310,7 +303,7 @@ module JSON::LD
310
303
  end
311
304
  compacted_item
312
305
  end
313
- map_key ||= context.compact_iri('@none', vocab: true, quiet: true)
306
+ map_key ||= context.compact_iri('@none', vocab: true)
314
307
  add_value(map_object, map_key, compacted_item,
315
308
  property_is_array: as_array)
316
309
  else
@@ -3,6 +3,12 @@
3
3
  require 'json'
4
4
  require 'bigdecimal'
5
5
  require 'set'
6
+ begin
7
+ # Attempt to load this to avoid unnecessary context fetches
8
+ require 'json-ld-preloaded'
9
+ rescue LoadError
10
+ # Silently allow this to fail
11
+ end
6
12
 
7
13
  module JSON::LD
8
14
  class Context
@@ -94,7 +100,7 @@ module JSON::LD
94
100
  # @param [String] term
95
101
  # @param [String] id
96
102
  # @param [String] type_mapping Type mapping
97
- # @param [Array<'@index', '@language', '@index', '@set', '@type', '@id', '@graph'>] container_mapping
103
+ # @param [Set<'@index', '@language', '@index', '@set', '@type', '@id', '@graph'>] container_mapping
98
104
  # @param [String] language_mapping
99
105
  # Language mapping of term, `false` is used if there is an explicit language mapping for this term
100
106
  # @param ["ltr", "rtl"] direction_mapping
@@ -140,12 +146,19 @@ module JSON::LD
140
146
 
141
147
  # Set container mapping, from an array which may include @set
142
148
  def container_mapping=(mapping)
143
- mapping = Array(mapping)
149
+ mapping = case mapping
150
+ when Set then mapping
151
+ when Array then Set.new(mapping)
152
+ when String then Set[mapping]
153
+ when nil then Set.new
154
+ else
155
+ raise "Shouldn't happen with #{mapping.inspect}"
156
+ end
144
157
  if @as_set = mapping.include?('@set')
145
158
  mapping = mapping.dup
146
159
  mapping.delete('@set')
147
160
  end
148
- @container_mapping = mapping.sort
161
+ @container_mapping = mapping
149
162
  @index ||= '@index' if mapping.include?('@index')
150
163
  end
151
164
 
@@ -201,7 +214,8 @@ module JSON::LD
201
214
  v = instance_variable_get("@#{acc}".to_sym)
202
215
  v = v.to_s if v.is_a?(RDF::Term)
203
216
  if acc == 'container_mapping'
204
- v.concat(%w(@set)) if as_set?
217
+ v = v.to_a
218
+ v << '@set' if as_set?
205
219
  v = v.first if v.length <= 1
206
220
  end
207
221
  defn << "#{acc}: #{v.inspect}" if v
@@ -492,7 +506,7 @@ module JSON::LD
492
506
  #
493
507
  # @param [Boolean] value
494
508
  def propagate=(value, **options)
495
- raise JsonLdError::InvalidContextMember, "@propagate may only be set in 1.1 mode" if processingMode("json-ld-1.0")
509
+ raise JsonLdError::InvalidContextEntry, "@propagate may only be set in 1.1 mode" if processingMode("json-ld-1.0")
496
510
  raise JsonLdError::InvalidPropagateValue, "@propagate must be boolean valued: #{value.inspect}" unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
497
511
  value
498
512
  end
@@ -626,7 +640,7 @@ module JSON::LD
626
640
  next unless context.has_key?(key)
627
641
  if key == '@import'
628
642
  # Retrieve remote context and merge the remaining context object into the result.
629
- raise JsonLdError::InvalidContextMember, "@import may only be used in 1.1 mode}" if result.processingMode("json-ld-1.0")
643
+ raise JsonLdError::InvalidContextEntry, "@import may only be used in 1.1 mode}" if result.processingMode("json-ld-1.0")
630
644
  raise JsonLdError::InvalidImportValue, "@import must be a string: #{context['@import'].inspect}" unless context['@import'].is_a?(String)
631
645
  source = RDF::URI(result.context_base || result.base).join(context['@import'])
632
646
  begin
@@ -640,7 +654,7 @@ module JSON::LD
640
654
  raise JsonLdError::InvalidRemoteContext, "#{source}" unless remote_doc.document.is_a?(Hash) && remote_doc.document.has_key?('@context')
641
655
  import_context = remote_doc.document['@context']
642
656
  raise JsonLdError::InvalidRemoteContext, "#{import_context.to_json} must be an object" unless import_context.is_a?(Hash)
643
- raise JsonLdError::InvalidContextMember, "#{import_context.to_json} must not include @import entry" if import_context.has_key?('@import')
657
+ raise JsonLdError::InvalidContextEntry, "#{import_context.to_json} must not include @import entry" if import_context.has_key?('@import')
644
658
  context.delete(key)
645
659
  context = import_context.merge(context)
646
660
  end
@@ -1162,7 +1176,7 @@ module JSON::LD
1162
1176
  def container(term)
1163
1177
  return [term] if term == '@list'
1164
1178
  term = find_definition(term)
1165
- term ? term.container_mapping : []
1179
+ term ? term.container_mapping : Set.new
1166
1180
  end
1167
1181
 
1168
1182
  ##
@@ -1281,18 +1295,24 @@ module JSON::LD
1281
1295
  # Used during Context Processing.
1282
1296
  # @param [Hash] defined
1283
1297
  # Used during Context Processing.
1284
- # @param [Boolean] quiet (false)
1298
+ # @param [Boolean] as_string (false) transform RDF::Resource values to string
1285
1299
  # @param [Hash{Symbol => Object}] options
1286
- # @return [RDF::URI, String]
1300
+ # @return [RDF::Resource, String]
1287
1301
  # IRI or String, if it's a keyword
1288
1302
  # @raise [JSON::LD::JsonLdError::InvalidIRIMapping] if the value cannot be expanded
1289
1303
  # @see https://www.w3.org/TR/json-ld11-api/#iri-expansion
1290
- def expand_iri(value, documentRelative: false, vocab: false, local_context: nil, defined: nil, quiet: false, **options)
1291
- return value unless value.is_a?(String)
1304
+ def expand_iri(value,
1305
+ documentRelative: false,
1306
+ vocab: false,
1307
+ local_context: nil,
1308
+ defined: nil,
1309
+ as_string: false,
1310
+ **options
1311
+ )
1312
+ return (value && as_string ? value.to_s : value) unless value.is_a?(String)
1292
1313
 
1293
1314
  return value if KEYWORDS.include?(value)
1294
1315
  return nil if value.match?(/^@[a-zA-Z]+$/)
1295
- #log_debug("expand_iri") {"value: #{value.inspect}"} unless quiet
1296
1316
 
1297
1317
  defined = defined || {} # if we initialized in the keyword arg we would allocate {} at each invokation, even in the 2 (common) early returns above.
1298
1318
 
@@ -1302,25 +1322,28 @@ module JSON::LD
1302
1322
  end
1303
1323
 
1304
1324
  if (v_td = term_definitions[value]) && KEYWORDS.include?(v_td.id)
1305
- #log_debug("") {"match with #{v_td.id}"} unless quiet
1306
- return v_td.id
1325
+ return (as_string ? v_td.id.to_s : v_td.id)
1307
1326
  end
1308
1327
 
1309
1328
  # If active context has a term definition for value, and the associated mapping is a keyword, return that keyword.
1310
1329
  # If vocab is true and the active context has a term definition for value, return the associated IRI mapping.
1311
1330
  if (v_td = term_definitions[value]) && (vocab || KEYWORDS.include?(v_td.id))
1312
- #log_debug("") {"match with #{v_td.id}"} unless quiet
1313
- return v_td.id
1331
+ return (as_string ? v_td.id.to_s : v_td.id)
1314
1332
  end
1315
1333
 
1316
1334
  # If value contains a colon (:), it is either an absolute IRI or a compact IRI:
1317
1335
  if value[1..-1].to_s.include?(':')
1318
1336
  prefix, suffix = value.split(':', 2)
1319
- #log_debug("") {"prefix: #{prefix.inspect}, suffix: #{suffix.inspect}, vocab: #{self.vocab.inspect}"} unless quiet
1320
1337
 
1321
1338
  # If prefix is underscore (_) or suffix begins with double-forward-slash (//), return value as it is already an absolute IRI or a blank node identifier.
1322
- return RDF::Node.new(namer.get_sym(suffix)) if prefix == '_'
1323
- return RDF::URI(value) if suffix.start_with?('//')
1339
+ if prefix == '_'
1340
+ v = RDF::Node.new(namer.get_sym(suffix))
1341
+ return (as_string ? v.to_s : v)
1342
+ end
1343
+ if suffix.start_with?('//')
1344
+ v = RDF::URI(value)
1345
+ return (as_string ? v.to_s : v)
1346
+ end
1324
1347
 
1325
1348
  # If local context is not null, it contains a key that equals prefix, and the value associated with the key that equals prefix in defined is not true, invoke the Create Term Definition algorithm, passing active context, local context, prefix as term, and defined. This will ensure that a term definition is created for prefix in active context during Context Processing.
1326
1349
  if local_context && local_context.has_key?(prefix) && !defined[prefix]
@@ -1329,15 +1352,14 @@ module JSON::LD
1329
1352
 
1330
1353
  # If active context contains a term definition for prefix, return the result of concatenating the IRI mapping associated with prefix and suffix.
1331
1354
  if (td = term_definitions[prefix]) && !td.id.nil? && td.prefix?
1332
- return td.id + suffix
1355
+ return (as_string ? td.id.to_s : td.id) + suffix
1333
1356
  elsif RDF::URI(value).absolute?
1334
1357
  # Otherwise, if the value has the form of an absolute IRI, return it
1335
- return RDF::URI(value)
1358
+ return (as_string ? value.to_s : RDF::URI(value))
1336
1359
  else
1337
1360
  # Otherwise, it is a relative IRI
1338
1361
  end
1339
1362
  end
1340
- #log_debug("") {"=> #{result.inspect}"} unless quiet
1341
1363
 
1342
1364
  result = if vocab && self.vocab
1343
1365
  # If vocab is true, and active context has a vocabulary mapping, return the result of concatenating the vocabulary mapping with value.
@@ -1352,8 +1374,7 @@ module JSON::LD
1352
1374
  else
1353
1375
  RDF::URI(value)
1354
1376
  end
1355
- #log_debug("") {"=> #{result}"} unless quiet
1356
- result
1377
+ result && as_string ? result.to_s : result
1357
1378
  end
1358
1379
 
1359
1380
  # The following constants are used to reduce object allocations in #compact_iri below
@@ -1378,18 +1399,15 @@ module JSON::LD
1378
1399
  # specifies whether the passed iri should be compacted using the active context's vocabulary mapping
1379
1400
  # @param [Boolean] reverse
1380
1401
  # specifies whether a reverse property is being compacted
1381
- # @param [Boolean] quiet (false)
1382
1402
  # @param [Hash{Symbol => Object}] options ({})
1383
1403
  #
1384
1404
  # @return [String] compacted form of IRI
1385
1405
  # @see https://www.w3.org/TR/json-ld11-api/#iri-compaction
1386
- def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **options)
1406
+ def compact_iri(iri, value: nil, vocab: nil, reverse: false, **options)
1387
1407
  return if iri.nil?
1388
1408
  iri = iri.to_s
1389
- #log_debug("compact_iri(#{iri.inspect}", options) {[value, vocab, reverse].inspect} unless quiet
1390
1409
 
1391
1410
  if vocab && inverse_context.has_key?(iri)
1392
- #log_debug("") {"vocab and key in inverse context"} unless quiet
1393
1411
  default_language = if self.default_direction
1394
1412
  "#{self.default_language}_#{self.default_direction}".downcase
1395
1413
  else
@@ -1406,7 +1424,6 @@ module JSON::LD
1406
1424
  tl, tl_value = "@type", "@reverse"
1407
1425
  containers << '@set'
1408
1426
  elsif list?(value)
1409
- #log_debug("") {"list(#{value.inspect})"} unless quiet
1410
1427
  # if value is a list object, then set type/language and type/language value to the most specific values that work for all items in the list as follows:
1411
1428
  containers << "@list" unless index?(value)
1412
1429
  list = value['@list']
@@ -1429,25 +1446,21 @@ module JSON::LD
1429
1446
  end
1430
1447
  common_language ||= item_language
1431
1448
  if item_language != common_language && value?(item)
1432
- #log_debug("") {"-- #{item_language} conflicts with #{common_language}, use @none"} unless quiet
1433
1449
  common_language = '@none'
1434
1450
  end
1435
1451
  common_type ||= item_type
1436
1452
  if item_type != common_type
1437
1453
  common_type = '@none'
1438
- #log_debug("") {"#{item_type} conflicts with #{common_type}, use @none"} unless quiet
1439
1454
  end
1440
1455
  end
1441
1456
 
1442
1457
  common_language ||= '@none'
1443
1458
  common_type ||= '@none'
1444
- #log_debug("") {"common type: #{common_type}, common language: #{common_language}"} unless quiet
1445
1459
  if common_type != '@none'
1446
1460
  tl, tl_value = '@type', common_type
1447
1461
  else
1448
1462
  tl_value = common_language
1449
1463
  end
1450
- #log_debug("") {"list: containers: #{containers.inspect}, type/language: #{tl.inspect}, type/language value: #{tl_value.inspect}"} unless quiet
1451
1464
  elsif graph?(value)
1452
1465
  # Prefer @index and @id containers, then @graph, then @index
1453
1466
  containers.concat(CONTAINERS_GRAPH_INDEX_INDEX) if index?(value)
@@ -1482,7 +1495,6 @@ module JSON::LD
1482
1495
  tl, tl_value = '@type', '@id'
1483
1496
  end
1484
1497
  containers << '@set'
1485
- #log_debug("") {"value: containers: #{containers.inspect}, type/language: #{tl.inspect}, type/language value: #{tl_value.inspect}"} unless quiet
1486
1498
  end
1487
1499
 
1488
1500
  containers << '@none'
@@ -1506,7 +1518,6 @@ module JSON::LD
1506
1518
  tl = '@any' if list?(value) && value['@list'].empty?
1507
1519
  preferred_values.concat([tl_value, '@none'].compact)
1508
1520
  end
1509
- #log_debug("") {"preferred_values: #{preferred_values.inspect}"} unless quiet
1510
1521
  preferred_values << '@any'
1511
1522
 
1512
1523
  # if containers included `@language` and preferred_values includes something of the form language-tag_direction, add just the _direction part, to select terms that have that direction.
@@ -1515,7 +1526,6 @@ module JSON::LD
1515
1526
  end
1516
1527
 
1517
1528
  if p_term = select_term(iri, containers, tl, preferred_values)
1518
- #log_debug("") {"=> term: #{p_term.inspect}"} unless quiet
1519
1529
  return p_term
1520
1530
  end
1521
1531
  end
@@ -1523,7 +1533,6 @@ module JSON::LD
1523
1533
  # At this point, there is no simple term that iri can be compacted to. If vocab is true and active context has a vocabulary mapping:
1524
1534
  if vocab && self.vocab && iri.start_with?(self.vocab) && iri.length > self.vocab.length
1525
1535
  suffix = iri[self.vocab.length..-1]
1526
- #log_debug("") {"=> vocab suffix: #{suffix.inspect}"} unless quiet
1527
1536
  return suffix unless term_definitions.has_key?(suffix)
1528
1537
  end
1529
1538
 
@@ -1566,10 +1575,8 @@ module JSON::LD
1566
1575
  if !vocab
1567
1576
  # transform iri to a relative IRI using the document's base IRI
1568
1577
  iri = remove_base(iri)
1569
- #log_debug("") {"=> relative iri: #{iri.inspect}"} unless quiet
1570
1578
  return iri
1571
1579
  else
1572
- #log_debug("") {"=> absolute iri: #{iri.inspect}"} unless quiet
1573
1580
  return iri
1574
1581
  end
1575
1582
  end
@@ -1830,9 +1837,9 @@ module JSON::LD
1830
1837
 
1831
1838
  private
1832
1839
 
1833
- CONTEXT_CONTAINER_ARRAY_TERMS = %w(@set @list @graph).freeze
1834
- CONTEXT_CONTAINER_ID_GRAPH = %w(@id @graph).freeze
1835
- CONTEXT_CONTAINER_INDEX_GRAPH = %w(@index @graph).freeze
1840
+ CONTEXT_CONTAINER_ARRAY_TERMS = Set.new(%w(@set @list @graph)).freeze
1841
+ CONTEXT_CONTAINER_ID_GRAPH = Set.new(%w(@id @graph)).freeze
1842
+ CONTEXT_CONTAINER_INDEX_GRAPH = Set.new(%w(@index @graph)).freeze
1836
1843
  CONTEXT_BASE_FRAG_OR_QUERY = %w(? #).freeze
1837
1844
  CONTEXT_TYPE_ID_VOCAB = %w(@id @vocab).freeze
1838
1845
 
@@ -1906,7 +1913,7 @@ module JSON::LD
1906
1913
  end.each do |term|
1907
1914
  next unless td = term_definitions[term]
1908
1915
 
1909
- container = td.container_mapping.join('')
1916
+ container = td.container_mapping.to_a.join('')
1910
1917
  if container.empty?
1911
1918
  container = td.as_set? ? %(@set) : %(@none)
1912
1919
  end
@@ -1943,7 +1950,7 @@ module JSON::LD
1943
1950
  lang_dir = td.direction_mapping ? "_#{td.direction_mapping}" : '@none'
1944
1951
  language_map[lang_dir] ||= term
1945
1952
  elsif default_direction
1946
- language_map[("#{td.language_mapping}_#{default_direction}").downcase] ||= term
1953
+ language_map["_#{default_direction}"] ||= term
1947
1954
  language_map['@none'] ||= term
1948
1955
  type_map['@none'] ||= term
1949
1956
  else
@@ -2058,7 +2065,7 @@ module JSON::LD
2058
2065
  "'@container' on term #{term.inspect} must be a string: #{container.inspect}"
2059
2066
  end
2060
2067
 
2061
- val = Array(container).dup
2068
+ val = Set.new(Array(container))
2062
2069
  val.delete('@set') if has_set = val.include?('@set')
2063
2070
 
2064
2071
  if val.include?('@list')
@@ -2088,7 +2095,7 @@ module JSON::LD
2088
2095
  processingMode('json-ld-1.0')
2089
2096
  raise JsonLdError::InvalidContainerMapping,
2090
2097
  "'@container' on term #{term.inspect} using @id cannot have any values other than @set and/or @graph, found #{container.inspect}" unless
2091
- (val - CONTEXT_CONTAINER_ID_GRAPH).empty?
2098
+ val.subset?(CONTEXT_CONTAINER_ID_GRAPH)
2092
2099
  # Okay
2093
2100
  elsif val.include?('@type') || val.include?('@graph')
2094
2101
  raise JsonLdError::InvalidContainerMapping,
@@ -9,13 +9,8 @@ module JSON::LD
9
9
  include Utils
10
10
 
11
11
  # The following constant is used to reduce object allocations
12
- CONTAINER_INDEX_ID_TYPE = Set.new(%w(@index @id @type)).freeze
13
- CONTAINER_GRAPH_INDEX = %w(@graph @index).freeze
14
- CONTAINER_INDEX = %w(@index).freeze
15
- CONTAINER_ID = %w(@id).freeze
16
- CONTAINER_LIST = %w(@list).freeze
17
- CONTAINER_TYPE = %w(@type).freeze
18
- CONTAINER_GRAPH_ID = %w(@graph @id).freeze
12
+ CONTAINER_INDEX_ID_TYPE = Set['@index', '@id', '@type'].freeze
13
+ KEY_ID = %w(@id).freeze
19
14
  KEYS_VALUE_LANGUAGE_TYPE_INDEX_DIRECTION = %w(@value @language @type @index @direction).freeze
20
15
  KEYS_SET_LIST_INDEX = %w(@set @list @index).freeze
21
16
  KEYS_INCLUDED_TYPE = %w(@included @type).freeze
@@ -36,7 +31,7 @@ module JSON::LD
36
31
  def expand(input, active_property, context, ordered: false, framing: false, from_map: false)
37
32
  #log_debug("expand") {"input: #{input.inspect}, active_property: #{active_property.inspect}, context: #{context.inspect}"}
38
33
  framing = false if active_property == '@default'
39
- expanded_active_property = context.expand_iri(active_property, vocab: true).to_s if active_property
34
+ expanded_active_property = context.expand_iri(active_property, vocab: true, as_string: true) if active_property
40
35
 
41
36
  # Use a term-specific context, if defined, based on the non-type-scoped context.
42
37
  property_scoped_context = context.term_definitions[active_property].context if active_property && context.term_definitions[active_property]
@@ -44,7 +39,7 @@ module JSON::LD
44
39
  result = case input
45
40
  when Array
46
41
  # If element is an array,
47
- is_list = context.container(active_property) == CONTAINER_LIST
42
+ is_list = context.container(active_property).include?('@list')
48
43
  value = input.each_with_object([]) do |v, memo|
49
44
  # Initialize expanded item to the result of using this algorithm recursively, passing active context, active property, and item as element.
50
45
  v = expand(v, active_property, context, ordered: ordered, framing: framing, from_map: from_map)
@@ -62,7 +57,7 @@ module JSON::LD
62
57
  value
63
58
  when Hash
64
59
  if context.previous_context
65
- expanded_key_map = input.keys.inject({}) {|memo, key| memo.merge(key => context.expand_iri(key, vocab: true).to_s)}
60
+ expanded_key_map = input.keys.inject({}) {|memo, key| memo.merge(key => context.expand_iri(key, vocab: true, as_string: true))}
66
61
  # Revert any previously type-scoped term definitions, unless this is from a map, a value object or a subject reference
67
62
  revert_context = !from_map &&
68
63
  !expanded_key_map.values.include?('@value') &&
@@ -139,7 +134,7 @@ module JSON::LD
139
134
  raise JsonLdError::InvalidLanguageTaggedValue,
140
135
  "when @language is used, @value must be a string: #{output_object.inspect}"
141
136
  elsif !Array(output_object['@type']).all? {|t|
142
- t.is_a?(String) && RDF::URI(t).absolute? && !t.start_with?('_:') ||
137
+ t.is_a?(String) && RDF::URI(t).valid? && !t.start_with?('_:') ||
143
138
  t.is_a?(Hash) && t.empty?}
144
139
  # Otherwise, if the result has a @type member and its value is not an IRI, an invalid typed value error has been detected and processing is aborted.
145
140
  raise JsonLdError::InvalidTypedValue,
@@ -164,8 +159,8 @@ module JSON::LD
164
159
 
165
160
  # If active property is null or @graph, drop free-floating values as follows:
166
161
  if (expanded_active_property || '@graph') == '@graph' &&
167
- (output_object.key?('@value') || output_object.key?('@list') ||
168
- (output_object.keys - CONTAINER_ID).empty? && !framing)
162
+ (output_object.key?('@value') || output_object.key?('@list') ||
163
+ (output_object.keys - KEY_ID).empty? && !framing)
169
164
  #log_debug(" =>") { "empty top-level: " + output_object.inspect}
170
165
  return nil
171
166
  end
@@ -202,14 +197,14 @@ module JSON::LD
202
197
  nests = []
203
198
 
204
199
  input_type = Array(input[type_key]).last
205
- input_type = context.expand_iri(input_type, vocab: true, quiet: true) if input_type
200
+ input_type = context.expand_iri(input_type, vocab: true, as_string: true) if input_type
206
201
 
207
202
  # Then, proceed and process each property and value in element as follows:
208
203
  keys = ordered ? input.keys.sort : input.keys
209
204
  keys.each do |key|
210
205
  # For each key and value in element, ordered lexicographically by key:
211
206
  value = input[key]
212
- expanded_property = context.expand_iri(key, vocab: true, quiet: true)
207
+ expanded_property = context.expand_iri(key, vocab: true)
213
208
 
214
209
  # If expanded property is null or it neither contains a colon (:) nor it is a keyword, drop key by continuing to the next key.
215
210
  next if expanded_property.is_a?(RDF::URI) && expanded_property.relative?
@@ -241,16 +236,16 @@ module JSON::LD
241
236
  # If expanded property is @id and value is not a string, an invalid @id value error has been detected and processing is aborted
242
237
  e_id = case value
243
238
  when String
244
- context.expand_iri(value, documentRelative: true, quiet: true).to_s
239
+ context.expand_iri(value, documentRelative: true, as_string: true)
245
240
  when Array
246
241
  # Framing allows an array of IRIs, and always puts values in an array
247
242
  raise JsonLdError::InvalidIdValue,
248
243
  "value of @id must be a string unless framing: #{value.inspect}" unless framing
249
- context.expand_iri(value, documentRelative: true, quiet: true).to_s
244
+ context.expand_iri(value, documentRelative: true, as_string: true)
250
245
  value.map do |v|
251
246
  raise JsonLdError::InvalidTypeValue,
252
247
  "@id value must be a string or array of strings for framing: #{v.inspect}" unless v.is_a?(String)
253
- context.expand_iri(v, documentRelative: true, quiet: true,).to_s
248
+ context.expand_iri(v, documentRelative: true, as_string: true)
254
249
  end
255
250
  when Hash
256
251
  raise JsonLdError::InvalidIdValue,
@@ -287,21 +282,21 @@ module JSON::LD
287
282
  value.map do |v|
288
283
  raise JsonLdError::InvalidTypeValue,
289
284
  "@type value must be a string or array of strings: #{v.inspect}" unless v.is_a?(String)
290
- type_scoped_context.expand_iri(v, vocab: true, documentRelative: true, quiet: true).to_s
285
+ type_scoped_context.expand_iri(v, vocab: true, documentRelative: true, as_string: true)
291
286
  end
292
287
  when String
293
- type_scoped_context.expand_iri(value, vocab: true, documentRelative: true, quiet: true).to_s
288
+ type_scoped_context.expand_iri(value, vocab: true, documentRelative: true, as_string: true)
294
289
  when Hash
295
290
  if !framing
296
291
  raise JsonLdError::InvalidTypeValue,
297
292
  "@type value must be a string or array of strings: #{value.inspect}"
298
293
  elsif value.keys.length == 1 &&
299
- type_scoped_context.expand_iri(value.keys.first, vocab: true, quiet: true).to_s == '@default'
294
+ type_scoped_context.expand_iri(value.keys.first, vocab: true) == '@default'
300
295
  # Expand values of @default, which must be a string, or array of strings expanding to IRIs
301
296
  [{'@default' => Array(value['@default']).map do |v|
302
297
  raise JsonLdError::InvalidTypeValue,
303
298
  "@type default value must be a string or array of strings: #{v.inspect}" unless v.is_a?(String)
304
- type_scoped_context.expand_iri(v, vocab: true, documentRelative: true, quiet: true).to_s
299
+ type_scoped_context.expand_iri(v, vocab: true, documentRelative: true, as_string: true)
305
300
  end}]
306
301
  elsif !value.empty?
307
302
  raise JsonLdError::InvalidTypeValue,
@@ -481,7 +476,7 @@ module JSON::LD
481
476
  expanded_value = if context.coerce(key) == '@json'
482
477
  # In JSON-LD 1.1, values can be native JSON
483
478
  {"@value" => value, "@type" => "@json"}
484
- elsif container.length == 1 && container.first == '@language' && value.is_a?(Hash)
479
+ elsif container.include?('@language') && value.is_a?(Hash)
485
480
  # Otherwise, if key's container mapping in active context is @language and value is a JSON object then value is expanded from a language map as follows:
486
481
 
487
482
  # Set multilingual array to an empty array.
@@ -490,7 +485,7 @@ module JSON::LD
490
485
  # For each key-value pair language-language value in value, ordered lexicographically by language
491
486
  keys = ordered ? value.keys.sort : value.keys
492
487
  keys.each do |k|
493
- expanded_k = context.expand_iri(k, vocab: true, quiet: true).to_s
488
+ expanded_k = context.expand_iri(k, vocab: true, as_string: true)
494
489
 
495
490
  if k !~ /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/ && expanded_k != '@none'
496
491
  warn "@language must be valid BCP47: #{k.inspect}"
@@ -510,7 +505,7 @@ module JSON::LD
510
505
  end
511
506
 
512
507
  ary
513
- elsif container.any? { |key| CONTAINER_INDEX_ID_TYPE.include?(key) } && value.is_a?(Hash)
508
+ elsif container.intersect?(CONTAINER_INDEX_ID_TYPE) && value.is_a?(Hash)
514
509
  # Otherwise, if key's container mapping in active context contains @index, @id, @type and value is a JSON object then value is expanded from an index map as follows:
515
510
 
516
511
  # Set ary to an empty array.
@@ -535,13 +530,13 @@ module JSON::LD
535
530
  map_context = container_context.parse(map_context, propagate: false) if map_context
536
531
  map_context ||= container_context
537
532
 
538
- expanded_k = container_context.expand_iri(k, vocab: true, quiet: true).to_s
533
+ expanded_k = container_context.expand_iri(k, vocab: true, as_string: true)
539
534
 
540
535
  # Initialize index value to the result of using this algorithm recursively, passing active context, key as active property, and index value as element.
541
536
  index_value = expand([value[k]].flatten, key, map_context, ordered: ordered, framing: framing, from_map: true)
542
537
  index_value.each do |item|
543
- case container
544
- when CONTAINER_GRAPH_INDEX, CONTAINER_INDEX
538
+ case
539
+ when container.include?('@index')
545
540
  # Indexed graph by graph name
546
541
  if !graph?(item) && container.include?('@graph')
547
542
  item = {'@graph' => as_array(item)}
@@ -553,18 +548,18 @@ module JSON::LD
553
548
  else
554
549
  # Expand key based on term
555
550
  expanded_k = k == '@none' ? '@none' : container_context.expand_value(index_key, k)
556
- index_property = container_context.expand_iri(index_key, vocab: true, quiet: true).to_s
551
+ index_property = container_context.expand_iri(index_key, vocab: true, as_string: true)
557
552
  item[index_property] = [expanded_k].concat(Array(item[index_property])) unless expanded_k == '@none'
558
553
  end
559
- when CONTAINER_GRAPH_ID, CONTAINER_ID
554
+ when container.include?('@id')
560
555
  # Indexed graph by graph name
561
556
  if !graph?(item) && container.include?('@graph')
562
557
  item = {'@graph' => as_array(item)}
563
558
  end
564
559
  # Expand k document relative
565
- expanded_k = container_context.expand_iri(k, documentRelative: true, quiet: true).to_s unless expanded_k == '@none'
560
+ expanded_k = container_context.expand_iri(k, documentRelative: true, as_string: true) unless expanded_k == '@none'
566
561
  item['@id'] ||= expanded_k unless expanded_k == '@none'
567
- when CONTAINER_TYPE
562
+ when container.include?('@type')
568
563
  item['@type'] = [expanded_k].concat(Array(item['@type'])) unless expanded_k == '@none'
569
564
  end
570
565
 
@@ -119,7 +119,7 @@ module JSON::LD
119
119
  end
120
120
  end
121
121
 
122
- # If frame has `@included`, recurse over it's sub-frame
122
+ # If frame has `@included`, recurse over its sub-frame
123
123
  if frame['@included']
124
124
  frame(state.merge(embedded: false), subjects, frame['@included'], parent: output, property: '@included', **options)
125
125
  end
@@ -42,7 +42,7 @@ module JSON::LD
42
42
 
43
43
  default_graph[name] ||= {'@id' => name} unless name == '@default'
44
44
 
45
- subject = ec.expand_iri(statement.subject).to_s
45
+ subject = ec.expand_iri(statement.subject, as_string: true)
46
46
  node = node_map[subject] ||= {'@id' => subject}
47
47
 
48
48
  # If predicate is rdf:datatype, note subject in compound literal subjects map
@@ -50,11 +50,11 @@ module JSON::LD
50
50
  # Either serialize using a datatype, or a compound-literal
51
51
  case @options[:rdfDirection]
52
52
  when 'i18n-datatype'
53
- datatype = RDF::URI("https://www.w3.org/ns/i18n##{item.fetch('@language', '')}_#{item['@direction']}")
53
+ datatype = RDF::URI("https://www.w3.org/ns/i18n##{item.fetch('@language', '').downcase}_#{item['@direction']}")
54
54
  when 'compound-literal'
55
55
  cl = RDF::Node.new
56
56
  yield RDF::Statement(cl, RDF.value, item['@value'].to_s)
57
- yield RDF::Statement(cl, RDF.to_uri + 'language', item['@language']) if item['@language']
57
+ yield RDF::Statement(cl, RDF.to_uri + 'language', item['@language'].downcase) if item['@language']
58
58
  yield RDF::Statement(cl, RDF.to_uri + 'direction', item['@direction'])
59
59
  return cl
60
60
  end
@@ -76,7 +76,13 @@ module JSON::LD
76
76
  return parse_list(item['@list'], graph_name: graph_name, &block)
77
77
  end
78
78
 
79
- subject = item['@id'] ? as_resource(item['@id']) : node
79
+ # Skip if '@id' is nil
80
+ subject = if item.has_key?('@id')
81
+ item['@id'].nil? ? nil : as_resource(item['@id'])
82
+ else
83
+ node
84
+ end
85
+
80
86
  #log_debug("item_to_rdf") {"subject: #{subject.to_ntriples rescue 'malformed rdf'}"}
81
87
  item.each do |property, values|
82
88
  case property
@@ -143,8 +143,8 @@ module JSON::LD
143
143
  datatype: TrueClass,
144
144
  default: true,
145
145
  control: :checkbox,
146
- on: ["--[no-]requireAll"],
147
- description: "Require all properties to match (true). Default is `true` use --no-compact-to-relative to disable.") {|arg| arg},
146
+ on: ["--[no-]require-all"],
147
+ description: "Require all properties to match (true). Default is `true` use --no-require-all to disable.") {|arg| arg},
148
148
  RDF::CLI::Option.new(
149
149
  symbol: :stream,
150
150
  datatype: TrueClass,
@@ -348,7 +348,7 @@ describe JSON::LD::Context do
348
348
  expect(subject.parse({
349
349
  "foo" => {"@id" => "http://example.com/", "@container" => "@list"}
350
350
  }).containers).to produce({
351
- "foo" => %w(@list)
351
+ "foo" => Set["@list"]
352
352
  }, logger)
353
353
  end
354
354
 
@@ -356,7 +356,7 @@ describe JSON::LD::Context do
356
356
  expect(subject.parse({
357
357
  "foo" => {"@id" => "http://example.com/", "@container" => "@type"}
358
358
  }).containers).to produce({
359
- "foo" => %w(@type)
359
+ "foo" => Set["@type"]
360
360
  }, logger)
361
361
  end
362
362
 
@@ -364,7 +364,7 @@ describe JSON::LD::Context do
364
364
  expect(subject.parse({
365
365
  "foo" => {"@id" => "http://example.com/", "@container" => "@id"}
366
366
  }).containers).to produce({
367
- "foo" => %w(@id)
367
+ "foo" => Set["@id"]
368
368
  }, logger)
369
369
  end
370
370
 
@@ -553,12 +553,12 @@ describe JSON::LD::Context do
553
553
  end
554
554
  end
555
555
 
556
- it "generates InvalidContextMember if using @propagate" do
557
- expect {context.parse({'@propagate' => true})}.to raise_error(JSON::LD::JsonLdError::InvalidContextMember)
556
+ it "generates InvalidContextEntry if using @propagate" do
557
+ expect {context.parse({'@propagate' => true})}.to raise_error(JSON::LD::JsonLdError::InvalidContextEntry)
558
558
  end
559
559
 
560
- it "generates InvalidContextMember if using @import" do
561
- expect {context.parse({'@import' => "location"})}.to raise_error(JSON::LD::JsonLdError::InvalidContextMember)
560
+ it "generates InvalidContextEntry if using @import" do
561
+ expect {context.parse({'@import' => "location"})}.to raise_error(JSON::LD::JsonLdError::InvalidContextEntry)
562
562
  end
563
563
 
564
564
  (JSON::LD::KEYWORDS - %w(@base @language @version @protected @propagate @vocab)).each do |kw|
@@ -1796,23 +1796,23 @@ describe JSON::LD::Context do
1796
1796
 
1797
1797
  it "uses TermDefinition" do
1798
1798
  {
1799
- "ex" => [],
1800
- "graph" => %w(@graph),
1801
- "graphSet" => %w(@graph),
1802
- "graphId" => %w(@graph @id),
1803
- "graphIdSet" => %w(@graph @id),
1804
- "graphNdx" => %w(@graph @index),
1805
- "graphNdxSet" => %w(@graph @index),
1806
- "id" => %w(@id),
1807
- "idSet" => %w(@id),
1808
- "language" => %w(@language),
1809
- "langSet" => %w(@language),
1810
- "list" => %w(@list),
1811
- "ndx" => %w(@index),
1812
- "ndxSet" => %w(@index),
1813
- "set" => [],
1814
- "type" => %w(@type),
1815
- "typeSet" => %w(@type),
1799
+ "ex" => Set.new,
1800
+ "graph" => Set["@graph"],
1801
+ "graphSet" => Set["@graph"],
1802
+ "graphId" => Set["@graph", "@id"],
1803
+ "graphIdSet" => Set["@graph", "@id"],
1804
+ "graphNdx" => Set["@graph", "@index"],
1805
+ "graphNdxSet" => Set["@graph", "@index"],
1806
+ "id" => Set['@id'],
1807
+ "idSet" => Set['@id'],
1808
+ "language" => Set['@language'],
1809
+ "langSet" => Set['@language'],
1810
+ "list" => Set['@list'],
1811
+ "ndx" => Set['@index'],
1812
+ "ndxSet" => Set['@index'],
1813
+ "set" => Set.new,
1814
+ "type" => Set['@type'],
1815
+ "typeSet" => Set['@type'],
1816
1816
  }.each do |defn, container|
1817
1817
  expect(subject.container(subject.term_definitions[defn])).to eq container
1818
1818
  end
@@ -1844,23 +1844,23 @@ describe JSON::LD::Context do
1844
1844
 
1845
1845
  it "uses array" do
1846
1846
  {
1847
- "ex" => [],
1848
- "graph" => %w(@graph),
1849
- "graphSet" => %w(@graph),
1850
- "graphId" => %w(@graph @id),
1851
- "graphIdSet" => %w(@graph @id),
1852
- "graphNdx" => %w(@graph @index),
1853
- "graphNdxSet" => %w(@graph @index),
1854
- "id" => %w(@id),
1855
- "idSet" => %w(@id),
1856
- "language" => %w(@language),
1857
- "langSet" => %w(@language),
1858
- "list" => %w(@list),
1859
- "ndx" => %w(@index),
1860
- "ndxSet" => %w(@index),
1861
- "set" => [],
1862
- "type" => %w(@type),
1863
- "typeSet" => %w(@type),
1847
+ "ex" => Set.new,
1848
+ "graph" => Set["@graph"],
1849
+ "graphSet" => Set["@graph"],
1850
+ "graphId" => Set["@graph", "@id"],
1851
+ "graphIdSet" => Set["@graph", "@id"],
1852
+ "graphNdx" => Set["@graph", "@index"],
1853
+ "graphNdxSet" => Set["@graph", "@index"],
1854
+ "id" => Set['@id'],
1855
+ "idSet" => Set['@id'],
1856
+ "language" => Set['@language'],
1857
+ "langSet" => Set['@language'],
1858
+ "list" => Set['@list'],
1859
+ "ndx" => Set['@index'],
1860
+ "ndxSet" => Set['@index'],
1861
+ "set" => Set.new,
1862
+ "type" => Set['@type'],
1863
+ "typeSet" => Set['@type'],
1864
1864
  }.each do |defn, container|
1865
1865
  expect(subject.container(defn)).to eq container
1866
1866
  end
@@ -2053,13 +2053,13 @@ describe JSON::LD::Context do
2053
2053
 
2054
2054
  context "with container_mapping @id @set" do
2055
2055
  subject {described_class.new("term", container_mapping: %w(@id @set))}
2056
- its(:container_mapping) {is_expected.to eq %w(@id)}
2056
+ its(:container_mapping) {is_expected.to eq Set['@id']}
2057
2057
  its(:to_rb) {is_expected.to eq %(TermDefinition.new("term", container_mapping: ["@id", "@set"]))}
2058
2058
  end
2059
2059
 
2060
2060
  context "with container_mapping @list" do
2061
2061
  subject {described_class.new("term", container_mapping: "@list")}
2062
- its(:container_mapping) {is_expected.to eq %w(@list)}
2062
+ its(:container_mapping) {is_expected.to eq Set['@list']}
2063
2063
  its(:to_rb) {is_expected.to eq %(TermDefinition.new("term", container_mapping: "@list"))}
2064
2064
  end
2065
2065
 
@@ -7,6 +7,8 @@ describe JSON::LD do
7
7
  m = Fixtures::SuiteTest::Manifest.open("#{Fixtures::SuiteTest::SUITE}expand-manifest.jsonld")
8
8
  describe m.name do
9
9
  m.entries.each do |t|
10
+ # MultiJson use OJ, by default, which doesn't handle native numbers the same as the JSON gem.
11
+ t.options[:adapter] = :json_gem if %w(#tjs12).include?(t.property('@id'))
10
12
  specify "#{t.property('@id')}: #{t.name} unordered#{' (negative test)' unless t.positiveTest?}" do
11
13
  t.options[:ordered] = false
12
14
  if %w(#t0068).include?(t.property('@id'))
@@ -132,6 +132,10 @@ module Fixtures
132
132
  {'specVersion' => "json-ld-1.1"}.merge(property('option') || {}).each do |k, v|
133
133
  opts[k.to_sym] = v
134
134
  end
135
+ if opts[:expandContext] && !RDF::URI(opts[:expandContext]).absolute?
136
+ # Resolve relative to manifest location
137
+ opts[:expandContext] = manifest_url.join(opts[:expandContext]).to_s
138
+ end
135
139
  opts
136
140
  end
137
141
  end
@@ -144,6 +148,7 @@ module Fixtures
144
148
  file = self.send("#{m}_loc".to_sym)
145
149
 
146
150
  dl_opts = {safe: true}
151
+ dl_opts[:contentType] = options[:contentType] if m == 'input' && options[:contentType]
147
152
  RDF::Util::File.open_file(file, **dl_opts) do |remote_doc|
148
153
  res = remote_doc.read
149
154
  end
@@ -1133,7 +1133,7 @@ describe JSON::LD::API do
1133
1133
  ],
1134
1134
  "en-US rtl": [
1135
1135
  %q({"http://example.org/label": {"@value": "en-US", "@language": "en-US", "@direction": "rtl"}}),
1136
- %q(_:a <http://example.org/label> "en-US"^^<https://www.w3.org/ns/i18n#en-US_rtl> .)
1136
+ %q(_:a <http://example.org/label> "en-US"^^<https://www.w3.org/ns/i18n#en-us_rtl> .)
1137
1137
  ]
1138
1138
  }.each do |title, (js, ttl)|
1139
1139
  it title do
@@ -1161,7 +1161,7 @@ describe JSON::LD::API do
1161
1161
  @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
1162
1162
  _:a <http://example.org/label> [
1163
1163
  rdf:value "en-US";
1164
- rdf:language "en-US";
1164
+ rdf:language "en-us";
1165
1165
  rdf:direction "rtl"
1166
1166
  ] .
1167
1167
  )
@@ -1218,7 +1218,7 @@ describe JSON::LD::API do
1218
1218
  "@id": "http://example.com/foo",
1219
1219
  "http://example.com/bar": {"@value": "bar", "@type": "http://example.com/baz z"}
1220
1220
  }),
1221
- output: %()
1221
+ exception: JSON::LD::JsonLdError::InvalidTypedValue
1222
1222
  },
1223
1223
  "Injected IRIs check" => {
1224
1224
  input: %({
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-ld
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg Kellogg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-10 00:00:00.000000000 Z
11
+ date: 2020-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0.1'
67
+ version: '0.2'
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.1'
74
+ version: '0.2'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: htmlentities
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -424,7 +424,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
424
424
  - !ruby/object:Gem::Version
425
425
  version: '0'
426
426
  requirements: []
427
- rubygems_version: 3.0.6
427
+ rubygems_version: 3.1.2
428
428
  signing_key:
429
429
  specification_version: 4
430
430
  summary: JSON-LD reader/writer for Ruby.