ldpath 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,259 +1,70 @@
1
- require 'parslet'
1
+ module Ldpath
2
+ class Program
2
3
 
3
- class Ldpath::Program < Parslet::Parser
4
- root :lines
5
- rule(:lines) { line.repeat }
6
- rule(:line) { expression >> newline }
7
- rule(:newline) { any.absent? | str("\n") >> str("\r").maybe }
8
- rule(:expression) { wsp | multiline_comment | namespace | mapping }
9
-
10
- rule(:multiline_comment) { (str('/*') >> (str('*/').absent? >> any).repeat >> str('*/')) }
11
-
12
- rule(:comma) { str(",") }
13
- rule(:scolon) { str(";") }
14
- rule(:colon) { str(":") }
15
- rule(:dcolon) { str("::") }
16
- rule(:assign) { str("=") }
17
- rule(:k_prefix) { str("@prefix")}
18
- rule(:k_graph) { str("@graph")}
19
-
20
- rule(:self_op) { str(".") }
21
- rule(:and_op) { str("&") }
22
- rule(:or_op) { str("|") }
23
- rule(:p_sep) { str("/") }
24
- rule(:plus) { str("+") }
25
- rule(:star) { str("*") }
26
- rule(:not_op) { str("!") }
27
- rule(:inverse) { str("^") }
28
- rule(:is) { str "is" }
29
- rule(:is_a) { str "is-a" }
30
- rule(:func) { str "fn:"}
31
- rule(:type) { str "^^" }
32
- rule(:lang) { str "@" }
33
-
34
- rule(:wsp) { (match["\s"] | str("\n")).repeat(1) }
35
- rule(:wsp?) { wsp.maybe }
36
-
37
- # todo: fixme
38
- rule(:uri) { (str("<") >> (str(">").absent? >> any).repeat >> str(">")) | (identifier.as(:prefix) >> str(":") >> identifier.as(:localName) )}
39
- rule(:identifier) { match["a-zA-Z0-9_"] >> (match["a-zA-Z0-9_'\\.-"]).repeat }
4
+ include Ldpath::Functions
40
5
 
