json-ld 2.1.5 → 2.1.6

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
  SHA1:
3
- metadata.gz: 87b6c40e1f1bff540f8c175e321087f60a7a6c04
4
- data.tar.gz: eeba4194d6cb10caa31214444882c18e8688d44c
3
+ metadata.gz: cbadebe1b0aed85dc5f64bf4981c8d54cf9b2ccb
4
+ data.tar.gz: 316d476a0f0be056a49c571f22cff6dd13feb6dc
5
5
  SHA512:
6
- metadata.gz: 972abe58a807190d6cb9228f80abec5198012c4c395973025b4ca50f5ea54142170999f7210769c621861e5136704dabc2f99932ab62dc9f7c9516b7ba931ae8
7
- data.tar.gz: db37dac97ad2569415b35bff8e1967d0126621dd978cc183e0d80e3dc998e2c4592a1e4f94bd5ffe39f35cb207867db6fe986092fb416fc9cd9266a6c103ad74
6
+ metadata.gz: b3f8ca774aff5ad98f71269f76c4a4a2bc8c2700c739cba09167185b58ae2a5d57ebdbcf412917c0c453d799d5cd2fd0510e745e87044e0c506f0648034556dc
7
+ data.tar.gz: cc5c07b85f8c3f77f8e6f0d07cd0a4e6d5478da02a7e2cccf62ef31bf9e47f9ad0b0a484f7e216efebef100ce8e452aa79526155700d1f42d953ad98419edea7
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.5
1
+ 2.1.6
@@ -3,6 +3,7 @@
3
3
  $:.unshift(File.expand_path("../ld", __FILE__))
4
4
  require 'rdf' # @see http://rubygems.org/gems/rdf
5
5
  require 'multi_json'
6
+ require 'set'
6
7
 
7
8
  module JSON
8
9
  ##
@@ -41,7 +42,7 @@ module JSON
41
42
  RDF.type.to_s => {"@type" => "@id"}
42
43
  }.freeze
43
44
 
44
- KEYWORDS = %w(
45
+ KEYWORDS = Set.new(%w(
45
46
  @base
46
47
  @container
47
48
  @context
@@ -62,7 +63,7 @@ module JSON
62
63
  @value
63
64
  @version
64
65
  @vocab
65
- ).freeze
66
+ )).freeze
66
67
 
67
68
  # Regexp matching an NCName.
