json-ld 0.1.4.2 → 0.1.5
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/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
|