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,20 @@
1
+ [
2
+ {
3
+ "@id": "_:bnode1",
4
+ "@type": ["http://xmlns.com/foaf/0.1/Person"],
5
+ "http://xmlns.com/foaf/0.1/homepage": [{"@value": "http://example.com/bob/"}],
6
+ "http://xmlns.com/foaf/0.1/name": [{"@value": "Bob"}]
7
+ },
8
+ {
9
+ "@id": "_:bnode2",
10
+ "@type": ["http://xmlns.com/foaf/0.1/Person"],
11
+ "http://xmlns.com/foaf/0.1/homepage": [{"@value": "http://example.com/eve/"}],
12
+ "http://xmlns.com/foaf/0.1/name": [{"@value": "Eve"}]
13
+ },
14
+ {
15
+ "@id": "_:bnode3",
16
+ "@type": ["http://xmlns.com/foaf/0.1/Person"],
17
+ "http://xmlns.com/foaf/0.1/homepage": [{"@value": "http://example.com/manu/"}],
18
+ "http://xmlns.com/foaf/0.1/name": [{"@value": "Manu"}]
19
+ }
20
+ ]
@@ -0,0 +1,23 @@
1
+ {
2
+ "@context": { "foaf": "http://xmlns.com/foaf/0.1/" },
3
+ "@graph": [
4
+ {
5
+ "@id": "_:bnode1",
6
+ "@type": "foaf:Person",
7
+ "foaf:homepage": "http://example.com/bob/",
8
+ "foaf:name": "Bob"
9
+ },
10
+ {
11
+ "@id": "_:bnode2",
12
+ "@type": "foaf:Person",
13
+ "foaf:homepage": "http://example.com/eve/",
14
+ "foaf:name": "Eve"
15
+ },
16
+ {
17
+ "@id": "_:bnode3",
18
+ "@type": "foaf:Person",
19
+ "foaf:homepage": "http://example.com/manu/",
20
+ "foaf:name": "Manu"
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,13 @@
1
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
2
+
3
+ [ a foaf:Person;
4
+ foaf:homepage "http://example.com/manu/";
5
+ foaf:name "Manu"] .
6
+
7
+ [ a foaf:Person;
8
+ foaf:homepage "http://example.com/eve/";
9
+ foaf:name "Eve"] .
10
+
11
+ [ a foaf:Person;
12
+ foaf:homepage "http://example.com/bob/";
13
+ foaf:name "Bob"] .
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,34 @@
1
+ {
2
+ "@context": {
3
+ "Book": "http://example.org/vocab#Book",
4
+ "Chapter": "http://example.org/vocab#Chapter",
5
+ "contains": {
6
+ "@id": "http://example.org/vocab#contains",
7
+ "@type": "@id"
8
+ },
9
+ "creator": "http://purl.org/dc/terms/creator",
10
+ "description": "http://purl.org/dc/terms/description",
11
+ "Library": "http://example.org/vocab#Library",
12
+ "title": "http://purl.org/dc/terms/title"
13
+ },
14
+ "@graph": [
15
+ {
16
+ "@id": "http://example.com/library",
17
+ "@type": "Library",
18
+ "contains": "http://example.org/library/the-republic"
19
+ },
20
+ {
21
+ "@id": "http://example.org/library/the-republic",
22
+ "@type": "Book",
23
+ "creator": "Plato",
24
+ "title": "The Republic",
25
+ "contains": "http://example.org/library/the-republic#introduction"
26
+ },
27
+ {
28
+ "@id": "http://example.org/library/the-republic#introduction",
29
+ "@type": "Chapter",
30
+ "description": "An introductory chapter on The Republic.",
31
+ "title": "The Introduction"
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "@context": {
3
+ "Book": "http://example.org/vocab#Book",
4
+ "Chapter": "http://example.org/vocab#Chapter",
5
+ "contains": {"@id": "http://example.org/vocab#contains", "@type": "@id"},
6
+ "creator": "http://purl.org/dc/terms/creator",
7
+ "description": "http://purl.org/dc/terms/description",
8
+ "Library": "http://example.org/vocab#Library",
9
+ "title": "http://purl.org/dc/terms/title"
10
+ }
11
+ }
@@ -0,0 +1,24 @@
1
+ [
2
+ {
3
+ "@id": "http://example.com/library",
4
+ "@type": ["http://example.org/vocab#Library"],
5
+ "http://example.org/vocab#contains": [{
6
+ "@id": "http://example.org/library/the-republic"
7
+ }]
8
+ },
9
+ {
10
+ "@id": "http://example.org/library/the-republic",
11
+ "@type": ["http://example.org/vocab#Book"],
12
+ "http://purl.org/dc/terms/creator": [{"@value": "Plato"}],
13
+ "http://purl.org/dc/terms/title": [{"@value": "The Republic"}],
14
+ "http://example.org/vocab#contains": [{
15
+ "@id": "http://example.org/library/the-republic#introduction"
16
+ }]
17
+ },
18
+ {
19
+ "@id": "http://example.org/library/the-republic#introduction",
20
+ "@type": ["http://example.org/vocab#Chapter"],
21
+ "http://purl.org/dc/terms/description": [{"@value": "An introductory chapter on The Republic."}],
22
+ "http://purl.org/dc/terms/title": [{"@value": "The Introduction"}]
23
+ }
24
+ ]
@@ -0,0 +1,18 @@
1
+ {
2
+ "@context": {
3
+ "Book": "http://example.org/vocab#Book",
4
+ "Chapter": "http://example.org/vocab#Chapter",
5
+ "contains": "http://example.org/vocab#contains",
6
+ "creator": "http://purl.org/dc/terms/creator",
7
+ "description": "http://purl.org/dc/terms/description",
8
+ "Library": "http://example.org/vocab#Library",
9
+ "title": "http://purl.org/dc/terms/title"
10
+ },
11
+ "@type": "Library",
12
+ "contains": {
13
+ "@type": "Book",
14
+ "contains": {
15
+ "@type": "Chapter"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "@context": {
3
+ "Book": "http://example.org/vocab#Book",
4
+ "Chapter": "http://example.org/vocab#Chapter",
5
+ "contains": "http://example.org/vocab#contains",
6
+ "creator": "http://purl.org/dc/terms/creator",
7
+ "description": "http://purl.org/dc/terms/description",
8
+ "Library": "http://example.org/vocab#Library",
9
+ "title": "http://purl.org/dc/terms/title"
10
+ },
11
+ "@graph": [
12
+ {
13
+ "@id": "http://example.com/library",
14
+ "@type": "Library",
15
+ "contains": {
16
+ "@id": "http://example.org/library/the-republic",
17
+ "@type": "Book",
18
+ "contains": {
19
+ "@id": "http://example.org/library/the-republic#introduction",
20
+ "@type": "Chapter",
21
+ "description": "An introductory chapter on The Republic.",
22
+ "title": "The Introduction"
23
+ },
24
+ "creator": "Plato",
25
+ "title": "The Republic"
26
+ }
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "@context": {
3
+ "Book": "http://example.org/vocab#Book",
4
+ "Chapter": "http://example.org/vocab#Chapter",
5
+ "contains": {"@id": "http://example.org/vocab#contains", "@type": "@id"},
6
+ "creator": "http://purl.org/dc/terms/creator",
7
+ "description": "http://purl.org/dc/terms/description",
8
+ "Library": "http://example.org/vocab#Library",
9
+ "title": "http://purl.org/dc/terms/title"
10
+ },
11
+ "@graph":
12
+ [{
13
+ "@id": "http://example.com/library",
14
+ "@type": "Library",
15
+ "contains": "http://example.org/library/the-republic"
16
+ },
17
+ {
18
+ "@id": "http://example.org/library/the-republic",
19
+ "@type": "Book",
20
+ "creator": "Plato",
21
+ "title": "The Republic",
22
+ "contains": "http://example.org/library/the-republic#introduction"
23
+ },
24
+ {
25
+ "@id": "http://example.org/library/the-republic#introduction",
26
+ "@type": "Chapter",
27
+ "description": "An introductory chapter on The Republic.",
28
+ "title": "The Introduction"
29
+ }]
30
+ }
@@ -0,0 +1,15 @@
1
+ @prefix dc: <http://purl.org/dc/terms/> .
2
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3
+
4
+ <http://example.com/library> a <http://example.org/vocab#Library>;
5
+ <http://example.org/vocab#contains> <http://example.org/library/the-republic> .
6
+
7
+ <http://example.org/library/the-republic> a <http://example.org/vocab#Book>;
8
+ dc:title "The Republic";
9
+ <http://example.org/vocab#contains> <http://example.org/library/the-republic#introduction>;
10
+ dc:creator "Plato" .
11
+
12
+ <http://example.org/library/the-republic#introduction> a <http://example.org/vocab#Chapter>;
13
+ dc:title "The Introduction";
14
+ dc:description "An introductory chapter on The Republic." .
15
+
@@ -0,0 +1,20 @@
1
+ {
2
+ "@context": {
3
+ "id1": "http://example.com/id1",
4
+ "t1": "http://example.com/t1",
5
+ "t2": "http://example.com/t2",
6
+ "term1": "http://example.com/term",
7
+ "term2": {"@id": "http://example.com/term", "@type": "t2"},
8
+ "term3": {"@id": "http://example.com/term", "@language": "en"},
9
+ "term4": {"@id": "http://example.com/term", "@container": "@list"},
10
+ "term5": {"@id": "http://example.com/term", "@language": null},
11
+ "@language": "de"
12
+ },
13
+ "@id": "id1",
14
+ "@type": "t1",
15
+ "term1": "v1",
16
+ "term2": "v2",
17
+ "term3": "v3",
18
+ "term4": [ 1, 2 ],
19
+ "term5": [ "v5", "plain literal" ]
20
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "@context": {
3
+ "id1": "http://example.com/id1",
4
+ "t1": "http://example.com/t1",
5
+ "t2": "http://example.com/t2",
6
+ "term1": "http://example.com/term",
7
+ "term2": {"@id": "http://example.com/term", "@type": "t2"},
8
+ "term3": {"@id": "http://example.com/term", "@language": "en"},
9
+ "term4": {"@id": "http://example.com/term", "@container": "@list"},
10
+ "term5": {"@id": "http://example.com/term", "@language": null},
11
+ "@language": "de"
12
+ }
13
+ }
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "@id": "http://example.com/id1",
4
+ "@type": ["http://example.com/t1"],
5
+ "http://example.com/term": [
6
+ {"@value": "v1","@language": "de"},
7
+ {"@value": "v2","@type": "http://example.com/t2"},
8
+ {"@value": "v3","@language": "en"},
9
+ {"@list": [{"@value": 1},{"@value": 2}]},
10
+ {"@value": "v5"},
11
+ {"@value": "plain literal"}
12
+ ]
13
+ }
14
+ ]
@@ -0,0 +1,12 @@
1
+ [{
2
+ "@id": "http://example.com/id1",
3
+ "@type": ["http://example.com/t1"],
4
+ "http://example.com/term": [
5
+ {"@value": "v1", "@language": "de"},
6
+ {"@value": "v2", "@type": "http://example.com/t2"},
7
+ {"@value": "v3", "@language": "en"},
8
+ {"@list": [1, 2]},
9
+ {"@value": "v5"},
10
+ {"@value": "plain literal"}
11
+ ]
12
+ }]
@@ -0,0 +1,640 @@
1
+ # coding: utf-8
2
+ $:.unshift "."
3
+ require 'spec_helper'
4
+
5
+ describe JSON::LD::API do
6
+ before(:each) { @debug = []}
7
+
8
+ context ".toRDF" do
9
+ context "unnamed nodes" do
10
+ {
11
+ "no @id" => [
12
+ %q({
13
+ "http://example.com/foo": "bar"
14
+ }),
15
+ %q([ <http://example.com/foo> "bar"] .)
16
+ ],
17
+ "@id with _:a" => [
18
+ %q({
19
+ "@id": "_:a",
20
+ "http://example.com/foo": "bar"
21
+ }),
22
+ %q([ <http://example.com/foo> "bar"] .)
23
+ ],
24
+ }.each do |title, (js, nt)|
25
+ it title do
26
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
27
+ end
28
+ end
29
+ end
30
+
31
+ context "nodes with @id" do
32
+ {
33
+ "with IRI" => [
34
+ %q({
35
+ "@id": "http://example.com/a",
36
+ "http://example.com/foo": "bar"
37
+ }),
38
+ %q(<http://example.com/a> <http://example.com/foo> "bar" .)
39
+ ],
40
+ "with empty term" => [
41
+ %({
42
+ "@context": {"": "http://example.com/"},
43
+ "@id": "",
44
+ "@type": "#{RDF::RDFS.Resource}"
45
+ }),
46
+ %(<http://example.com/> a <#{RDF::RDFS.Resource}>)
47
+ ],
48
+ }.each do |title, (js, nt)|
49
+ it title do
50
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
51
+ end
52
+ end
53
+
54
+ context "with relative IRIs" do
55
+ {
56
+ "base" => [
57
+ %({
58
+ "@id": "",
59
+ "@type": "#{RDF::RDFS.Resource}"
60
+ }),
61
+ %(<http://example.org/> a <#{RDF::RDFS.Resource}>)
62
+ ],
63
+ "relative" => [
64
+ %({
65
+ "@id": "a/b",
66
+ "@type": "#{RDF::RDFS.Resource}"
67
+ }),
68
+ %(<http://example.org/a/b> a <#{RDF::RDFS.Resource}>)
69
+ ],
70
+ "hash" => [
71
+ %({
72
+ "@id": "#a",
73
+ "@type": "#{RDF::RDFS.Resource}"
74
+ }),
75
+ %(<http://example.org/#a> a <#{RDF::RDFS.Resource}>)
76
+ ],
77
+ }.each do |title, (js, nt)|
78
+ it title do
79
+ parse(js, :base => "http://example.org/").should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ context "typed nodes" do
86
+ {
87
+ "one type" => [
88
+ %q({
89
+ "@type": "http://example.com/foo"
90
+ }),
91
+ %q([ a <http://example.com/foo> ] .)
92
+ ],
93
+ "two types" => [
94
+ %q({
95
+ "@type": ["http://example.com/foo", "http://example.com/baz"]
96
+ }),
97
+ %q([ a <http://example.com/foo>, <http://example.com/baz> ] .)
98
+ ],
99
+ }.each do |title, (js, nt)|
100
+ it title do
101
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
102
+ end
103
+ end
104
+ end
105
+
106
+ context "key/value" do
107
+ {
108
+ "string" => [
109
+ %q({
110
+ "http://example.com/foo": "bar"
111
+ }),
112
+ %q([ <http://example.com/foo> "bar" ] .)
113
+ ],
114
+ "strings" => [
115
+ %q({
116
+ "http://example.com/foo": ["bar", "baz"]
117
+ }),
118
+ %q([ <http://example.com/foo> "bar", "baz" ] .)
119
+ ],
120
+ "IRI" => [
121
+ %q({
122
+ "http://example.com/foo": {"@id": "http://example.com/bar"}
123
+ }),
124
+ %q([ <http://example.com/foo> <http://example.com/bar> ] .)
125
+ ],
126
+ "IRIs" => [
127
+ %q({
128
+ "http://example.com/foo": [{"@id": "http://example.com/bar"}, {"@id": "http://example.com/baz"}]
129
+ }),
130
+ %q([ <http://example.com/foo> <http://example.com/bar>, <http://example.com/baz> ] .)
131
+ ],
132
+ }.each do |title, (js, nt)|
133
+ it title do
134
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
135
+ end
136
+ end
137
+ end
138
+
139
+ context "literals" do
140
+ {
141
+ "plain literal" =>
142
+ [
143
+ %q({"@id": "http://greggkellogg.net/foaf#me", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"}),
144
+ %q(<http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .)
145
+ ],
146
+ "explicit plain literal" =>
147
+ [
148
+ %q({"http://xmlns.com/foaf/0.1/name": {"@value": "Gregg Kellogg"}}),
149
+ %q(_:a <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .)
150
+ ],
151
+ "language tagged literal" =>
152
+ [
153
+ %q({"http://www.w3.org/2000/01/rdf-schema#label": {"@value": "A plain literal with a lang tag.", "@language": "en-us"}}),
154
+ %q(_:a <http://www.w3.org/2000/01/rdf-schema#label> "A plain literal with a lang tag."@en-us .)
155
+ ],
156
+ "I18N literal with language" =>
157
+ [
158
+ %q([{
159
+ "@id": "http://greggkellogg.net/foaf#me",
160
+ "http://xmlns.com/foaf/0.1/knows": {"@id": "http://www.ivan-herman.net/foaf#me"}
161
+ },{
162
+ "@id": "http://www.ivan-herman.net/foaf#me",
163
+ "http://xmlns.com/foaf/0.1/name": {"@value": "Herman Iván", "@language": "hu"}
164
+ }]),
165
+ %q(
166
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.net/foaf#me> .
167
+ <http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Herman Iv\u00E1n"@hu .
168
+ )
169
+ ],
170
+ "explicit datatyped literal" =>
171
+ [
172
+ %q({
173
+ "@id": "http://greggkellogg.net/foaf#me",
174
+ "http://purl.org/dc/terms/created": {"@value": "1957-02-27", "@type": "http://www.w3.org/2001/XMLSchema#date"}
175
+ }),
176
+ %q(
177
+ <http://greggkellogg.net/foaf#me> <http://purl.org/dc/terms/created> "1957-02-27"^^<http://www.w3.org/2001/XMLSchema#date> .
178
+ )
179
+ ],
180
+ }.each do |title, (js, nt)|
181
+ it title do
182
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
183
+ end
184
+ end
185
+ end
186
+
187
+ context "prefixes" do
188
+ {
189
+ "empty prefix" => [
190
+ %q({"@context": {"": "http://example.com/default#"}, ":foo": "bar"}),
191
+ %q(_:a <http://example.com/default#foo> "bar" .)
192
+ ],
193
+ "empty suffix" => [
194
+ %q({"@context": {"prefix": "http://example.com/default#"}, "prefix:": "bar"}),
195
+ %q(_:a <http://example.com/default#> "bar" .)
196
+ ],
197
+ "prefix:suffix" => [
198
+ %q({"@context": {"prefix": "http://example.com/default#"}, "prefix:foo": "bar"}),
199
+ %q(_:a <http://example.com/default#foo> "bar" .)
200
+ ]
201
+ }.each_pair do |title, (js, nt)|
202
+ it title do
203
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
204
+ end
205
+ end
206
+ end
207
+
208
+ context "overriding keywords" do
209
+ {
210
+ "'url' for @id, 'a' for @type" => [
211
+ %q({
212
+ "@context": {"url": "@id", "a": "@type", "name": "http://schema.org/name"},
213
+ "url": "http://example.com/about#gregg",
214
+ "a": "http://schema.org/Person",
215
+ "name": "Gregg Kellogg"
216
+ }),
217
+ %q(
218
+ <http://example.com/about#gregg> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
219
+ <http://example.com/about#gregg> <http://schema.org/name> "Gregg Kellogg" .
220
+ )
221
+ ],
222
+ }.each do |title, (js, nt)|
223
+ it title do
224
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
225
+ end
226
+ end
227
+ end
228
+
229
+ context "chaining" do
230
+ {
231
+ "explicit subject" =>
232
+ [
233
+ %q({
234
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
235
+ "@id": "http://greggkellogg.net/foaf#me",
236
+ "foaf:knows": {
237
+ "@id": "http://www.ivan-herman.net/foaf#me",
238
+ "foaf:name": "Ivan Herman"
239
+ }
240
+ }),
241
+ %q(
242
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.net/foaf#me> .
243
+ <http://www.ivan-herman.net/foaf#me> <http://xmlns.com/foaf/0.1/name> "Ivan Herman" .
244
+ )
245
+ ],
246
+ "implicit subject" =>
247
+ [
248
+ %q({
249
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
250
+ "@id": "http://greggkellogg.net/foaf#me",
251
+ "foaf:knows": {
252
+ "foaf:name": "Manu Sporny"
253
+ }
254
+ }),
255
+ %q(
256
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> _:a .
257
+ _:a <http://xmlns.com/foaf/0.1/name> "Manu Sporny" .
258
+ )
259
+ ],
260
+ }.each do |title, (js, nt)|
261
+ it title do
262
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
263
+ end
264
+ end
265
+ end
266
+
267
+ context "multiple values" do
268
+ {
269
+ "literals" =>
270
+ [
271
+ %q({
272
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
273
+ "@id": "http://greggkellogg.net/foaf#me",
274
+ "foaf:knows": ["Manu Sporny", "Ivan Herman"]
275
+ }),
276
+ %q(
277
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> "Manu Sporny" .
278
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> "Ivan Herman" .
279
+ )
280
+ ],
281
+ }.each do |title, (js, nt)|
282
+ it title do
283
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
284
+ end
285
+ end
286
+ end
287
+
288
+ context "lists" do
289
+ {
290
+ "Empty" =>
291
+ [
292
+ %q({
293
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
294
+ "@id": "http://greggkellogg.net/foaf#me",
295
+ "foaf:knows": {"@list": []}
296
+ }),
297
+ %q(
298
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
299
+ )
300
+ ],
301
+ "single value" =>
302
+ [
303
+ %q({
304
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
305
+ "@id": "http://greggkellogg.net/foaf#me",
306
+ "foaf:knows": {"@list": ["Manu Sporny"]}
307
+ }),
308
+ %q(
309
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> _:a .
310
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Manu Sporny" .
311
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
312
+ )
313
+ ],
314
+ "single value (with coercion)" =>
315
+ [
316
+ %q({
317
+ "@context": {
318
+ "foaf": "http://xmlns.com/foaf/0.1/",
319
+ "foaf:knows": { "@container": "@list"}
320
+ },
321
+ "@id": "http://greggkellogg.net/foaf#me",
322
+ "foaf:knows": ["Manu Sporny"]
323
+ }),
324
+ %q(
325
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> _:a .
326
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Manu Sporny" .
327
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
328
+ )
329
+ ],
330
+ "multiple values" =>
331
+ [
332
+ %q({
333
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
334
+ "@id": "http://greggkellogg.net/foaf#me",
335
+ "foaf:knows": {"@list": ["Manu Sporny", "Dave Longley"]}
336
+ }),
337
+ %q(
338
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> _:a .
339
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Manu Sporny" .
340
+ _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b .
341
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Dave Longley" .
342
+ _:b <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
343
+ )
344
+ ],
345
+ }.each do |title, (js, nt)|
346
+ it title do
347
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
348
+ end
349
+ end
350
+ end
351
+
352
+ context "context" do
353
+ {
354
+ "@id coersion" =>
355
+ [
356
+ %q({
357
+ "@context": {
358
+ "knows": {"@id": "http://xmlns.com/foaf/0.1/knows", "@type": "@id"}
359
+ },
360
+ "@id": "http://greggkellogg.net/foaf#me",
361
+ "knows": "http://www.ivan-herman.net/foaf#me"
362
+ }),
363
+ %q(
364
+ <http://greggkellogg.net/foaf#me> <http://xmlns.com/foaf/0.1/knows> <http://www.ivan-herman.net/foaf#me> .
365
+ )
366
+ ],
367
+ "datatype coersion" =>
368
+ [
369
+ %q({
370
+ "@context": {
371
+ "dcterms": "http://purl.org/dc/terms/",
372
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
373
+ "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:date"}
374
+ },
375
+ "@id": "http://greggkellogg.net/foaf#me",
376
+ "created": "1957-02-27"
377
+ }),
378
+ %q(
379
+ <http://greggkellogg.net/foaf#me> <http://purl.org/dc/terms/created> "1957-02-27"^^<http://www.w3.org/2001/XMLSchema#date> .
380
+ )
381
+ ],
382
+ "sub-objects with context" => [
383
+ %q({
384
+ "@context": {"foo": "http://example.com/foo"},
385
+ "foo": {
386
+ "@context": {"foo": "http://example.org/foo"},
387
+ "foo": "bar"
388
+ }
389
+ }),
390
+ %q(
391
+ _:a <http://example.com/foo> _:b .
392
+ _:b <http://example.org/foo> "bar" .
393
+ )
394
+ ],
395
+ "contexts with a list processed in order" => [
396
+ %q({
397
+ "@context": [
398
+ {"foo": "http://example.com/foo"},
399
+ {"foo": "http://example.org/foo"}
400
+ ],
401
+ "foo": "bar"
402
+ }),
403
+ %q(
404
+ _:b <http://example.org/foo> "bar" .
405
+ )
406
+ ],
407
+ "term definition resolves term as IRI" => [
408
+ %q({
409
+ "@context": [
410
+ {"foo": "http://example.com/foo"},
411
+ {"bar": "foo"}
412
+ ],
413
+ "bar": "bar"
414
+ }),
415
+ %q(
416
+ _:b <http://example.com/foo> "bar" .
417
+ )
418
+ ],
419
+ "term definition resolves prefix as IRI" => [
420
+ %q({
421
+ "@context": [
422
+ {"foo": "http://example.com/foo#"},
423
+ {"bar": "foo:bar"}
424
+ ],
425
+ "bar": "bar"
426
+ }),
427
+ %q(
428
+ _:b <http://example.com/foo#bar> "bar" .
429
+ )
430
+ ],
431
+ "IRI resolution uses term from current context, not active context" => [
432
+ %q({
433
+ "@context": [
434
+ {"foo": "not-this#"},
435
+ {
436
+ "foo": "http://example.com/foo#",
437
+ "bar": "foo:bar"
438
+ }
439
+ ],
440
+ "bar": "bar"
441
+ }),
442
+ %q(
443
+ _:b <http://example.com/foo#bar> "bar" .
444
+ )
445
+ ],
446
+ "@language" => [
447
+ %q({
448
+ "@context": {
449
+ "foo": "http://example.com/foo#",
450
+ "@language": "en"
451
+ },
452
+ "foo:bar": "baz"
453
+ }),
454
+ %q(
455
+ _:a <http://example.com/foo#bar> "baz"@en .
456
+ )
457
+ ],
458
+ "@language with override" => [
459
+ %q({
460
+ "@context": {
461
+ "foo": "http://example.com/foo#",
462
+ "@language": "en"
463
+ },
464
+ "foo:bar": {"@value": "baz", "@language": "fr"}
465
+ }),
466
+ %q(
467
+ _:a <http://example.com/foo#bar> "baz"@fr .
468
+ )
469
+ ],
470
+ "@language with plain" => [
471
+ %q({
472
+ "@context": {
473
+ "foo": "http://example.com/foo#",
474
+ "@language": "en"
475
+ },
476
+ "foo:bar": {"@value": "baz"}
477
+ }),
478
+ %q(
479
+ _:a <http://example.com/foo#bar> "baz" .
480
+ )
481
+ ],
482
+ }.each do |title, (js, nt)|
483
+ it title do
484
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
485
+ end
486
+ end
487
+
488
+ context "coercion" do
489
+ context "term def with @id + @type" do
490
+ {
491
+ "dt with term" => [
492
+ %q({
493
+ "@context": [
494
+ {"date": "http://www.w3.org/2001/XMLSchema#date", "term": "http://example.org/foo#"},
495
+ {"foo": {"@id": "term", "@type": "date"}}
496
+ ],
497
+ "foo": "bar"
498
+ }),
499
+ %q(
500
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
501
+ [ <http://example.org/foo#> "bar"^^xsd:date ] .
502
+ )
503
+ ],
504
+ "@id with term" => [
505
+ %q({
506
+ "@context": [
507
+ {"foo": {"@id": "http://example.org/foo#bar", "@type": "@id"}}
508
+ ],
509
+ "foo": "http://example.org/foo#bar"
510
+ }),
511
+ %q(
512
+ _:a <http://example.org/foo#bar> <http://example.org/foo#bar> .
513
+ )
514
+ ],
515
+ "coercion without term definition" => [
516
+ %q({
517
+ "@context": [
518
+ {
519
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
520
+ "dc": "http://purl.org/dc/terms/"
521
+ },
522
+ {
523
+ "dc:date": {"@type": "xsd:date"}
524
+ }
525
+ ],
526
+ "dc:date": "2011-11-23"
527
+ }),
528
+ %q(
529
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
530
+ @prefix dc: <http://purl.org/dc/terms/> .
531
+ [ dc:date "2011-11-23"^^xsd:date] .
532
+ )
533
+ ],
534
+ }.each do |title, (js, nt)|
535
+ it title do
536
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
537
+ end
538
+ end
539
+ end
540
+ end
541
+
542
+ context "lists" do
543
+ context "term def with @id + @type + @container" do
544
+ {
545
+ "dt with term" => [
546
+ %q({
547
+ "@context": [
548
+ {"date": "http://www.w3.org/2001/XMLSchema#date", "term": "http://example.org/foo#"},
549
+ {"foo": {"@id": "term", "@type": "date", "@container": "@list"}}
550
+ ],
551
+ "foo": ["bar"]
552
+ }),
553
+ %q(
554
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
555
+ [ <http://example.org/foo#> ("bar"^^xsd:date) ] .
556
+ )
557
+ ],
558
+ "@id with term" => [
559
+ %q({
560
+ "@context": [
561
+ {"foo": {"@id": "http://example.org/foo#bar", "@type": "@id", "@container": "@list"}}
562
+ ],
563
+ "foo": ["http://example.org/foo#bar"]
564
+ }),
565
+ %q(
566
+ _:a <http://example.org/foo#bar> (<http://example.org/foo#bar>) .
567
+ )
568
+ ],
569
+ }.each do |title, (js, nt)|
570
+ it title do
571
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
572
+ end
573
+ end
574
+ end
575
+ end
576
+ end
577
+
578
+ context "advanced features" do
579
+ {
580
+ "number syntax (decimal)" =>
581
+ [
582
+ %q({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3}),
583
+ %q(_:a <http://example/measure#cups> "5.3"^^<http://www.w3.org/2001/XMLSchema#double> .)
584
+ ],
585
+ "number syntax (double)" =>
586
+ [
587
+ %q({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3e0}),
588
+ %q(_:a <http://example/measure#cups> "5.3"^^<http://www.w3.org/2001/XMLSchema#double> .)
589
+ ],
590
+ "number syntax (integer)" =>
591
+ [
592
+ %q({"@context": { "chem": "http://example/chem#"}, "chem:protons": 12}),
593
+ %q(_:a <http://example/chem#protons> "12"^^<http://www.w3.org/2001/XMLSchema#integer> .)
594
+ ],
595
+ "boolan syntax" =>
596
+ [
597
+ %q({"@context": { "sensor": "http://example/sensor#"}, "sensor:active": true}),
598
+ %q(_:a <http://example/sensor#active> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .)
599
+ ],
600
+ "Array top element" =>
601
+ [
602
+ %q([
603
+ {"@id": "http://example.com/#me", "@type": "http://xmlns.com/foaf/0.1/Person"},
604
+ {"@id": "http://example.com/#you", "@type": "http://xmlns.com/foaf/0.1/Person"}
605
+ ]),
606
+ %q(
607
+ <http://example.com/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
608
+ <http://example.com/#you> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
609
+ )
610
+ ],
611
+ "@graph with array of objects value" =>
612
+ [
613
+ %q({
614
+ "@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
615
+ "@graph": [
616
+ {"@id": "http://example.com/#me", "@type": "foaf:Person"},
617
+ {"@id": "http://example.com/#you", "@type": "foaf:Person"}
618
+ ]
619
+ }),
620
+ %q(
621
+ <http://example.com/#me> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
622
+ <http://example.com/#you> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
623
+ )
624
+ ],
625
+ }.each do |title, (js, nt)|
626
+ it title do
627
+ parse(js).should be_equivalent_graph(nt, :trace => @debug, :inputDocument => js)
628
+ end
629
+ end
630
+ end
631
+ end
632
+
633
+ def parse(input, options = {})
634
+ @debug = []
635
+ graph = options[:graph] || RDF::Graph.new
636
+ options = {:debug => @debug, :validate => true, :canonicalize => false}.merge(options)
637
+ JSON::LD::API.toRDF(StringIO.new(input), nil, nil, options) {|st| graph << st}
638
+ graph
639
+ end
640
+ end