json-ld 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +1 -1
- data/VERSION +1 -1
- data/lib/json/ld.rb +7 -18
- data/lib/json/ld/format.rb +22 -4
- data/lib/json/ld/normalize.rb +120 -0
- data/lib/json/ld/reader.rb +124 -86
- data/lib/json/ld/version.rb +1 -1
- data/lib/json/ld/writer.rb +66 -57
- metadata +26 -27
data/README
CHANGED
@@ -24,7 +24,7 @@ Full documentation available on [RubyDoc](http://rubydoc.info/gems/json-ld/0.0.4
|
|
24
24
|
|
25
25
|
##Dependencies
|
26
26
|
* [Ruby](http://ruby-lang.org/) (>= 1.8.7) or (>= 1.8.1 with [Backports][])
|
27
|
-
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.
|
27
|
+
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.4)
|
28
28
|
* [JSON](https://rubygems.org/gems/json) (>= 1.5.1)
|
29
29
|
|
30
30
|
## Installation
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.8
|
data/lib/json/ld.rb
CHANGED
@@ -23,35 +23,24 @@ module JSON
|
|
23
23
|
require 'json'
|
24
24
|
require 'json/ld/extensions'
|
25
25
|
require 'json/ld/format'
|
26
|
-
autoload :
|
27
|
-
autoload :
|
28
|
-
autoload :
|
29
|
-
|
30
|
-
# Keywords
|
31
|
-
BASE = '@base'.freeze
|
32
|
-
COERCE = '@coerce'.freeze
|
33
|
-
CONTEXT = '@context'.freeze
|
34
|
-
DATATYPE = '@datatype'.freeze
|
35
|
-
IRI = '@iri'.freeze
|
36
|
-
LANGUAGE = '@language'.freeze
|
37
|
-
LITERAL = '@literal'.freeze
|
38
|
-
SUBJECT = '@subject'.freeze
|
39
|
-
TYPE = '@type'.freeze
|
40
|
-
VOCAB = '@vocab'.freeze
|
26
|
+
autoload :Normalize, 'json/ld/normalize'
|
27
|
+
autoload :Reader, 'json/ld/reader'
|
28
|
+
autoload :VERSION, 'json/ld/version'
|
29
|
+
autoload :Writer, 'json/ld/writer'
|
41
30
|
|
42
31
|
# Default context
|
43
32
|
# @see http://json-ld.org/spec/ED/20110507/#the-default-context
|
44
33
|
DEFAULT_CONTEXT = {
|
45
34
|
'@coerce' => {
|
46
|
-
|
35
|
+
'@iri' => ['@type']
|
47
36
|
}
|
48
37
|
}.freeze
|
49
38
|
|
50
39
|
# Default type coercion, in property => datatype order
|
51
40
|
DEFAULT_COERCE = {
|
52
|
-
|
41
|
+
'@type' => '@iri',
|
53
42
|
RDF.first.to_s => false, # Make sure @coerce isn't generated for this
|
54
|
-
RDF.rest.to_s =>
|
43
|
+
RDF.rest.to_s => '@iri',
|
55
44
|
}.freeze
|
56
45
|
|
57
46
|
def self.debug?; @debug; end
|
data/lib/json/ld/format.rb
CHANGED
@@ -21,13 +21,32 @@ module JSON::LD
|
|
21
21
|
#
|
22
22
|
# @see http://www.w3.org/TR/rdf-testcases/#ntriples
|
23
23
|
class Format < RDF::Format
|
24
|
-
content_type 'application/ld+json',
|
25
|
-
|
26
|
-
|
24
|
+
content_type 'application/ld+json',
|
25
|
+
:extensions => [:jsonld, :json, :ld],
|
26
|
+
:alias => 'application/x-ld+json'
|
27
27
|
content_encoding 'utf-8'
|
28
28
|
|
29
29
|
reader { JSON::LD::Reader }
|
30
30
|
writer { JSON::LD::Writer }
|
31
|
+
|
32
|
+
##
|
33
|
+
# Sample detection to see if it matches JSON-LD
|
34
|
+
#
|
35
|
+
# Use a text sample to detect the format of an input file. Sub-classes implement
|
36
|
+
# a matcher sufficient to detect probably format matches, including disambiguating
|
37
|
+
# between other similar formats.
|
38
|
+
#
|
39
|
+
# @param [String] sample Beginning several bytes (~ 1K) of input.
|
40
|
+
# @return [Boolean]
|
41
|
+
def self.detect(sample)
|
42
|
+
!!sample.match(/\{\s*"@(subject|context|type|iri)"/m)
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Override normal symbol generation
|
47
|
+
def self.to_sym
|
48
|
+
:jsonld
|
49
|
+
end
|
31
50
|
end
|
32
51
|
|
33
52
|
# Alias for JSON-LD format
|
@@ -39,7 +58,6 @@ module JSON::LD
|
|
39
58
|
# RDF::Format.for(:jsonld).reader #=> JSON::LD::Reader
|
40
59
|
# RDF::Format.for(:jsonld).writer #=> JSON::LD::Writer
|
41
60
|
class JSONLD < RDF::Format
|
42
|
-
content_type 'application/ld+json', :extension => :jsonld
|
43
61
|
content_encoding 'utf-8'
|
44
62
|
|
45
63
|
reader { JSON::LD::Reader }
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module JSON::LD
|
2
|
+
##
|
3
|
+
# Normalize Nodes in a graph. Uses [Normalization Algorithm](http://json-ld.org/spec/latest/#normalization-1)
|
4
|
+
# from [JSON-LD specification](http://json-ld.org/spec/latest/).
|
5
|
+
#
|
6
|
+
# This module takes a graph and returns a new graph, with BNode names normalized to allow
|
7
|
+
# for a canonical ordering of all statements within a graph.
|
8
|
+
#
|
9
|
+
# @example Normalize a graph
|
10
|
+
# JSON::LD::normalize(graph) => graph
|
11
|
+
#
|
12
|
+
# @see http://json-ld.org/spec/latest
|
13
|
+
# @see http://json-ld.org/spec/latest/#normalization-1
|
14
|
+
# @author [Gregg Kellogg](http://greggkellogg.net/)
|
15
|
+
class Normalize
|
16
|
+
##
|
17
|
+
# Create a new normalization instance
|
18
|
+
# @param [RDF::Enumerable] graph
|
19
|
+
def initialize(graph)
|
20
|
+
@graph = graph
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Perform normalization, and return a new graph with node identifiers normalized
|
25
|
+
# @return [RDF::Graph]
|
26
|
+
def normalize
|
27
|
+
# Create an empty list of expanded nodes and recursively process every object in the expanded input that is not an
|
28
|
+
# expanded IRI, typed literal or language literal
|
29
|
+
nodes = graph.subjects.select {|s| s.node?}
|
30
|
+
|
31
|
+
forward_mapping = {}
|
32
|
+
reverse_mapping = {}
|
33
|
+
@node_properties = {}
|
34
|
+
graph.each_statment do |st|
|
35
|
+
# Create a forward mapping that relates graph nodes to the IRIs of the targets nodes that they reference. For example,
|
36
|
+
# if a node alpha refers to a node beta via a property, the key in the forward mapping is the subject IRI of alpha and
|
37
|
+
# the value is an array containing at least the subject IRI of beta.
|
38
|
+
if st.subject.node? && st.object.uri?
|
39
|
+
forward_mapping[st.subject] ||= {}
|
40
|
+
forward_mapping[st.subject] << st.object
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create a reverse mapping that relates graph nodes to every other node that refers to them in the graph. For example,
|
44
|
+
# if a node alpha refers to a node beta via a property, the key in the reverse mapping is the subject IRI for beta and
|
45
|
+
# the value is an array containing at least the IRI for alpha.
|
46
|
+
if st.object.node? && st.subject.uri?
|
47
|
+
reverse_mapping[st.object] ||= {}
|
48
|
+
reverse_mapping[st.object] << st.subject
|
49
|
+
end
|
50
|
+
|
51
|
+
# For node comparisons, keep track of properties of each node
|
52
|
+
if st.subject.node?
|
53
|
+
@node_properties[st.subject] ||= {}
|
54
|
+
@node_properties[st.subject][st.predicate] ||= []
|
55
|
+
@node_properties[st.subject][st.predicate] << st.object
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Label every unlabeled node according to the Label Generation Algorithm in descending order using the Deep
|
60
|
+
# Comparison Algorithm to determine the sort order.
|
61
|
+
node_mapping = {}
|
62
|
+
gen = "c14n_1"
|
63
|
+
nodes.sort {|a, b| deep_comparison(a) <=> deep_comparison(b) }.each do |node|
|
64
|
+
# name with Label Generation Algorithm and create mapping from original node to new name
|
65
|
+
node_mapping[node] = RDF::Node.new(gen)
|
66
|
+
gen = gen.succ
|
67
|
+
end
|
68
|
+
|
69
|
+
# Add statements to new graph using new node names
|
70
|
+
graph = RDF::Graph.new
|
71
|
+
|
72
|
+
@graph.each_statement do |st|
|
73
|
+
if st.subject.node? || st.object.node?
|
74
|
+
st = st.dup
|
75
|
+
st.subject = node_mapping.fetch(st.subject, st.subject)
|
76
|
+
st.object = node_mapping.fetch(st.object, st.object)
|
77
|
+
end
|
78
|
+
graph << st
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return new graph
|
82
|
+
graph
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def shallow_comparison(a, b)
|
87
|
+
# 1. Compare the total number of node properties. The node with fewer properties is first.
|
88
|
+
prop_count_a = @node_properties[a].keys.length
|
89
|
+
prop_count_b = @node_properties[b].keys.length
|
90
|
+
return prop_count_a <=> prop_count_b unless prop_count_a == prop_count_b
|
91
|
+
|
92
|
+
# 2. Lexicographically sort the property IRIs for each node and compare the sorted lists. If an IRI is found to be
|
93
|
+
# lexicographically smaller, the node containing that IRI is first.
|
94
|
+
p_iri_a = @node_properties[a].keys.map(&:to_s).sort.first
|
95
|
+
p_iri_b = @node_properties[a].keys.map(&:to_s).sort.first
|
96
|
+
return p_iri_a <=> p_iri_b unless p_iri_a == p_iri_b
|
97
|
+
|
98
|
+
# 3. Compare the property values against one another:
|
99
|
+
@node_properties
|
100
|
+
alpha_list
|
101
|
+
end
|
102
|
+
|
103
|
+
def deep_comparison(a, b)
|
104
|
+
comp = shallow_comparison(a, b)
|
105
|
+
if comp == 0
|
106
|
+
end
|
107
|
+
comp
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Normalize a graph, returning a new graph with node names normalized
|
113
|
+
def normalize(graph)
|
114
|
+
norm = Normalize.new
|
115
|
+
norm.normalize
|
116
|
+
end
|
117
|
+
module_meathod :normalize
|
118
|
+
|
119
|
+
end
|
120
|
+
|
data/lib/json/ld/reader.rb
CHANGED
@@ -38,7 +38,7 @@ module JSON::LD
|
|
38
38
|
|
39
39
|
# A list of current, in-scope URI mappings.
|
40
40
|
#
|
41
|
-
# @attr [Hash{
|
41
|
+
# @attr [Hash{String => String}]
|
42
42
|
attr :mappings, true
|
43
43
|
|
44
44
|
# The default vocabulary
|
@@ -60,8 +60,15 @@ module JSON::LD
|
|
60
60
|
#
|
61
61
|
# As the value may be an array, this is maintained as a reverse mapping of `property` => `type`.
|
62
62
|
#
|
63
|
-
# @attr [Hash{
|
64
|
-
attr :coerce
|
63
|
+
# @attr [Hash{String => String}]
|
64
|
+
attr :coerce
|
65
|
+
|
66
|
+
# List coercion
|
67
|
+
#
|
68
|
+
# The @list keyword is used to specify that properties having an array value are to be treated
|
69
|
+
# as an ordered list, rather than a normal unordered list
|
70
|
+
# @attr [Array<String>]
|
71
|
+
attr :list
|
65
72
|
|
66
73
|
##
|
67
74
|
# Create new evaluation context
|
@@ -73,6 +80,7 @@ module JSON::LD
|
|
73
80
|
@mappings = {}
|
74
81
|
@vocab = nil
|
75
82
|
@coerce = {}
|
83
|
+
@list = []
|
76
84
|
yield(self) if block_given?
|
77
85
|
end
|
78
86
|
|
@@ -80,6 +88,7 @@ module JSON::LD
|
|
80
88
|
v = %w([EvaluationContext) + %w(base vocab).map {|a| "#{a}='#{self.send(a).inspect}'"}
|
81
89
|
v << "mappings[#{mappings.keys.length}]=#{mappings}"
|
82
90
|
v << "coerce[#{coerce.keys.length}]=#{coerce}"
|
91
|
+
v << "list[#{list.length}]=#{list}"
|
83
92
|
v.join(", ") + "]"
|
84
93
|
end
|
85
94
|
end
|
@@ -100,7 +109,8 @@ module JSON::LD
|
|
100
109
|
begin
|
101
110
|
@doc = JSON.load(input)
|
102
111
|
rescue JSON::ParserError => e
|
103
|
-
raise RDF::ReaderError, "Failed to parse input document: #{e.message}"
|
112
|
+
raise RDF::ReaderError, "Failed to parse input document: #{e.message}" if validate?
|
113
|
+
@doc = JSON.parse("{}")
|
104
114
|
end
|
105
115
|
|
106
116
|
if block_given?
|
@@ -119,9 +129,9 @@ module JSON::LD
|
|
119
129
|
@callback = block
|
120
130
|
|
121
131
|
# initialize the evaluation context with the appropriate base
|
122
|
-
ec = EvaluationContext.new do |
|
123
|
-
|
124
|
-
parse_context(
|
132
|
+
ec = EvaluationContext.new do |e|
|
133
|
+
e.base = @base_uri if @base_uri
|
134
|
+
parse_context(e, DEFAULT_CONTEXT)
|
125
135
|
end
|
126
136
|
|
127
137
|
traverse("", @doc, nil, nil, ec)
|
@@ -150,7 +160,7 @@ module JSON::LD
|
|
150
160
|
# @param [EvaluationContext] ec
|
151
161
|
# The active context
|
152
162
|
def traverse(path, element, subject, property, ec)
|
153
|
-
add_debug(path
|
163
|
+
add_debug(path) {"traverse: s=#{subject.inspect}, p=#{property.inspect}, e=#{ec.inspect}"}
|
154
164
|
object = nil
|
155
165
|
|
156
166
|
case element
|
@@ -161,119 +171,105 @@ module JSON::LD
|
|
161
171
|
|
162
172
|
# 2.1) If a @context keyword is found, the processor merges each key-value pair in
|
163
173
|
# the local context into the active context ...
|
164
|
-
if element[
|
174
|
+
if element['@context']
|
165
175
|
# Merge context
|
166
|
-
ec = parse_context(ec.dup, element[
|
176
|
+
ec = parse_context(ec.dup, element['@context'])
|
167
177
|
prefixes.merge!(ec.mappings) # Update parsed prefixes
|
168
178
|
end
|
169
179
|
|
170
180
|
# 2.2) Create a new associative array by mapping the keys from the current associative array ...
|
171
181
|
new_element = {}
|
172
182
|
element.each do |k, v|
|
173
|
-
k = ec.mappings[k.
|
183
|
+
k = ec.mappings[k.to_s] while ec.mappings.has_key?(k.to_s)
|
174
184
|
new_element[k] = v
|
175
185
|
end
|
176
186
|
unless element == new_element
|
177
|
-
add_debug(path
|
187
|
+
add_debug(path) {"traverse: keys after map: #{new_element.keys.inspect}"}
|
178
188
|
element = new_element
|
179
189
|
end
|
180
190
|
|
181
191
|
# Other shortcuts to allow use of this method for terminal associative arrays
|
182
|
-
if element[
|
183
|
-
# Return the IRI found from the value
|
184
|
-
object = expand_term(element[
|
192
|
+
if element['@iri'].is_a?(String)
|
193
|
+
# 2.3 Return the IRI found from the value
|
194
|
+
object = expand_term(element['@iri'], ec.base, ec)
|
185
195
|
add_triple(path, subject, property, object) if subject && property
|
186
196
|
return
|
187
|
-
elsif element[
|
197
|
+
elsif element['@literal']
|
198
|
+
# 2.4
|
188
199
|
literal_opts = {}
|
189
|
-
literal_opts[:datatype] = expand_term(element[
|
190
|
-
literal_opts[:language] = element[
|
191
|
-
object = RDF::Literal.new(element[
|
200
|
+
literal_opts[:datatype] = expand_term(element['@datatype'], ec.vocab.to_s, ec) if element['@datatype']
|
201
|
+
literal_opts[:language] = element['@language'].to_sym if element['@language']
|
202
|
+
object = RDF::Literal.new(element['@literal'], literal_opts)
|
192
203
|
add_triple(path, subject, property, object) if subject && property
|
193
204
|
return
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
205
|
+
elsif element['@list']
|
206
|
+
# 2.4a (Lists)
|
207
|
+
parse_list("#{path}[#{'@list'}]", element['@list'], subject, property, ec)
|
208
|
+
return
|
209
|
+
elsif element['@subject'].is_a?(String)
|
210
|
+
# 2.5 Subject
|
211
|
+
# 2.5.1 Set active object (subject)
|
212
|
+
active_subject = expand_term(element['@subject'], ec.base, ec)
|
213
|
+
elsif element['@subject']
|
214
|
+
# 2.5.2 Recursively process hash or Array values
|
215
|
+
traverse("#{path}[#{'@subject'}]", element['@subject'], subject, property, ec)
|
204
216
|
else
|
205
|
-
# 2.
|
206
|
-
# was not discovered, then:
|
207
|
-
# 2.3.7.1) Generate a blank node identifier and set it as the active subject.
|
217
|
+
# 2.6) Generate a blank node identifier and set it as the active subject.
|
208
218
|
active_subject = RDF::Node.new
|
209
219
|
end
|
210
|
-
|
211
|
-
# 2.3.1.1) If the inherited subject and inherited property values are
|
212
|
-
# specified, generate a triple using the inherited subject for the
|
213
|
-
# subject, the inherited property for the property, and the active
|
214
|
-
# subject for the object.
|
215
|
-
# 2.3.7.2) Complete any previously incomplete triples by running all substeps of Step 2.2.1.
|
220
|
+
|
216
221
|
add_triple(path, subject, property, active_subject) if subject && property
|
217
222
|
subject = active_subject
|
218
223
|
|
219
224
|
element.each do |key, value|
|
220
|
-
# 2.
|
225
|
+
# 2.7) If a key that is not @context, @subject, or @type, set the active property by
|
221
226
|
# performing Property Processing on the key.
|
222
227
|
property = case key
|
223
|
-
when
|
224
|
-
when /^@/ then
|
228
|
+
when '@type' then '@type'
|
229
|
+
when /^@/ then next
|
225
230
|
else expand_term(key, ec.vocab, ec)
|
226
231
|
end
|
227
232
|
|
228
|
-
|
233
|
+
# 2.7.3
|
234
|
+
if ec.list.include?(property.to_s) && value.is_a?(Array)
|
235
|
+
# 2.7.3.1 (Lists) If the active property is the target of a @list coercion, and the value is an array,
|
236
|
+
# process the value as a list starting at Step 3a.
|
237
|
+
parse_list("#{path}[#{key}]", value, subject, property, ec)
|
238
|
+
else
|
239
|
+
traverse("#{path}[#{key}]", value, subject, property, ec)
|
240
|
+
end
|
229
241
|
end
|
230
242
|
when Array
|
231
243
|
# 3) If a regular array is detected, process each value in the array by doing the following:
|
232
244
|
element.each_with_index do |v, i|
|
233
|
-
|
234
|
-
when Hash, String
|
235
|
-
traverse("#{path}[#{i}]", v, subject, property, ec)
|
236
|
-
when Array
|
237
|
-
# 3.3) If the value is a regular array, should we support RDF List/Sequence Processing?
|
238
|
-
last = v.pop
|
239
|
-
first_bnode = last ? RDF::Node.new : RDF.nil
|
240
|
-
add_triple("#{path}[#{i}][]", subject, property, first_bnode)
|
241
|
-
|
242
|
-
v.each do |list_item|
|
243
|
-
traverse("#{path}[#{i}][]", list_item, first_bnode, RDF.first, ec)
|
244
|
-
rest_bnode = RDF::Node.new
|
245
|
-
add_triple("#{path}[#{i}][]", first_bnode, RDF.rest, rest_bnode)
|
246
|
-
first_bnode = rest_bnode
|
247
|
-
end
|
248
|
-
if last
|
249
|
-
traverse("#{path}[#{i}][]", last, first_bnode, RDF.first, ec)
|
250
|
-
add_triple("#{path}[#{i}][]", first_bnode, RDF.rest, RDF.nil)
|
251
|
-
end
|
252
|
-
end
|
245
|
+
traverse("#{path}[#{i}]", v, subject, property, ec)
|
253
246
|
end
|
254
247
|
when String
|
255
248
|
# Perform coersion of the value, or generate a literal
|
256
|
-
add_debug(path
|
257
|
-
|
249
|
+
add_debug(path) do
|
250
|
+
"traverse(#{element}): coerce?(#{property.inspect}) == #{ec.coerce[property.to_s].inspect}, " +
|
251
|
+
"ec=#{ec.coerce.inspect}"
|
252
|
+
end
|
253
|
+
object = if ec.coerce[property.to_s] == '@iri'
|
258
254
|
expand_term(element, ec.base, ec)
|
259
255
|
elsif ec.coerce[property.to_s]
|
260
256
|
RDF::Literal.new(element, :datatype => ec.coerce[property.to_s])
|
261
257
|
else
|
262
258
|
RDF::Literal.new(element)
|
263
259
|
end
|
264
|
-
property = RDF.type if property ==
|
260
|
+
property = RDF.type if property == '@type'
|
265
261
|
add_triple(path, subject, property, object) if subject && property
|
266
262
|
when Float
|
267
263
|
object = RDF::Literal::Double.new(element)
|
268
|
-
add_debug(path
|
264
|
+
add_debug(path) {"traverse(#{element}): native: #{object.inspect}"}
|
269
265
|
add_triple(path, subject, property, object) if subject && property
|
270
266
|
when Fixnum
|
271
267
|
object = RDF::Literal.new(element)
|
272
|
-
add_debug(path
|
268
|
+
add_debug(path) {"traverse(#{element}): native: #{object.inspect}"}
|
273
269
|
add_triple(path, subject, property, object) if subject && property
|
274
270
|
when TrueClass, FalseClass
|
275
271
|
object = RDF::Literal::Boolean.new(element)
|
276
|
-
add_debug(path
|
272
|
+
add_debug(path) {"traverse(#{element}): native: #{object.inspect}"}
|
277
273
|
add_triple(path, subject, property, object) if subject && property
|
278
274
|
else
|
279
275
|
raise RDF::ReaderError, "Traverse to unknown element: #{element.inspect} of type #{element.class}"
|
@@ -291,7 +287,7 @@ module JSON::LD
|
|
291
287
|
# @raise [ReaderError] Checks parameter types and raises if they are incorrect if parsing mode is _validate_.
|
292
288
|
def add_triple(path, subject, predicate, object)
|
293
289
|
statement = RDF::Statement.new(subject, predicate, object)
|
294
|
-
add_debug(path
|
290
|
+
add_debug(path) {"statement: #{statement.to_ntriples}"}
|
295
291
|
@callback.call(statement)
|
296
292
|
end
|
297
293
|
|
@@ -299,8 +295,11 @@ module JSON::LD
|
|
299
295
|
# Add debug event to debug array, if specified
|
300
296
|
#
|
301
297
|
# @param [XML Node, any] node:: XML Node or string for showing context
|
302
|
-
# @param [String] message
|
303
|
-
|
298
|
+
# @param [String] message
|
299
|
+
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
300
|
+
def add_debug(node, message = "")
|
301
|
+
return unless ::JSON::LD.debug? || @options[:debug]
|
302
|
+
message = message + yield if block_given?
|
304
303
|
puts "#{node}: #{message}" if JSON::LD::debug?
|
305
304
|
@options[:debug] << "#{node}: #{message}" if @options[:debug].is_a?(Array)
|
306
305
|
end
|
@@ -323,39 +322,77 @@ module JSON::LD
|
|
323
322
|
end
|
324
323
|
|
325
324
|
context.each do |key, value|
|
326
|
-
add_debug("parse_context(#{key})"
|
325
|
+
add_debug("parse_context(#{key})") {value.inspect}
|
327
326
|
case key
|
328
|
-
when
|
329
|
-
when
|
330
|
-
when
|
327
|
+
when '@vocab' then ec.vocab = value
|
328
|
+
when '@base' then ec.base = uri(value)
|
329
|
+
when '@coerce'
|
331
330
|
# Process after prefix mapping
|
332
331
|
else
|
333
332
|
# Spec confusion: The text indicates to merge each key-value pair into the active context. Is any
|
334
333
|
# processing performed on the values. For instance, could a value be a CURIE, or {"@iri": <value>}?
|
335
334
|
# Examples indicate that there is no such processing, and each value should be an absolute IRI. The
|
336
335
|
# wording makes this unclear.
|
337
|
-
ec.mappings[key.
|
336
|
+
ec.mappings[key.to_s] = value
|
338
337
|
end
|
339
338
|
end
|
340
339
|
|
341
|
-
if context[
|
340
|
+
if context['@coerce']
|
342
341
|
# Spec confusion: doc says to merge each key-value mapping to the local context's @coerce mapping,
|
343
342
|
# overwriting duplicate values. In the case where a mapping is indicated to a list of properties
|
344
343
|
# (e.g., { "@iri": ["foaf:homepage", "foaf:member"] }, does this overwrite a previous mapping
|
345
344
|
# of { "@iri": "foaf:knows" }, or add to it.
|
346
|
-
add_error RDF::ReaderError, "Expected @coerce to reference an associative array" unless context[
|
347
|
-
context[
|
345
|
+
add_error RDF::ReaderError, "Expected @coerce to reference an associative array" unless context['@coerce'].is_a?(Hash)
|
346
|
+
context['@coerce'].each do |type, property|
|
347
|
+
add_debug("parse_context: @coerce") {"type=#{type}, prop=#{property}"}
|
348
348
|
type_uri = expand_term(type, ec.vocab, ec).to_s
|
349
349
|
[property].flatten.compact.each do |prop|
|
350
350
|
p = expand_term(prop, ec.vocab, ec).to_s
|
351
|
-
|
351
|
+
if type == '@list'
|
352
|
+
# List is managed separate from types, as it is maintained in normal form.
|
353
|
+
ec.list << p unless ec.list.include?(p)
|
354
|
+
else
|
355
|
+
ec.coerce[p] = type_uri
|
356
|
+
end
|
352
357
|
end
|
353
358
|
end
|
354
359
|
end
|
355
360
|
|
356
361
|
ec
|
357
362
|
end
|
358
|
-
|
363
|
+
|
364
|
+
##
|
365
|
+
# Parse a List
|
366
|
+
#
|
367
|
+
# @param [String] path
|
368
|
+
# location within JSON hash
|
369
|
+
# @param [Array] list
|
370
|
+
# The Array to serialize as a list
|
371
|
+
# @param [RDF::URI] subject
|
372
|
+
# Inherited subject
|
373
|
+
# @param [RDF::URI] property
|
374
|
+
# Inherited property
|
375
|
+
# @param [EvaluationContext] ec
|
376
|
+
# The active context
|
377
|
+
def parse_list(path, list, subject, property, ec)
|
378
|
+
add_debug(path) {"list: #{list.inspect}, s=#{subject.inspect}, p=#{property.inspect}, e=#{ec.inspect}"}
|
379
|
+
|
380
|
+
last = list.pop
|
381
|
+
first_bnode = last ? RDF::Node.new : RDF.nil
|
382
|
+
add_triple("#{path}", subject, property, first_bnode)
|
383
|
+
|
384
|
+
list.each do |list_item|
|
385
|
+
traverse("#{path}", list_item, first_bnode, RDF.first, ec)
|
386
|
+
rest_bnode = RDF::Node.new
|
387
|
+
add_triple("#{path}", first_bnode, RDF.rest, rest_bnode)
|
388
|
+
first_bnode = rest_bnode
|
389
|
+
end
|
390
|
+
if last
|
391
|
+
traverse("#{path}", last, first_bnode, RDF.first, ec)
|
392
|
+
add_triple("#{path}", first_bnode, RDF.rest, RDF.nil)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
359
396
|
##
|
360
397
|
# Expand a term using the specified context
|
361
398
|
#
|
@@ -367,11 +404,9 @@ module JSON::LD
|
|
367
404
|
# @raise [RDF::ReaderError] if the term cannot be expanded
|
368
405
|
# @see http://json-ld.org/spec/ED/20110507/#markup-of-rdf-concepts
|
369
406
|
def expand_term(term, base, ec)
|
370
|
-
#add_debug("expand_term", "term=#{term.inspect}, base=#{base.inspect}, ec=#{ec.inspect}"
|
407
|
+
#add_debug("expand_term", {"term=#{term.inspect}, base=#{base.inspect}, ec=#{ec.inspect}"}
|
371
408
|
prefix, suffix = term.split(":", 2)
|
372
|
-
|
373
|
-
return if prefix == '_'
|
374
|
-
if prefix == :_
|
409
|
+
if prefix == '_'
|
375
410
|
bnode(suffix)
|
376
411
|
elsif ec.mappings.has_key?(prefix)
|
377
412
|
uri(ec.mappings[prefix] + suffix.to_s)
|
@@ -392,9 +427,12 @@ module JSON::LD
|
|
392
427
|
end
|
393
428
|
|
394
429
|
# Keep track of allocated BNodes
|
430
|
+
#
|
431
|
+
# Don't actually use the name provided, to prevent name alias issues.
|
432
|
+
# @return [RDF::Node]
|
395
433
|
def bnode(value = nil)
|
396
434
|
@bnode_cache ||= {}
|
397
|
-
@bnode_cache[value.to_s] ||= RDF::Node.new
|
435
|
+
@bnode_cache[value.to_s] ||= RDF::Node.new
|
398
436
|
end
|
399
437
|
end
|
400
438
|
end
|
data/lib/json/ld/version.rb
CHANGED
data/lib/json/ld/writer.rb
CHANGED
@@ -7,7 +7,7 @@ module JSON::LD
|
|
7
7
|
# and then serialize the graph.
|
8
8
|
#
|
9
9
|
# @example Obtaining a JSON-LD writer class
|
10
|
-
# RDF::Writer.for(:jsonld) #=>
|
10
|
+
# RDF::Writer.for(:jsonld) #=> JSON::LD::Writer
|
11
11
|
# RDF::Writer.for("etc/test.json")
|
12
12
|
# RDF::Writer.for(:file_name => "etc/test.json")
|
13
13
|
# RDF::Writer.for(:file_extension => "json")
|
@@ -47,7 +47,7 @@ module JSON::LD
|
|
47
47
|
# end
|
48
48
|
# end
|
49
49
|
#
|
50
|
-
# Select the :
|
50
|
+
# Select the :normalize option to output JSON-LD in canonical form
|
51
51
|
#
|
52
52
|
# @see http://json-ld.org/spec/ED/20110507/
|
53
53
|
# @see http://json-ld.org/spec/ED/20110507/#the-normalization-algorithm
|
@@ -69,6 +69,10 @@ module JSON::LD
|
|
69
69
|
# @attr [Hash{String => String}]
|
70
70
|
attr :coerce, true
|
71
71
|
|
72
|
+
##
|
73
|
+
# Local implementation of ruby Hash class to allow for ordering in 1.8.x implementations.
|
74
|
+
#
|
75
|
+
# @return [Hash, InsertOrderPreservingHash]
|
72
76
|
def self.new_hash
|
73
77
|
if RUBY_VERSION < "1.9"
|
74
78
|
InsertOrderPreservingHash.new
|
@@ -99,6 +103,8 @@ module JSON::LD
|
|
99
103
|
# the encoding to use on the output stream (Ruby 1.9+)
|
100
104
|
# @option options [Boolean] :canonicalize (false)
|
101
105
|
# whether to canonicalize literals when serializing
|
106
|
+
# @option options [Boolean] :normalize (false)
|
107
|
+
# Output document in [normalized form](http://json-ld.org/spec/latest/#normalization-1)
|
102
108
|
# @option options [Hash] :prefixes (Hash.new)
|
103
109
|
# the prefix mappings to use (not supported by all writers)
|
104
110
|
# @option options [#to_s] :base_uri (nil)
|
@@ -115,7 +121,7 @@ module JSON::LD
|
|
115
121
|
def initialize(output = $stdout, options = {}, &block)
|
116
122
|
super do
|
117
123
|
@graph = RDF::Graph.new
|
118
|
-
@iri_to_prefix = DEFAULT_CONTEXT.dup.delete_if {|k,v| k ==
|
124
|
+
@iri_to_prefix = DEFAULT_CONTEXT.dup.delete_if {|k,v| k == '@coerce'}.invert
|
119
125
|
@coerce = DEFAULT_COERCE.merge(options[:coerce] || {})
|
120
126
|
if block_given?
|
121
127
|
case block.arity
|
@@ -132,7 +138,7 @@ module JSON::LD
|
|
132
138
|
# @param [Graph] graph
|
133
139
|
# @return [void]
|
134
140
|
def write_graph(graph)
|
135
|
-
add_debug "Add graph #{graph.inspect}"
|
141
|
+
add_debug {"Add graph #{graph.inspect}"}
|
136
142
|
@graph = graph
|
137
143
|
end
|
138
144
|
|
@@ -162,18 +168,18 @@ module JSON::LD
|
|
162
168
|
# @return [void]
|
163
169
|
# @see #write_triple
|
164
170
|
def write_epilogue
|
165
|
-
@base_uri = RDF::URI(@options[:base_uri]) if @options[:base_uri] && !@options[:
|
166
|
-
@vocab = @options[:vocab] unless @options[:
|
171
|
+
@base_uri = RDF::URI(@options[:base_uri]) if @options[:base_uri] && !@options[:normalize]
|
172
|
+
@vocab = @options[:vocab] unless @options[:normalize]
|
167
173
|
@debug = @options[:debug]
|
168
174
|
|
169
175
|
reset
|
170
176
|
|
171
|
-
add_debug "\nserialize: graph: #{@graph.size}"
|
177
|
+
add_debug {"\nserialize: graph: #{@graph.size}"}
|
172
178
|
|
173
179
|
preprocess
|
174
180
|
|
175
181
|
# Don't generate context for canonical output
|
176
|
-
json_hash = @options[:
|
182
|
+
json_hash = @options[:normalize] ? new_hash : start_document
|
177
183
|
|
178
184
|
elements = []
|
179
185
|
order_subjects.each do |subject|
|
@@ -187,13 +193,13 @@ module JSON::LD
|
|
187
193
|
if elements.length == 1 && elements.first.is_a?(Hash)
|
188
194
|
json_hash.merge!(elements.first)
|
189
195
|
else
|
190
|
-
json_hash[
|
196
|
+
json_hash['@subject'] = elements
|
191
197
|
end
|
192
198
|
|
193
199
|
if @output.is_a?(Hash)
|
194
200
|
@output.merge!(json_hash)
|
195
201
|
else
|
196
|
-
json_state = if @options[:
|
202
|
+
json_state = if @options[:normalize]
|
197
203
|
JSON::State.new(
|
198
204
|
:indent => "",
|
199
205
|
:space => "",
|
@@ -235,17 +241,17 @@ module JSON::LD
|
|
235
241
|
short == value.to_s ? (get_curie(value) || value.to_s) : short
|
236
242
|
when :predicate
|
237
243
|
# attempt vocab replacement
|
238
|
-
short =
|
244
|
+
short = '@type' if value == RDF.type
|
239
245
|
short ||= value.to_s.sub(@vocab.to_s, "")
|
240
246
|
short == value.to_s ? (get_curie(value) || value.to_s) : short
|
241
247
|
else
|
242
248
|
# Encode like a subject
|
243
249
|
iri_range?(options[:property]) ?
|
244
250
|
format_uri(value, :position => :subject) :
|
245
|
-
{
|
251
|
+
{'@iri' => format_uri(value, :position => :subject)}
|
246
252
|
end
|
247
253
|
|
248
|
-
add_debug
|
254
|
+
add_debug {"format_uri(#{options.inspect}, #{value.inspect}) => #{result.inspect}"}
|
249
255
|
result
|
250
256
|
end
|
251
257
|
|
@@ -268,11 +274,11 @@ module JSON::LD
|
|
268
274
|
# Property referencing literal for type coercion
|
269
275
|
# @return [Object]
|
270
276
|
def format_literal(literal, options = {})
|
271
|
-
if options[:
|
277
|
+
if options[:normal] || @options[:normalize]
|
272
278
|
ret = new_hash
|
273
|
-
ret[
|
274
|
-
ret[
|
275
|
-
ret[
|
279
|
+
ret['@literal'] = literal.value
|
280
|
+
ret['@datatype'] = format_uri(literal.datatype, :position => :subject) if literal.has_datatype?
|
281
|
+
ret['@language'] = literal.language.to_s if literal.has_language?
|
276
282
|
return ret.delete_if {|k,v| v.nil?}
|
277
283
|
end
|
278
284
|
|
@@ -284,7 +290,7 @@ module JSON::LD
|
|
284
290
|
# Datatype coercion where literal has the same datatype
|
285
291
|
literal.value
|
286
292
|
else
|
287
|
-
format_literal(literal, :
|
293
|
+
format_literal(literal, :normal => true)
|
288
294
|
end
|
289
295
|
end
|
290
296
|
end
|
@@ -295,12 +301,12 @@ module JSON::LD
|
|
295
301
|
# @param [Hash{Symbol => Object}] options
|
296
302
|
# @option options [RDF::URI] property
|
297
303
|
# Property referencing literal for type coercion
|
298
|
-
# @return [Array<
|
304
|
+
# @return [Hash{"@list" => Array<Object>}]
|
299
305
|
def format_list(object, options = {})
|
300
306
|
predicate = options[:property]
|
301
307
|
list = []
|
302
308
|
|
303
|
-
add_debug "format_list(#{object}, #{predicate})"
|
309
|
+
add_debug {"format_list(#{object}, #{predicate})"}
|
304
310
|
|
305
311
|
@depth += 1
|
306
312
|
while object do
|
@@ -308,7 +314,7 @@ module JSON::LD
|
|
308
314
|
p = @graph.properties(object)
|
309
315
|
item = p.fetch(RDF.first.to_s, []).first
|
310
316
|
if item
|
311
|
-
add_debug "format_list serialize #{item.inspect}"
|
317
|
+
add_debug {"format_list serialize #{item.inspect}"}
|
312
318
|
list << if predicate || item.literal?
|
313
319
|
property(predicate, item)
|
314
320
|
else
|
@@ -320,8 +326,8 @@ module JSON::LD
|
|
320
326
|
@depth -= 1
|
321
327
|
|
322
328
|
# Returns
|
323
|
-
add_debug "format_list => #{
|
324
|
-
|
329
|
+
add_debug {"format_list => #{{'@list' => list}.inspect}"}
|
330
|
+
{'@list' => list}
|
325
331
|
end
|
326
332
|
|
327
333
|
private
|
@@ -330,26 +336,26 @@ module JSON::LD
|
|
330
336
|
# @return [Hash]
|
331
337
|
def start_document
|
332
338
|
ctx = new_hash
|
333
|
-
ctx[
|
334
|
-
ctx[
|
339
|
+
ctx['@base'] = base_uri.to_s if base_uri
|
340
|
+
ctx['@vocab'] = vocab.to_s if vocab
|
335
341
|
|
336
342
|
# Prefixes
|
337
343
|
prefixes.keys.sort {|a,b| a.to_s <=> b.to_s}.each do |k|
|
338
344
|
next if DEFAULT_CONTEXT.has_key?(k.to_s)
|
339
|
-
add_debug "prefix[#{k}] => #{prefixes[k]}"
|
345
|
+
add_debug {"prefix[#{k}] => #{prefixes[k]}"}
|
340
346
|
ctx[k.to_s] = prefixes[k].to_s
|
341
347
|
end
|
342
348
|
|
343
349
|
# Coerce
|
344
|
-
add_debug "start_doc: coerce= #{coerce.inspect}"
|
350
|
+
add_debug {"start_doc: coerce= #{coerce.inspect}"}
|
345
351
|
unless coerce == DEFAULT_COERCE
|
346
352
|
c_h = new_hash
|
347
353
|
coerce.keys.sort.each do |k|
|
348
|
-
next if [
|
354
|
+
next if ['@type', RDF.type.to_s].include?(k.to_s)
|
349
355
|
next if [DEFAULT_COERCE[k], false, RDF::XSD.integer.to_s, RDF::XSD.boolean.to_s].include?(coerce[k])
|
350
|
-
k_iri = k ==
|
356
|
+
k_iri = k == '@iri' ? '@iri' : format_uri(k, :position => :predicate)
|
351
357
|
d_iri = format_uri(coerce[k], :position => :subject)
|
352
|
-
add_debug "coerce[#{k_iri}] => #{d_iri}, k=#{k.inspect}"
|
358
|
+
add_debug {"coerce[#{k_iri}] => #{d_iri}, k=#{k.inspect}"}
|
353
359
|
case c_h[d_iri]
|
354
360
|
when nil
|
355
361
|
c_h[d_iri] = k_iri
|
@@ -360,14 +366,14 @@ module JSON::LD
|
|
360
366
|
end
|
361
367
|
end
|
362
368
|
|
363
|
-
ctx[
|
369
|
+
ctx['@coerce'] = c_h unless c_h.empty?
|
364
370
|
end
|
365
371
|
|
366
|
-
add_debug "start_doc: context=#{ctx.inspect}"
|
372
|
+
add_debug {"start_doc: context=#{ctx.inspect}"}
|
367
373
|
|
368
374
|
# Return hash with @context, or empty
|
369
375
|
r = new_hash
|
370
|
-
r[
|
376
|
+
r['@context'] = ctx unless ctx.empty?
|
371
377
|
r
|
372
378
|
end
|
373
379
|
|
@@ -386,7 +392,7 @@ module JSON::LD
|
|
386
392
|
# prefixes.
|
387
393
|
# @param [Statement] statement
|
388
394
|
def preprocess_statement(statement)
|
389
|
-
add_debug "preprocess: #{statement.inspect}"
|
395
|
+
add_debug {"preprocess: #{statement.inspect}"}
|
390
396
|
references = ref_count(statement.object) + 1
|
391
397
|
@references[statement.object] = references
|
392
398
|
@subjects[statement.subject] = true
|
@@ -414,35 +420,35 @@ module JSON::LD
|
|
414
420
|
|
415
421
|
subject_done(subject)
|
416
422
|
properties = @graph.properties(subject)
|
417
|
-
add_debug "subject: #{subject.inspect}, props: #{properties.inspect}"
|
423
|
+
add_debug {"subject: #{subject.inspect}, props: #{properties.inspect}"}
|
418
424
|
|
419
425
|
@graph.query(:subject => subject).each do |st|
|
420
426
|
raise RDF::WriterError, "Illegal use of predicate #{st.predicate.inspect}, not supported in RDF/XML" unless st.predicate.uri?
|
421
427
|
end
|
422
428
|
|
423
|
-
if subject.node? && ref_count(subject) > (options[:property] ? 1 : 0) && options[:
|
429
|
+
if subject.node? && ref_count(subject) > (options[:property] ? 1 : 0) && options[:normalize]
|
424
430
|
raise RDF::WriterError, "Can't serialize named node when normalizing"
|
425
431
|
end
|
426
432
|
|
427
433
|
# Subject may be a list
|
428
434
|
if is_valid_list?(subject)
|
429
435
|
add_debug "subject is a list"
|
430
|
-
defn[
|
436
|
+
defn['@subject'] = format_list(subject)
|
431
437
|
properties.delete(RDF.first.to_s)
|
432
438
|
properties.delete(RDF.rest.to_s)
|
433
439
|
|
434
440
|
# Special case, if there are no properties, then we can just serialize the list itself
|
435
|
-
return defn
|
441
|
+
return defn if properties.empty?
|
436
442
|
elsif subject.uri? || ref_count(subject) > 1
|
437
443
|
add_debug "subject is a uri"
|
438
444
|
# Don't need to set subject if it's a Node without references
|
439
|
-
defn[
|
445
|
+
defn['@subject'] = format_uri(subject, :position => :subject)
|
440
446
|
else
|
441
447
|
add_debug "subject is an unreferenced BNode"
|
442
448
|
end
|
443
449
|
|
444
450
|
prop_list = order_properties(properties)
|
445
|
-
#add_debug "=> property order: #{prop_list.to_sentence}"
|
451
|
+
#add_debug {"=> property order: #{prop_list.to_sentence}"}
|
446
452
|
|
447
453
|
prop_list.each do |prop|
|
448
454
|
predicate = RDF::URI.intern(prop)
|
@@ -450,11 +456,11 @@ module JSON::LD
|
|
450
456
|
p_iri = format_uri(predicate, :position => :predicate)
|
451
457
|
@depth += 1
|
452
458
|
defn[p_iri] = property(predicate, properties[prop])
|
453
|
-
add_debug "prop(#{p_iri}) => #{properties[prop]} => #{defn[p_iri].inspect}"
|
459
|
+
add_debug {"prop(#{p_iri}) => #{properties[prop]} => #{defn[p_iri].inspect}"}
|
454
460
|
@depth -= 1
|
455
461
|
end
|
456
462
|
|
457
|
-
add_debug "subject: #{subject} has defn: #{defn.inspect}"
|
463
|
+
add_debug {"subject: #{subject} has defn: #{defn.inspect}"}
|
458
464
|
defn
|
459
465
|
end
|
460
466
|
|
@@ -490,7 +496,7 @@ module JSON::LD
|
|
490
496
|
# @param [RDF::Resource] resource
|
491
497
|
# @return [String, nil] value to use to identify IRI
|
492
498
|
def get_curie(resource)
|
493
|
-
add_debug "get_curie(#{resource.inspect})"
|
499
|
+
add_debug {"get_curie(#{resource.inspect})"}
|
494
500
|
case resource
|
495
501
|
when RDF::Node
|
496
502
|
return resource.to_s
|
@@ -500,7 +506,7 @@ module JSON::LD
|
|
500
506
|
return nil unless resource.absolute?
|
501
507
|
when RDF::URI
|
502
508
|
iri = resource.to_s
|
503
|
-
return iri if options[:
|
509
|
+
return iri if options[:normalize]
|
504
510
|
else
|
505
511
|
return nil
|
506
512
|
end
|
@@ -555,7 +561,7 @@ module JSON::LD
|
|
555
561
|
|
556
562
|
return @subjects.keys.sort do |a,b|
|
557
563
|
format_iri(a, :position => :subject) <=> format_iri(b, :position => :subject)
|
558
|
-
end if @options[:
|
564
|
+
end if @options[:normalize]
|
559
565
|
|
560
566
|
# Start with base_uri
|
561
567
|
if base_uri && @subjects.keys.include?(base_uri)
|
@@ -583,16 +589,16 @@ module JSON::LD
|
|
583
589
|
# @param [RDF::URI] predicate
|
584
590
|
# @return [Boolean]
|
585
591
|
def iri_range?(predicate)
|
586
|
-
return false if predicate.nil? || @options[:
|
592
|
+
return false if predicate.nil? || @options[:normalize]
|
587
593
|
|
588
594
|
unless coerce.has_key?(predicate.to_s)
|
589
595
|
# objects of all statements with the predicate may not be literal
|
590
596
|
coerce[predicate.to_s] = @graph.query(:predicate => predicate).to_a.any? {|st| st.object.literal?} ?
|
591
|
-
false :
|
597
|
+
false : '@iri'
|
592
598
|
end
|
593
599
|
|
594
|
-
add_debug "iri_range(#{predicate}) = #{coerce[predicate.to_s].inspect}"
|
595
|
-
coerce[predicate.to_s] ==
|
600
|
+
add_debug {"iri_range(#{predicate}) = #{coerce[predicate.to_s].inspect}"}
|
601
|
+
coerce[predicate.to_s] == '@iri'
|
596
602
|
end
|
597
603
|
|
598
604
|
##
|
@@ -612,7 +618,7 @@ module JSON::LD
|
|
612
618
|
dt = false
|
613
619
|
end
|
614
620
|
end
|
615
|
-
add_debug "range(#{predicate}) = #{dt.inspect}"
|
621
|
+
add_debug {"range(#{predicate}) = #{dt.inspect}"}
|
616
622
|
coerce[predicate.to_s] = dt
|
617
623
|
end
|
618
624
|
|
@@ -630,8 +636,11 @@ module JSON::LD
|
|
630
636
|
|
631
637
|
# Add debug event to debug array, if specified
|
632
638
|
#
|
633
|
-
# @param [String] message
|
634
|
-
|
639
|
+
# @param [String] message
|
640
|
+
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
641
|
+
def add_debug(message = "")
|
642
|
+
return unless ::JSON::LD.debug? || @options[:debug]
|
643
|
+
message = message + yield if block_given?
|
635
644
|
msg = "#{" " * @depth * 2}#{message}"
|
636
645
|
STDERR.puts msg if ::JSON::LD::debug?
|
637
646
|
@debug << msg if @debug.is_a?(Array)
|
@@ -641,26 +650,26 @@ module JSON::LD
|
|
641
650
|
def is_valid_list?(l)
|
642
651
|
props = @graph.properties(l)
|
643
652
|
unless l.node? && props.has_key?(RDF.first.to_s) || l == RDF.nil
|
644
|
-
add_debug "is_valid_list: false, #{l.inspect}: #{props.inspect}"
|
653
|
+
add_debug {"is_valid_list: false, #{l.inspect}: #{props.inspect}"}
|
645
654
|
return false
|
646
655
|
end
|
647
656
|
|
648
657
|
while l && l != RDF.nil do
|
649
|
-
#add_debug "is_valid_list(length): #{props.length}"
|
658
|
+
#add_debug {"is_valid_list(length): #{props.length}"}
|
650
659
|
return false unless props.has_key?(RDF.first.to_s) && props.has_key?(RDF.rest.to_s)
|
651
660
|
n = props[RDF.rest.to_s]
|
652
661
|
unless n.is_a?(Array) && n.length == 1
|
653
|
-
add_debug "is_valid_list: false, #{n.inspect}"
|
662
|
+
add_debug {"is_valid_list: false, #{n.inspect}"}
|
654
663
|
return false
|
655
664
|
end
|
656
665
|
l = n.first
|
657
666
|
unless l.node? || l == RDF.nil
|
658
|
-
add_debug "is_valid_list: false, #{l.inspect}"
|
667
|
+
add_debug {"is_valid_list: false, #{l.inspect}"}
|
659
668
|
return false
|
660
669
|
end
|
661
670
|
props = @graph.properties(l)
|
662
671
|
end
|
663
|
-
add_debug "is_valid_list: valid"
|
672
|
+
add_debug {"is_valid_list: valid"}
|
664
673
|
true
|
665
674
|
end
|
666
675
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-ld
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,23 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-09-15 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rdf
|
17
|
-
requirement: &
|
16
|
+
requirement: &2169730540 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
21
20
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.3.
|
21
|
+
version: 0.3.4
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *2169730540
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: json
|
28
|
-
requirement: &
|
27
|
+
requirement: &2169729780 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: 1.5.1
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *2169729780
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: yard
|
39
|
-
requirement: &
|
38
|
+
requirement: &2169728940 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: 0.6.0
|
45
44
|
type: :development
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *2169728940
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: rspec
|
50
|
-
requirement: &
|
49
|
+
requirement: &2169727620 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,21 +54,21 @@ dependencies:
|
|
55
54
|
version: 2.5.0
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *2169727620
|
59
58
|
- !ruby/object:Gem::Dependency
|
60
59
|
name: rdf-spec
|
61
|
-
requirement: &
|
60
|
+
requirement: &2169703000 !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ! '>='
|
65
64
|
- !ruby/object:Gem::Version
|
66
|
-
version: 0.3.
|
65
|
+
version: 0.3.4
|
67
66
|
type: :development
|
68
67
|
prerelease: false
|
69
|
-
version_requirements: *
|
68
|
+
version_requirements: *2169703000
|
70
69
|
- !ruby/object:Gem::Dependency
|
71
70
|
name: rdf-n3
|
72
|
-
requirement: &
|
71
|
+
requirement: &2169702100 !ruby/object:Gem::Requirement
|
73
72
|
none: false
|
74
73
|
requirements:
|
75
74
|
- - ! '>='
|
@@ -77,10 +76,10 @@ dependencies:
|
|
77
76
|
version: 0.3.3
|
78
77
|
type: :development
|
79
78
|
prerelease: false
|
80
|
-
version_requirements: *
|
79
|
+
version_requirements: *2169702100
|
81
80
|
- !ruby/object:Gem::Dependency
|
82
81
|
name: rdf-isomorphic
|
83
|
-
requirement: &
|
82
|
+
requirement: &2169700640 !ruby/object:Gem::Requirement
|
84
83
|
none: false
|
85
84
|
requirements:
|
86
85
|
- - ! '>='
|
@@ -88,10 +87,10 @@ dependencies:
|
|
88
87
|
version: 0.3.4
|
89
88
|
type: :development
|
90
89
|
prerelease: false
|
91
|
-
version_requirements: *
|
90
|
+
version_requirements: *2169700640
|
92
91
|
- !ruby/object:Gem::Dependency
|
93
92
|
name: sxp
|
94
|
-
requirement: &
|
93
|
+
requirement: &2169698280 !ruby/object:Gem::Requirement
|
95
94
|
none: false
|
96
95
|
requirements:
|
97
96
|
- - ! '>='
|
@@ -99,10 +98,10 @@ dependencies:
|
|
99
98
|
version: '0'
|
100
99
|
type: :development
|
101
100
|
prerelease: false
|
102
|
-
version_requirements: *
|
101
|
+
version_requirements: *2169698280
|
103
102
|
- !ruby/object:Gem::Dependency
|
104
103
|
name: sparql-algebra
|
105
|
-
requirement: &
|
104
|
+
requirement: &2169697020 !ruby/object:Gem::Requirement
|
106
105
|
none: false
|
107
106
|
requirements:
|
108
107
|
- - ! '>='
|
@@ -110,10 +109,10 @@ dependencies:
|
|
110
109
|
version: '0'
|
111
110
|
type: :development
|
112
111
|
prerelease: false
|
113
|
-
version_requirements: *
|
112
|
+
version_requirements: *2169697020
|
114
113
|
- !ruby/object:Gem::Dependency
|
115
114
|
name: sparql-grammar
|
116
|
-
requirement: &
|
115
|
+
requirement: &2169695840 !ruby/object:Gem::Requirement
|
117
116
|
none: false
|
118
117
|
requirements:
|
119
118
|
- - ! '>='
|
@@ -121,7 +120,7 @@ dependencies:
|
|
121
120
|
version: '0'
|
122
121
|
type: :development
|
123
122
|
prerelease: false
|
124
|
-
version_requirements: *
|
123
|
+
version_requirements: *2169695840
|
125
124
|
description: JSON-LD reader/writer for Ruby.
|
126
125
|
email: public-rdf-ruby@w3.org
|
127
126
|
executables: []
|
@@ -134,11 +133,11 @@ files:
|
|
134
133
|
- VERSION
|
135
134
|
- lib/json/ld/extensions.rb
|
136
135
|
- lib/json/ld/format.rb
|
136
|
+
- lib/json/ld/normalize.rb
|
137
137
|
- lib/json/ld/reader.rb
|
138
138
|
- lib/json/ld/version.rb
|
139
139
|
- lib/json/ld/writer.rb
|
140
140
|
- lib/json/ld.rb
|
141
|
-
has_rdoc: false
|
142
141
|
homepage: http://github.com/gkellogg/json-ld
|
143
142
|
licenses:
|
144
143
|
- Public Domain
|
@@ -160,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
159
|
version: '0'
|
161
160
|
requirements: []
|
162
161
|
rubyforge_project: json-ld
|
163
|
-
rubygems_version: 1.
|
162
|
+
rubygems_version: 1.8.10
|
164
163
|
signing_key:
|
165
164
|
specification_version: 3
|
166
165
|
summary: JSON-LD reader/writer for Ruby.
|