ldpath 1.0.0 → 1.2.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 +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'
|