ldpath 0.0.2 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: feb1911da55e6e56d33cb8bccea249060b59f7da
4
- data.tar.gz: 87eab8d2813362a18c9ff45707325542f45ec657
3
+ metadata.gz: 76772761e5cb85b3f0d16df78e8673524dd4849b
4
+ data.tar.gz: 292da39f546dd6151e6754a060ffadf9464df44d
5
5
  SHA512:
6
- metadata.gz: 111dbf2d32a03ab3199d622f1ea78c94322a24733e0120c537ed43d2f42c592e650ab72e67f067cf6578d4be2ddcdbfd6756d09369c2e9d8c1fb7757f7624bb2
7
- data.tar.gz: 5dc5e8488936d2d14114522cb1880a05e165edc317b6a433b247dff8e235af989419a7fac28b71a8f5741da7a8d0b2b33c3e6d10179a0a3b830461ff748a970e
6
+ metadata.gz: 536f06a5bb004c85e76ff303cc39cb27204bb853126eb18049e98d9b5bd64e16aa477cc1b1be8314f0ea199fdbd0c186f2b89fb150c3aa45f3e293c339c1c949
7
+ data.tar.gz: a3914cc93b8b07c9086ecaac7d8a12502cbcb5dfd4a02dd916163ccd92bc8e740176a5379ecc3ddb5904eeb01318f80359dc178673f18a4f838d5a7a6eef6447
data/README.md CHANGED
@@ -37,7 +37,7 @@ output = program.evaluate uri, context
37
37
 
38
38
  ## Contributing
39
39
 
