json-ld 0.1.4.2 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/json/ld.rb +1 -0
- data/lib/json/ld/evaluation_context.rb +60 -25
- data/spec/evaluation_context_spec.rb +99 -6
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.5
|
data/lib/json/ld.rb
CHANGED
@@ -64,6 +64,14 @@ module JSON::LD
|
|
64
64
|
# This adds a language to plain strings that aren't otherwise coerced
|
65
65
|
# @attr [String]
|
66
66
|
attr :default_language, true
|
67
|
+
|
68
|
+
# Default vocabulary
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# Sets the default vocabulary used for expanding terms which
|
72
|
+
# aren't otherwise absolute IRIs
|
73
|
+
# @attr [String]
|
74
|
+
attr :vocab, true
|
67
75
|
|
68
76
|
# Global options used in generating IRIs
|
69
77
|
# @attr [Hash] options
|
@@ -149,8 +157,22 @@ module JSON::LD
|
|
149
157
|
ec
|
150
158
|
when Hash
|
151
159
|
new_ec = self.dup
|
152
|
-
new_ec.provided_context = context
|
153
|
-
|
160
|
+
new_ec.provided_context = context.dup
|
161
|
+
|
162
|
+
{
|
163
|
+
'@language' => :default_language=,
|
164
|
+
'@vocab' => :vocab=
|
165
|
+
}.each do |key, setter|
|
166
|
+
v = context.fetch(key, false)
|
167
|
+
if v.nil? || v.is_a?(String)
|
168
|
+
context.delete(key)
|
169
|
+
debug("parse") {"Hash[#{key}] = #{v.inspect}"}
|
170
|
+
new_ec.send(setter, v)
|
171
|
+
elsif v
|
172
|
+
raise InvalidContext::Syntax, "#{key.inspect} is invalid"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
154
176
|
num_updates = 1
|
155
177
|
while num_updates > 0 do
|
156
178
|
num_updates = 0
|
@@ -159,8 +181,9 @@ module JSON::LD
|
|
159
181
|
context.each do |key, value|
|
160
182
|
# Expand a string value, unless it matches a keyword
|
161
183
|
debug("parse") {"Hash[#{key}] = #{value.inspect}"}
|
162
|
-
|
163
|
-
|
184
|
+
|
185
|
+
if KEYWORDS.include?(key)
|
186
|
+
raise InvalidContext::Syntax, "key #{key.inspect} must not be a keyword"
|
164
187
|
elsif term_valid?(key)
|
165
188
|
# Remove all coercion information for the property
|
166
189
|
new_ec.set_coerce(key, nil)
|
@@ -172,9 +195,7 @@ module JSON::LD
|
|
172
195
|
raise InvalidContext::Syntax, "unknown mapping for #{key.inspect} to #{value.class}" unless value.is_a?(String) || value.nil?
|
173
196
|
|
174
197
|
iri = new_ec.expand_iri(value, :position => :predicate) if value.is_a?(String)
|
175
|
-
if iri &&
|
176
|
-
raise InvalidContext::Syntax, "key #{key.inspect} must not be a keyword"
|
177
|
-
elsif iri && new_ec.mappings.fetch(key, nil) != iri
|
198
|
+
if iri && new_ec.mappings.fetch(key, nil) != iri
|
178
199
|
# Record term definition
|
179
200
|
new_ec.set_mapping(key, iri)
|
180
201
|
num_updates += 1
|
@@ -254,6 +275,7 @@ module JSON::LD
|
|
254
275
|
debug {"=> context: #{inspect}"}
|
255
276
|
ctx = Hash.ordered
|
256
277
|
ctx['@language'] = default_language.to_s if default_language
|
278
|
+
ctx['@vocab'] = vocab.to_s if vocab
|
257
279
|
|
258
280
|
# Mappings
|
259
281
|
mappings.keys.sort{|a, b| a.to_s <=> b.to_s}.each do |k|
|
@@ -453,7 +475,7 @@ module JSON::LD
|
|
453
475
|
return iri unless iri.is_a?(String)
|
454
476
|
prefix, suffix = iri.split(':', 2)
|
455
477
|
return mapping(iri) if mapping(iri) # If it's an exact match
|
456
|
-
debug("expand_iri") {"prefix: #{prefix.inspect}, suffix: #{suffix.inspect}"} unless options[:quiet]
|
478
|
+
debug("expand_iri") {"prefix: #{prefix.inspect}, suffix: #{suffix.inspect}, vocab: #{vocab.inspect}"} unless options[:quiet]
|
457
479
|
base = self.base unless [:predicate, :datatype].include?(options[:position])
|
458
480
|
prefix = prefix.to_s
|
459
481
|
case
|
@@ -462,6 +484,7 @@ module JSON::LD
|
|
462
484
|
when suffix.to_s[0,2] == '//' then uri(iri)
|
463
485
|
when mappings.has_key?(prefix) then uri(mappings[prefix] + suffix.to_s)
|
464
486
|
when base then base.join(iri)
|
487
|
+
when vocab then uri("#{vocab}#{iri}")
|
465
488
|
else
|
466
489
|
# Otherwise, it must be an absolute IRI
|
467
490
|
u = uri(iri)
|
@@ -535,10 +558,20 @@ module JSON::LD
|
|
535
558
|
least_distance = term_map.values.max
|
536
559
|
terms = term_map.keys.select {|t| term_map[t] == least_distance}
|
537
560
|
|
538
|
-
# If
|
539
|
-
#
|
540
|
-
#
|
541
|
-
|
561
|
+
# If terms is empty, and the active context has a @vocab which is a
|
562
|
+
# prefix of iri where the resulting relative IRI is not a term in the
|
563
|
+
# active context. The resulting relative IRI is the unmatched part of iri.
|
564
|
+
if vocab && terms.empty? && iri.to_s.index(vocab) == 0
|
565
|
+
terms << iri.to_s.sub(vocab, '')
|
566
|
+
debug("vocab") {"vocab: #{vocab}, rel: #{terms.first}"}
|
567
|
+
end
|
568
|
+
|
569
|
+
# If terms is empty, add a compact IRI representation of iri for each
|
570
|
+
# term in the active context which maps to an IRI which is a prefix for
|
571
|
+
# iri where the resulting compact IRI is not a term in the active
|
572
|
+
# context. The resulting compact IRI is the term associated with the
|
573
|
+
# partially matched IRI in the active context concatenated with a colon
|
574
|
+
# (:) character and the unmatched part of iri.
|
542
575
|
if terms.empty?
|
543
576
|
debug("curies") {"mappings: #{mappings.inspect}"}
|
544
577
|
curies = mappings.keys.map do |k|
|
@@ -566,20 +599,22 @@ module JSON::LD
|
|
566
599
|
end
|
567
600
|
|
568
601
|
debug("curies") {"selected #{terms.inspect}"}
|
602
|
+
end
|
569
603
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
604
|
+
# If we still don't have any terms and we're using standard_prefixes,
|
605
|
+
# try those, and add to mapping
|
606
|
+
if terms.empty? && @options[:standard_prefixes]
|
607
|
+
terms = RDF::Vocabulary.
|
608
|
+
select {|v| iri.index(v.to_uri.to_s) == 0}.
|
609
|
+
map do |v|
|
610
|
+
prefix = v.__name__.to_s.split('::').last.downcase
|
611
|
+
set_mapping(prefix, v.to_uri.to_s)
|
612
|
+
iri.sub(v.to_uri.to_s, "#{prefix}:").sub(/:$/, '')
|
613
|
+
end
|
614
|
+
debug("curies") {"using standard prefies: #{terms.inspect}"}
|
615
|
+
end
|
582
616
|
|
617
|
+
if terms.empty?
|
583
618
|
# If there is a mapping from the complete IRI to null, return null,
|
584
619
|
# otherwise, return the complete IRI.
|
585
620
|
if mappings.has_key?(iri.to_s) && !mapping(iri)
|
@@ -589,7 +624,7 @@ module JSON::LD
|
|
589
624
|
terms << iri.to_s
|
590
625
|
end
|
591
626
|
end
|
592
|
-
|
627
|
+
|
593
628
|
# Get the first term based on distance and lexecographical order
|
594
629
|
# Prefer terms that don't have @container @set over other terms, unless as set is true
|
595
630
|
terms = terms.sort do |a, b|
|
@@ -86,6 +86,12 @@ describe JSON::LD::EvaluationContext do
|
|
86
86
|
}).default_language.should produce("en", @debug)
|
87
87
|
end
|
88
88
|
|
89
|
+
it "extracts @vocab" do
|
90
|
+
subject.parse({
|
91
|
+
"@vocab" => "http://schema.org/"
|
92
|
+
}).vocab.should produce("http://schema.org/", @debug)
|
93
|
+
end
|
94
|
+
|
89
95
|
it "maps term with IRI value" do
|
90
96
|
subject.parse({
|
91
97
|
"foo" => "http://example.com/"
|
@@ -154,6 +160,15 @@ describe JSON::LD::EvaluationContext do
|
|
154
160
|
}, @debug)
|
155
161
|
end
|
156
162
|
|
163
|
+
it "expands terms using @vocab" do
|
164
|
+
subject.parse({
|
165
|
+
"foo" => "bar",
|
166
|
+
"@vocab" => "http://example.com/"
|
167
|
+
}).mappings.should produce({
|
168
|
+
"foo" => "http://example.com/bar"
|
169
|
+
}, @debug)
|
170
|
+
end
|
171
|
+
|
157
172
|
context "with null" do
|
158
173
|
it "removes @language if set to null" do
|
159
174
|
subject.parse([
|
@@ -166,6 +181,17 @@ describe JSON::LD::EvaluationContext do
|
|
166
181
|
]).default_language.should produce(nil, @debug)
|
167
182
|
end
|
168
183
|
|
184
|
+
it "removes @vocab if set to null" do
|
185
|
+
subject.parse([
|
186
|
+
{
|
187
|
+
"@vocab" => "http://schema.org/"
|
188
|
+
},
|
189
|
+
{
|
190
|
+
"@vocab" => nil
|
191
|
+
}
|
192
|
+
]).vocab.should produce(nil, @debug)
|
193
|
+
end
|
194
|
+
|
169
195
|
it "loads initial context" do
|
170
196
|
init_ec = JSON::LD::EvaluationContext.new
|
171
197
|
nil_ec = subject.parse(nil)
|
@@ -197,6 +223,7 @@ describe JSON::LD::EvaluationContext do
|
|
197
223
|
"@container as array" => {"foo" => {"@container" => []}},
|
198
224
|
"@container as string" => {"foo" => {"@container" => "true"}},
|
199
225
|
"@language as @id" => {"@language" => {"@id" => "http://example.com/"}},
|
226
|
+
"@vocab as @id" => {"@vocab" => {"@id" => "http://example.com/"}},
|
200
227
|
}.each do |title, context|
|
201
228
|
it title do
|
202
229
|
lambda {
|
@@ -206,15 +233,15 @@ describe JSON::LD::EvaluationContext do
|
|
206
233
|
end
|
207
234
|
end
|
208
235
|
|
209
|
-
(JSON::LD::KEYWORDS - %w(@language)).each do |kw|
|
210
|
-
it "does not
|
236
|
+
(JSON::LD::KEYWORDS - %w(@language @vocab)).each do |kw|
|
237
|
+
it "does not redefine #{kw} as a string" do
|
211
238
|
lambda {
|
212
239
|
ec = subject.parse({kw => "http://example.com/"})
|
213
240
|
ec.serialize.should produce({}, @debug)
|
214
241
|
}.should raise_error(JSON::LD::InvalidContext::Syntax)
|
215
242
|
end
|
216
243
|
|
217
|
-
it "does not
|
244
|
+
it "does not redefine #{kw} with an @id" do
|
218
245
|
lambda {
|
219
246
|
ec = subject.parse({kw => {"@id" => "http://example.com/"}})
|
220
247
|
ec.serialize.should produce({}, @debug)
|
@@ -235,7 +262,7 @@ describe JSON::LD::EvaluationContext do
|
|
235
262
|
end
|
236
263
|
|
237
264
|
describe "#serialize" do
|
238
|
-
it "
|
265
|
+
it "context document" do
|
239
266
|
ctx = StringIO.new(@ctx_json)
|
240
267
|
def ctx.content_type; "application/ld+json"; end
|
241
268
|
|
@@ -246,7 +273,7 @@ describe JSON::LD::EvaluationContext do
|
|
246
273
|
}, @debug)
|
247
274
|
end
|
248
275
|
|
249
|
-
it "
|
276
|
+
it "context array" do
|
250
277
|
ctx = [
|
251
278
|
{"foo" => "http://example.com/"},
|
252
279
|
{"baz" => "bob"}
|
@@ -258,7 +285,7 @@ describe JSON::LD::EvaluationContext do
|
|
258
285
|
}, @debug)
|
259
286
|
end
|
260
287
|
|
261
|
-
it "
|
288
|
+
it "context hash" do
|
262
289
|
ctx = {"foo" => "http://example.com/"}
|
263
290
|
|
264
291
|
ec = subject.parse(ctx)
|
@@ -276,6 +303,15 @@ describe JSON::LD::EvaluationContext do
|
|
276
303
|
}, @debug)
|
277
304
|
end
|
278
305
|
|
306
|
+
it "@vocab" do
|
307
|
+
subject.vocab = "http://example.com/"
|
308
|
+
subject.serialize.should produce({
|
309
|
+
"@context" => {
|
310
|
+
"@vocab" => "http://example.com/"
|
311
|
+
}
|
312
|
+
}, @debug)
|
313
|
+
end
|
314
|
+
|
279
315
|
it "term mappings" do
|
280
316
|
subject.set_mapping("foo", "http://example.com/")
|
281
317
|
subject.serialize.should produce({
|
@@ -458,6 +494,18 @@ describe JSON::LD::EvaluationContext do
|
|
458
494
|
}, @debug)
|
459
495
|
end
|
460
496
|
|
497
|
+
it "compacts IRIs using @vocab" do
|
498
|
+
subject.vocab = 'http://example.org/'
|
499
|
+
subject.set_mapping("term", 'http://example.org/term')
|
500
|
+
subject.set_coerce("term", "http://example.org/datatype")
|
501
|
+
subject.serialize.should produce({
|
502
|
+
"@context" => {
|
503
|
+
"@vocab" => 'http://example.org/',
|
504
|
+
"term" => {"@id" => "term", "@type" => "datatype"}
|
505
|
+
}
|
506
|
+
}, @debug)
|
507
|
+
end
|
508
|
+
|
461
509
|
context "extra keys or values" do
|
462
510
|
{
|
463
511
|
"extra key" => {
|
@@ -544,6 +592,33 @@ describe JSON::LD::EvaluationContext do
|
|
544
592
|
end
|
545
593
|
end
|
546
594
|
end
|
595
|
+
|
596
|
+
context "@vocab" do
|
597
|
+
before(:each) { subject.vocab = "http://example.com/"}
|
598
|
+
{
|
599
|
+
:subject => false,
|
600
|
+
:predicate => true,
|
601
|
+
:object => false,
|
602
|
+
:datatype => true
|
603
|
+
}.each do |position, r|
|
604
|
+
context "as #{position}" do
|
605
|
+
{
|
606
|
+
"absolute IRI" => ["http://example.org/", "http://example.org/", true],
|
607
|
+
"term" => ["ex", "http://example.org/", true],
|
608
|
+
"prefix:suffix" => ["ex:suffix", "http://example.org/suffix", true],
|
609
|
+
"keyword" => ["@type", "@type", true],
|
610
|
+
"empty" => [":suffix", "http://empty/suffix", true],
|
611
|
+
"unmapped" => ["foo", "http://example.com/foo", true],
|
612
|
+
"empty term" => ["", "http://empty/", true],
|
613
|
+
}.each do |title, (input,result,abs)|
|
614
|
+
result = nil unless r || abs
|
615
|
+
it title do
|
616
|
+
subject.expand_iri(input).should produce(result, @debug)
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
end
|
547
622
|
end
|
548
623
|
|
549
624
|
describe "#compact_iri" do
|
@@ -568,6 +643,24 @@ describe JSON::LD::EvaluationContext do
|
|
568
643
|
end
|
569
644
|
end
|
570
645
|
|
646
|
+
context "with @vocab" do
|
647
|
+
before(:each) { subject.vocab = "http://example.org/"}
|
648
|
+
|
649
|
+
{
|
650
|
+
"absolute IRI" => ["http://example.com/", "http://example.com/"],
|
651
|
+
"term" => ["ex", "http://example.org/"],
|
652
|
+
"prefix:suffix" => ["suffix", "http://example.org/suffix"],
|
653
|
+
"keyword" => ["@type", "@type"],
|
654
|
+
"empty" => [":suffix", "http://empty/suffix"],
|
655
|
+
"unmapped" => ["foo", "foo"],
|
656
|
+
"bnode" => ["_:a", RDF::Node("a")],
|
657
|
+
}.each do |title, (result, input)|
|
658
|
+
it title do
|
659
|
+
subject.compact_iri(input).should produce(result, @debug)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
571
664
|
context "with value" do
|
572
665
|
let(:ctx) do
|
573
666
|
c = subject.parse({
|
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdf
|