json-ld 0.1.3 → 0.1.4

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