ldpath 0.0.0 → 0.0.1

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: a7fcb1c90659a5df73d2317bb95e7b6e94a084b6
4
- data.tar.gz: 126daa1e8f17111e55ee2778d3b1e0a20a44b486
3
+ metadata.gz: 154cc858a4b03022c48012acdb9e897c105a7c3f
4
+ data.tar.gz: 5c99156666f615486d5b8134bcd869e0f9b44590
5
5
  SHA512:
6
- metadata.gz: 16bbc3af47c263842b9ae8d370103cacc2b23665da21e1420cdd2c667b3c90dd8e0063e34339b8924b8c47aea8eeb4db54d84b4eca0502bfb100be895ec9c467
7
- data.tar.gz: d9fc526a8eaa84254990752f45476244bfd826d83136b14c9304bd9316765ab3f4d361431a071967cd87d28f9ee2bafccd2285b83c0ac81e597fe207e00376eb
6
+ metadata.gz: 6a9879ef3a8345d8c0a5c82ab79b048c9143cd1da9c33b5d53e8940d54187666723c9c67f5114efa9d7e2485aa4c28e8d63c2d43919571f8f955169485106fb2
7
+ data.tar.gz: 81f9a84ff7d8a761327c833b8acd6a1ff96403c3e512c02fa6c060755817aab69d9382bcaa3782048a2d1d6c7c983528a155b2554a961c71fe4bb711d0fb7d6b
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ldpath
2
2
 