40
- 1. Fork it ( http://github.com/<my-github-username>/ldpath/fork )
40
+ 1. Fork it ( http://github.com/cbeer/ldpath.rb/fork )
41
41
  2. Create your feature branch (`git checkout -b my-new-feature`)
42
42
  3. Commit your changes (`git commit -am 'Add some feature'`)
43
43
  4. Push to the branch (`git push origin my-new-feature`)
data/bin/ldpath ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'open-uri'
5
+ require 'ldpath'
6
+ require 'byebug'
7
+
8
+ begin
9
+ require 'rest-client'
10
+ rescue LoadError
11
+ end
12
+
13
+ options = {}
14
+ OptionParser.new do |opts|
15
+ opts.banner = "Usage: ldpath [options] URI"
16
+
17
+ opts.on("--program=STRING_URI_OR_FILE", "LDPath program to run (- for STDIN)") do |program|
18
+ if File.exists? program or program =~ /^http/
19
+ options[:program] = open(program).read
20
+ elsif program.strip == "-"
21
+ options[:program] = $stdin.read
22
+ else
23
+ options[:program] = program
24
+ end
25
+ end
26
+ end.parse!
27
+
28
+ uri = ARGV.shift
29
+
30
+ puts Ldpath::Program.parse(options[:program]).evaluate(RDF::URI.new(uri)).to_json
data/ldpath.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Chris Beer"]
10
10
  spec.email = ["cabeer@stanford.edu"]
11
11
  spec.summary = %q{Ruby implementation of LDPath}
12
- spec.homepage = "http://github.com/cbeer"
12
+ spec.homepage = "https://github.com/cbeer/ldpath.rb"
13
13
  spec.license = "Apache 2"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
@@ -1,7 +1,7 @@
1
1
  module Ldpath
2
2
  module Functions
3
3
  def concat uri, context, *args
4
- args.join
4
+ args.flatten.compact.join
5
5
  end
6
6
 
7
7
  def first uri, context, *args
@@ -11,29 +11,57 @@ module Ldpath
11
11
  def last uri, context, *args
12
12
  args.flatten.compact.last
13
13
  end
14
+
15
+ def count uri, context, *args
16
+ args.flatten.compact.length
17
+ end
14
18
 
15
19
  def eq uri, context, *args
16
-
20
+ a, b, *rem = args.flatten
21
+ unless rem.empty?
22
+ raise "Too many arguments to fn:eq"
23
+ end
24
+ a == b
17
25
  end
18
26
 
19
27
  def ne uri, context, *args
20
-
28
+ a, b, *rem = args.flatten
29
+ unless rem.empty?
30
+ raise "Too many arguments to fn:ne"
31
+ end
32
+ a != b
21
33
  end
22
34
 
23
35
  def lt uri, context, *args
24
-
36
+ a, b, *rem = args.flatten
37
+ unless rem.empty?
38
+ raise "Too many arguments to fn:lt"
39
+ end
40
+ a < b
25
41
  end
26
42
 
27
43
  def le uri, context, *args
28
-
44
+ a, b, *rem = args.flatten
45
+ unless rem.empty?
46
+ raise "Too many arguments to fn:le"
47
+ end
48
+ a <= b
29
49
  end
30
50
 
31
51
  def gt uri, context, *args
32
-
52
+ a, b, *rem = args.flatten
53
+ unless rem.empty?
54
+ raise "Too many arguments to fn:gt"
55
+ end
56
+ a > b
33
57
  end
34
58
 
35
59
  def ge uri, context, *args
36
-
60
+ a, b, *rem = args.flatten
61
+ unless rem.empty?
62
+ raise "Too many arguments to fn:ge"
63
+ end
64
+ a >= b
37
65
  end
38
66
 
39
67
  # collections
@@ -130,7 +158,6 @@ module Ldpath
130
158
  end
131
159
 
132
160
  def endsWith uri, context, str, suffix
133
-
134
161
  Array(str).map { |x| x.end_with? suffix }
135
162
  end
136
163
 
@@ -141,6 +168,13 @@ module Ldpath
141
168
  def predicates uri, context, *args
142
169
  context.query([uri, nil, nil]).map(&:predicate).uniq
143
170
  end
171
+
172
+ def xpath uri, context, xpath, node
173
+ x = Array(xpath).flatten.first
174
+ Array(node).flatten.compact.map do |n|
175
+ Nokogiri::XML(n).xpath(x, prefixes.map { |k,v| [k, v.to_s] }).map(&:text)
176
+ end
177
+ end
144
178
 
145
179
  end
146
180
  end
data/lib/ldpath/parser.rb CHANGED
@@ -4,15 +4,21 @@ module Ldpath
4
4
  class Parser < Parslet::Parser
5
5
  root :lines
6
6
  rule(:lines) { line.repeat }
7
- rule(:line) { expression >> wsp? >> (newline | eof) }
7
+ rule(:line) { ((wsp >> expression) | expression) >> space_not_newline? >> (newline | eof) }
8
8
 
9
9
  rule(:newline) { (str("\n") >> str("\r").maybe).repeat(1) }
10
10
  rule(:eof) { any.absent? }
11
- rule(:wsp) { (match["\\t "] | multiline_comment).repeat(1) }
11
+
12
+ rule(:space) { match('\s').repeat(1) }
13
+ rule(:spaces?) { space.maybe }
14
+ rule(:space_not_newline) { str("\n").absent? >> space }
15
+ rule(:space_not_newline?) { space_not_newline.maybe }
16
+
17
+ rule(:wsp) { (space | multiline_comment).repeat(1) }
12
18
  rule(:wsp?) { wsp.maybe }
13
19
  rule(:multiline_comment) { (str('/*') >> (str('*/').absent? >> any).repeat >> str('*/') ) }
14
20
 
15
- rule(:expression) { wsp | namespace | mapping | graph }
21
+ rule(:expression) { wsp | namespace | mapping | graph | filter | boost }
16
22
 
17
23
  rule(:int) { match("\\d+") }
18
24
 
@@ -23,6 +29,8 @@ module Ldpath
23
29
  rule(:assign) { str("=") }
24
30
  rule(:k_prefix) { str("@prefix")}
25
31
  rule(:k_graph) { str("@graph")}
32
+ rule(:k_filter) { str("@filter")}
33
+ rule(:k_boost) { str("@boost")}
26
34
 
27
35
  rule(:self_op) { str(".") }
28
36
  rule(:and_op) { str("&") }
@@ -57,9 +65,7 @@ module Ldpath
57
65
  rule(:identifier) { match["a-zA-Z0-9_"] >> (match["a-zA-Z0-9_'\\.-"]).repeat }
58
66
 
59
67
  rule(:strlit) {
60
- wsp? >>
61
- str('"') >> (str("\\") >> str("\"") | (str('"').absent? >> any)).repeat.as(:literal) >> str('"') >>
62
- wsp?
68
+ str('"') >> (str("\\") >> str("\"") | (str('"').absent? >> any)).repeat.as(:literal) >> str('"')
63
69
  }
64
70
 
65
71
  rule(:node) {
@@ -69,24 +75,20 @@ module Ldpath
69
75
  # @prefix id = uri ;
70
76
  rule(:namespace) {
71
77
  (
72
- wsp? >>
73
78
  k_prefix >> wsp? >>
74
79
  identifier.as(:id) >> wsp? >>
75
80
  colon >> wsp? >>
76
- uri.as(:uri) >> wsp? >>
77
- scolon.maybe >> wsp?
81
+ uri.as(:uri) >> space_not_newline? >> scolon.maybe
78
82
  ).as(:namespace)
79
83
  }
80
84
 
81
85
  # @graph uri, uri, uri ;
82
86
  rule(:graph) {
83
87
  k_graph >> wsp? >>
84
- uri_list.as(:graphs) >> wsp? >>
85
- scolon
88
+ uri_list.as(:graphs) >> wsp? >> scolon
86
89
  }
87
90
 
88
91
  rule(:uri_list) {
89
- wsp? >>
90
92
  uri.as(:uri) >>
91
93
  (
92
94
  wsp? >>
@@ -94,22 +96,41 @@ module Ldpath
94
96
  uri_list.as(:rest)
95
97
  ).repeat
96
98
  }
99
+
100
+ # @filter test ;
101
+ rule(:filter) {
102
+ (k_filter >> wsp? >> node_test.as(:test) >> wsp? >> scolon).as(:filter)
103
+ }
104
+
105
+ # @boost selector ;
106
+ rule(:boost) {
107
+ (k_boost >> wsp? >> selector.as(:selector) >> wsp? >> scolon).as(:boost)
108
+ }
97
109
 
98
110
  # id = . ;
99
111
  rule(:mapping) {
100
112
  (
101
- identifier.as(:name) >> wsp? >>
113
+ (uri_in_brackets | prefix_and_localname | identifier).as(:name) >> wsp? >>
102
114
  assign >> wsp? >>
103
- selector.as(:selector) >> wsp? >>
104
- (
105
- dcolon >> wsp? >>
106
- uri.as(:field_type)
107
- ).maybe >> wsp? >>
108
- scolon
115
+ selector.as(:selector) >>
116
+ ( wsp? >>
117
+ dcolon >> wsp? >> field_type
118
+ ).maybe >> wsp? >> scolon
109
119
  ).as(:mapping)
110
120
  }
111
121
 
122
+ rule(:field_type) {
123
+ uri.as(:field_type) >> field_type_options.maybe
124
+ }
125
+
126
+ rule(:field_type_options) {
127
+ str("(") >> wsp? >> (field_type_option >> (wsp? >> comma >> wsp? >> field_type_option).repeat).as(:options) >> wsp? >> str(")")
128
+ }
112
129
 
130
+ rule(:field_type_option) {
131
+ identifier.as(:key) >> wsp? >> assign >> wsp? >> strlit.as(:value)
132
+ }
133
+
113
134
  # selector groups
114
135
  rule(:selector) {
115
136
  (
@@ -128,11 +149,10 @@ module Ldpath
128
149
  }
129
150
 
130
151
  rule(:testing_selector) {
131
- wsp? >>
132
152
  atomic_selector.as(:delegate) >>
133
153
  str("[") >> wsp? >>
134
154
  node_test.as(:test) >> wsp? >>
135
- str("]") >> wsp?
155
+ str("]")
136
156
  }
137
157
 
138
158
  rule(:atomic_selector) {
@@ -163,80 +183,70 @@ module Ldpath
163
183
  ## x / y
164
184
  rule(:path_selector) {
165
185
  (
166
- wsp? >>
167
186
  atomic_or_testing_selector.as(:left) >> wsp? >>
168
187
  p_sep >> wsp? >>
169
- atomic_or_testing_or_path_selector.as(:right) >> wsp?
188
+ atomic_or_testing_or_path_selector.as(:right)
170
189
  ).as(:path)
171
190
  }
172
191
 
173
192
  ## x & y
174
193
  rule(:intersection_selector) {
175
194
  (
176
- wsp? >>
177
195
  atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
178
196
  and_op >> wsp? >>
179
- selector.as(:right) >> wsp?
197
+ selector.as(:right)
180
198
  ).as(:intersection)
181
199
  }
182
200
 
183
201
  ## x | y
184
202
  rule(:union_selector) {
185
203
  (
186
- wsp? >>
187
204
  atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
188
205
  or_op >> wsp? >>
189
- selector.as(:right) >> wsp?
206
+ selector.as(:right)
190
207
  ).as(:union)
191
208
  }
192
209
 
193
210
  # Atomic Selectors
194
211
  rule(:self_selector) {
195
- wsp? >>
196
- self_op.as(:self) >> wsp?
212
+ self_op.as(:self)
197
213
  }
198
214
 
199
215
  # fn:x() or fn:x(1,2,3)
200
216
  rule(:function_selector) {
201
217
  func >> identifier.as(:fname) >> str("()") |
202
- func >> identifier.as(:fname) >> str("(") >> arglist.as(:arglist) >> str(")")
218
+ func >> identifier.as(:fname) >> str("(") >> wsp? >> arglist.as(:arglist) >> wsp? >> str(")")
203
219
  }
204
220
 
205
221
  rule(:arglist) {
206
- wsp? >>
207
222
  selector >>
208
223
  (
209
224
  wsp? >>
210
225
  comma >> wsp? >>
211
226
  selector
212
- ).repeat >>
213
- wsp?
227
+ ).repeat
214
228
  }
215
229
 
216
230
  # xyz
217
231
  rule(:loose_property_selector) {
218
- wsp? >>
219
232
  loose >>
220
233
  wsp? >>
221
- uri.as(:loose_property) >> wsp?
234
+ uri.as(:loose_property)
222
235
  }
223
236
 
224
237
  # xyz
225
238
  rule(:property_selector) {
226
- wsp? >>
227
- uri.as(:property) >> wsp?
239
+ uri.as(:property)
228
240
  }
229
241
 
230
242
  # *
231
243
  rule(:wildcard_selector) {
232
- wsp? >>
233
- star.as(:wildcard) >> wsp?
244
+ star.as(:wildcard)
234
245
  }
235
246
 
236
247
  # ^xyz
237
248
  rule(:reverse_property_selector) {
238
- wsp? >>
239
- inverse >> uri.as(:reverse_property) >> wsp?
249
+ inverse >> uri.as(:reverse_property)
240
250
  }
241
251
 
242
252
  rule(:string_constant_selector) {
@@ -246,7 +256,6 @@ module Ldpath
246
256
  # (x)*
247
257
  rule(:recursive_path_selector) {
248
258
  (
249
- wsp? >>
250
259
  str("(") >> wsp? >>
251
260
  selector.as(:delegate) >> wsp? >>
252
261
  str(")") >>
@@ -254,23 +263,21 @@ module Ldpath
254
263
  star |
255
264
  plus |
256
265
  (str("{") >> wsp? >> int.as(:min).maybe >> wsp? >>str(",") >> wsp? >> int.as(:max).maybe >> wsp? >>str("}") ).as(:range)
257
- ).as(:repeat) >> wsp?
266
+ ).as(:repeat)
258
267
  ).as(:recursive)
259
268
  }
260
269
 
261
270
  rule(:grouped_selector) {
262
- wsp? >>
263
271
  str("(") >> wsp? >>
264
272
  selector >> wsp? >>
265
- str(")") >> wsp?
273
+ str(")")
266
274
  }
267
275
 
268
276
  rule(:tap_selector) {
269
- wsp? >>
270
277
  tap >>
271
- str("<") >>
272
- identifier.as(:identifier) >>
273
- str(">") >>
278
+ str("<") >> wsp? >>
279
+ identifier.as(:identifier) >> wsp? >>
280
+ str(">") >> wsp? >>
274
281
  (atomic_selector).as(:tap)
275
282
  }
276
283
 
@@ -294,78 +301,67 @@ module Ldpath
294
301
  }
295
302
 
296
303
  rule(:grouped_test) {
297
- wsp? >>
298
304
  str("(") >> wsp? >>
299
305
  node_test >> wsp? >>
300
- str(")") >> wsp?
306
+ str(")")
301
307
  }
302
308
 
303
309
  rule(:not_test) {
304
310
  (
305
- wsp? >>
306
- not_op >> node_test.as(:delegate) >>
307
- wsp?
311
+ not_op >> node_test.as(:delegate)
308
312
  ).as(:not)
309
313
  }
310
314
 
311
315
  rule(:and_test) {
312
316
  (
313
- wsp? >>
314
317
  atomic_node_test.as(:left) >> wsp? >>
315
318
  and_op >> wsp? >>
316
- node_test.as(:right) >> wsp?
319
+ node_test.as(:right)
317
320
  ).as(:and)
318
321
  }
319
322
 
320
323
  rule(:or_test) {
321
324
  (
322
- wsp? >>
323
325
  atomic_node_test.as(:left) >> wsp? >>
324
326
  or_op >> wsp? >>
325
- node_test.as(:right) >> wsp?
327
+ node_test.as(:right)
326
328
  ).as(:or)
327
329
  }
328
330
 
329
331
  # @en
330
332
  rule(:literal_language_test) {
331
- wsp? >>
332
- lang >> identifier.as(:lang) >>
333
- wsp?
333
+ lang >> identifier.as(:lang)
334
334
  }
335
335
 
336
336
  # ^^xyz
337
337
  rule(:literal_type_test) {
338
- wsp? >>
339
- type >> uri.as(:type) >>
340
- wsp?
338
+ type >> uri.as(:type)
341
339
  }
342
340
 
343
341
  rule(:is_a_test) {
344
342
  (
345
- wsp? >>
346
343
  is_a >> wsp? >>
347
- node.as(:right) >>
348
- wsp?
344
+ node.as(:right)
349
345
  ).as(:is_a)
350
346
  }
351
347
 
352
348
  rule(:path_equality_test) {
353
349
  (
354
- wsp? >>
355
350
  selector >> wsp? >>
356
351
  is >> wsp? >>
357
- node.as(:right) >> wsp?
352
+ node.as(:right)
358
353
  ).as(:is)
359
354
  }
360
355
 
361
356
  rule(:function_test) {
362
- wsp? >>
363
357
  (
364
358
  func >> identifier.as(:fname) >> str("()") |
365
359
  func >> identifier.as(:fname) >> str("(") >>
360
+ wsp? >>
366
361
  arglist.as(:arglist) >>
362
+ wsp? >>
367
363
  str(")")
368
- ) >> wsp?
364
+ )
369
365
  }
370
366
 
371
367
  rule(:path_test) {
@@ -8,7 +8,7 @@ module Ldpath
8
8
  parsed = parser.parse(program)
9
9
  ast = transform.apply parsed, transform_context
10
10
 
11
- Ldpath::Program.new ast.compact
11
+ Ldpath::Program.new ast.compact, transform_context
12
12
  end
13
13
 
14
14
  private
@@ -21,16 +21,19 @@ module Ldpath
21
21
  end
22
22
  end
23
23
 
24
- attr_reader :mappings, :cache, :loaded
25
- def initialize mappings, cache = RDF::Util::Cache.new
24
+ attr_reader :mappings, :cache, :loaded, :prefixes, :filters
25
+ def initialize mappings, options = {}
26
+
26
27
  @mappings ||= mappings
27
- @cache = cache
28
+ @cache = options[:cache] || RDF::Util::Cache.new
29
+ @prefixes = options[:prefixes] || {}
30
+ @filters = options[:filters] || []
28
31
  @loaded = {}
29
32
  end
30
33
 
31
34
  def loading uri, context
32
- if uri.to_s =~ /^http/ and !loaded[uri]
33
- context << load_graph(uri)
35
+ if uri.to_s =~ /^http/ and !loaded[uri.to_s]
36
+ context << load_graph(uri.to_s)
34
37
  end
35
38
  end
36
39
 
@@ -50,6 +53,10 @@ module Ldpath
50
53
  h = {}
51
54
  context ||= load_graph(uri.to_s)
52
55
 
56
+ unless filters.empty?
57
+ return h unless filters.all? { |f| f.evaluate(self, uri, context) }
58
+ end
59
+
53
60
  mappings.each do |m|
54
61
  h[m.name] ||= []
55
62
  h[m.name] += case m.selector
@@ -37,7 +37,7 @@ module Ldpath
37
37
  i
38
38
  end
39
39
  end
40
- program.func_call fname, uri, context, args
40
+ program.func_call fname, uri, context, *args
41
41
  end.flatten.compact
42
42
  end
43
43
  end
@@ -21,6 +21,7 @@ module Ldpath
21
21
 
22
22
  def apply obj, context = nil
23
23
  context ||= { }
24
+ context[:filters] ||= []
24
25
  context[:prefixes] ||= {}.merge(self.class.default_prefixes)
25
26
  super obj, context
26
27
  end
@@ -38,6 +39,17 @@ module Ldpath
38
39
  rule(prefix: simple(:prefix), localName: simple(:localName)) do
39
40
  (prefixes[prefix.to_s] || RDF::Vocabulary.new(prefix.to_s))[localName]
40
41
  end
42
+
43
+ rule(filter: subtree(:filter)) do
44
+ filters << filter[:test]
45
+ nil
46
+ end
47
+
48
+ rule(boost: subtree(:boost)) do
49
+ # no-op
50
+ nil
51
+ end
52
+
41
53
 
42
54
  # Mappings
43
55
 
@@ -1,3 +1,3 @@
1
1
  module Ldpath
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -19,11 +19,9 @@
19
19
 
20
20
  @graph test:context, foo:ctx, test:bar ;
21
21
 
22
- /*
23
22
  @filter test:type is foo:bar | test:p1 & is-a test:Case ;
24
23
 
25
24
  @boost foo:boost / ^test:boost ;
26
- */
27
25
 
28
26
  path = test:p1 / test:p2 :: test:type ;
29
27
  lang_test = test:p1[@en] :: test:type ;
@@ -34,8 +32,7 @@ group = (test:p1 / test:p2) :: test:type ;
34
32
 
35
33
  inverse = ^test:incoming :: test:type ;
36
34
 
37
- config = test:foo :: test:type ;
38
- /*
35
+ config = test:foo :: test:type(c1="true", c2="false", c3="1.234") ;
36
+
39
37
  foo:bar = test:foo :: test:type ;
40
- <http://test/> = test:test :: test:type ;
41
- */
38
+ <http://test/> = test:test :: test:type ;
@@ -64,6 +64,11 @@ describe Ldpath::Parser do
64
64
  subject.expression.parse "@graph test:context, foo:ctx, test:bar ;"
65
65
  end
66
66
 
67
+
68
+ it "may be a filter" do
69
+ subject.expression.parse "@filter is-a test:Context ;"
70
+ end
71
+
67
72
  it "may be a mapping" do
68
73
  subject.expression.parse "id = . ;"
69
74
  end
@@ -133,7 +138,7 @@ describe Ldpath::Parser do
133
138
  end
134
139
 
135
140
  it "should parse path mappings" do
136
- subject.parse("xyz = info:a / info:b :: a:b;\n")
141
+ subject.mapping.parse("xyz = info:a / info:b :: a:b;")
137
142
  end
138
143
 
139
144
  it "recursive_path_selector" do
@@ -163,7 +168,7 @@ describe Ldpath::Parser do
163
168
  end
164
169
 
165
170
  it "should parse the namespaces.ldpath" do
166
- subject.parse File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "namespaces.ldpath")))
171
+ subject.parse_with_debug File.read(File.expand_path(File.join(__FILE__, "..", "fixtures", "namespaces.ldpath")))
167
172
  end
