json-ld 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|