41
- rule(:namespace) {
42
- k_prefix >>
43
- wsp? >>
44
- identifier.as(:id) >>
45
- wsp? >>
46
- colon >>
47
- wsp? >>
48
- uri.as(:uri) >>
49
- wsp? >>
50
- scolon.maybe
51
- }
52
-
53
- rule(:mapping) {
54
- name_selector_mapping
55
- }
56
-
57
- rule(:name_selector_mapping) {
58
- identifier.as(:name) >>
59
- wsp? >>
60
- assign >>
61
- wsp? >>
62
- selector.as(:selector) >>
63
- wsp? >>
64
- (
65
- dcolon >> wsp? >>
66
- uri.as(:type)
67
- ).maybe >>
68
- wsp? >>
69
- scolon
70
- }
71
-
72
- rule(:selector) {
73
- (
74
- compound_selector |
75
- testing_selector |
76
- atomic_selector
77
- ).as(:result)
78
- }
79
-
80
- rule(:compound_selector) {
81
- (
82
- union_selector |
83
- intersection_selector |
84
- path_selector
85
- ).as(:result)
86
- }
87
-
88
- rule(:grouped_selector) {
89
- wsp? >>
90
- str("(") >> wsp? >> selector.as(:result) >> wsp? >> str(")") >> wsp?
91
- }
92
-
93
- rule(:path_selector) {
94
- wsp? >>
95
- atomic_or_testing_selector.as(:left) >>
96
- wsp? >>
97
- p_sep >>
98
- wsp? >>
99
- atomic_or_testing_or_path_selector.as(:right) >>
100
- wsp?
101
- }
102
-
103
- rule(:intersection_selector) {
104
- wsp? >>
105
- atomic_or_testing_or_path_selector.as(:left) >>
106
- wsp? >>
107
- and_op >>
108
- wsp? >>
109
- selector.as(:right) >>
110
- wsp?
111
- }
112
-
113
- rule(:union_selector) {
114
- wsp? >>
115
- atomic_or_testing_or_path_selector.as(:left) >>
6
+ class << self
7
+ def parse program, transform_context = {}
8
+ parsed = parser.parse(program)
9
+ ast = transform.apply parsed, transform_context
10
+
11
+ Ldpath::Program.new ast.compact
12
+ end
13
+
14
+ private
15
+ def transform
16
+ Ldpath::Transform.new
17
+ end
18
+
19
+ def parser
20
+ @parser ||= Ldpath::Parser.new
21
+ end
22
+ end
116
23
 
117
- wsp? >>
118
- or_op >>
24
+ attr_reader :mappings
25
+ def initialize mappings
26
+ @mappings ||= mappings
27
+ @cache = {}
28
+ end
119
29
 
120
- wsp? >>
121
- selector.as(:right) >>
30
+ def loading uri, context
31
+ if uri.to_s =~ /^http/ and !context.has_subject?(uri)
32
+ @cache[uri] ||= RDF::Graph.load(uri)
33
+ context << @cache[uri]
34
+ end
35
+ end
36
+
37
+ def evaluate uri, context = nil
38
+ h = {}
39
+ context ||= RDF::Graph.load uri.to_s
40
+
41
+ mappings.each do |m|
42
+ h[m.name] = case m.selector
43
+ when Selector
44
+ m.selector.evaluate(self, uri, context).map do |x|
45
+ next x unless m.field_type
46
+ RDF::Literal.new(x.to_s, datatype: m.field_type).canonicalize.object
47
+ end
48
+ else
49
+ Array(m.selector)
50
+ end
51
+ end
52
+
53
+ h
54
+ end
122
55
 
123
- wsp?
124
- }
125
-
126
- rule(:atomic_or_testing_or_path_selector) {
127
- (path_selector | atomic_or_testing_selector).as(:result)
128
- }
129
-
130
- rule(:atomic_or_testing_selector) {
131
- (testing_selector | atomic_selector).as(:result)
132
- }
133
-
134
- rule(:atomic_selector) {
135
- (
136
- self_selector |
137
- property_selector |
138
- wildcard_selector |
139
- reverse_property_selector |
140
- function_selector |
141
- # string_constant_selector |
142
- # recursive_path_selector |
143
- grouped_selector
144
- ).as(:result)
145
- }
146
-
147
- rule(:self_selector) {
148
- wsp? >> self_op >> wsp?
149
- }
150
-
151
- rule(:property_selector) {
152
- wsp? >> uri >> wsp?
153
- }
154
-
155
- rule(:reverse_property_selector) {
156
- wsp? >> inverse >> uri.as(:uri) >> wsp?
157
- }
158
-
159
- rule(:wildcard_selector) {
160
- wsp? >> star >> wsp?
161
- }
162
-
163
- rule(:testing_selector) {
164
- wsp? >>
165
- atomic_selector.as(:delegate) >>
166
- str("[") >>
167
- wsp? >>
168
- node_test.as(:test) >>
169
- wsp? >>
170
- str("]") >> wsp?
171
- }
172
-
173
- rule(:node_test) {
174
- grouped_test |
175
- not_test |
176
- and_test |
177
- or_test |
178
- atomic_node_test
179
- }
180
-
181
- rule(:grouped_test) {
182
- wsp? >> str("(") >> wsp? >> node_test >> wsp? >> str(")") >> wsp?
183
- }
184
-
185
- rule(:atomic_node_test) {
186
- # literal_language_test |
187
- # literal_type_test |
188
- is_a_test |
189
- path_equality_test |
190
- function_test |
191
- path_test
192
- }
193
-
194
- rule(:not_test) {
195
- wsp? >> not_op >> node_test.as(:delegate) >> wsp?
196
- }
197
-
198
- rule(:and_test) {
199
- wsp? >> atomic_node_test >> wsp? >> and_op >> wsp? >> node_test >> wsp?
200
- }
201
-
202
- rule(:or_test) {
203
- wsp? >> atomic_node_test >> wsp? >> or_op >> wsp? >> node_test >> wsp?
204
- }
205
-
206
- rule(:strlit) {
207
- wsp? >> str('"') >> (str('"').absent? >> any).repeat >> str('"') >> wsp?
208
- }
209
-
210
- rule(:node) {
211
- uri.as(:uri) | strlit.as(:literal)
212
- }
213
-
214
- rule(:is_a_test) {
215
- wsp? >> is_a >> wsp? >> node.as(:node) >> wsp?
216
- }
217
-
218
- rule(:path_equality_test) {
219
- selector.as(:path) >> is >> node.as(:node)
220
- }
221
-
222
- rule(:function_selector) {
223
- (
224
- func >> identifier.as(:fname) >> str("()") |
225
- func >> identifier.as(:fname) >> str("(") >>
226
- wsp? >>
227
- (selector.as(:argument)) >>
228
- (
229
- (wsp? >> str(",") >> wsp? >> selector.as(:argument)).repeat
230
- ).maybe >>
231
- wsp? >>
232
- str(")")
233
- )
234
- }
235
-
236
- rule(:function_test) {
237
- (
238
- func >> identifier.as(:fname) >> str("()") |
239
- func >> identifier.as(:fname) >> str("(") >>
240
- wsp? >>
241
- (selector.as(:argument)) >>
242
- (
243
- (wsp? >> str(",") >> wsp? >> selector.as(:argument)).repeat
244
- ).maybe >>
245
- wsp? >>
246
- str(")")
247
- )
248
- }
249
-
250
- rule(:path_test) {
251
- (
252
- path_selector |
253
- testing_selector |
254
- atomic_selector
255
- ).as(:path)
256
- }
257
-
56
+ def func_call fname, uri, context, *arguments
57
+ if function_method? fname
58
+ public_send(fname, uri, context, *arguments)
59
+ else
60
+ raise "No such function: #{fname}"
61
+ end
62
+ end
63
+
64
+ private
65
+ def function_method? function
66
+ Functions.public_instance_methods(false).include? function.to_sym
67
+ end
258
68
 
