ldpath 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module Ldpath
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -4,172 +4,232 @@ require 'parslet/convenience'
4
4
  describe Ldpath::Parser do
5
5
  subject { Ldpath::Parser.new }
6
6
  context ".parse" do
7
-
8
- describe "lines" do
7
+ describe "doc" do
9
8
  it "should parse line-oriented data" do
10
- subject.lines.parse " \n \n"
9
+ subject.doc.parse " \n \n"
11
10
  end
12
11
  end
13
-
14
- describe "line" do
15
- it "may be a line ending in a newline" do
16
- subject.line.parse " \n"
17
- end
18
-
19
- it "may be a line ending in EOF" do
20
- subject.line.parse("/* abc */")
21
- end
22
- end
23
-
24
- describe "newline" do
12
+
13
+ describe "eol" do
25
14
  it 'may be a \n character' do
26
- subject.newline.parse("\n")
15
+ subject.eol.parse("\n")
27
16
  end
28
-
17
+
29
18
  it 'may be a \n\r' do
30
- subject.newline.parse("\n\r")
19
+ subject.eol.parse("\n\r")
31
20
  end
32
21
  end
33
-
22
+
34
23
  describe "eof" do
35
24
  it "is the eof" do
36
25
  subject.eof.parse ""
37
26
  end
38
27
  end
39
-
28
+
40
29
  describe "wsp" do
41
30
  it "may be a space" do
42
31
  subject.wsp.parse " "
43
32
  end
44
-
33
+
45
34
  it "may be a tab" do
46
35
  subject.wsp.parse "\t"
47
36
  end
48
-
37
+
49
38
  it "may be a multiline comment" do
50
39
  subject.wsp.parse "/* xyz */"
51
40
  end
52
- end
53
-
54
- describe "expression" do
55
- it "may be whitespace" do
56
- subject.expression.parse " "
41
+
42
+ it "may be a single line comment" do
43
+ subject.wsp.parse "# xyz"
57
44
  end
58
-
45
+ end
46
+
47
+ describe "directive" do
59
48
  it "may be a namespace declaration" do
60
- subject.expression.parse "@prefix x : info:x ;"
49
+ subject.directive.parse "@prefix x : <info:x> ;"
61
50
  end
62
-
51
+
63
52
  it "may be a graph" do
64
- subject.expression.parse "@graph test:context, foo:ctx, test:bar ;"
53
+ subject.directive.parse "@graph test:context, foo:ctx, test:bar ;"
65
54
  end
66
-
67
55
 
68
56
  it "may be a filter" do
69
- subject.expression.parse "@filter is-a test:Context ;"
57
+ subject.directive.parse "@filter is-a test:Context ;"
58
+ end
59
+ end
60
+
61
+ describe "prefixID" do
62
+ it "should parse prefix mappings" do
63
+ subject.prefixID.parse "@prefix x : <info:x> ;"
70
64
  end
71
-
65
+
66
+ it "should parse the null prefix" do
67
+ subject.prefixID.parse "@prefix : <info:x> ;"
68
+ end
69
+ end
70
+
71
+ describe "statement" do
72
72
  it "may be a mapping" do
73
- subject.expression.parse "id = . ;"
73
+ subject.statement.parse "id = . ;"
74
74
  end
75
75
  end
76
-
77
- describe "uri" do
78
- it "may be a bracketed uri" do
79
- result = subject.uri.parse "<info:x>"
80
- expect(result[:uri]).to eq "info:x"
81
- end
82
-
83
- it "may be a namespace and local name" do
84
- result = subject.uri.parse "info:x"
85
- expect(result[:uri][:prefix]).to eq "info"
86
- expect(result[:uri][:localName]).to eq "x"
76
+
77
+ describe "iri" do
78
+ it "may be an iriref" do
79
+ result = subject.iri.parse "<info:x>"
80
+ expect(result[:iri]).to eq "info:x"
81
+ end
82
+
83
+ it "may be a prefixed name" do
84
+ result = subject.iri.parse "info:x"
85
+ expect(result[:iri][:prefix]).to eq "info"
86
+ expect(result[:iri][:localName]).to eq "x"
87
87
  end
88
88
  end
89
-
89
+
90
90
  describe "identifier" do
91
91
  it "must start with an alphanumeric character" do
92
92
  subject.identifier.parse "a"
93
93
  subject.identifier.parse "J"
94
- subject.identifier.parse "4"
95
- subject.identifier.parse "_"
96
94
  end
97
-
95
+
98
96
  it "may have additional alphanumeric characters" do
99
97
  subject.identifier.parse "aJ0_.-"
100
98
  end
99
+
100
+ it "may not end in a dot" do
101
+ expect { subject.identifier.parse "aJ0_.-." }.to raise_error
102
+ end
101
103
  end
102
-
103
- describe "strlit" do
104
+
105
+ describe "string" do
104
106
  it "is the content between \"" do
105
- subject.strlit.parse '"abc"'
107
+ subject.string.parse '"abc"'
106
108
  end