68
69
  NC_REGEXP = Regexp.new(
@@ -174,7 +174,7 @@ module JSON::LD
174
174
  end
175
175
 
176
176
  # If, after the algorithm outlined above is run, the resulting element is an JSON object with just a @graph property, element is set to the value of @graph's value.
177
- result = result['@graph'] if result.is_a?(Hash) && result.keys == %w(@graph)
177
+ result = result['@graph'] if result.is_a?(Hash) && result.length == 1 && result.key?('@graph')
178
178
 
179
179
  # Finally, if element is a JSON object, it is wrapped into an array.
180
180
  result = [result].compact unless result.is_a?(Array)
@@ -277,7 +277,9 @@ module JSON::LD
277
277
  create_node_map(value, graph_maps)
278
278
 
279
279
  default_graph = graph_maps['@default']
280
- graph_maps.keys.kw_sort.reject {|k| k == '@default'}.each do |graph_name|
280
+ graph_maps.keys.kw_sort.each do |graph_name|
281
+ next if graph_name == '@default'
282
+
281
283
  graph = graph_maps[graph_name]
282
284
  entry = default_graph[graph_name] ||= {'@id' => graph_name}
283
285
  nodes = entry['@graph'] ||= []
@@ -43,7 +43,7 @@ module JSON::LD
43
43
  # @null objects are used in framing
44
44
  return nil if element.has_key?('@null')
45
45
 
46
- if element.keys.any? {|k| %w(@id @value).include?(k)}
46
+ if element.key?('@id') || element.key?('@value')
47
47
  result = context.compact_value(property, element, log_depth: @options[:log_depth])
48
48
  unless result.is_a?(Hash)
49
49
  #log_debug("") {"=> scalar result: #{result.inspect}"}
@@ -58,7 +58,7 @@ module JSON::LD
58
58
  expanded_value = element[expanded_property]
59
59
  #log_debug("") {"#{expanded_property}: #{expanded_value.inspect}"}
60
60
 
61
- if %w(@id @type).include?(expanded_property)
61
+ if expanded_property == '@id' || expanded_property == '@type'
62
62
  compacted_value = [expanded_value].flatten.compact.map do |expanded_type|
63
63
  context.compact_iri(expanded_type, vocab: (expanded_property == '@type'), log_depth: @options[:log_depth])
64
64
  end
@@ -118,14 +118,14 @@ module JSON::LD
118
118
  end
119
119
 
120
120
  # Otherwise, if expanded property is @index, @value, or @language:
121
- if %w(@index @value @language).include?(expanded_property)
121
+ if expanded_property == '@index' || expanded_property == '@value' || expanded_property == '@language'
122
122
  al = context.compact_iri(expanded_property, vocab: true, quiet: true)
123
123
  #log_debug(expanded_property) {"#{al} => #{expanded_value.inspect}"}
124
124
  result[al] = expanded_value
125
125
  next
126
126
  end
127
127
 
128
- if expanded_value == []
128
+ if expanded_value.empty?
129
129
  item_active_property =
130
130
  context.compact_iri(expanded_property,
131
131
  value: expanded_value,
@@ -181,7 +181,7 @@ module JSON::LD
181
181
  end
182
182
  end
183
183
 
184
- if %w(@language @index @id @type).include?(container)
184
+ if container == '@language' || container == '@index' || container == '@id' || container == '@type'
185
185
  map_object = nest_result[item_active_property] ||= {}
186
186
  compacted_item = case container
187
187
  when '@id'
@@ -218,7 +218,7 @@ module JSON::LD
218
218
  end
219
219
 
220
220
  # Re-order result keys
221
- result.keys.kw_sort.inject({}) {|map, kk| map[kk] = result[kk]; map}
221
+ result.keys.kw_sort.each_with_object({}) {|kk, memo| memo[kk] = result[kk]}
222
222
  else
223
223
  # For other types, the compacted value is the element value
224
224
  #log_debug("compact") {element.class.to_s}
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
  require 'json'
4
4
  require 'bigdecimal'
5
+ require 'set'
5
6
 
6
7
  module JSON::LD
7
8
  class Context
@@ -112,7 +113,7 @@ module JSON::LD
112
113
  def container_mapping=(mapping)
113
114
  mapping = Array(mapping)
114
115
  if @as_set = mapping.include?('@set')
115
- mapping -= %w(@set)
116
+ mapping.delete('@set')
116
117
  end
117
118
  @container_mapping = mapping.first
118
119
  end
@@ -554,7 +555,7 @@ module JSON::LD
554
555
  end
555
556
 
556
557
  # Since keywords cannot be overridden, term must not be a keyword. Otherwise, an invalid value has been detected, which is an error.
557
- if KEYWORDS.include?(term) && !%w(@vocab @language @version).include?(term)
558
+ if KEYWORDS.include?(term) && (term != '@vocab' && term != '@language' && term != '@version')
558
559
  raise JsonLdError::KeywordRedefinition, "term must not be a keyword: #{term.inspect}" if
559
560
  @options[:validate]
560
561
  elsif !term_valid?(term) && @options[:validate]
@@ -606,7 +607,7 @@ module JSON::LD
606
607
  else
607
608
  :error
608
609
  end
609
- unless %w(@id @vocab).include?(type) || type.is_a?(RDF::URI) && type.absolute?
610
+ unless (type == '@id' || type == '@vocab') || type.is_a?(RDF::URI) && type.absolute?
610
611
  raise JsonLdError::InvalidTypeMapping, "unknown mapping for '@type': #{type.inspect} on term #{term.inspect}"
611
612
  end
612
613
  #log_debug("") {"type_mapping: #{type.inspect}"}
@@ -615,7 +616,7 @@ module JSON::LD
615
616
 
616
617
  if value.has_key?('@reverse')
617
618
  raise JsonLdError::InvalidReverseProperty, "unexpected key in #{value.inspect} on term #{term.inspect}" if
618
- value.keys.any? {|k| %w(@id @nest).include?(k)}
619
+ value.key?('@id') || value.key?('@nest')
619
620
  raise JsonLdError::InvalidIRIMapping, "expected value of @reverse to be a string: #{value['@reverse'].inspect} on term #{term.inspect}" unless
620
621
  value['@reverse'].is_a?(String)
621
622
 
@@ -633,7 +634,7 @@ module JSON::LD
633
634
  container = value['@container']
634
635
  raise JsonLdError::InvalidReverseProperty,
635
636
  "unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" unless
636
- container.is_a?(String) && ['@set', '@index'].include?(container)
637
+ container.is_a?(String) && (container == '@set' || container == '@index')
637
638
  definition.container_mapping = check_container(container, local_context, defined, term)
638
639
  end
639
640
  definition.reverse_property = true
@@ -654,7 +655,7 @@ module JSON::LD
654
655
  (simple_term || ((processingMode || 'json-ld-1.0') == 'json-ld-1.0'))
655
656
  elsif term.include?(':')
656
657
  # If term is a compact IRI with a prefix that is a key in local context then a dependency has been found. Use this algorithm recursively passing active context, local context, the prefix as term, and defined.
657
- prefix, suffix = term.split(':')
658
+ prefix, suffix = term.split(':', 2)
658
659
  create_term_definition(local_context, prefix, defined) if local_context.has_key?(prefix)
659
660
 
660
661
  definition.id = if td = term_definitions[prefix]
@@ -791,7 +792,7 @@ module JSON::LD
791
792
  (statements[statement.subject] ||= []) << statement
792
793
 
793
794
  # Keep track of predicate ranges
794
- if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
795
+ if [RDF::RDFS.range, RDF::SCHEMA.rangeIncludes].include?(statement.predicate)
795
796
  (ranges[statement.subject] ||= []) << statement.object
796
797
  end
797
798
  end
@@ -799,7 +800,7 @@ module JSON::LD
799
800
  # Add term definitions for each class and property not in vocab, and
800
801
  # for those properties having an object range
801
802
  statements.each do |subject, values|
802
- types = values.select {|v| v.predicate == RDF.type}.map(&:object)
803
+ types = values.each_with_object([]) { |v, memo| memo << v.object if v.predicate == RDF.type }
803
804
  is_property = types.any? {|t| t.to_s.include?("Property")}
804
805
 
805
806
  term = subject.to_s.split(/[\/\#]/).last
@@ -886,7 +887,7 @@ module JSON::LD
886
887
  # @param [Term, #to_s] term in unexpanded form
887
888
  # @return [Boolean]
888
889
  def as_array?(term)
889
- return true if %w(@graph @list).include?(term)
890
+ return true if term == '@graph' || term == '@list'
890
891
  term = find_definition(term)
891
892
  term && (term.as_set || term.container_mapping == '@list')
892
893
  end
@@ -979,12 +980,14 @@ module JSON::LD
979
980
  # IRI or String, if it's a keyword
980
981
  # @raise [JSON::LD::JsonLdError::InvalidIRIMapping] if the value cannot be expanded
981
982
  # @see http://json-ld.org/spec/latest/json-ld-api/#iri-expansion
982
- def expand_iri(value, documentRelative: false, vocab: false, local_context: nil, defined: {}, quiet: false, **options)
983
+ def expand_iri(value, documentRelative: false, vocab: false, local_context: nil, defined: nil, quiet: false, **options)
983
984
  return value unless value.is_a?(String)
984
985
 
985
986
  return value if KEYWORDS.include?(value)
986
987
  #log_debug("expand_iri") {"value: #{value.inspect}"} unless quiet
987
988
 
989
+ defined = defined || {} # if we initialized in the keyword arg we would allocate {} at each invokation, even in the 2 (common) early returns above.
990
+
988
991
  # If local context is not null, it contains a key that equals value, and the value associated with the key that equals value in defined is not true, then invoke the Create Term Definition subalgorithm, passing active context, local context, value as term, and defined. This will ensure that a term definition is created for value in active context during Context Processing.
989
992
  if local_context && local_context.has_key?(value) && !defined[value]
990
993
  create_term_definition(local_context, value, defined)
@@ -1003,7 +1006,7 @@ module JSON::LD
1003
1006
 
1004
1007
  # 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.
1005
1008
  return RDF::Node.new(namer.get_sym(suffix)) if prefix == '_'
1006
- return RDF::URI(value) if suffix[0,2] == '//'
1009
+ return RDF::URI(value) if suffix.start_with?('//')
1007
1010
 
1008
1011
  # 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.
1009
1012
  if local_context && local_context.has_key?(prefix) && !defined[prefix]
@@ -1138,7 +1141,7 @@ module JSON::LD
1138
1141
  tl_value ||= '@null'
1139
1142
  preferred_values = []
1140
1143
  preferred_values << '@reverse' if tl_value == '@reverse'
1141
- if %w(@id @reverse).include?(tl_value) && value.is_a?(Hash) && value.has_key?('@id')
1144
+ if (tl_value == '@id' || tl_value == '@reverse') && value.is_a?(Hash) && value.has_key?('@id')
1142
1145
  t_iri = compact_iri(value['@id'], vocab: true, document_relative: true)
1143
1146
  if (r_td = term_definitions[t_iri]) && r_td.id == value['@id']
1144
1147
  preferred_values.concat(%w(@vocab @id @none))
@@ -1204,6 +1207,8 @@ module JSON::LD
1204
1207
  end
1205
1208
  end
1206
1209
 
1210
+ RDF_LITERAL_NATIVE_TYPES = Set.new([RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double]).freeze
1211
+
1207
1212
  ##
1208
1213
  # If active property has a type mapping in the active context set to @id or @vocab, a JSON object with a single member @id whose value is the result of using the IRI Expansion algorithm on value is returned.
1209
1214
  #
@@ -1246,7 +1251,7 @@ module JSON::LD
1246
1251
  when RDF::Literal
1247
1252
  #log_debug("Literal") {"datatype: #{value.datatype.inspect}"}
1248
1253
  res = {}
1249
- if useNativeTypes && [RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double].include?(value.datatype)
1254
+ if useNativeTypes && RDF_LITERAL_NATIVE_TYPES.include?(value.datatype)
1250
1255
  res['@value'] = value.object
1251
1256
  res['@type'] = uri(coerce(property)) if coerce(property)
1252
1257
  else
@@ -1297,7 +1302,7 @@ module JSON::LD
1297
1302
  def compact_value(property, value, options = {})
1298
1303
  #log_debug("compact_value") {"property: #{property.inspect}, value: #{value.inspect}"}
1299
1304
 
1300
- num_members = value.keys.length
1305
+ num_members = value.length
1301
1306
 
1302
1307
  num_members -= 1 if index?(value) && container(property) == '@index'
1303
1308
  if num_members > 2
@@ -1407,7 +1412,7 @@ module JSON::LD
1407
1412
  def coerce(property)
1408
1413
  # Map property, if it's not an RDF::Value
1409
1414
  # @type is always is an IRI
1410
- return '@id' if [RDF.type, '@type'].include?(property)
1415
+ return '@id' if property == RDF.type || property == '@type'
1411
1416
  term_definitions[property] && term_definitions[property].type_mapping
1412
1417
  end
1413
1418
 
@@ -1573,9 +1578,10 @@ module JSON::LD
1573
1578
  #
1574
1579
  # @return [Array<RDF::URI>]
1575
1580
  def mappings
1576
- term_definitions.inject({}) do |memo, (t,td)|
1577
- memo[t] = td ? td.id : nil
1578
- memo
1581
+ {}.tap do |memo|
1582
+ term_definitions.each_pair do |t,td|
1583
+ memo[t] = td ? td.id : nil
1584
+ end
1579
1585
  end
1580
1586
  end
1581
1587
 
@@ -1595,9 +1601,10 @@ module JSON::LD
1595
1601
  # @return [Array<String>]
1596
1602
  # @deprecated
1597
1603
  def languages
1598
- term_definitions.inject({}) do |memo, (t,td)|
1599
- memo[t] = td.language_mapping
1600
- memo
1604
+ {}.tap do |memo|
1605
+ term_definitions.each_pair do |t,td|
1606
+ memo[t] = td.language_mapping
1607
+ end
1601
1608
  end
1602
1609
  end
1603
1610
 
@@ -1610,7 +1617,7 @@ module JSON::LD
1610
1617
  end
1611
1618
 
1612
1619
  val = Array(container)
1613
- val -= %w(@set) if has_set = val.include?('@set')
1620
+ val.delete('@set') if has_set = val.include?('@set')
1614
1621
 
1615
1622
  raise JsonLdError::InvalidContainerMapping,
1616
1623
  "'@container' has more than one value other than @set" if val.length > 1
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
+ require 'set'
4
+
3
5
  module JSON::LD
4
6
  ##
5
7
  # Expand module, used as part of API
@@ -22,7 +24,7 @@ module JSON::LD
22
24
  when Array
23
25
  # If element is an array,
24
26
  is_list = context.container(active_property) == '@list'
25
- value = input.map do |v|
27
+ value = input.each_with_object([]) do |v, memo|
26
28
  # Initialize expanded item to the result of using this algorithm recursively, passing active context, active property, and item as element.
27
29
  v = expand(v, active_property, context, ordered: ordered)
28
30
 
@@ -30,8 +32,8 @@ module JSON::LD
30
32
  raise JsonLdError::ListOfLists,
31
33
  "A list may not contain another list" if
32
34
  is_list && (v.is_a?(Array) || list?(v))
33
- v
34
- end.flatten.compact
35
+ memo << v unless v.nil?
36
+ end
35
37
 
36
38
  value
37
39
  when Hash
@@ -42,13 +44,11 @@ module JSON::LD
42
44
  end
43
45
 
44
46
  output_object = {}
45
- keys = ordered ? input.keys.kw_sort : input.keys
46
47
 
47
48
  # See if keys mapping to @type have terms with a local context
48
- input.keys.select do |key|
49
- context.expand_iri(key, vocab: true) == '@type'
50
- end.each do |key|
51
- Array(input[key]).each do |term|
49
+ input.each_pair do |key, val|
50
+ next unless context.expand_iri(key, vocab: true) == '@type'
51
+ Array(val).each do |term|
52
52
  term_context = context.term_definitions[term].context if context.term_definitions[term]
53
53
  context = term_context ? context.parse(term_context) : context
54
54
  end
@@ -62,19 +62,20 @@ module JSON::LD
62
62
  # If result contains the key @value:
63
63
  if value?(output_object)
64
64
  unless (output_object.keys - %w(@value @language @type @index)).empty? &&
65
- (output_object.keys & %w(@language @type)).length < 2
65
+ !(output_object.key?('@language') && output_object.key?('@type'))
66
66
  # The result must not contain any keys other than @value, @language, @type, and @index. It must not contain both the @language key and the @type key. Otherwise, an invalid value object error has been detected and processing is aborted.
67
67
  raise JsonLdError::InvalidValueObject,
68
68
  "value object has unknown keys: #{output_object.inspect}"
69
69
  end
70
70
 
71
- output_object.delete('@language') if Array(output_object['@language']).join('').to_s.empty?
72
- output_object.delete('@type') if Array(output_object['@type']).join('').to_s.empty?
71
+ output_object.delete('@language') if output_object.key?('@language') && Array(output_object['@language']).empty?
72
+ output_object.delete('@type') if output_object.key?('@type') && Array(output_object['@type']).empty?
73
73
 
74
74
  # If the value of result's @value key is null, then set result to null.
75
- return nil if Array(output_object['@value']).empty?
75
+ ary = Array(output_object['@value'])
76
+ return nil if ary.empty?
76
77
 
77
- if !Array(output_object['@value']).all? {|v| v.is_a?(String) || v.is_a?(Hash) && v.empty?} && output_object.has_key?('@language')
78
+ if !ary.all? {|v| v.is_a?(String) || v.is_a?(Hash) && v.empty?} && output_object.has_key?('@language')
78
79
  # Otherwise, if the value of result's @value member is not a string and result contains the key @language, an invalid language-tagged value error has been detected (only strings can be language-tagged) and processing is aborted.
79
80
  raise JsonLdError::InvalidLanguageTaggedValue,
80
81
  "when @language is used, @value must be a string: #{output_object.inspect}"
@@ -88,7 +89,7 @@ module JSON::LD
88
89
  elsif !output_object.fetch('@type', []).is_a?(Array)
89
90
  # Otherwise, if result contains the key @type and its associated value is not an array, set it to an array containing only the associated value.
90
91
  output_object['@type'] = [output_object['@type']]
91
- elsif output_object.keys.any? {|k| %w(@set @list).include?(k)}
92
+ elsif output_object.key?('@set') || output_object.key?('@list')
92
93
  # Otherwise, if result contains the key @set or @list:
93
94
  # The result must contain at most one other key and that key must be @index. Otherwise, an invalid set or list object error has been detected and processing is aborted.
94
95
  raise JsonLdError::InvalidSetOrListObject,
@@ -96,15 +97,15 @@ module JSON::LD
96
97
  (output_object.keys - %w(@set @list @index)).empty?
97
98
 
98
99
  # If result contains the key @set, then set result to the key's associated value.
99
- return output_object['@set'] if output_object.keys.include?('@set')
100
+ return output_object['@set'] if output_object.key?('@set')
100
101
  end
101
102
 
102
103
  # If result contains only the key @language, set result to null.
103
- return nil if output_object.keys == %w(@language)
104
+ return nil if output_object.length == 1 && output_object.key?('@language')
104
105
 
105
106
  # If active property is null or @graph, drop free-floating values as follows:
106
107
  if (active_property || '@graph') == '@graph' &&
107
- (output_object.keys.any? {|k| %w(@value @list).include?(k)} ||
108
+ (output_object.key?('@value') || output_object.key?('@list') ||
108
109
  (output_object.keys - %w(@id)).empty? && !framing)
109
110
  #log_debug(" =>") { "empty top-level: " + output_object.inspect}
110
111
  return nil
@@ -112,7 +113,7 @@ module JSON::LD
112
113
 
113
114
  # Re-order result keys if ordering
114
115
  if ordered
115
- output_object.keys.kw_sort.inject({}) {|map, kk| map[kk] = output_object[kk]; map}
116
+ output_object.keys.kw_sort.each_with_object({}) {|kk, memo| memo[kk] = output_object[kk]}
116
117
  else
117
118
  output_object
118
119
  end
@@ -127,6 +128,8 @@ module JSON::LD
127
128
  end
128
129
 
129
130
  private
131
+ CONTAINER_MAPPING_INDEX_ID_TYPE = Set.new(%w(@index @id @type)).freeze
132
+
130
133
  # Expand each key and value of element adding them to result
131
134
  def expand_object(input, active_property, context, output_object, ordered: false)
132
135
  framing = @options[:processingMode].include?("expand-frame")
@@ -304,7 +307,7 @@ module JSON::LD
304
307
  end
305
308
 
306
309
  # If expanded value contains members other than @reverse:
307
- unless value.keys.reject {|k| k == '@reverse'}.empty?
310
+ if !value.key?('@reverse') || value.length > 1
308
311
  # If result does not have an @reverse member, create one and set its value to an empty JSON object.
309
312
  reverse_map = output_object['@reverse'] ||= {}
310
313
  value.each do |property, items|
@@ -368,7 +371,7 @@ module JSON::LD
368
371
  end
369
372
 
370
373
  ary
371
- elsif %w(@index @id @type).include?(container) && value.is_a?(Hash)
374
+ elsif CONTAINER_MAPPING_INDEX_ID_TYPE.include?(container) && value.is_a?(Hash)
372
375
  # Otherwise, if key's container mapping in active context is @index, @id, @type, an IRI or Blank Node and value is a JSON object then value is expanded from an index map as follows:
373
376
 
374
377
  # Set ary to an empty array.
@@ -17,13 +17,14 @@ class Array
17
17
  # @yieldreturn [Integer]
18
18
  # @return [Array]
19
19
  KW_ORDER = %w(@base @id @value @type @language @vocab @container @graph @list @set @index).freeze
20
+ KW_ORDER_CACHE = KW_ORDER.each_with_object({}) do |kw, memo|
21
+ memo[kw] = "@#{KW_ORDER.index(kw)}"
22
+ end.freeze
20
23
 
21
24
  # Order, considering keywords to come before other strings
22
25
  def kw_sort
23
26
  self.sort do |a, b|
24
- a = "@#{KW_ORDER.index(a)}" if KW_ORDER.include?(a)
25
- b = "@#{KW_ORDER.index(b)}" if KW_ORDER.include?(b)
26
- a <=> b
27
+ KW_ORDER_CACHE.fetch(a, a) <=> KW_ORDER_CACHE.fetch(b, b)
27
28
  end
28
29
  end
29
30
 
@@ -19,7 +19,7 @@ module JSON::LD
19
19
  # RDF::Format.file_extensions #=> {:jsonld => [JSON::LD::Format] }
20
20
  #
21
21
  # @see http://www.w3.org/TR/json-ld/
22
- # @see http://json-ld.org/test-suite/
22
+ # @see https://json-ld.org/test-suite/
23
23
  class Format < RDF::Format
24
24
  content_type 'application/ld+json',
25
25
  extension: :jsonld,
@@ -53,6 +53,7 @@ module JSON::LD
53
53
  description: "Expand JSON-LD or parsed RDF",
54
54
  parse: false,
55
55
  help: "expand [--context <context-file>] files ...",
56
+ filter: {output_format: :jsonld}, # Only shows output format set
56
57
  lambda: ->(files, options) do
57
58
  out = options[:output] || $stdout
58
59
  out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
@@ -80,11 +81,13 @@ module JSON::LD
80
81
  end
81
82
  end
82
83
  end
83
- end
84
+ end,
85
+ option_use: {context: :removed}
84
86
  },
85
87
  compact: {
86
88
  description: "Compact JSON-LD or parsed RDF",
87
89
  parse: false,
90
+ filter: {output_format: :jsonld}, # Only shows output format set
88
91
  help: "compact --context <context-file> files ...",
89
92
  lambda: ->(files, options) do
90
93
  raise ArgumentError, "Compacting requires a context" unless options[:context]
@@ -115,12 +118,22 @@ module JSON::LD
115
118
  end
116
119
  end
117
120
  end
118
- end
121
+ end,
122
+ options: [
123
+ RDF::CLI::Option.new(
124
+ symbol: :context,
125
+ datatype: RDF::URI,
126
+ control: :url2,
127
+ use: :required,
128
+ on: ["--context CONTEXT"],
129
+ description: "Context to use when compacting.") {|arg| RDF::URI(arg)},
130
+ ]
119
131
  },
120
132
  flatten: {
121
133
  description: "Flatten JSON-LD or parsed RDF",
122
134
  parse: false,
123
135
  help: "flatten [--context <context-file>] files ...",
136
+ filter: {output_format: :jsonld}, # Only shows output format set
124
137
  lambda: ->(files, options) do
125
138
  out = options[:output] || $stdout
126
139
  out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
@@ -155,6 +168,7 @@ module JSON::LD
155
168
  description: "Frame JSON-LD or parsed RDF",
156
169
  parse: false,
157
170
  help: "frame --frame <frame-file> files ...",
171
+ filter: {output_format: :jsonld}, # Only shows output format set
158
172
  lambda: ->(files, options) do
159
173
  raise ArgumentError, "Framing requires a frame" unless options[:frame]
160
174
  out = options[:output] || $stdout
@@ -184,7 +198,17 @@ module JSON::LD
184
198
  end
185
199
  end
186
200
  end
187
- end
201
+ end,
202
+ option_use: {context: :removed},
203
+ options: [
204
+ RDF::CLI::Option.new(
205
+ symbol: :frame,
206
+ datatype: RDF::URI,
207
+ control: :url2,
208
+ use: :required,
209
+ on: ["--frame FRAME"],
210
+ description: "Frame to use when serializing.") {|arg| RDF::URI(arg)}
211
+ ]
188
212
  },
189
213
  }
190
214
  end
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
+ require 'set'
4
+
3
5
  module JSON::LD
4
6
  module Frame
5
7
  include Utils
@@ -96,7 +98,7 @@ module JSON::LD
96
98
  recurse, subframe = (state[:graph] != '@merged'), {}
97
99
  else
98
100
  subframe = frame['@graph'].first
99
- recurse = !%w(@merged @default).include?(id)
101
+ recurse = !(id == '@merged' || id == '@default')
100
102
  subframe = {} unless subframe.is_a?(Hash)
101
103
  end
102
104
 
@@ -152,7 +154,9 @@ module JSON::LD
152
154
  end
153
155
 
154
156
  # handle defaults in order
155
- frame.keys.kw_sort.reject {|p| p.start_with?('@')}.each do |prop|
157
+ frame.keys.kw_sort.each do |prop|
158
+ next if prop.start_with?('@')
159
+
156
160
  # if omit default is off, then include default values for properties that appear in the next frame but are not in the matching subject
157
161
  n = frame[prop].first || {}
158
162
  omit_default_on = get_frame_flag(n, options, :omitDefault)
@@ -187,21 +191,26 @@ module JSON::LD
187
191
  ##
188
192
  # Recursively find and count blankNode identifiers.
189
193
  # @return [Hash{String => Integer}]
190
- def count_blank_node_identifiers(input, results = {})
194
+ def count_blank_node_identifiers(input)
195
+ {}.tap do |results|
196
+ count_blank_node_identifiers_internal(input, results)
197
+ end
198
+ end
199
+
200
+ def count_blank_node_identifiers_internal(input, results)
191
201
  case input
192
- when Array
193
- input.map {|o| count_blank_node_identifiers(o, results)}
194
- when Hash
195
- input.each do |k, v|
196
- count_blank_node_identifiers(v, results)
197
- end
198
- when String
199
- if input.start_with?('_:')
200
- results[input] ||= 0
201
- results[input] += 1
202
- end
202
+ when Array
203
+ input.each {|o| count_blank_node_identifiers_internal(o, results)}
204
+ when Hash
205
+ input.each do |k, v|
206
+ count_blank_node_identifiers_internal(v, results)
207
+ end
208
+ when String
209
+ if input.start_with?('_:')
210
+ results[input] ||= 0
211
+ results[input] += 1
212
+ end
203
213
  end
204
- results
205
214
  end
206
215
 
207
216
  ##
@@ -260,13 +269,14 @@ module JSON::LD
260
269
  #
261
270
  # @return all of the matched subjects.
262
271
  def filter_subjects(state, subjects, frame, flags)
263
- subjects.inject({}) do |memo, id|
272
+ subjects.each_with_object({}) do |id, memo|
264
273
  subject = state[:graphMap][state[:graph]][id]
265
274
  memo[id] = subject if filter_subject(subject, frame, state, flags)
266
- memo
267
275
  end
268
276
  end
269
277
 
278
+ EXCLUDED_FRAMING_KEYWORDS = Set.new(%w(@default @embed @explicit @omitDefault @requireAll)).freeze
279
+
270
280
  ##
271
281
  # Returns true if the given node matches the given frame.
272
282
  #
@@ -320,7 +330,7 @@ module JSON::LD
320
330
  validate_frame(v)
321
331
  has_default = v.has_key?('@default')
322
332
  # Exclude framing keywords
323
- v = v.dup.delete_if {|kk,vv| %w(@default @embed @explicit @omitDefault @requireAll).include?(kk)}
333
+ v = v.reject {|kk,vv| EXCLUDED_FRAMING_KEYWORDS.include?(kk)}
324
334
  end
325
335
 
326
336
 
@@ -490,7 +500,11 @@ module JSON::LD
490
500
  # @param [Hash] flags the current framing flags.
491
501
  # @return [Array<Hash>] the implicit frame.
492
502
  def create_implicit_frame(flags)
493
- flags.keys.inject({}) {|memo, key| memo["@#{key}"] = [flags[key]]; memo}
503
+ {}.tap do |memo|
504
+ flags.each_pair do |key, val|
505
+ memo["@#{key}"] = [val]
506
+ end
507
+ end
494
508
  end
495
509
 
496
510
  private
@@ -512,8 +526,8 @@ module JSON::LD
512
526
  v2, t2, l2 = Array(pattern['@value']), Array(pattern['@type']), Array(pattern['@language'])
513
527
  return true if (v2 + t2 + l2).empty?
514
528
  return false unless v2.include?(v1) || v2 == [{}]
515
- return false unless t2.include?(t1) || t1 && t2 == [{}] || t1.nil? && (t2 || []) == []
516
- return false unless l2.include?(l1) || l1 && l2 == [{}] || l1.nil? && (l2 || []) == []
529
+ return false unless t2.include?(t1) || t1 && t2 == [{}] || t1.nil? && (t2 || []).empty?
530
+ return false unless l2.include?(l1) || l1 && l2 == [{}] || l1.nil? && (l2 || []).empty?
517
531
  true
518
532
  end
519
533
  end
@@ -15,10 +15,17 @@ module JSON::LD
15
15
  def self.options
16
16
  super + [
17
17
  RDF::CLI::Option.new(
18
- symbol: :compactArrays,
19
- datatype: TrueClass,
20
- on: ["--compact-arrays"],
21
- description: "Replaces arrays with just one element with that element during compaction.") {true},
18
+ symbol: :expandContext,
19
+ control: :url2,
20
+ datatype: RDF::URI,
21
+ on: ["--expand-context CONTEXT"],
22
+ description: "Context to use when expanding.") {|arg| RDF::URI(arg)},
23
+ RDF::CLI::Option.new(
24
+ symbol: :processing_mode,
25
+ datatype: %w(json-ld-1.0 json-ld-1.1),
26
+ control: :radio,
27
+ on: ["--processingMode MODE", %w(json-ld-1.0 json-ld-1.1)],
28
+ description: "Set Processing Mode (json-ld-1.0 or json-ld-1.1)"),
22
29
  ]
23
30
  end
24
31
 
@@ -88,7 +88,7 @@ module JSON::LD
88
88
  node_definition
89
89
  end
90
90
  @id = @attributes['@id']
91
- @anon = @id.nil? || @id.to_s[0,2] == '_:'
91
+ @anon = @id.nil? || @id.to_s.start_with?('_:')
92
92
  end
93
93
 
94
94
  ##
@@ -110,19 +110,19 @@ module JSON::LD
110
110
  # @return [Hash] deresolved attribute hash
111
111
  def deresolve
112
112
  node_definition = if resolved?
113
- deresolved = attributes.keys.inject({}) do |memo, prop|
114
- value = attributes[prop]
115
- memo[prop] = case value
116
- when Resource
117
- {'id' => value.id}
118
- when Array
119
- value.map do |v|
120
- v.is_a?(Resource) ? {'id' => v.id} : v
113
+ deresolved = [].tap do |memo|
114
+ attributes.each_pair do |prop, value|
115
+ memo[prop] = case value
116
+ when Resource
117
+ {'id' => value.id}
118
+ when Array
119
+ value.map do |v|
120
+ v.is_a?(Resource) ? {'id' => v.id} : v
121
+ end
122
+ else
123
+ value
121
124
  end
122
- else
123
- value
124
125
  end
125
- memo
126
126
  end
127
127
  deresolved
128
128
  else
@@ -188,7 +188,7 @@ module JSON::LD
188
188
 
189
189
  #$logger.debug "resolve(0): #{attributes.inspect}"
190
190
  @attributes.each do |k, v|
191
- next if %w(id type).include?(k)
191
+ next if k == 'id' || k == 'type'
192
192
  @attributes[k] = update_obj(@attributes[k], reference_map)
193
193
  end
194
194
  #$logger.debug "resolve(1): #{attributes.inspect}"
@@ -20,7 +20,7 @@ module JSON::LD
20
20
  # @param [Object] value
21
21
  # @return [Boolean]
22
22
  def node_reference?(value)
23
- value.is_a?(Hash) && value.keys == %w(@id)
23
+ value.is_a?(Hash) && value.length == 1 && value.key?('@id')
24
24
  end
25
25
 
26
26
  ##
@@ -40,9 +40,9 @@ module JSON::LD
40
40
  def blank_node?(value)
41
41
  case value
42
42
  when nil then true
43
- when String then value[0,2] == '_:'
43
+ when String then value.start_with?('_:')
44
44
  else
45
- (node?(value) || node_reference?(value)) && value.fetch('@id', '_:')[0,2] == '_:'
45
+ (node?(value) || node_reference?(value)) && value.fetch('@id', '_:').start_with?('_:')
46
46
  end
47
47
  end
48
48
 
@@ -80,7 +80,7 @@ module JSON::LD
80
80
  # @return [RDF::Resource]
81
81
  def as_resource(id, base = nil)
82
82
  @nodes ||= {} # Re-use BNodes
83
- if id[0,2] == '_:'
83
+ if id.start_with?('_:')
84
84
  (@nodes[id] ||= RDF::Node.new(namer.get_sym(id)))
85
85
  elsif base
86
86
  base.join(id)
@@ -75,31 +75,37 @@ module JSON::LD
75
75
  RDF::CLI::Option.new(
76
76
  symbol: :compactArrays,
77
77
  datatype: TrueClass,
78
+ control: :checkbox,
78
79
  on: ["--compact-arrays"],
79
80
  description: "Replaces arrays with just one element with that element during compaction.") {true},
80
81
  RDF::CLI::Option.new(
81
82
  symbol: :compactToRelative,
82
83
  datatype: TrueClass,
84
+ control: :checkbox,
83
85
  on: ["--compact-to-relative"],
84
86
  description: "Creates document relative IRIs when compacting, if `true`, otherwise leaves expanded. Default is `true` use --no-compact-to-relative to disable.") {true},
85
87
  RDF::CLI::Option.new(
86
88
  symbol: :context,
87
89
  datatype: RDF::URI,
90
+ control: :url2,
88
91
  on: ["--context CONTEXT"],
89
- description: "Context to use when serializing. Constructed context for native serialization.") {|arg| RDF::URI(arg)},
92
+ description: "Context to use when compacting.") {|arg| RDF::URI(arg)},
90
93
  RDF::CLI::Option.new(
91
- symbol: :frame,
92
- datatype: RDF::URI,
93
- on: ["--frame FRAME"],
94
- description: "Frame to use when serializing.") {|arg| RDF::URI(arg)},
94
+ symbol: :processing_mode,
95
+ datatype: %w(json-ld-1.0 json-ld-1.1),
96
+ control: :radio,
97
+ on: ["--processingMode MODE", %w(json-ld-1.0 json-ld-1.1)],
98
+ description: "Set Processing Mode (json-ld-1.0 or json-ld-1.1)"),
95
99
  RDF::CLI::Option.new(
96
100
  symbol: :stream,
97
101
  datatype: TrueClass,
102
+ control: :checkbox,
98
103
  on: ["--stream"],
99
104
  description: "Do not attempt to optimize graph presentation, suitable for streaming large graphs.") {true},