168
173
  end
169
174
  end
@@ -72,33 +72,114 @@ EOF
72
72
  end
73
73
 
74
74
  describe "functions" do
75
-
76
- subject do
77
- Ldpath::Program.parse <<-EOF
75
+ let(:program) do
76
+ Ldpath::Program.parse <<-EOF
78
77
  @prefix dcterms : <http://purl.org/dc/terms/> ;
79
78
  ab = fn:concat("a", "b") ;
80
79
  title = fn:concat(dcterms:title, dcterms:description) ;
80
+ title_mix = fn:concat("!", dcterms:title) ;
81
+ title_missing = fn:concat("z", dcterms:genre) ;
81
82
  first_a = fn:first("a", "b") ;
83
+ first_b = fn:first(dcterms:genre, "b") ;
84
+ last_a = fn:last("a", dcterms:genre) ;
82
85
  last_b = fn:last("a", "b") ;
86
+ count_5 = fn:count("a", "b", "c", "d", "e");
87
+ count_3 = fn:count(dcterms:hasPart);
88
+ count_still_3 = fn:count(dcterms:hasPart, dcterms:genre);
89
+ eq_true = fn:eq("a", "a");
90
+ eq_false = fn:eq("a", "b");
91
+ eq_node_true = fn:eq(dcterms:description, "Description");
92
+ xpath_test = fn:xpath("//title", "<root><title>xyz</title></root>");
83
93
  EOF