107
-
109
+
108
110
  it "should handle escaped characters" do
109
- subject.strlit.parse '"a\"b"'
111
+ subject.string.parse '"a\"b"'
112
+ end
113
+
114
+ it "should handle single quoted strings" do
115
+ subject.string.parse "'abc'"
116
+ end
117
+
118
+ it "should handle long strings" do
119
+ str = <<-EOF
120
+ """
121
+ xyz
122
+ """
123
+ EOF
124
+
125
+ subject.string.parse str.strip
126
+ end
127
+
128
+ it "should handle long single-quoted strings" do
129
+ str = <<-EOF
130
+ '''
131
+ xyz
132
+ '''
133
+ EOF
134
+
135
+ subject.string.parse str.strip
110
136
  end
111
137
  end
112
-
138
+
113
139
  describe "node" do
114
140
  it "may be a uri" do
115
141
  subject.node.parse "info:x"
116
142
  end
117
-
143
+
118
144
  it "may be a literal" do
119
145
  subject.node.parse '"a"'
120
146
  end
147
+
148
+ it "may be a typed literal" do
149
+ subject.node.parse '"a"^^info:x'
150
+ end
151
+
152
+ it "may be a language literal" do
153
+ subject.node.parse '"a"@en'
154
+ end
155
+
156
+ it "may be a numeric literal" do
157
+ subject.node.parse '0'
158
+ end
159
+
160
+ it "may be a boolean literal" do
161
+ subject.node.parse 'true'
162
+ end
121
163
  end
122
-
123
- describe "selectors" do
164
+
165
+ describe "selectors" do
124
166
  it "should parse mappings" do
125
167
  subject.parse("xyz = . ;\n")
126
168
  end
127
-
169
+
128
170
  it "should parse wildcards" do
129
171
  subject.parse("xyz = * ;\n")
130
172
  end
131
-
173
+
132
174
  it "should parse reverse properties" do
133
175
  subject.parse("xyz = ^info:a ;\n")
134
176
  end
135
-
177
+
136
178
  it "should parse uri mappings" do
137
179
  subject.parse("xyz = <info:a> ;\n")
138
180
  end
139
-
181
+
140
182
  it "should parse path mappings" do
141
183
  subject.mapping.parse("xyz = info:a / info:b :: a:b;")
142
184
  end
143
-
185
+
186
+ it "should parse path selectors" do
187
+ subject.selector.parse("info:a / info:b")
188
+ end
189
+
144
190
  it "recursive_path_selector" do
145
191
  subject.recursive_path_selector.parse("(foo:go)*")
146
192
  end
147
-
193
+
148
194
  it "function_selector" do
149
195
  subject.selector.parse('fn:concat(foaf:givename," ",foaf:surname)')
150
196
  end
151
-
197
+
152
198
  it "tap_selector" do
153
199
  subject.selector.parse('?<a><info:a>')
154
200
  end
155
-
201
+
156
202
  it "loose_selector" do
157
203
  subject.selector.parse('~<info:a>')
158
204
  end
159
205
  end
160
-
206
+
161
207
  describe "integration tests" do
208
+ it "should parse a simple example" do
209
+ tree = subject.parse <<-EOF
210
+ @prefix dcterms : <http://purl.org/dc/terms/> ;
211
+ topic = <http://xmlns.com/foaf/0.1/primaryTopic> :: xsd:string ;
212
+ EOF
213
+ expect(tree.length).to eq 2
214
+ expect(tree.first).to include :prefixID
215
+ expect(tree.first[:prefixID]).to include id: 'dcterms'
216
+ expect(tree.first[:prefixID]).to include iri: 'http://purl.org/dc/terms/'
217
+ expect(tree.last).to include :mapping
218
+ expect(tree.last[:mapping]).to include name: 'topic'
219
+ expect(tree.last[:mapping]).to include :selector
220
+ end
221
+
162
222
  it "should parse the foaf example" do
163
223
  subject.parse File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "foaf_example.program")))
164
224
  end
165
-
225
+
166
226
  it "should parse the program.ldpath" do
167
227
  subject.parse File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "program.ldpath")))
168
228
  end
169
-
229
+
170
230
  it "should parse the namespaces.ldpath" do
171
- subject.parse_with_debug File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "namespaces.ldpath")))
231
+ subject.parse File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "namespaces.ldpath")))
172
232
  end
173
- end
233
+ end
174
234
  end
175
235
  end
@@ -25,16 +25,16 @@ is_test = .[dcterms:title is "Hello, world!"] ;
25
25
  is_not_test = .[!(dcterms:title is "Hello, world!")] ;
26
26
  EOF
27
27
  end
28
-
28
+
29
29
  let(:object) { RDF::URI.new("info:a") }
30
30
  let(:parent) { RDF::URI.new("info:b") }
31
31
  let(:child) { RDF::URI.new("info:c") }
32
32
  let(:grandparent) { RDF::URI.new("info:d") }
33
-
33
+
34
34
  let(:graph) do
35
35
  RDF::Graph.new
