json-ld 0.1.3 → 0.1.4

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.
Files changed (78) hide show
  1. data/History.markdown +3 -0
  2. data/VERSION +1 -1
  3. data/bin/jsonld +134 -0
  4. data/lib/json/ld/api.rb +4 -4
  5. data/lib/json/ld/frame.rb +2 -1
  6. data/lib/json/ld/from_rdf.rb +1 -1
  7. data/spec/api_spec.rb +66 -0
  8. data/spec/compact_spec.rb +420 -0
  9. data/spec/evaluation_context_spec.rb +1039 -0
  10. data/spec/expand_spec.rb +625 -0
  11. data/spec/format_spec.rb +71 -0
  12. data/spec/frame_spec.rb +542 -0
  13. data/spec/from_rdf_spec.rb +316 -0
  14. data/spec/matchers.rb +67 -0
  15. data/spec/reader_spec.rb +79 -0
  16. data/spec/spec_helper.rb +56 -0
  17. data/spec/suite_helper.rb +184 -0
  18. data/spec/suite_spec.rb +104 -0
  19. data/spec/support/extensions.rb +10 -0
  20. data/spec/test-files/test-1-automatic.json +10 -0
  21. data/spec/test-files/test-1-compacted.json +10 -0
  22. data/spec/test-files/test-1-context.json +7 -0
  23. data/spec/test-files/test-1-expanded.json +5 -0
  24. data/spec/test-files/test-1-input.json +10 -0
  25. data/spec/test-files/test-1-normalized.json +8 -0
  26. data/spec/test-files/test-1-rdf.ttl +7 -0
  27. data/spec/test-files/test-2-automatic.json +27 -0
  28. data/spec/test-files/test-2-compacted.json +20 -0
  29. data/spec/test-files/test-2-context.json +7 -0
  30. data/spec/test-files/test-2-expanded.json +16 -0
  31. data/spec/test-files/test-2-input.json +20 -0
  32. data/spec/test-files/test-2-normalized.json +32 -0
  33. data/spec/test-files/test-2-rdf.ttl +14 -0
  34. data/spec/test-files/test-3-compacted.json +11 -0
  35. data/spec/test-files/test-3-context.json +8 -0
  36. data/spec/test-files/test-3-expanded.json +10 -0
  37. data/spec/test-files/test-3-input.json +11 -0
  38. data/spec/test-files/test-3-normalized.json +13 -0
  39. data/spec/test-files/test-3-rdf.ttl +7 -0
  40. data/spec/test-files/test-4-automatic.json +10 -0
  41. data/spec/test-files/test-4-compacted.json +10 -0
  42. data/spec/test-files/test-4-context.json +7 -0
  43. data/spec/test-files/test-4-expanded.json +6 -0
  44. data/spec/test-files/test-4-input.json +10 -0
  45. data/spec/test-files/test-4-rdf.ttl +5 -0
  46. data/spec/test-files/test-5-automatic.json +13 -0
  47. data/spec/test-files/test-5-compacted.json +13 -0
  48. data/spec/test-files/test-5-context.json +7 -0
  49. data/spec/test-files/test-5-expanded.json +9 -0
  50. data/spec/test-files/test-5-input.json +13 -0
  51. data/spec/test-files/test-5-rdf.ttl +6 -0
  52. data/spec/test-files/test-6-automatic.json +10 -0
  53. data/spec/test-files/test-6-compacted.json +10 -0
  54. data/spec/test-files/test-6-context.json +7 -0
  55. data/spec/test-files/test-6-expanded.json +10 -0
  56. data/spec/test-files/test-6-input.json +10 -0
  57. data/spec/test-files/test-6-rdf.ttl +5 -0
  58. data/spec/test-files/test-7-automatic.json +20 -0
  59. data/spec/test-files/test-7-compacted.json +23 -0
  60. data/spec/test-files/test-7-context.json +4 -0
  61. data/spec/test-files/test-7-expanded.json +20 -0
  62. data/spec/test-files/test-7-input.json +23 -0
  63. data/spec/test-files/test-7-rdf.ttl +13 -0
  64. data/spec/test-files/test-8-automatic.json +1 -0
  65. data/spec/test-files/test-8-compacted.json +34 -0
  66. data/spec/test-files/test-8-context.json +11 -0
  67. data/spec/test-files/test-8-expanded.json +24 -0
  68. data/spec/test-files/test-8-frame.json +18 -0
  69. data/spec/test-files/test-8-framed.json +29 -0
  70. data/spec/test-files/test-8-input.json +30 -0
  71. data/spec/test-files/test-8-rdf.ttl +15 -0
  72. data/spec/test-files/test-9-compacted.json +20 -0
  73. data/spec/test-files/test-9-context.json +13 -0
  74. data/spec/test-files/test-9-expanded.json +14 -0
  75. data/spec/test-files/test-9-input.json +12 -0
  76. data/spec/to_rdf_spec.rb +640 -0
  77. data/spec/writer_spec.rb +161 -0
  78. metadata +150 -22
