json-ld 3.1.7 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,10 +11,10 @@ module RDF
11
11
  class Statement
12
12
  # Validate extended RDF
13
13
  def valid_extended?
14
- has_subject? && subject.resource? && subject.valid_extended? &&
15
- has_predicate? && predicate.resource? && predicate.valid_extended? &&
16
- has_object? && object.term? && object.valid_extended? &&
17
- (has_graph? ? (graph_name.resource? && graph_name.valid_extended?) : true)
14
+ subject? && subject.resource? && subject.valid_extended? &&
15
+ predicate? && predicate.resource? && predicate.valid_extended? &&
16
+ object? && object.term? && object.valid_extended? &&
17
+ (graph? ? (graph_name.resource? && graph_name.valid_extended?) : true)
18
18
  end
19
19
  end
20
20
 
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
+ require 'json/canonicalization'
4
+
3
5
  module JSON::LD
4
6
  module Flatten
5
7
  include Utils
@@ -7,6 +9,10 @@ module JSON::LD
7
9
  ##
8
10
  # This algorithm creates a JSON object node map holding an indexed representation of the graphs and nodes represented in the passed expanded document. All nodes that are not uniquely identified by an IRI get assigned a (new) blank node identifier. The resulting node map will have a member for every graph in the document whose value is another object with a member for every node represented in the document. The default graph is stored under the @default member, all other graphs are stored under their graph name.
9
11
  #
12
+ # For RDF-star/JSON-LD-star:
13
+ # * Values of `@id` can be an object (embedded node); when these are used as keys in a Node Map, they are serialized as canonical JSON, and de-serialized when flattening.
14
+ # * The presence of `@annotation` implies an embedded node and the annotation object is removed from the node/value object in which it appears.
15
+ #
10
16
  # @param [Array, Hash] element
11
17
  # Expanded JSON-LD input
12
18
  # @param [Hash] graph_map A map of graph name to subjects
@@ -16,12 +22,15 @@ module JSON::LD
16
22
  # Node identifier
17
23
  # @param [String] active_property (nil)
18
24
  # Property within current node
25
+ # @param [Boolean] reverse (false)
26
+ # Processing a reverse relationship
19
27
  # @param [Array] list (nil)
20
28
  # Used when property value is a list
21
29
  def create_node_map(element, graph_map,
22
30
  active_graph: '@default',
23
31
  active_subject: nil,
24
32
  active_property: nil,
33
+ reverse: false,
25
34
  list: nil)
26
35
  if element.is_a?(Array)
27
36
  # If element is an array, process each entry in element recursively by passing item for element, node map, active graph, active subject, active property, and list.
@@ -30,21 +39,45 @@ module JSON::LD
30
39
  active_graph: active_graph,
31
40
  active_subject: active_subject,
32
41
  active_property: active_property,
42
+ reverse: false,
33
43
  list: list)
34
44
  end
35
45
  elsif !element.is_a?(Hash)
36
46
  raise "Expected hash or array to create_node_map, got #{element.inspect}"
37
47
  else
38
48
  graph = (graph_map[active_graph] ||= {})
39
- subject_node = graph[active_subject]
49
+ subject_node = !reverse && graph[active_subject.is_a?(Hash) ? active_subject.to_json_c14n : active_subject]
40
50
 
41
51
  # Transform BNode types
42
- if element.has_key?('@type')
52
+ if element.key?('@type')
43
53
  element['@type'] = Array(element['@type']).map {|t| blank_node?(t) ? namer.get_name(t) : t}
44
54
  end
45
55
 
46
56
  if value?(element)
47
57
  element['@type'] = element['@type'].first if element ['@type']
58
+
59
+ # For rdfstar, if value contains an `@annotation` member ...
60
+ # note: active_subject will not be nil, and may be an object itself.
61
+ if element.key?('@annotation')
62
+ # rdfstar being true is implicit, as it is checked in expansion
63
+ as = node_reference?(active_subject) ?
64
+ active_subject['@id'] :
65
+ active_subject
66
+ star_subject = {
67
+ "@id" => as,
68
+ active_property => [element]
69
+ }
70
+
71
+ # Note that annotation is an array, make the reified subject the id of each member of that array.
72
+ annotation = element.delete('@annotation').map do |a|
73
+ a.merge('@id' => star_subject)
74
+ end
75
+
76
+ # Invoke recursively using annotation.
77
+ create_node_map(annotation, graph_map,
78
+ active_graph: active_graph)
79
+ end
80
+
48
81
  if list.nil?
