ldpath 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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