@@ -0,0 +1,316 @@
1
+ # coding: utf-8
2
+ $:.unshift "."
3
+ require 'spec_helper'
4
+ require 'rdf/spec/writer'
5
+
6
+ describe JSON::LD::API do
7
+ describe ".fromRDF" do
8
+ context "simple tests" do
9
+ it "One subject IRI object" do
10
+ input = %(<http://a/b> <http://a/c> <http://a/d> .)
11
+ serialize(input).should produce([
12
+ {
13
+ '@id' => "http://a/b",
14
+ "http://a/c" => [{"@id" => "http://a/d"}]
15
+ }], @debug)
16
+ end
17
+
18
+ it "should generate object list" do
19
+ input = %(@prefix : <http://example.com/> . :b :c :d, :e .)
20
+ serialize(input).
21
+ should produce([{
22
+ '@id' => "http://example.com/b",
23
+ "http://example.com/c" => [
24
+ {"@id" => "http://example.com/d"},
25
+ {"@id" => "http://example.com/e"}
26
+ ]
27
+ }], @debug)
28
+ end
29
+
30
+ it "should generate property list" do
31
+ input = %(@prefix : <http://example.com/> . :b :c :d; :e :f .)
32
+ serialize(input).
33
+ should produce([{
34
+ '@id' => "http://example.com/b",
35
+ "http://example.com/c" => [{"@id" => "http://example.com/d"}],
36
+ "http://example.com/e" => [{"@id" => "http://example.com/f"}]
37
+ }], @debug)
38
+ end
39
+
40
+ it "serializes multiple subjects" do
41
+ input = %q(
42
+ @prefix : <http://www.w3.org/2006/03/test-description#> .
43
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
44
+ <test-cases/0001> a :TestCase .
45
+ <test-cases/0002> a :TestCase .
46
+ )
47
+ serialize(input).
48
+ should produce([
49
+ {'@id' => "test-cases/0001", '@type' => ["http://www.w3.org/2006/03/test-description#TestCase"]},
50
+ {'@id' => "test-cases/0002", '@type' => ["http://www.w3.org/2006/03/test-description#TestCase"]}
51
+ ], @debug)
52
+ end
53
+ end
54
+
55
+ context "literals" do
56
+ it "coerces typed literal" do
57
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b "foo"^^ex:d .)
58
+ serialize(input).should produce([{
59
+ '@id' => "http://example.com/a",
60
+ "http://example.com/b" => [{"@value" => "foo", "@type" => "http://example.com/d"}]
61
+ }], @debug)
62
+ end
63
+
64
+ it "coerces integer" do
65
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b 1 .)
66
+ serialize(input).should produce([{
67
+ '@id' => "http://example.com/a",
68
+ "http://example.com/b" => [{"@value" => "1","@type" => "http://www.w3.org/2001/XMLSchema#integer"}]
69
+ }], @debug)
70
+ end
71
+
72
+ it "coerces boolean" do
73
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b true .)
74
+ serialize(input).should produce([{
75
+ '@id' => "http://example.com/a",
76
+ "http://example.com/b" => [{"@value" => "true","@type" => "http://www.w3.org/2001/XMLSchema#boolean"}]
77
+ }], @debug)
78
+ end
79
+
80
+ it "coerces decmal" do
81
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b 1.0 .)
82
+ serialize(input).should produce([{
83
+ '@id' => "http://example.com/a",
84
+ "http://example.com/b" => [{"@value" => "1.0", "@type" => "http://www.w3.org/2001/XMLSchema#decimal"}]
85
+ }], @debug)
86
+ end
87
+
88
+ it "coerces double" do
89
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b 1.0e0 .)
90
+ serialize(input).should produce([{
91
+ '@id' => "http://example.com/a",
92
+ "http://example.com/b" => [{"@value" => "1.0E0","@type" => "http://www.w3.org/2001/XMLSchema#double"}]
93
+ }], @debug)
94
+ end
95
+
96
+ it "encodes language literal" do
97
+ input = %(@prefix ex: <http://example.com/> . ex:a ex:b "foo"@en-us .)
98
+ serialize(input).should produce([{
99
+ '@id' => "http://example.com/a",
100
+ "http://example.com/b" => [{"@value" => "foo", "@language" => "en-us"}]
101
+ }], @debug)
102
+ end
103
+ end
104
+
105
+ context "anons" do
106
+ it "should generate bare anon" do
107
+ input = %(@prefix : <http://example.com/> . _:a :a :b .)
108
+ serialize(input).should produce([{
109
+ "@id" => "_:a",
110
+ "http://example.com/a" => [{"@id" => "http://example.com/b"}]
111
+ }], @debug)
112
+ end
113
+
114
+ it "should generate anon as object" do
115
+ input = %(@prefix : <http://example.com/> . :a :b _:a . _:a :c :d .)
116
+ serialize(input).should produce([
117
+ {
118
+ "@id" => "_:a",
119
+ "http://example.com/c" => [{"@id" => "http://example.com/d"}]
120
+ },
121
+ {
122
+ "@id" => "http://example.com/a",
123
+ "http://example.com/b" => [{"@id" => "_:a"}]
124
+ },
125
+ ], @debug)
126
+ end
127
+ end
128
+
129
+ context "lists" do
130
+ it "should generate literal list" do
131
+ input = %(
132
+ @prefix : <http://example.com/> .
133
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
134
+ :a :b ("apple" "banana") .
135
+ )
136
+ serialize(input).should produce([{
137
+ '@id' => "http://example.com/a",
138
+ "http://example.com/b" => [{
139
+ "@list" => [
140
+ {"@value" => "apple"},
141
+ {"@value" => "banana"}
142
+ ]
143
+ }]
144
+ }], @debug)
145
+ end
146
+
147
+ it "should generate iri list" do
148
+ input = %(@prefix : <http://example.com/> . :a :b (:c) .)
149
+ serialize(input).should produce([{
150
+ '@id' => "http://example.com/a",
151
+ "http://example.com/b" => [{
152
+ "@list" => [
153
+ {"@id" => "http://example.com/c"}
154
+ ]
155
+ }]
156
+ }], @debug)
157
+ end
158
+
159
+ it "should generate empty list" do
160
+ input = %(@prefix : <http://example.com/> . :a :b () .)
161
+ serialize(input).should produce([{
162
+ '@id' => "http://example.com/a",
163
+ "http://example.com/b" => [{"@list" => []}]
164
+ }], @debug)
165
+ end
166
+
167
+ it "should generate single element list" do
168
+ input = %(@prefix : <http://example.com/> . :a :b ( "apple" ) .)
169
+ serialize(input).should produce([{
170
+ '@id' => "http://example.com/a",
171
+ "http://example.com/b" => [{"@list" => [{"@value" => "apple"}]}]
172
+ }], @debug)
173
+ end
174
+
175
+ it "should generate single element list without @type" do
176
+ input = %(
177
+ @prefix : <http://example.com/> . :a :b ( _:a ) . _:a :b "foo" .)
178
+ serialize(input).should produce([
179
+ {
180
+ '@id' => "_:a",
181
+ "http://example.com/b" => [{"@value" => "foo"}]
182
+ },
183
+ {
184
+ '@id' => "http://example.com/a",
185
+ "http://example.com/b" => [{"@list" => [{"@id" => "_:a"}]}]
186
+ },
187
+ ], @debug)
188
+ end
189
+ end
190
+
191
+ context "quads" do
192
+ {
193
+ "simple named graph" => {
194
+ :input => %(
195
+ <http://example.com/a> <http://example.com/b> <http://example.com/c> <http://example.com/U> .
196
+ ),
197
+ :output => [
198
+ {
199
+ "@id" => "http://example.com/U",
200
+ "@graph" => [{
201
+ "@id" => "http://example.com/a",
202
+ "http://example.com/b" => [{"@id" => "http://example.com/c"}]
203
+ }]
204
+ }
205
+ ]
206
+ },
207
+ "with properties" => {
208
+ :input => %(
209
+ <http://example.com/a> <http://example.com/b> <http://example.com/c> <http://example.com/U> .
210
+ <http://example.com/U> <http://example.com/d> <http://example.com/e> .
211
+ ),
212
+ :output => [
213
+ {
214
+ "@id" => "http://example.com/U",
215
+ "@graph" => [{
216
+ "@id" => "http://example.com/a",
217
+ "http://example.com/b" => [{"@id" => "http://example.com/c"}]
218
+ }],
219
+ "http://example.com/d" => [{"@id" => "http://example.com/e"}]
220
+ }
221
+ ]
222
+ },
223
+ "with lists" => {
224
+ :input => %(
225
+ <http://example.com/a> <http://example.com/b> _:a <http://example.com/U> .
226
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/c> <http://example.com/U> .
227
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.com/U> .
228
+ <http://example.com/U> <http://example.com/d> _:b .
229
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/e> .
230
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
231
+ ),
232
+ :output => [
233
+ {
234
+ "@id" => "http://example.com/U",
235
+ "@graph" => [{
236
+ "@id" => "http://example.com/a",
237
+ "http://example.com/b" => [{"@list" => [{"@id" => "http://example.com/c"}]}]
238
+ }],
239
+ "http://example.com/d" => [{"@list" => [{"@id" => "http://example.com/e"}]}]
240
+ }
241
+ ]
242
+ },
243
+ "Two Graphs with same subject and lists" => {
244
+ :input => %(
245
+ <http://example.com/a> <http://example.com/b> _:a <http://example.com/U> .
246
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/c> <http://example.com/U> .
247
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.com/U> .
248
+ <http://example.com/a> <http://example.com/b> _:b <http://example.com/V> .
249
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://example.com/e> <http://example.com/V> .
250
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.com/V> .
251
+ ),
252
+ :output => [
253
+ {
254
+ "@id" => "http://example.com/U",
255
+ "@graph" => [
256
+ {
257
+ "@id" => "http://example.com/a",
258
+ "http://example.com/b" => [{
259
+ "@list" => [{"@id" => "http://example.com/c"}]
260
+ }]
261
+ }
262
+ ]
263
+ },
264
+ {
265
+ "@id" => "http://example.com/V",
266
+ "@graph" => [
267
+ {
268
+ "@id" => "http://example.com/a",
269
+ "http://example.com/b" => [{
270
+ "@list" => [{"@id" => "http://example.com/e"}]
271
+ }]
272
+ }
273
+ ]
274
+ }
275
+ ]
276
+ },
277
+ }.each_pair do |name, properties|
278
+ it name do
279
+ r = serialize(properties[:input], :reader => RDF::NQuads::Reader)
280
+ r.should produce(properties[:output], @debug)
281
+ end
282
+ end
283
+ end
284
+
285
+ context "notType option" do
286
+ it "uses @type if set to false" do
287
+ input = %(@prefix ex: <http://example.com/> . ex:a a ex:b .)
288
+ serialize(input, :notType => false).should produce([{
289
+ '@id' => "http://example.com/a",
290
+ "@type" => ["http://example.com/b"]
291
+ }], @debug)
292
+ end
293
+
294
+ it "does not use @type if set to true" do
295
+ input = %(@prefix ex: <http://example.com/> . ex:a a ex:b .)
296
+ serialize(input, :notType => true).should produce([{
297
+ '@id' => "http://example.com/a",
298
+ RDF.type.to_s => [{"@id" => "http://example.com/b"}]
299
+ }], @debug)
300
+ end
301
+ end
302
+ end
303
+
304
+ def parse(input, options = {})
305
+ reader = options[:reader] || RDF::Turtle::Reader
306
+ RDF::Repository.new << reader.new(input, options)
307
+ end
308
+
309
+ # Serialize ntstr to a string and compare against regexps
310
+ def serialize(ntstr, options = {})
311
+ g = ntstr.is_a?(String) ? parse(ntstr, options) : ntstr
312
+ @debug = [] << g.dump(:trig)
313
+ statements = g.each_statement.to_a
314
+ JSON::LD::API.fromRDF(statements, nil, options.merge(:debug => @debug))
315
+ end
316
+ end
data/spec/matchers.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'rdf/isomorphic'
2
+ require 'rspec/matchers'
3
+ require 'json'
4
+
5
+ Info = Struct.new(:about, :information, :trace, :inputDocument, :outputDocument, :expectedResults)
6
+
7
+ def normalize(graph)
8
+ case graph
9
+ when RDF::Graph then graph
10
+ when IO, StringIO
11
+ RDF::Graph.new.load(graph, :base => @info.about)
12
+ else
13
+ # Figure out which parser to use
14
+ g = RDF::Graph.new
15
+ reader_class = detect_format(graph)
16
+ reader_class.new(graph, :base => @info.about).each {|s| g << s}
17
+ g
18
+ end
19
+ end
20
+
21
+ RSpec::Matchers.define :be_equivalent_graph do |expected, info|
22
+ match do |actual|
23
+ @info = if info.respond_to?(:about)
24
+ info
25
+ elsif info.is_a?(Hash)
26
+ identifier = info[:identifier] || expected.is_a?(RDF::Graph) ? expected.context : info[:about]
27
+ trace = info[:trace]
28
+ trace = trace.join("\n") if trace.is_a?(Array)
29
+ Info.new(identifier, info[:information] || "", trace, info[:inputDocument])
30
+ else
31
+ Info.new(expected.is_a?(RDF::Graph) ? expected.context : info, info.to_s)
32
+ end
33
+ @expected = normalize(expected)
34
+ @actual = normalize(actual)
35
+ @actual.isomorphic_with?(@expected)
36
+ end
37
+
38
+ failure_message_for_should do |actual|
39
+ info = @info.respond_to?(:information) ? @info.information : @info.inspect
40
+ if @expected.is_a?(RDF::Graph) && @actual.size != @expected.size
41
+ "Graph entry count differs:\nexpected: #{@expected.size}\nactual: #{@actual.size}"
42
+ elsif @expected.is_a?(Array) && @actual.size != @expected.length
43
+ "Graph entry count differs:\nexpected: #{@expected.length}\nactual: #{@actual.size}"
44
+ else
45
+ "Graph differs"
46
+ end +
47
+ "\n#{info + "\n" unless info.empty?}" +
48
+ "Unsorted Expected:\n#{@expected.dump(:nquads, :standard_prefixes => true)}" +
49
+ "Unsorted Results:\n#{@actual.dump(:nquads, :standard_prefixes => true)}" +
50
+ (@info.inputDocument ? "Input file: #{@info.inputDocument}\n" : "") +
51
+ (@info.outputDocument ? "Output file: #{@info.outputDocument}\n" : "") +
52
+ (@info.trace ? "\nDebug:\n#{@info.trace}" : "")
53
+ end
54
+ end
55
+
56
+ RSpec::Matchers.define :produce do |expected, info|
57
+ match do |actual|
58
+ actual.should == expected
59
+ end
60
+
61
+ failure_message_for_should do |actual|
62
+ "Expected: #{expected.is_a?(String) ? expected : expected.to_json(JSON_STATE)}\n" +
63
+ "Actual : #{actual.is_a?(String) ? actual : actual.to_json(JSON_STATE)}\n" +
64
+ #(expected.is_a?(Hash) && actual.is_a?(Hash) ? "Diff: #{expected.diff(actual).to_json(JSON_STATE)}\n" : "") +
65
+ "Processing results:\n#{info.join("\n")}"
66
+ end
67
+ end
@@ -0,0 +1,79 @@
1
+ # coding: utf-8
2
+ $:.unshift "."
3
+ require 'spec_helper'
4
+ require 'rdf/spec/reader'
5
+
6
+ describe JSON::LD::Reader do
7
+ before :each do
8
+ @reader = JSON::LD::Reader.new(StringIO.new(""))
9
+ end
10
+
11
+ it_should_behave_like RDF_Reader
12
+
13
+ describe ".for" do
14
+ formats = [
15
+ :jsonld,
16
+ "etc/doap.jsonld",
17
+ {:file_name => 'etc/doap.jsonld'},
18
+ {:file_extension => 'jsonld'},
19
+ {:content_type => 'application/ld+json'},
20
+ {:content_type => 'application/x-ld+json'},
21
+ ].each do |arg|
22
+ it "discovers with #{arg.inspect}" do
23
+ RDF::Reader.for(arg).should == JSON::LD::Reader
24
+ end
25
+ end
26
+ end
27
+
28
+ context :interface do
29
+ subject { %q({
30
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
31
+ "@id": "_:bnode1",
32
+ "@type": "foaf:Person",
33
+ "foaf:homepage": "http://example.com/bob/",
34
+ "foaf:name": "Bob"
35
+ }) }
36
+
37
+ describe "#initialize" do
38
+ it "yields reader given string" do
39
+ inner = mock("inner")
40
+ inner.should_receive(:called).with(JSON::LD::Reader)
41
+ JSON::LD::Reader.new(subject) do |reader|
42
+ inner.called(reader.class)
43
+ end
44
+ end
45
+
46
+ it "yields reader given IO" do
47
+ inner = mock("inner")
48
+ inner.should_receive(:called).with(JSON::LD::Reader)
49
+ JSON::LD::Reader.new(StringIO.new(subject)) do |reader|
50
+ inner.called(reader.class)
51
+ end
52
+ end
53
+
54
+ it "returns reader" do
55
+ JSON::LD::Reader.new(subject).should be_a(JSON::LD::Reader)
56
+ end
57
+ end
58
+
59
+ describe "#each_statement" do
60
+ it "yields statements" do
61
+ inner = mock("inner")
62
+ inner.should_receive(:called).with(RDF::Statement).exactly(3)
63
+ JSON::LD::Reader.new(subject).each_statement do |statement|
64
+ inner.called(statement.class)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#each_triple" do
70
+ it "yields statements" do
71
+ inner = mock("inner")
72
+ inner.should_receive(:called).exactly(3)
73
+ JSON::LD::Reader.new(subject).each_triple do |subject, predicate, object|
74
+ inner.called(subject.class, predicate.class, object.class)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end