49
82
  add_value(subject_node, active_property, element, property_is_array: true, allow_duplicate: false)
50
83
  else
@@ -64,13 +97,19 @@ module JSON::LD
64
97
  end
65
98
  else
66
99
  # Element is a node object
67
- id = element.delete('@id')
68
- id = namer.get_name(id) if blank_node?(id)
100
+ ser_id = id = element.delete('@id')
101
+ if id.is_a?(Hash)
102
+ # Index graph using serialized id
103
+ ser_id = id.to_json_c14n
104
+ elsif id.nil?
105
+ ser_id = id = namer.get_name
106
+ end
69
107
 
70
- node = graph[id] ||= {'@id' => id}
108
+ node = graph[ser_id] ||= {'@id' => id}
71
109
 
72
- if active_subject.is_a?(Hash)
73
- # If subject is a hash, then we're processing a reverse-property relationship.
110
+ if reverse
111
+ # Note: active_subject is a Hash
112
+ # We're processing a reverse-property relationship.
74
113
  add_value(node, active_property, active_subject, property_is_array: true, allow_duplicate: false)
75
114
  elsif active_property
76
115
  reference = {'@id' => id}
@@ -81,7 +120,30 @@ module JSON::LD
81
120
  end
82
121
  end
83
122
 
84
- if element.has_key?('@type')
123
+ # For rdfstar, if node contains an `@annotation` member ...
124
+ # note: active_subject will not be nil, and may be an object itself.
125
+ # XXX: what if we're reversing an annotation?
126
+ if element.key?('@annotation')
127
+ # rdfstar being true is implicit, as it is checked in expansion
128
+ as = node_reference?(active_subject) ?
129
+ active_subject['@id'] :
130
+ active_subject
131
+ star_subject = reverse ?
132
+ {"@id" => node['@id'], active_property => [{'@id' => as}]} :
133
+ {"@id" => as, active_property => [{'@id' => node['@id']}]}
134
+
135
+ # Note that annotation is an array, make the reified subject the id of each member of that array.
136
+ annotation = element.delete('@annotation').map do |a|
137
+ a.merge('@id' => star_subject)
138
+ end
139
+
140
+ # Invoke recursively using annotation.
141
+ create_node_map(annotation, graph_map,
142
+ active_graph: active_graph,
143
+ active_subject: star_subject)
144
+ end
145
+
146
+ if element.key?('@type')
85
147
  add_value(node, '@type', element.delete('@type'), property_is_array: true, allow_duplicate: false)
86
148
  end
87
149
 
@@ -99,7 +161,8 @@ module JSON::LD
99
161
  create_node_map(value, graph_map,
100
162
  active_graph: active_graph,
101
163
  active_subject: referenced_node,
102
- active_property: property)
164
+ active_property: property,
165
+ reverse: true)
103
166
  end
104
167
  end
105
168
  end
@@ -128,7 +191,72 @@ module JSON::LD
128
191
  end
129
192
  end
130
193
 