100
105
  RDF::CLI::Option.new(
101
106
  symbol: :useRdfType,
102
107
  datatype: TrueClass,
108
+ control: :checkbox,
103
109
  on: ["--use-rdf-type"],
104
110
  description: "Treat `rdf:type` like a normal property instead of using `@type`.") {true},
105
111
  ]
@@ -67,7 +67,7 @@ describe JSON::LD::Format do
67
67
  end
68
68
  end
69
69
 
70
- describe ".cli_commands", skip: ("TextMate OptionParser issues" if ENV['TM_SELECTED_FILE']) do
70
+ describe ".cli_commands" do
71
71
  require 'rdf/cli'
72
72
  let(:ttl) {File.expand_path("../test-files/test-1-rdf.ttl", __FILE__)}
73
73
  let(:json) {File.expand_path("../test-files/test-1-input.json", __FILE__)}
@@ -75,37 +75,37 @@ describe JSON::LD::Format do
75
75
 
76
76
  describe "#expand" do
77
77
  it "expands RDF" do
78
- expect {RDF::CLI.exec(["expand", ttl], format: :ttl)}.to write.to(:output)
78
+ expect {RDF::CLI.exec(["expand", ttl], format: :ttl, output_format: :jsonld)}.to write.to(:output)
79
79
  end