3
- TODO: Write a gem description
3
+ This is a ruby implementation of [LDPath](http://marmotta.apache.org/ldpath/language.html), a language for selecting values linked data resources.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,8 +18,23 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ ```ruby
22
+ require 'ldpath'
22
23
 
24
+ my_program = <<-EOF
25
+ @prefix dcterms : <http://purl.org/dc/terms/> ;
26
+ title = dcterms:title :: xsd:string ;
27
+ EOF
28
+
29
+ uri = RDF::URI.new "info:a"
30
+
31
+ context = RDF::Graph.new << [uri, RDF::DC.title, "Some Title"]
32
+
33
+ program = Ldpath::Program.parse my_program
34
+ output = program.evaluate uri, context
35
+ # => { ... }
36
+ ```
37
+
23
38
  ## Contributing
24
39
 
25
40
  1. Fork it ( http://github.com/<my-github-username>/ldpath/fork )
data/ldpath.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_dependency "parslet"
21
+ spec.add_dependency "linkeddata"
21
22
 
22
23
  spec.add_development_dependency "bundler", "~> 1.5"
23
24
  spec.add_development_dependency "rake"
data/lib/ldpath.rb CHANGED
@@ -1,5 +1,18 @@
1
1
  require "ldpath/version"
2
+ require 'linkeddata'
2
3
 
3
4
  module Ldpath
5
+ require 'ldpath/field_mapping'
6
+ require 'ldpath/selectors'
7
+ require 'ldpath/tests'
8
+ require 'ldpath/parser'
9
+ require 'ldpath/transform'
10
+ require 'ldpath/functions'
4
11
  require 'ldpath/program'
12
+
13
+ class << self
14
+ def evaluate program, uri, context
15
+ Ldpath::Program.parse(program).evaluate(uri, context)
16
+ end
17
+ end
5
18
  end
@@ -0,0 +1,2 @@
1
+ class Ldpath::FieldMapping < Struct.new(:name, :selector, :field_type)
2
+ end
@@ -0,0 +1,144 @@
1
+ module Ldpath
2
+ module Functions
3
+ def concat uri, context, *args
4
+ args.join
5
+ end
6
+
7
+ def first uri, context, *args
8
+ args.flatten.compact.first
9
+ end
10
+
11
+ def last uri, context, *args
12
+ args.flatten.compact.last
13
+ end
14
+
15
+ def eq uri, context, *args
16
+
17
+ end
18
+
19
+ def ne uri, context, *args
20
+
21
+ end
22
+
23
+ def lt uri, context, *args
24
+
25
+ end
26
+
27
+ def le uri, context, *args
28
+
29
+ end
30
+
31
+ def gt uri, context, *args
32
+
33
+ end
34
+
35
+ def ge uri, context, *args
36
+
37
+ end
38
+
39
+ # collections
40
+ def flatten uri, context, *args
41
+
42
+ end
43
+
44
+ def get uri, context, *args
45
+ end
46
+
47
+ def subList uri, context, *args
48
+
49
+ end
50
+
51
+ # dates
52
+
53
+ def earliest uri, context, *args
54
+ args.flatten.min
55
+ end
56
+
57
+ def latest uri, context, *args
58
+ args.flatten.max
59
+ end
60
+
61
+ # math
62
+
63
+ def min uri, context, *args
64
+ args.flatten.min
65
+ end
66
+
67
+ def max uri, context, *args
68
+ args.flatten.max
69
+ end
70
+
71
+ def round uri, context, *args
72
+ args.map do |n|
73
+ Array(n).map do |i|
74
+ i.respond_to? :round ? i.round : i
75
+ end
76
+ end
77
+ end
78
+
79
+ def sum uri, context, *args
80
+ args.inject(0) { |sum, n| sum + n }
81
+ end
82
+
83
+ # text
84
+
85
+ def replace uri, context, str, pattern, replacement
86
+ regex = Regexp.parse(pattern)
87
+ Array(str).map do |x|
88
+ x.gsub(regex, replacement)
89
+ end
90
+ end
91
+
92
+ def strlen uri, context, str
93
+ Array(str).map { |x| x.length }
94
+ end
95
+
96
+ def wc uri, context, str
97
+ Array(str).map { |x| x.split.length }
98
+ end
99
+
100
+ def strLeft uri, context, str, left
101
+ Array(str).map { |x| x[0..left.to_i] }
102
+ end
103
+
104
+ def strRight uri, context, str, right
105
+ Array(str).map { |x| x[right.to_i..x.length] }
106
+ end
107
+
108
+ def substr uri, context, str, left, right
109
+ Array(str).map { |x| x[left.to_i..right.to_i] }
110
+ end
111
+
112
+ def strJoin uri, context, str, sep = "", prefix = "", suffix = ""
113
+ prefix + Array(str).join(sep) + suffix
114
+ end
115
+
116
+ def equals uri, context, str, other
117
+ Array(str).map { |x| x == other }
118
+ end
119
+
120
+ def equalsIgnoreCase uri, context, str, other
121
+ Array(str).map { |x| x.downcase == other.downcase }
122
+ end
123
+
124
+ def contains uri, context, str, substr
125
+ Array(str).map { |x| x.include? substr }
126
+ end
127
+
128
+ def startsWith uri, context, str, suffix
129
+
130
+ Array(str).map { |x| x.start_with? suffix }
131
+ end
132
+
133
+ def endsWith uri, context, str, suffix
134
+
135
+ Array(str).map { |x| x.end_with? suffix }
136
+ end
137
+
138
+ def isEmpty uri, context, str
139
+
140
+ Array(str).map(&:empty?)
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,358 @@
1
+ require 'parslet'
2
+
3
+ module Ldpath
4
+ class Parser < Parslet::Parser
5
+ root :lines
6
+ rule(:lines) { line.repeat }
7
+ rule(:line) { expression >> wsp? >> (newline | eof) }
8
+
9
+ rule(:newline) { (str("\n") >> str("\r").maybe).repeat(1) }
10
+ rule(:eof) { any.absent? }
11
+ rule(:wsp) { (match["\\t "] | multiline_comment).repeat(1) }
12
+ rule(:wsp?) { wsp.maybe }
13
+ rule(:multiline_comment) { (str('/*') >> (str('*/').absent? >> any).repeat >> str('*/') ) }
14
+
15
+ rule(:expression) { wsp | namespace | mapping | graph }
16
+
17
+ rule(:int) { match("\\d+") }
18
+
19
+ rule(:comma) { str(",") }
20
+ rule(:scolon) { str(";") }
21
+ rule(:colon) { str(":") }
22
+ rule(:dcolon) { str("::") }
23
+ rule(:assign) { str("=") }
24
+ rule(:k_prefix) { str("@prefix")}
25
+ rule(:k_graph) { str("@graph")}
26
+
27
+ rule(:self_op) { str(".") }
28
+ rule(:and_op) { str("&") }
29
+ rule(:or_op) { str("|") }
30
+ rule(:p_sep) { str("/") }
31
+ rule(:plus) { str("+") }
32
+ rule(:star) { str("*") }
33
+ rule(:not_op) { str("!") }
34
+ rule(:inverse) { str("^") }
35
+ rule(:is) { str "is" }
36
+ rule(:is_a) { str "is-a" }
37
+ rule(:func) { str "fn:"}
38
+ rule(:type) { str "^^" }
39
+ rule(:lang) { str "@" }
40
+
41
+ # todo: fixme
42
+ rule(:uri) do
43
+ uri_in_brackets |
44
+ prefix_and_localname
45
+ end
46
+
47
+ rule(:uri_in_brackets) do
48
+ str("<") >> (str(">").absent? >> any).repeat.as(:uri) >> str(">")
49
+ end
50
+
51
+ rule(:prefix_and_localname) do
52
+ (identifier.as(:prefix) >> str(":") >> identifier.as(:localName)).as(:uri)
53
+ end
54
+
55
+ rule(:identifier) { match["a-zA-Z0-9_"] >> (match["a-zA-Z0-9_'\\.-"]).repeat }
56
+
57
+ rule(:strlit) {
58
+ wsp? >>
59
+ str('"') >> (str("\\") >> str("\"") | (str('"').absent? >> any)).repeat.as(:literal) >> str('"') >>
60
+ wsp?
61
+ }
62
+
63
+ rule(:node) {
64
+ uri.as(:uri) | strlit.as(:literal)
65
+ }
66
+
67
+ # @prefix id = uri ;
68
+ rule(:namespace) {
69
+ (
70
+ wsp? >>
71
+ k_prefix >> wsp? >>
72
+ identifier.as(:id) >> wsp? >>
73
+ colon >> wsp? >>
74
+ uri.as(:uri) >> wsp? >>
75
+ scolon.maybe >> wsp?
76
+ ).as(:namespace)
77
+ }
78
+
79
+ # @graph uri, uri, uri ;
80
+ rule(:graph) {
81
+ k_graph >> wsp? >>
82
+ uri_list.as(:graphs) >> wsp? >>
83
+ scolon
84
+ }
85
+
86
+ rule(:uri_list) {
87
+ wsp? >>
88
+ uri.as(:uri) >>
89
+ (
90
+ wsp? >>
91
+ comma >> wsp? >>
92
+ uri_list.as(:rest)
93
+ ).repeat
94
+ }
95
+
96
+ # id = . ;
97
+ rule(:mapping) {
98
+ (
99
+ identifier.as(:name) >> wsp? >>
100
+ assign >> wsp? >>
101
+ selector.as(:selector) >> wsp? >>
102
+ (
103
+ dcolon >> wsp? >>
104
+ uri.as(:field_type)
105
+ ).maybe >> wsp? >>
106
+ scolon
107
+ ).as(:mapping)
108
+ }
109
+
110
+
111
+ # selector groups
112
+ rule(:selector) {
113
+ (
114
+ compound_selector |
115
+ testing_selector |
116
+ atomic_selector
117
+ )
118
+ }
119
+
120
+ rule(:compound_selector) {
121
+ (
122
+ union_selector |
123
+ intersection_selector |
124
+ path_selector
125
+ )
126
+ }
127
+
128
+ rule(:testing_selector) {
129
+ wsp? >>
130
+ atomic_selector.as(:delegate) >>
131
+ str("[") >> wsp? >>
132
+ node_test.as(:test) >> wsp? >>
133
+ str("]") >> wsp?
134
+ }
135
+
136
+ rule(:atomic_selector) {
137
+ (
138
+ self_selector |
139
+ function_selector |
140
+ property_selector |
141
+ wildcard_selector |
142
+ reverse_property_selector |
143
+ string_constant_selector |
144
+ recursive_path_selector |
145
+ grouped_selector
146
+ )
147
+ }
148
+
149
+ rule(:atomic_or_testing_selector) {
150
+ (testing_selector | atomic_selector)
151
+ }
152
+
153
+ rule(:atomic_or_testing_or_path_selector) {
154
+ (path_selector | atomic_or_testing_selector)
155
+ }
156
+
157
+ # Compound selectors
158
+ ## x / y
159
+ rule(:path_selector) {
160
+ (
161
+ wsp? >>
162
+ atomic_or_testing_selector.as(:left) >> wsp? >>
163
+ p_sep >> wsp? >>
164
+ atomic_or_testing_or_path_selector.as(:right) >> wsp?
165
+ ).as(:path)
166
+ }
167
+
168
+ ## x & y
169
+ rule(:intersection_selector) {
170
+ (
171
+ wsp? >>
172
+ atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
173
+ and_op >> wsp? >>
174
+ selector.as(:right) >> wsp?
175
+ ).as(:intersection)
176
+ }
177
+
178
+ ## x | y
179
+ rule(:union_selector) {
180
+ (
181
+ wsp? >>
182
+ atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
183
+ or_op >> wsp? >>
184
+ selector.as(:right) >> wsp?
185
+ ).as(:union)
186
+ }
187
+
188
+ # Atomic Selectors
189
+ rule(:self_selector) {
190
+ wsp? >>
191
+ self_op.as(:self) >> wsp?
192
+ }
193
+
194
+ # fn:x() or fn:x(1,2,3)
195
+ rule(:function_selector) {
196
+ func >> identifier.as(:fname) >> str("()") |
197
+ func >> identifier.as(:fname) >> str("(") >> arglist.as(:arglist) >> str(")")
198
+ }
199
+
200
+ rule(:arglist) {
201
+ wsp? >>
202
+ selector >>
203
+ (
204
+ wsp? >>
205
+ comma >> wsp? >>
206
+ selector
207
+ ).repeat >>
208
+ wsp?
209
+ }
210
+
211
+ # xyz
212
+ rule(:property_selector) {
213
+ wsp? >>
214
+ uri.as(:property) >> wsp?
215
+ }
216
+
217
+ # *
218
+ rule(:wildcard_selector) {
219
+ wsp? >>
220
+ star.as(:wildcard) >> wsp?
221
+ }
222
+
223
+ # ^xyz
224
+ rule(:reverse_property_selector) {
225
+ wsp? >>
226
+ inverse >> uri.as(:reverse_property) >> wsp?
227
+ }
228
+
229
+ rule(:string_constant_selector) {
230
+ strlit
231
+ }
232
+
233
+ # (x)*
234
+ rule(:recursive_path_selector) {
235
+ (
236
+ wsp? >>
237
+ str("(") >> wsp? >>
238
+ selector.as(:delegate) >> wsp? >>
239
+ str(")") >>
240
+ (
241
+ star |
242
+ plus |
243
+ (str("{") >> wsp? >> int.as(:min).maybe >> wsp? >>str(",") >> wsp? >> int.as(:max).maybe >> wsp? >>str("}") ).as(:range)
244
+ ).as(:repeat) >> wsp?
245
+ ).as(:recursive)
246
+ }
247
+
248
+ rule(:grouped_selector) {
249
+ wsp? >>
250
+ str("(") >> wsp? >>
251
+ selector >> wsp? >>
252
+ str(")") >> wsp?
253
+ }
254
+
255
+ # Testing Selectors
256
+
257
+ rule(:node_test) {
258
+ grouped_test |
259
+ not_test |
260
+ and_test |
261
+ or_test |
262
+ atomic_node_test
263
+ }
264
+
265
+ rule(:atomic_node_test) {
266
+ literal_language_test |
267
+ literal_type_test |
268
+ is_a_test |
269
+ path_equality_test |
270
+ function_test |
271
+ path_test
272
+ }
273
+
274
+ rule(:grouped_test) {
275
+ wsp? >>
276
+ str("(") >> wsp? >>
277
+ node_test >> wsp? >>
278
+ str(")") >> wsp?
279
+ }
280
+
281
+ rule(:not_test) {
282
+ (
283
+ wsp? >>
284
+ not_op >> node_test.as(:delegate) >>
285
+ wsp?
286
+ ).as(:not)
287
+ }
288
+
289
+ rule(:and_test) {
290
+ (
291
+ wsp? >>
292
+ atomic_node_test.as(:left) >> wsp? >>
293
+ and_op >> wsp? >>
294
+ node_test.as(:right) >> wsp?
295
+ ).as(:and)
296
+ }
297
+
298
+ rule(:or_test) {
299
+ (
300
+ wsp? >>
301
+ atomic_node_test.as(:left) >> wsp? >>
302
+ or_op >> wsp? >>
303
+ node_test.as(:right) >> wsp?
304
+ ).as(:or)
305
+ }
306
+
307
+ # @en
308
+ rule(:literal_language_test) {
309
+ wsp? >>
310
+ lang >> identifier.as(:lang) >>
311
+ wsp?
312
+ }
313
+
314
+ # ^^xyz
315
+ rule(:literal_type_test) {
316
+ wsp? >>
317
+ type >> uri.as(:type) >>
318
+ wsp?
319
+ }
320
+
321
+ rule(:is_a_test) {
322
+ (
323
+ wsp? >>
324
+ is_a >> wsp? >>
325
+ node.as(:right) >>
326
+ wsp?
327
+ ).as(:is_a)
328
+ }
329
+
330
+ rule(:path_equality_test) {
331
+ (
332
+ wsp? >>
333
+ selector >> wsp? >>
334
+ is >> wsp? >>
335
+ node.as(:right) >> wsp?
336
+ ).as(:is)
337
+ }
338
+
339
+ rule(:function_test) {
340
+ wsp? >>
341
+ (
342
+ func >> identifier.as(:fname) >> str("()") |
343
+ func >> identifier.as(:fname) >> str("(") >>
344
+ arglist.as(:arglist) >>
345
+ str(")")
346
+ ) >> wsp?
347
+ }
348
+
349
+ rule(:path_test) {
350
+ (
351
+ path_selector |
352
+ testing_selector |
353
+ atomic_selector
354
+ )
355
+ }
356
+
357
+ end
358
+ end