194
+ ##
195
+ # Create annotations
196
+ #
197
+ # Updates a node map from which annotations have been folded into embedded triples to re-extract the annotations.
198
+ #
199
+ # Map entries where the key is of the form of a canonicalized JSON object are used to find keys with the `@id` and property components. If found, the original map entry is removed and entries added to an `@annotation` property of the associated value.
200
+ #
201
+ # * Keys which are of the form of a canonicalized JSON object are examined in inverse order of length.
202
+ # * Deserialize the key into a map, and re-serialize the value of `@id`.
203
+ # * If the map contains an entry with that value (after re-canonicalizing, as appropriate), and the associated antry has a item which matches the non-`@id` item from the map, the node is used to create an `@annotation` entry within that value.
204
+ #
205
+ # @param [Hash{String => Hash}] node_map
206
+ # @return [Hash{String => Hash}]
207
+ def create_annotations(node_map)
208
+ node_map.keys.
209
+ select {|k| k.start_with?('{')}.
210
+ sort_by(&:length).
211
+ reverse.each do |key|
212
+
213
+ annotation = node_map[key]
214
+ # Deserialize key, and re-serialize the `@id` value.
215
+ emb = annotation['@id'].dup
216
+ id = emb.delete('@id')
217
+ property, value = emb.to_a.first
218
+
219
+ # If id is a map, set it to the result of canonicalizing that value, otherwise to itself.
220
+ id = id.to_json_c14n if id.is_a?(Hash)
221
+
222
+ next unless node_map.key?(id)
223
+ # If node map has an entry for id and that entry contains the same property and value from entry:
224
+ node = node_map[id]
225
+
226
+ next unless node.key?(property)
227
+
228
+ node[property].each do |emb_value|
229
+ next unless emb_value == value.first
230
+
231
+ node_map.delete(key)
232
+ annotation.delete('@id')
233
+ add_value(emb_value, '@annotation', annotation, property_is_array: true) unless
234
+ annotation.empty?
235
+ end
236
+ end
237
+ end
238
+
239
+ ##
240
+ # Rename blank nodes recursively within an embedded object
241
+ #
242
+ # @param [Object] node
243
+ # @return [Hash]
244
+ def rename_bnodes(node)
245
+ case node
246
+ when Array
247
+ node.map {|n| rename_bnodes(n)}
248
+ when Hash
249
+ node.inject({}) do |memo, (k, v)|
250
+ v = namer.get_name(v) if k == '@id' && v.is_a?(String) && blank_node?(v)
251
+ memo.merge(k => rename_bnodes(v))
252
+ end
253
+ else
254
+ node
255
+ end
256
+ end
257
+
131
258
  private
259
+
132
260
  ##
133
261
  # Merge nodes from all graphs in the graph_map into a new node map
134
262
  #
@@ -57,7 +57,7 @@ module JSON::LD
57
57
  lambda: ->(files, **options) do
58
58
  out = options[:output] || $stdout
59
59
  out.set_encoding(Encoding::UTF_8) if RUBY_PLATFORM == "java"
60
- options = options.merge(expandContext: options.delete(:context)) if options.has_key?(:context)
60
+ options = options.merge(expandContext: options.delete(:context)) if options.key?(:context)
61
61
  options[:base] ||= options[:base_uri]
62
62
  if options[:format] == :jsonld
63
63
  if files.empty?
@@ -174,6 +174,13 @@ module JSON::LD
174
174
  use: :required,
175
175
  on: ["--context CONTEXT"],
176
176
  description: "Context to use when compacting.") {|arg| RDF::URI(arg)},
177
+ RDF::CLI::Option.new(
178
+ symbol: :createAnnotations,
179
+ datatype: TrueClass,
180
+ default: false,
181
+ control: :checkbox,
182
+ on: ["--[no-]create-annotations"],
183
+ description: "Unfold embedded nodes which can be represented using `@annotation`."),
177
184
  ]
178
185
  },