69
+ end
259
70
  end
@@ -0,0 +1,124 @@
1
+ module Ldpath
2
+ class Selector
3
+ def evaluate program, uris, context
4
+ Array(uris).map do |uri|
5
+ loading program, uri, context
6
+ evaluate_one uri, context
7
+ end.flatten.compact
8
+ end
9
+
10
+ def loading program, uri, context
11
+ program.loading uri, context
12
+ end
13
+ end
14
+
15
+ class SelfSelector < Selector
16
+ def evaluate_one uri, context
17
+ uri
18
+ end
19
+ end
20
+
21
+ class FunctionSelector < Selector
22
+ attr_reader :fname, :arguments
23
+
24
+ def initialize fname, arguments
25
+ @fname = fname
26
+ @arguments = arguments
27
+ end
28
+
29
+ def evaluate program, uris, context
30
+ Array(uris).map do |uri|
31
+ loading program, uri, context
32
+ args = arguments.map do |i|
33
+ case i
34
+ when Selector
35
+ i.evaluate(program, uri, context)
36
+ else
37
+ i
38
+ end
39
+ end
40
+ program.func_call fname, uri, context, *arguments
41
+ end.flatten.compact
42
+ end
43
+ end
44
+
45
+ class PropertySelector < Selector
46
+ attr_reader :property
47
+ def initialize property
48
+ @property = property
49
+ end
50
+
51
+ def evaluate_one uri, context
52
+ context.query([uri, property, nil]).map(&:object)
53
+ end
54
+ end
55
+
56
+ class WildcardSelector < Selector
57
+ def evaluate_one uri, context
58
+ context.query([uri, nil, nil]).map(&:object)
59
+ end
60
+ end
61
+
62
+ class ReversePropertySelector < Selector
63
+ attr_reader :property
64
+ def initialize property
65
+ @property = property
66
+ end
67
+
68
+ def evaluate_one uri, context
69
+ context.query([nil, property, uri]).map(&:subject)
70
+ end
71
+ end
72
+
73
+ class RecursivePathSelector < Selector
74
+ attr_reader :property, :repeat
75
+ def initialize property, repeat
76
+ @property = property
77
+ @repeat = repeat
78
+ end
79
+
80
+ def evaluate program, uris, context
81
+ result = []
82
+ input = Array(uris)
83
+
84
+ Range.new(0,repeat.min,true).each do
85
+ input = property.evaluate program, input, context
86
+ end
87
+
88
+ repeat.each_with_index do |i, idx|
89
+ break if input.empty? or idx > 25 # we're probably lost..
90
+ input = property.evaluate program, input, context
91
+ result |= input
92
+ end
93
+ result.flatten.compact
94
+ end
95
+ end
96
+
97
+ class CompoundSelector < Selector
98
+ attr_reader :left, :right
99
+ def initialize left, right
100
+ @left = left
101
+ @right = right
102
+ end
103
+ end
104
+
105
+ class PathSelector < CompoundSelector
106
+ def evaluate program, uris, context
107
+ output = left.evaluate(program, uris, context)
108
+ right.evaluate(program, output, context)
109
+ end
110
+ end
111
+
112
+ class UnionSelector < CompoundSelector
113
+ def evaluate program, uris, context
114
+ left.evaluate(program, uris, context) | right.evaluate(program, uris, context)
115
+ end
116
+ end
117
+
118
+ class IntersectionSelector < CompoundSelector
119
+ def evaluate program, uris, context
120
+ left.evaluate(program, uris, context) & right.evaluate(program, uris, context)
121
+ end
122
+ end
123
+
124
+ end
@@ -0,0 +1,102 @@
1
+ module Ldpath
2
+
3
+ class TestSelector < Selector
4
+ attr_reader :delegate, :test
5
+
6
+ def initialize delegate, test
7
+ @delegate = delegate
8
+ @test = test
9
+ end
10
+
11
+ def evaluate program, uris, context
12
+ entries = delegate.evaluate program, uris, context
13
+ entries.select do |uri|
14
+ Array(test.evaluate(program, uri, context)).any? do |x|
15
+ x
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class LanguageTest < TestSelector
22
+ attr_reader :lang
23
+ def initialize lang
24
+ @lang = lang
25
+ end
26
+
27
+ def evaluate program, uri, context
28
+ return unless uri.literal?
29
+ if (lang == "none" && !uri.has_language?) or uri.language == lang
30
+ uri
31
+ end
32
+ end
33
+ end
34
+
35
+ class TypeTest < TestSelector
36
+ attr_reader :type
37
+ def initialize type
38
+ @type = type
39
+ end
40
+
41
+ def evaluate program, uri, context
42
+ return unless uri.literal?
43
+ if uri.has_datatype? and uri.datatype == type
44
+ uri
45
+ end
46
+ end
47
+ end
48
+
49
+ class NotTest < TestSelector
50
+ attr_reader :delegate
51
+
52
+ def initialize delegate
53
+ @delegate = delegate
54
+ end
55
+
56
+ def evaluate program, uri, context
57
+ !Array(delegate.evaluate(program, uri, context)).any? { |x| x }
58
+ end
59
+ end
60
+
61
+ class OrTest < TestSelector
62
+ attr_reader :left, :right
63
+
64
+ def initialize left, right
65
+ @left = left
66
+ @right = right
67
+ end
68
+
69
+ def evaluate program, uri, context
70
+ left.evaluate(program, uri, context).any? || right.evaluate(program, uri, context).any?
71
+ end
72
+ end
73
+
74
+ class AndTest < TestSelector
75
+
76
+ attr_reader :left, :right
77
+
78
+ def initialize left, right
79
+ @left = left
80
+ @right = right
81
+ end
82
+
83
+ def evaluate program, uri, context
84
+ left.evaluate(program, uri, context).compact.any? &&
85
+ right.evaluate(program, uri, context).compact.any?
86
+ end
87
+ end
88
+
89
+ class IsTest < TestSelector
90
+
91
+ attr_reader :left, :right
92
+
93
+ def initialize left, right
94
+ @left = left
95
+ @right = right
96
+ end
97
+
98
+ def evaluate program, uri, context
99
+ left.evaluate(program, uri, context).compact.include?(right)
100
+ end
101
+ end
102
+ end