ldpath 0.1.0 → 0.2.0

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.
@@ -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