179
186
  frame: {
data/lib/json/ld/frame.rb CHANGED
@@ -52,7 +52,7 @@ module JSON::LD
52
52
  state[:uniqueEmbeds][state[:graph]] ||= {}
53
53
  end
54
54
 
55
- if flags[:embed] == '@link' && link.has_key?(id)
55
+ if flags[:embed] == '@link' && link.key?(id)
56
56
  # add existing linked subject
57
57
  add_frame_output(parent, property, link[id])
58
58
  next
@@ -66,7 +66,7 @@ module JSON::LD
66
66
  warn "[DEPRECATION] #{flags[:embed]} is not a valid value of @embed in 1.1 mode.\n"
67
67
  end
68
68
 
69
- if !state[:embedded] && state[:uniqueEmbeds][state[:graph]].has_key?(id)
69
+ if !state[:embedded] && state[:uniqueEmbeds][state[:graph]].key?(id)
70
70
  # Skip adding this node object to the top-level, as it was included in another node object
71
71
  next
72
72
  elsif state[:embedded] &&
@@ -76,7 +76,7 @@ module JSON::LD
76
76
  next
77
77
  elsif state[:embedded] &&
78
78
  %w(@first @once).include?(flags[:embed]) &&
79
- state[:uniqueEmbeds][state[:graph]].has_key?(id)
79
+ state[:uniqueEmbeds][state[:graph]].key?(id)
80
80
 
81
81
  # if only the first match should be embedded
82
82
  # Embed unless already embedded
@@ -97,7 +97,7 @@ module JSON::LD
97
97
  state[:subjectStack] << {subject: subject, graph: state[:graph]}
98
98
 
99
99
  # Subject is also the name of a graph
100
- if state[:graphMap].has_key?(id)
100
+ if state[:graphMap].key?(id)
101
101
  # check frame's "@graph" to see what to do next
102
102
  # 1. if it doesn't exist and state.graph === "@merged", don't recurse
103
103
  # 2. if it doesn't exist and state.graph !== "@merged", recurse
@@ -105,7 +105,7 @@ module JSON::LD
105
105
  # 4. if "@default" then don't recurse
106
106
  # 5. recurse
107
107
  recurse, subframe = false, nil
108
- if !frame.has_key?('@graph')
108
+ if !frame.key?('@graph')
109
109
  recurse, subframe = (state[:graph] != '@merged'), {}
110
110
  else
111
111
  subframe = frame['@graph'].first
@@ -134,7 +134,7 @@ module JSON::LD
134
134
  end
135
135
 
136
136
  # explicit is on and property isn't in frame, skip processing
137
- next if flags[:explicit] && !frame.has_key?(prop)
137
+ next if flags[:explicit] && !frame.key?(prop)
138
138
 
139
139
  # add objects
140
140
  objects.each do |o|
@@ -267,7 +267,7 @@ module JSON::LD
267
267
  # If, after replacement, an array contains only the value null remove the value, leaving an empty array.
268
268
  input.map {|o| cleanup_preserve(o)}
269
269
  when Hash
270
- if input.has_key?('@preserve')
270
+ if input.key?('@preserve')
271
271
  # Replace with the content of `@preserve`
272
272
  cleanup_preserve(input['@preserve'].first)
273
273
  else
@@ -388,7 +388,7 @@ module JSON::LD
388
388
  is_empty = v.empty?
389
389
  if v = v.first
390
390
  validate_frame(v)
391
- has_default = v.has_key?('@default')
391
+ has_default = v.key?('@default')
392
392
  end
393
393
 
394
394
  # No longer a wildcard pattern if frame has any non-keyword properties
@@ -40,8 +40,10 @@ module JSON::LD
40
40
 
41
41
  default_graph[name] ||= {'@id' => name} unless name == '@default'
42
42
 
43
- subject = statement.subject.to_s
44
- node = node_map[subject] ||= resource_representation(statement.subject,useNativeTypes)
43
+ subject = statement.subject.statement? ?
44
+ resource_representation(statement.subject, useNativeTypes)['@id'].to_json_c14n :
45
+ statement.subject.to_s
46
+ node = node_map[subject] ||= resource_representation(statement.subject, useNativeTypes)
45
47
 
46
48
  # If predicate is rdf:datatype, note subject in compound literal subjects map
47
49
  if @options[:rdfDirection] == 'compound-literal' && statement.predicate == RDF.to_uri + 'direction'
@@ -50,12 +52,14 @@ module JSON::LD
50
52
 
51
53
  # If object is an IRI, blank node identifier, or statement, and node map does not have an object member, create one and initialize its value to a new JSON object consisting of a single member @id whose value is set to object.
52
54
  unless statement.object.literal?
53
- node_map[statement.object.to_s] ||=
55
+ object = statement.object.statement? ?
56
+ resource_representation(statement.object, useNativeTypes)['@id'].to_json_c14n :
57
+ statement.object.to_s
58
+ node_map[object] ||=
54
59
  resource_representation(statement.object, useNativeTypes)
55
60
  end
56
61
 
57
62
  # If predicate equals rdf:type, and object is an IRI or blank node identifier, append object to the value of the @type member of node. If no such member exists, create one and initialize it to an array whose only item is object. Finally, continue to the next RDF triple.
58
- # XXX JSON-LD* does not support embedded value of @type
59
63
  if statement.predicate == RDF.type && statement.object.resource? && !useRdfType
60
64
  merge_value(node, '@type', statement.object.to_s)
61
65
  next
@@ -75,7 +79,7 @@ module JSON::LD
75
79
  property: statement.predicate.to_s,
76
80
  value: value
77
81
  })