94
+ end
95
+
96
+ let(:object) { RDF::URI.new("info:a") }
97
+
98
+ let(:graph) do
99
+ graph = RDF::Graph.new
100
+ graph << [object, RDF::DC.title, "Hello, world!"]
101
+ graph << [object, RDF::DC.description, "Description"]
102
+ graph << [object, RDF::DC.hasPart, "a"]
103
+ graph << [object, RDF::DC.hasPart, "b"]
104
+ graph << [object, RDF::DC.hasPart, "c"]
105
+
106
+ graph
107
+ end
108
+
109
+ subject do
110
+ program.evaluate object, graph
111
+ end
112
+
113
+ describe "concat" do
114
+ it "should concatenate simple string arguments" do
115
+ expect(subject).to include "ab" => ["ab"]
84
116
  end
85
117
 
86
- let(:object) { RDF::URI.new("info:a") }
87
-
88
- let(:graph) do
89
- graph = RDF::Graph.new
90
- graph << [object, RDF::DC.title, "Hello, world!"]
91
- graph << [object, RDF::DC.description, "Description"]
118
+ it "should concatenate node values" do
119
+ expect(subject).to include "title" => ["Hello, world!Description"]
120
+ end
92
121
 
93
- graph
122
+ it "should allow a mixture of string and node values" do
123
+ expect(subject).to include "title_mix" => ["!Hello, world!"]
124
+ end
125
+
126
+ it "should ignore missing node values" do
127
+ expect(subject).to include "title_missing" => ["z"]
128
+ end
129
+ end
130
+
131
+ describe "first" do
132
+ it "should take the first value" do
133
+ expect(subject).to include "first_a" => ["a"]
134
+ end
135
+
136
+ it "should skip missing values" do
137
+ expect(subject).to include "first_b" => ["b"]
138
+ end
139
+ end
140
+
141
+ describe "last" do
142
+ it "should take the last value" do
143
+ expect(subject).to include "last_b" => ["b"]
144
+ end
145
+
146
+ it "should skip missing values" do
147
+ expect(subject).to include "last_a" => ["a"]
148
+ end
149
+ end
150
+
151
+ describe "count" do
152
+ it "should return the number of arguments" do
153
+ expect(subject).to include "count_5" => [5]
154
+ end
155
+
156
+ it "should count the number of values for nodes" do
157
+ expect(subject).to include "count_3" => [3]
158
+ end
159
+
160
+ it "should skip missing nodes" do
161
+ expect(subject).to include "count_still_3" => [3]
162
+ end
163
+ end
164
+
165
+ describe "eq" do
166
+ it "checks if the arguments match" do
167
+ expect(subject).to include "eq_true" => [true]
168
+ end
169
+
170
+ it "checks if the arguments fail to match" do
171
+ expect(subject).to include "eq_false" => [false]
172
+ end
173
+
174
+ it "checks node values" do
175
+ expect(subject).to include "eq_node_true" => [true]
176
+ end
177
+ end
178
+
179
+ describe "xpath" do
180
+ it "evaluates xpath queries against the string contents" do
181
+ expect(subject).to include "xpath_test" => ["xyz"]
94
182
  end