36
36
  end
37
-
37
+
38
38
  it "should work" do
39
39
  graph << [object, RDF::DC.title, "Hello, world!"]
40
40
  graph << [object, RDF::DC.isPartOf, parent]
@@ -70,7 +70,7 @@ EOF
70
70
  expect(result["is_not_test"]).to be_empty
71
71
  end
72
72
  end
73
-
73
+
74
74
  describe "functions" do
75
75
  let(:program) do
76
76
  Ldpath::Program.parse <<-EOF
@@ -94,7 +94,7 @@ EOF
94
94
  end
95
95
 
96
96
  let(:object) { RDF::URI.new("info:a") }
97
-
97
+
98
98
  let(:graph) do
99
99
  graph = RDF::Graph.new
100
100
  graph << [object, RDF::DC.title, "Hello, world!"]
@@ -137,7 +137,7 @@ EOF
137
137
  expect(subject).to include "first_b" => ["b"]
138
138
  end
139
139
  end
140
-
140
+
141
141
  describe "last" do
142
142
  it "should take the last value" do
143
143
  expect(subject).to include "last_b" => ["b"]
@@ -182,17 +182,15 @@ EOF
182
182
  end
183
183
  end
184
184
  end
185
-
185
+
186
186
  describe "Data loading" do
187
187
  subject do
188
-
189
188
  Ldpath::Program.parse <<-EOF
190
189
  @prefix dcterms : <http://purl.org/dc/terms/> ;
191
190
  title = foaf:primaryTopic / dc:title :: xsd:string ;
192
191
  EOF
193
-
194
192
  end
195
-
193
+
196
194
  it "should work" do
197
195
  result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5.rdf")
198
196
  expect(result["title"]).to match_array "Huw Stephens"
@@ -217,17 +215,17 @@ EOF
217
215
  let(:object) { RDF::URI.new("info:a") }
218
216
  let(:child) { RDF::URI.new("info:b") }
219
217
  let(:grandchild) { RDF::URI.new("info:c") }
220
-
218
+
221
219
  let(:graph) do
222
220
  graph = RDF::Graph.new
223
-
221
+
224
222
  graph << [object, RDF::DC.title, "Object"]
225
223
  graph << [child, RDF::DC.title, "Child"]
226
224
  graph << [object, RDF::DC.hasPart, child]
227
225
 
228
226
  graph
229
227
  end
230
-
228
+
231
229
  subject do
232
230
  Ldpath::Program.parse <<-EOF
233
231
  @prefix dcterms : <http://purl.org/dc/terms/> ;
@@ -243,22 +241,22 @@ child_title_with_tap = dcterms:hasPart / ?<tap>fn:predicates() / dcterms:title :
243
241
  expect(result["tap"]).to eq ["http://purl.org/dc/terms/title"]
244
242
  end
245
243
  end
246
-
244
+
247
245
  describe "loose selector" do
248
246
  let(:object) { RDF::URI.new("info:a") }
249
247
  let(:child) { RDF::URI.new("info:b") }
250
248
  let(:grandchild) { RDF::URI.new("info:c") }
251
-
249
+
252
250
  let(:graph) do
253
251
  graph = RDF::Graph.new
254
-
252
+
255
253
  graph << [object, RDF::DC.title, "Object"]
256
254
  graph << [child, RDF::DC.title, "Child"]
257
255
  graph << [object, RDF::DC.hasPart, child]
258
256
 
259
257
  graph
260
258
  end
261
-
259
+
262
260
  subject do
263
261
  Ldpath::Program.parse <<-EOF
264
262
  @prefix dcterms : <http://purl.org/dc/terms/> ;
@@ -275,7 +273,6 @@ title_with_loose = ~dc:title :: xsd:string ;
275
273
  end
276
274
 
277
275
  describe "filter" do
278
-
279
276
  subject do
280
277
  Ldpath::Program.parse <<-EOF
281
278
  @prefix dcterms : <http://purl.org/dc/terms/> ;
@@ -287,28 +284,25 @@ title_with_loose = ~dc:title :: xsd:string ;
287
284
 
288
285
  let(:object) { RDF::URI.new("info:a") }
289
286
  let(:other_object) { RDF::URI.new("info:b") }
290
-
291
-
287
+
292
288
  let(:graph) do
293
289
  graph = RDF::Graph.new
294
-
290
+
295
291
  graph << [object, RDF.type, RDF::DC.Agent]
296
292
  graph << [object, RDF::DC.title, "Title"]
297
293
  graph << [other_object, RDF::DC.title, "Other Title"]
298
294
 
299
295
  graph
300
296
  end
301
-
297
+
302
298
  it "should work" do
303
299
  result = subject.evaluate object, graph
304
300
  expect(result["title"]).to eq ["Title"]
305
301
  end
306
-
302
+
307
303
  it "filters objects that don't match" do
308
304
  result = subject.evaluate other_object, graph
309
305
  expect(result).to be_empty
310
306
  end
311
-
312
-
313
307
  end
314
308
  end