78
- elsif referenced_once.has_key?(statement.object.to_s)
82
+ elsif referenced_once.key?(statement.object.to_s)
79
83
  referenced_once[statement.object.to_s] = false
80
84
  elsif statement.object.node?
81
85
  referenced_once[statement.object.to_s] = {
@@ -112,8 +116,7 @@ module JSON::LD
112
116
  end
113
117
  end
114
118
 
115
- # Skip to next graph, unless this one has lists
116
- next unless nil_var = graph_object[RDF.nil.to_s]
119
+ nil_var = graph_object.fetch(RDF.nil.to_s, {})
117
120
 
118
121
  # For each item usage in the usages member of nil, perform the following steps:
119
122
  nil_var.fetch(:usages, []).each do |usage|
@@ -141,12 +144,15 @@ module JSON::LD
141
144
  head['@list'] = list.reverse
142
145
  list_nodes.each {|node_id| graph_object.delete(node_id)}
143
146
  end
147
+
148
+ # Create annotations on graph object
149
+ create_annotations(graph_object)
144
150
  end
145
151
 
146
152
  result = []
147
153
  default_graph.keys.opt_sort(ordered: @options[:ordered]).each do |subject|
148
154
  node = default_graph[subject]
149
- if graph_map.has_key?(subject)
155
+ if graph_map.key?(subject)
150
156
  node['@graph'] = []
151
157
  graph_map[subject].keys.opt_sort(ordered: @options[:ordered]).each do |s|
152
158
  n = graph_map[subject][s]
@@ -136,11 +136,10 @@ module JSON::LD
136
136
  input
137
137
  else
138
138
  begin
139
- require 'nokogumbo' unless defined?(::Nokogumbo)
140
139
  input = input.read if input.respond_to?(:read)
141
- ::Nokogiri::HTML5(input.dup.force_encoding('utf-8'), max_parse_errors: 1000)
142
- rescue LoadError
143
- ::Nokogiri::HTML.parse(input, 'utf-8')
140
+ ::Nokogiri::HTML5(input.force_encoding('utf-8'), max_parse_errors: 1000)
141
+ rescue LoadError, NoMethodError
142
+ ::Nokogiri::HTML.parse(input, base_uri.to_s, 'utf-8')
144
143
  end
145
144
  end
146
145
 
@@ -68,6 +68,7 @@ module JSON::LD
68
68
  # @raise [RDF::ReaderError] if the JSON document cannot be loaded
69
69
  def initialize(input = $stdin, **options, &block)
70
70
  options[:base_uri] ||= options[:base]
71
+ options[:rename_bnodes] = false unless options.key?(:rename_bnodes)
71
72
  super do
72
73
  @options[:base] ||= base_uri.to_s if base_uri
73
74
  # Trim non-JSON stuff in script.
@@ -136,7 +136,7 @@ module JSON::LD
136
136
  when '@type'
137
137
  # Set the type-scoped context to the context on input, for use later
138
138
  raise JsonLdError::InvalidStreamingKeyOrder,
139
- "found #{key} in state #{state}" unless [:await_context, :await_type].include?(state)
139
+ "found #{key} in state #{state}" unless %i(await_context await_type).include?(state)
140
140
 
141
141
  type_scoped_context = context
142
142
  as_array(value).sort.each do |term|
@@ -159,7 +159,7 @@ module JSON::LD
159
159
  raise JsonLdError::InvalidSetOrListObject,
160
160
  "found #{key} in state #{state}" if is_list_or_set
161
161
  raise JsonLdError::CollidingKeywords,
162
- "found #{key} in state #{state}" unless [:await_context, :await_type, :await_id].include?(state)
162
+ "found #{key} in state #{state}" unless %i(await_context await_type await_id).include?(state)
163
163
 
164
164
  # Set our actual id, and use for replacing any provisional statements using our existing node_id, which is provisional
165
165
  raise JsonLdError::InvalidIdValue,
@@ -209,7 +209,7 @@ module JSON::LD
209
209
  # Expanded values must be node objects
210
210
  have_statements = false
211
211
  parse_object(value, active_property, context) do |st|
212
- have_statements ||= st.has_subject?
212
+ have_statements ||= st.subject?
213
213
  block.call(st)
214
214
  end
215
215
  raise JsonLdError::InvalidIncludedValue, "values of @included must expand to node objects" unless have_statements
@@ -232,7 +232,7 @@ module JSON::LD
232
232
  when '@list'
233
233
  raise JsonLdError::InvalidSetOrListObject,
234
234
  "found #{key} in state #{state}" if
235
- ![:await_context, :await_type, :await_id].include?(state)
235
+ !%i(await_context await_type await_id).include?(state)
236
236
  is_list_or_set = true
237
237
  if subject
238
238
  node_id = parse_list(value, active_property, context, &block)
@@ -277,7 +277,7 @@ module JSON::LD
277
277
  when '@set'
278
278
  raise JsonLdError::InvalidSetOrListObject,
279
279
  "found #{key} in state #{state}" if
280
- ![:await_context, :await_type, :await_id].include?(state)
280
+ !%i(await_context await_type await_id).include?(state)
281
281
  is_list_or_set = true
282
282
  value = as_array(value).compact
283
283
  parse_object(value, active_property, context, subject: subject, predicate: predicate, &block)
@@ -64,8 +64,8 @@ module JSON::LD
64
64
  {"@value" => MultiJson.load(statement.object.to_s), "@type" => "@json"}
65
65
  else
66
66
  lit = {"@value" => statement.object.to_s}
67
- lit["@type"] = statement.object.datatype.to_s if statement.object.has_datatype?
68
- lit["@language"] = statement.object.language.to_s if statement.object.has_language?
67
+ lit["@type"] = statement.object.datatype.to_s if statement.object.datatype?
68
+ lit["@language"] = statement.object.language.to_s if statement.object.language?
69
69
  lit
70
70
  end
71
71
  end
@@ -91,7 +91,7 @@ module JSON::LD
91
91
  def start_graph(resource)
92
92
  #log_debug("start_graph") {"state: #{@state.inspect}, resource: #{resource}"}
93
93
  if resource
94
- @output.puts(",") if [:wrote_node, :wrote_graph].include?(@state)
94
+ @output.puts(",") if %i(wrote_node wrote_graph).include?(@state)
95
95
  @output.puts %({"@id": "#{resource}", "@graph": [)
96
96
  @state = :in_graph
97
97
  end
@@ -109,7 +109,7 @@ module JSON::LD
109
109
 
110
110
  def end_node
111
111
  #log_debug("end_node") {"state: #{@state.inspect}, node: #{@current_node_def.to_json}"}
112
- @output.puts(",") if [:wrote_node, :wrote_graph].include?(@state)
112
+ @output.puts(",") if %i(wrote_node wrote_graph).include?(@state)
113
113
  if @current_node_def
114
114
  node_def = if context
115
115
  compacted = JSON::LD::API.compact(@current_node_def, context, rename_bnodes: false, **@options)
@@ -48,7 +48,7 @@ module JSON::LD
48
48
  # Only valid for rdf:JSON
49
49
  value = value.to_json_c14n
50
50
  else
51
- if item.has_key?('@direction') && @options[:rdfDirection]
51
+ if item.key?('@direction') && @options[:rdfDirection]
52
52
  # Either serialize using a datatype, or a compound-literal
53
53
  case @options[:rdfDirection]
54
54
  when 'i18n-datatype'
@@ -63,7 +63,7 @@ module JSON::LD
63
63
  end
64
64
 
65
65
  # Otherwise, if datatype is null, set it to xsd:string or xsd:langString, depending on if item has a @language key.
66
- datatype ||= item.has_key?('@language') ? RDF.langString : RDF::XSD.string
66
+ datatype ||= item.key?('@language') ? RDF.langString : RDF::XSD.string
67
67
  if datatype == RDF::URI(RDF.to_uri + "JSON")
68
68
  value = value.to_json_c14n
69
69
  end
data/lib/json/ld/utils.rb CHANGED
@@ -11,8 +11,8 @@ module JSON::LD
11
11
  # @return [Boolean]
12
12
  def node?(value)
13
13
  value.is_a?(Hash) &&
14
- !(value.has_key?('@value') || value.has_key?('@list') || value.has_key?('@set')) &&
15
- (value.length > 1 || !value.has_key?('@id'))
14
+ !(value.key?('@value') || value.key?('@list') || value.key?('@set')) &&
15
+ (value.length > 1 || !value.key?('@id'))
16
16
  end
17
17
 
18
18
  ##
@@ -29,7 +29,7 @@ module JSON::LD
29
29
  # @return [Boolean]
30
30
  def node_or_ref?(value)
31
31
  value.is_a?(Hash) &&
32
- !(value.has_key?('@value') || value.has_key?('@list') || value.has_key?('@set'))
32
+ !(value.key?('@value') || value.key?('@list') || value.key?('@set'))
33
33
  end
34
34
 
35
35
  ##
@@ -66,7 +66,7 @@ module JSON::LD
66
66
  # @param [Object] value
67
67
  # @return [Boolean]
68
68
  def simple_graph?(value)
69
- graph?(value) && !value.has_key?('@id')
69
+ graph?(value) && !value.key?('@id')
70
70
  end
71
71
 
72
72
  ##
@@ -75,7 +75,7 @@ module JSON::LD
75
75
  # @param [Object] value
76
76
  # @return [Boolean]
77
77
  def list?(value)
78
- value.is_a?(Hash) && value.has_key?('@list')
78
+ value.is_a?(Hash) && value.key?('@list')
79
79
  end
80
80
 
81
81
  ##
@@ -84,7 +84,7 @@ module JSON::LD
84
84
  # @param [Object] value
85
85
  # @return [Boolean]
86
86
  def index?(value)
87
- value.is_a?(Hash) && value.has_key?('@index')
87
+ value.is_a?(Hash) && value.key?('@index')
88
88
  end
89
89
 
90
90
  ##
@@ -93,7 +93,7 @@ module JSON::LD
93
93
  # @param [Object] value
94
94
  # @return [Boolean]
95
95
  def value?(value)
96
- value.is_a?(Hash) && value.has_key?('@value')
96
+ value.is_a?(Hash) && value.key?('@value')
97
97
  end
98
98
 
99
99
  ##
@@ -170,7 +170,7 @@ module JSON::LD
170
170
  end
171
171
  elsif subject[property]
172
172
  # check if subject already has value if duplicates not allowed
173
- _has_value = !allow_duplicate && has_value(subject, property, value)
173
+ _has_value = !allow_duplicate && has_value?(subject, property, value)
174
174
 
175
175
  # make property an array if value not present or always an array
176
176
  if !subject[property].is_a?(Array) && (!_has_value || property_is_array)
@@ -188,7 +188,7 @@ module JSON::LD
188
188
  # @param property the property to look for.
189
189
  #
190
190
  # @return [Boolean] true if the subject has the given property, false if not.
191
- def has_property(subject, property)
191
+ def property?(subject, property)
192
192
  return false unless value = subject[property]
193
193
  !value.is_a?(Array) || !value.empty?
194
194
  end
@@ -200,8 +200,8 @@ module JSON::LD
200
200
  # @param [Object] value the value to check.
201
201
  #
202
202
  # @return [Boolean] true if the value exists, false if not.
203
- def has_value(subject, property, value)
204
- if has_property(subject, property)
203
+ def has_value?(subject, property, value)
204
+ if property?(subject, property)
205
205
  val = subject[property]
206
206
  is_list = list?(val)
207
207
  if val.is_a?(Array) || is_list
@@ -265,7 +265,7 @@ module JSON::LD
265
265
  # @return [String]
266
266
  def get_sym(old = "")
267
267
  old = old.to_s.sub(/_:/, '')
268
- if old && self.has_key?(old)
268
+ if old && self.key?(old)
269
269
  self[old]
270
270
  elsif !old.empty?
271
271
  self[old] = RDF::Node.new.to_unique_base[2..-1]
@@ -289,7 +289,7 @@ module JSON::LD
289
289
  # @return [String]
290
290
  def get_sym(old = "")
291
291
  old = old.to_s.sub(/_:/, '')
292
- if !old.empty? && self.has_key?(old)
292
+ if !old.empty? && self.key?(old)
293
293
  self[old]
294
294
  elsif !old.empty?
295
295
  @num += 1
@@ -237,8 +237,8 @@ module JSON::LD
237
237
  # @yield [writer]
238
238
  # @yieldparam [RDF::Writer] writer
239
239
  def initialize(output = $stdout, **options, &block)
240
- options[:base_uri] ||= options[:base] if options.has_key?(:base)
241
- options[:base] ||= options[:base_uri] if options.has_key?(:base_uri)
240
+ options[:base_uri] ||= options[:base] if options.key?(:base)
241
+ options[:base] ||= options[:base_uri] if options.key?(:base_uri)
242
242
  super do
243
243
  @repo = RDF::Repository.new
244
244
 
data/lib/json/ld.rb CHANGED
@@ -47,6 +47,7 @@ module JSON
47
47
  DEFAULT_CONTEXT = "http://schema.org"
48
48
 
49
49
  KEYWORDS = Set.new(%w(
50
+ @annotation
50
51
  @base
51
52
  @container
52
53
  @context
@@ -116,6 +117,7 @@ module JSON
116
117
  class CollidingKeywords < JsonLdError; @code = "colliding keywords"; end
117
118
  class ConflictingIndexes < JsonLdError; @code = "conflicting indexes"; end
118
119
  class CyclicIRIMapping < JsonLdError; @code = "cyclic IRI mapping"; end
120
+ class InvalidAnnotation < JsonLdError; @code = "invalid annotation"; end
119
121
  class InvalidBaseIRI < JsonLdError; @code = "invalid base IRI"; end
120
122
  class InvalidContainerMapping < JsonLdError; @code = "invalid container mapping"; end
121
123
  class InvalidContextEntry < JsonLdError; @code = "invalid context entry"; end
@@ -137,7 +139,7 @@ module JSON
137
139
  class InvalidNestValue < JsonLdError; @code = "invalid @nest value"; end
138
140
  class InvalidPrefixValue < JsonLdError; @code = "invalid @prefix value"; end
139
141
  class InvalidPropagateValue < JsonLdError; @code = "invalid @propagate value"; end
140
- class InvalidEmbeddedNode < JsonLdError; @code = "invalid reified node"; end
142
+ class InvalidEmbeddedNode < JsonLdError; @code = "invalid embedded node"; end
141
143
  class InvalidRemoteContext < JsonLdError; @code = "invalid remote context"; end
142
144
  class InvalidReverseProperty < JsonLdError; @code = "invalid reverse property"; end
143
145
  class InvalidReversePropertyMap < JsonLdError; @code = "invalid reverse property map"; end
data/spec/api_spec.rb CHANGED
@@ -44,7 +44,7 @@ describe JSON::LD::API do
44
44
  end
45
45
 
46
46
  context "Test Files" do
47
- %w(oj json_gem ok_json yajl).map(&:to_sym).each do |adapter|
47
+ %i(oj json_gem ok_json yajl).each do |adapter|
48
48
  context "with MultiJson adapter #{adapter.inspect}" do
49
49
  Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), 'test-files/*-input.*'))) do |filename|
50
50
  test = File.basename(filename).sub(/-input\..*$/, '')