80
80
  it "expands JSON" do
81
- expect {RDF::CLI.exec(["expand", json], format: :jsonld, validate: false)}.to write.to(:output)
81
+ expect {RDF::CLI.exec(["expand", json], format: :jsonld, output_format: :jsonld, validate: false)}.to write.to(:output)
82
82
  end
83
83
  end
84
84
 
85
85
  describe "#compact" do
86
86
  it "compacts RDF" do
87
- expect {RDF::CLI.exec(["compact", ttl], context: context, format: :ttl, validate: false)}.to write.to(:output)
87
+ expect {RDF::CLI.exec(["compact", ttl], context: context, format: :ttl, output_format: :jsonld, validate: false)}.to write.to(:output)
88
88
  end
89
89
  it "compacts JSON" do
90
- expect {RDF::CLI.exec(["compact", json], context: context, format: :jsonld, validate: false)}.to write.to(:output)
90
+ expect {RDF::CLI.exec(["compact", json], context: context, format: :jsonld, output_format: :jsonld, validate: false)}.to write.to(:output)
91
91
  end
92
92
  end
93
93
 
94
94
  describe "#flatten" do
95
95
  it "flattens RDF" do
96
- expect {RDF::CLI.exec(["flatten", ttl], context: context, format: :ttl, validate: false)}.to write.to(:output)
96
+ expect {RDF::CLI.exec(["flatten", ttl], context: context, format: :ttl, output_format: :jsonld, validate: false)}.to write.to(:output)
97
97
  end