95
-
96
- it "should work" do
97
- result = subject.evaluate object, graph
98
- expect(result["ab"]).to match_array "ab"
99
- expect(result["title"]).to match_array "Hello, world!Description"
100
- expect(result["first_a"]).to match_array "a"
101
- expect(result["last_b"]).to match_array "b"
102
183
  end
103
184
  end
104
185
 
@@ -192,4 +273,42 @@ title_with_loose = ~dc:title :: xsd:string ;
192
273
  expect(result["title_with_loose"]).to eq result["title"]
193
274
  end
194
275
  end
276
+
277
+ describe "filter" do
278
+
279
+ subject do
280
+ Ldpath::Program.parse <<-EOF
281
+ @prefix dcterms : <http://purl.org/dc/terms/> ;
282
+ @prefix dc: <http://purl.org/dc/elements/1.1/> ;
283
+ @filter is-a dcterms:Agent ;
284
+ title = dcterms:title :: xsd:string ;
285
+ EOF
286
+ end
287
+
288
+ let(:object) { RDF::URI.new("info:a") }
289
+ let(:other_object) { RDF::URI.new("info:b") }
290
+
291
+
292
+ let(:graph) do
293
+ graph = RDF::Graph.new
294
+
295
+ graph << [object, RDF.type, RDF::DC.Agent]
296
+ graph << [object, RDF::DC.title, "Title"]
297
+ graph << [other_object, RDF::DC.title, "Other Title"]
298
+
299
+ graph
300
+ end
301
+
302
+ it "should work" do
303
+ result = subject.evaluate object, graph
304
+ expect(result["title"]).to eq ["Title"]
305
+ end
306
+
307
+ it "filters objects that don't match" do
308
+ result = subject.evaluate other_object, graph
309
+ expect(result).to be_empty
310
+ end
311
+
312
+
313
+ end
195
314
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ldpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Beer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-02 00:00:00.000000000 Z
11
+ date: 2015-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -97,7 +97,8 @@ dependencies:
97
97
  description:
98
98
  email:
99
99
  - cabeer@stanford.edu
100
- executables: []
100
+ executables:
101
+ - ldpath
101
102
  extensions: []
102
103
  extra_rdoc_files: []
103
104
  files:
@@ -108,6 +109,7 @@ files:
108
109
  - LICENSE.txt
109
110
  - README.md
110
111
  - Rakefile
112
+ - bin/ldpath
111
113
  - ldpath.gemspec
112
114
  - lib/ldpath.rb
113
115
  - lib/ldpath/field_mapping.rb
@@ -126,7 +128,7 @@ files:
126
128
  - spec/ldpath_spec.rb
127
129
  - spec/ldpath_transform_spec.rb
128
130
  - spec/spec_helper.rb
129
- homepage: http://github.com/cbeer
131
+ homepage: https://github.com/cbeer/ldpath.rb
130
132
  licenses:
131
133
  - Apache 2
132
134
  metadata: {}
@@ -146,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
148
  version: '0'
147
149
  requirements: []
148
150
  rubyforge_project:
149
- rubygems_version: 2.4.5
151
+ rubygems_version: 2.4.6
150
152
  signing_key:
151
153
  specification_version: 4
152
154
  summary: Ruby implementation of LDPath