ldpath 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +49 -0
- data/.rubocop.yml +40 -1
- data/.travis.yml +3 -1
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTING.md +45 -13
- data/Gemfile +3 -6
- data/README.md +15 -4
- data/Rakefile +2 -0
- data/bin/ldpath +6 -1
- data/ldpath.gemspec +11 -8
- data/lib/ldpath/field_mapping.rb +2 -0
- data/lib/ldpath/functions.rb +4 -4
- data/lib/ldpath/loaders/direct.rb +17 -0
- data/lib/ldpath/loaders/graph.rb +15 -0
- data/lib/ldpath/loaders/linked_data_fragment.rb +31 -0
- data/lib/ldpath/loaders.rb +9 -0
- data/lib/ldpath/parser.rb +4 -2
- data/lib/ldpath/program.rb +19 -9
- data/lib/ldpath/result.rb +7 -13
- data/lib/ldpath/selectors.rb +45 -26
- data/lib/ldpath/tests.rb +26 -5
- data/lib/ldpath/transform.rb +16 -14
- data/lib/ldpath/version.rb +3 -1
- data/lib/ldpath.rb +15 -8
- data/spec/ldpath_parser_spec.rb +6 -4
- data/spec/ldpath_program_spec.rb +113 -70
- data/spec/ldpath_spec.rb +2 -0
- data/spec/ldpath_transform_spec.rb +5 -3
- data/spec/lib/functions/list_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -18
- metadata +51 -19
data/lib/ldpath/selectors.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Ldpath
|
2
4
|
class Selector
|
3
5
|
def evaluate(program, uris, context)
|
4
6
|
return to_enum(:evaluate, program, uris, context) unless block_given?
|
7
|
+
|
5
8
|
enum_wrap(uris).map do |uri|
|
6
9
|
loading program, uri, context
|
7
10
|
enum_flatten_one(evaluate_one(uri, context)).each do |x|
|
@@ -14,6 +17,10 @@ module Ldpath
|
|
14
17
|
program.loading uri, context
|
15
18
|
end
|
16
19
|
|
20
|
+
def initialize(*_args)
|
21
|
+
# abstract base class
|
22
|
+
end
|
23
|
+
|
17
24
|
protected
|
18
25
|
|
19
26
|
def enum_wrap(object)
|
@@ -29,14 +36,12 @@ module Ldpath
|
|
29
36
|
[object]
|
30
37
|
end
|
31
38
|
end
|
32
|
-
|
33
|
-
def enum_flatten_one(object)
|
39
|
+
|
40
|
+
def enum_flatten_one(object, &block)
|
34
41
|
return to_enum(:enum_flatten_one, object) unless block_given?
|
35
42
|
|
36
43
|
enum_wrap(object).each do |e|
|
37
|
-
enum_wrap(e).each
|
38
|
-
yield v
|
39
|
-
end
|
44
|
+
enum_wrap(e).each(&block)
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
@@ -53,6 +58,8 @@ module Ldpath
|
|
53
58
|
def initialize(fname, arguments = [])
|
54
59
|
@fname = fname
|
55
60
|
@arguments = Array(arguments)
|
61
|
+
|
62
|
+
super
|
56
63
|
end
|
57
64
|
|
58
65
|
def evaluate(program, uris, context)
|
@@ -77,8 +84,11 @@ module Ldpath
|
|
77
84
|
|
78
85
|
class PropertySelector < Selector
|
79
86
|
attr_reader :property
|
87
|
+
|
80
88
|
def initialize(property)
|
81
89
|
@property = property
|
90
|
+
|
91
|
+
super
|
82
92
|
end
|
83
93
|
|
84
94
|
def evaluate_one(uri, context)
|
@@ -88,8 +98,11 @@ module Ldpath
|
|
88
98
|
|
89
99
|
class LoosePropertySelector < Selector
|
90
100
|
attr_reader :property
|
101
|
+
|
91
102
|
def initialize(property)
|
92
103
|
@property = property
|
104
|
+
|
105
|
+
super
|
93
106
|
end
|
94
107
|
|
95
108
|
def evaluate_one(uri, context)
|
@@ -103,8 +116,11 @@ module Ldpath
|
|
103
116
|
|
104
117
|
class NegatedPropertySelector < Selector
|
105
118
|
attr_reader :properties
|
119
|
+
|
106
120
|
def initialize(*properties)
|
107
121
|
@properties = properties
|
122
|
+
|
123
|
+
super
|
108
124
|
end
|
109
125
|
|
110
126
|
def evaluate_one(uri, context)
|
@@ -122,8 +138,11 @@ module Ldpath
|
|
122
138
|
|
123
139
|
class ReversePropertySelector < Selector
|
124
140
|
attr_reader :property
|
141
|
+
|
125
142
|
def initialize(property)
|
126
143
|
@property = property
|
144
|
+
|
145
|
+
super
|
127
146
|
end
|
128
147
|
|
129
148
|
def evaluate_one(uri, context)
|
@@ -133,34 +152,39 @@ module Ldpath
|
|
133
152
|
|
134
153
|
class RecursivePathSelector < Selector
|
135
154
|
attr_reader :property, :repeat
|
155
|
+
|
136
156
|
def initialize(property, repeat)
|
137
157
|
@property = property
|
138
158
|
@repeat = repeat
|
159
|
+
|
160
|
+
super
|
139
161
|
end
|
140
162
|
|
141
|
-
def evaluate(program, uris, context)
|
163
|
+
def evaluate(program, uris, context, &block)
|
142
164
|
return to_enum(:evaluate, program, uris, context) unless block_given?
|
143
165
|
|
144
166
|
input = enum_wrap(uris)
|
145
167
|
|
146
|
-
(0..repeat.max).each_with_index do |
|
147
|
-
break if input.none? || (repeat.max == Ldpath::Transform::
|
168
|
+
(0..repeat.max).each_with_index do |_i, idx|
|
169
|
+
break if input.none? || (repeat.max == Ldpath::Transform::INFINITY && idx > 25) # we're probably lost..
|
170
|
+
|
148
171
|
input = property.evaluate program, input, context
|
149
172
|
|
150
173
|
next unless idx >= repeat.min
|
151
174
|
|
152
|
-
enum_wrap(input).each
|
153
|
-
yield x
|
154
|
-
end
|
175
|
+
enum_wrap(input).each(&block)
|
155
176
|
end
|
156
177
|
end
|
157
178
|
end
|
158
179
|
|
159
180
|
class CompoundSelector < Selector
|
160
181
|
attr_reader :left, :right
|
182
|
+
|
161
183
|
def initialize(left, right)
|
162
184
|
@left = left
|
163
185
|
@right = right
|
186
|
+
|
187
|
+
super
|
164
188
|
end
|
165
189
|
end
|
166
190
|
|
@@ -174,46 +198,41 @@ module Ldpath
|
|
174
198
|
end
|
175
199
|
|
176
200
|
class UnionSelector < CompoundSelector
|
177
|
-
def evaluate(program, uris, context)
|
201
|
+
def evaluate(program, uris, context, &block)
|
178
202
|
return to_enum(:evaluate, program, uris, context) unless block_given?
|
179
203
|
|
180
|
-
enum_union(left.evaluate(program, uris, context), right.evaluate(program, uris, context)).each
|
181
|
-
yield x
|
182
|
-
end
|
204
|
+
enum_union(left.evaluate(program, uris, context), right.evaluate(program, uris, context)).each(&block)
|
183
205
|
end
|
184
206
|
|
185
207
|
private
|
186
208
|
|
187
|
-
def enum_union(left, right)
|
209
|
+
def enum_union(left, right, &block)
|
188
210
|
return to_enum(:enum_union, left, right) unless block_given?
|
189
211
|
|
190
|
-
enum_wrap(left).each
|
191
|
-
yield e
|
192
|
-
end
|
212
|
+
enum_wrap(left).each(&block)
|
193
213
|
|
194
|
-
enum_wrap(right).each
|
195
|
-
yield e
|
196
|
-
end
|
214
|
+
enum_wrap(right).each(&block)
|
197
215
|
end
|
198
216
|
end
|
199
217
|
|
200
218
|
class IntersectionSelector < CompoundSelector
|
201
|
-
def evaluate(program, uris, context)
|
219
|
+
def evaluate(program, uris, context, &block)
|
202
220
|
return to_enum(:evaluate, program, uris, context) unless block_given?
|
203
221
|
|
204
222
|
result = left.evaluate(program, uris, context).to_a & right.evaluate(program, uris, context).to_a
|
205
223
|
|
206
|
-
result.each
|
207
|
-
yield x
|
208
|
-
end
|
224
|
+
result.each(&block)
|
209
225
|
end
|
210
226
|
end
|
211
227
|
|
212
228
|
class TapSelector < Selector
|
213
229
|
attr_reader :identifier, :tap
|
230
|
+
|
214
231
|
def initialize(identifier, tap)
|
215
232
|
@identifier = identifier
|
216
233
|
@tap = tap
|
234
|
+
|
235
|
+
super
|
217
236
|
end
|
218
237
|
|
219
238
|
def evaluate(program, uris, context)
|
data/lib/ldpath/tests.rb
CHANGED
@@ -1,42 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Ldpath
|
2
4
|
class TestSelector < Selector
|
3
5
|
attr_reader :delegate, :test
|
4
6
|
|
5
|
-
def initialize(delegate, test)
|
7
|
+
def initialize(delegate = nil, test = nil)
|
6
8
|
@delegate = delegate
|
7
9
|
@test = test
|
10
|
+
|
11
|
+
super
|
8
12
|
end
|
9
13
|
|
10
14
|
def evaluate(program, uris, context)
|
15
|
+
return to_enum(:evaluate, program, uris, context) unless block_given?
|
16
|
+
|
11
17
|
entries = delegate.evaluate program, uris, context
|
12
18
|
entries.select do |uri|
|
13
|
-
enum_wrap(test.evaluate(program, uri, context)).any? do |x|
|
19
|
+
result = enum_wrap(test.evaluate(program, uri, context)).any? do |x|
|
14
20
|
x
|
15
21
|
end
|
22
|
+
yield uri if result
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
20
27
|
class LanguageTest < TestSelector
|
21
28
|
attr_reader :lang
|
29
|
+
|
22
30
|
def initialize(lang)
|
23
31
|
@lang = lang
|
32
|
+
|
33
|
+
super
|
24
34
|
end
|
25
35
|
|
26
36
|
def evaluate(_program, uri, _context)
|
27
37
|
return unless uri.literal?
|
28
38
|
|
29
|
-
uri if (lang == "none" && !uri.has_language?) || uri.language == lang
|
39
|
+
uri if (lang.to_s == "none" && !uri.has_language?) || uri.language.to_s == lang.to_s
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
33
43
|
class TypeTest < TestSelector
|
34
44
|
attr_reader :type
|
45
|
+
|
35
46
|
def initialize(type)
|
36
47
|
@type = type
|
48
|
+
|
49
|
+
super
|
37
50
|
end
|
38
51
|
|
39
|
-
def evaluate(
|
52
|
+
def evaluate(_program, uri, _context)
|
40
53
|
return unless uri.literal?
|
41
54
|
|
42
55
|
uri if uri.has_datatype? && uri.datatype == type
|
@@ -48,10 +61,12 @@ module Ldpath
|
|
48
61
|
|
49
62
|
def initialize(delegate)
|
50
63
|
@delegate = delegate
|
64
|
+
|
65
|
+
super
|
51
66
|
end
|
52
67
|
|
53
68
|
def evaluate(program, uri, context)
|
54
|
-
|
69
|
+
enum_wrap(delegate.evaluate(program, uri, context)).none? { |x| x }
|
55
70
|
end
|
56
71
|
end
|
57
72
|
|
@@ -61,6 +76,8 @@ module Ldpath
|
|
61
76
|
def initialize(left, right)
|
62
77
|
@left = left
|
63
78
|
@right = right
|
79
|
+
|
80
|
+
super
|
64
81
|
end
|
65
82
|
|
66
83
|
def evaluate(program, uri, context)
|
@@ -74,6 +91,8 @@ module Ldpath
|
|
74
91
|
def initialize(left, right)
|
75
92
|
@left = left
|
76
93
|
@right = right
|
94
|
+
|
95
|
+
super
|
77
96
|
end
|
78
97
|
|
79
98
|
def evaluate(program, uri, context)
|
@@ -88,6 +107,8 @@ module Ldpath
|
|
88
107
|
def initialize(left, right)
|
89
108
|
@left = left
|
90
109
|
@right = right
|
110
|
+
|
111
|
+
super
|
91
112
|
end
|
92
113
|
|
93
114
|
def evaluate(program, uri, context)
|
data/lib/ldpath/transform.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Ldpath
|
2
4
|
class Transform < Parslet::Transform
|
3
5
|
attr_reader :prefixes
|
@@ -5,17 +7,17 @@ module Ldpath
|
|
5
7
|
class << self
|
6
8
|
def default_prefixes
|
7
9
|
@default_prefixes ||= {
|
8
|
-
"rdf"
|
10
|
+
"rdf" => RDF::Vocabulary.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
|
9
11
|
"rdfs" => RDF::Vocabulary.new("http://www.w3.org/2000/01/rdf-schema#"),
|
10
|
-
"owl"
|
12
|
+
"owl" => RDF::Vocabulary.new("http://www.w3.org/2002/07/owl#"),
|
11
13
|
"skos" => RDF::Vocabulary.new("http://www.w3.org/2004/02/skos/core#"),
|
12
|
-
"dc"
|
13
|
-
"xsd"
|
14
|
-
"lmf"
|
15
|
-
"fn"
|
14
|
+
"dc" => RDF::Vocabulary.new("http://purl.org/dc/elements/1.1/"),
|
15
|
+
"xsd" => RDF::Vocabulary.new("http://www.w3.org/2001/XMLSchema#"), # (LMF base index datatypes/XML Schema)
|
16
|
+
"lmf" => RDF::Vocabulary.new("http://www.newmedialab.at/lmf/types/1.0/"), # (LMF extended index datatypes)
|
17
|
+
"fn" => RDF::Vocabulary.new("http://www.newmedialab.at/lmf/functions/1.0/"), # (LMF index functions)
|
16
18
|
"foaf" => RDF::Vocabulary.new("http://xmlns.com/foaf/0.1/"),
|
17
19
|
"info" => RDF::Vocabulary.new("info:"),
|
18
|
-
"urn"
|
20
|
+
"urn" => RDF::Vocabulary.new("urn:")
|
19
21
|
}
|
20
22
|
end
|
21
23
|
end
|
@@ -29,8 +31,8 @@ module Ldpath
|
|
29
31
|
end
|
30
32
|
|
31
33
|
# Core types
|
32
|
-
rule(true
|
33
|
-
rule(false
|
34
|
+
rule(true => simple(true)) { true }
|
35
|
+
rule(false => simple(false)) { false }
|
34
36
|
rule(integer: simple(:integer)) { integer.to_i }
|
35
37
|
rule(double: simple(:double)) { double.to_f }
|
36
38
|
rule(decimal: simple(:decimal)) { decimal.to_f }
|
@@ -71,7 +73,7 @@ module Ldpath
|
|
71
73
|
# Mappings
|
72
74
|
|
73
75
|
rule(mapping: subtree(:mapping)) do
|
74
|
-
FieldMapping.new
|
76
|
+
FieldMapping.new(**mapping)
|
75
77
|
end
|
76
78
|
|
77
79
|
## Selectors
|
@@ -106,11 +108,11 @@ module Ldpath
|
|
106
108
|
end
|
107
109
|
|
108
110
|
rule(range: subtree(:range)) do
|
109
|
-
range.fetch(:min, 0).to_i..range.fetch(:max,
|
111
|
+
range.fetch(:min, 0).to_i..range.fetch(:max, INFINITY).to_f
|
110
112
|
end
|
111
113
|
|
112
|
-
rule(range: '*') { 0..
|
113
|
-
rule(range: '+') { 1..
|
114
|
+
rule(range: '*') { 0..INFINITY }
|
115
|
+
rule(range: '+') { 1..INFINITY }
|
114
116
|
rule(range: '?') { 0..1 }
|
115
117
|
|
116
118
|
rule(delegate: subtree(:delegate), repeat: simple(:repeat)) do
|
@@ -177,6 +179,6 @@ module Ldpath
|
|
177
179
|
IntersectionSelector.new left, right
|
178
180
|
end
|
179
181
|
|
180
|
-
|
182
|
+
INFINITY = 1.0 / 0.0
|
181
183
|
end
|
182
184
|
end
|
data/lib/ldpath/version.rb
CHANGED
data/lib/ldpath.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "ldpath/version"
|
2
|
-
require 'linkeddata'
|
3
4
|
require 'logger'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'rdf'
|
7
|
+
require 'rdf/vocab'
|
8
|
+
# require rdf/ntriples may not be necessary, may only really be necessary
|
9
|
+
# for ldpath_program_spec.rb tests, but I'm not certain, and I don't think it hurts
|
10
|
+
# to do it here.
|
11
|
+
require 'rdf/ntriples'
|
4
12
|
|
5
13
|
module Ldpath
|
6
14
|
require 'ldpath/field_mapping'
|
@@ -11,6 +19,7 @@ module Ldpath
|
|
11
19
|
require 'ldpath/functions'
|
12
20
|
require 'ldpath/program'
|
13
21
|
require 'ldpath/result'
|
22
|
+
require 'ldpath/loaders'
|
14
23
|
|
15
24
|
class << self
|
16
25
|
attr_writer :logger
|
@@ -20,13 +29,11 @@ module Ldpath
|
|
20
29
|
end
|
21
30
|
|
22
31
|
def logger
|
23
|
-
@logger ||=
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
32
|
+
@logger ||= if defined? Rails
|
33
|
+
Rails.logger
|
34
|
+
else
|
35
|
+
Logger.new($stderr)
|
36
|
+
end
|
30
37
|
end
|
31
38
|
end
|
32
39
|
end
|
data/spec/ldpath_parser_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'pp'
|
3
5
|
require 'parslet/convenience'
|
@@ -228,10 +230,10 @@ describe Ldpath::Parser do
|
|
228
230
|
|
229
231
|
describe "integration tests" do
|
230
232
|
it "should parse a simple example" do
|
231
|
-
tree = subject.parse
|
232
|
-
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
233
|
-
topic = <http://xmlns.com/foaf/0.1/primaryTopic> :: xsd:string ;
|
234
|
-
EOF
|
233
|
+
tree = subject.parse <<~EOF
|
234
|
+
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
235
|
+
topic = <http://xmlns.com/foaf/0.1/primaryTopic> :: xsd:string ;
|
236
|
+
EOF
|
235
237
|
expect(tree.length).to eq 2
|
236
238
|
expect(tree.first).to include :prefixID
|
237
239
|
expect(tree.first[:prefixID]).to include id: 'dcterms'
|