98
98
  it "flattens JSON" do
99
- expect {RDF::CLI.exec(["flatten", json], context: context, format: :jsonld, validate: false)}.to write.to(:output)
99
+ expect {RDF::CLI.exec(["flatten", json], context: context, format: :jsonld, output_format: :jsonld, validate: false)}.to write.to(:output)
100
100
  end
101
101
  end
102
102
 
103
103
  describe "#frame" do
104
104
  it "frames RDF" do
105
- expect {RDF::CLI.exec(["frame", ttl], frame: context, format: :ttl)}.to write.to(:output)
105
+ expect {RDF::CLI.exec(["frame", ttl], frame: context, format: :ttl, output_format: :jsonld)}.to write.to(:output)
106
106
  end
107
107
  it "frames JSON" do
108
- expect {RDF::CLI.exec(["frame", json], frame: context, format: :jsonld, validate: false)}.to write.to(:output)
108
+ expect {RDF::CLI.exec(["frame", json], frame: context, format: :jsonld, output_format: :jsonld, validate: false)}.to write.to(:output)
109
109
  end
110
110
  end
111
111
  end
@@ -14,10 +14,10 @@ require 'rdf/spec/matchers'
14
14
  require 'yaml'
15
15
  begin
16
16
  require 'simplecov'
17
- require 'coveralls'
17
+ require 'coveralls' unless ENV['NOCOVERALLS']
18
18
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
19
19
  SimpleCov::Formatter::HTMLFormatter,
20
- Coveralls::SimpleCov::Formatter
20
+ (Coveralls::SimpleCov::Formatter unless ENV['NOCOVERALLS'])
21
21
  ])
22
22
  SimpleCov.start do
23
23
  add_filter "/spec/"
@@ -5,7 +5,7 @@ require 'support/extensions'
5
5
  # For now, override RDF::Utils::File.open_file to look for the file locally before attempting to retrieve it
6
6
  module RDF::Util
7
7
  module File
8
- REMOTE_PATH = "http://json-ld.org/test-suite/"
8
+ REMOTE_PATH = "https://json-ld.org/test-suite/"
9
9
  LOCAL_PATH = ::File.expand_path("../json-ld.org/test-suite", __FILE__) + '/'
10
10
 
11
11
  class << self
@@ -69,7 +69,7 @@ end
69
69
 
70
70
  module Fixtures
71
71
  module SuiteTest
72
- SUITE = RDF::URI("http://json-ld.org/test-suite/")
72
+ SUITE = RDF::URI("https://json-ld.org/test-suite/")
73
73
 
74
74
  class Manifest < JSON::LD::Resource
75
75
  def self.open(file)
@@ -108,7 +108,7 @@ module Fixtures
108
108
  def options
109
109
  @options ||= begin
110
110
  opts = {documentLoader: Fixtures::SuiteTest.method(:documentLoader)}
111
- {'specVersion' => "1.1"}.merge(property('option') || {}).each do |k, v|
111
+ {'specVersion' => "json-ld-1.1"}.merge(property('option') || {}).each do |k, v|
112
112
  opts[k.to_sym] = v
113
113
  end
114
114
  opts
@@ -162,7 +162,7 @@ module Fixtures
162
162
  end
163
163
  options = {validate: true}.merge(options)
164
164
 
165
- unless options[:specVersion] == "1.1"
165
+ unless options[:specVersion] == "json-ld-1.1"
166
166
  skip "not a 1.1 test"
167
167
  return
168
168
  end
@@ -287,7 +287,7 @@ module Fixtures
287
287
  end
288
288
  end
289
289
 
290
- REMOTE_PATH = "http://json-ld.org/test-suite/"
290
+ REMOTE_PATH = "https://json-ld.org/test-suite/"
291
291
  LOCAL_PATH = ::File.expand_path("../json-ld.org/test-suite", __FILE__) + '/'
292
292
  ##
293
293
  # Document loader to use for tests having `useDocumentLoader` option
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: 2.1.5
4
+ version: 2.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg Kellogg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-10 00:00:00.000000000 Z
11
+ date: 2017-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdf
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.2.8
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
29
  version: '2.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.2.8
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: multi_json
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -342,7 +348,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
342
348
  - !ruby/object:Gem::Version
343
349
  version: '0'
344
350
  requirements: []
345
- rubyforge_project: json-ld
351
+ rubyforge_project:
346
352
  rubygems_version: 2.6.12
347
353
  signing_key:
348
354
  specification_version: 4