ldpath 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/ldpath.gemspec +1 -0
- data/lib/ldpath/functions.rb +4 -2
- data/lib/ldpath/parser.rb +23 -1
- data/lib/ldpath/program.rb +26 -9
- data/lib/ldpath/selectors.rb +39 -3
- data/lib/ldpath/transform.rb +12 -0
- data/lib/ldpath/version.rb +1 -1
- data/lib/ldpath.rb +15 -0
- data/spec/ldpath_parser_spec.rb +8 -0
- data/spec/ldpath_program_spec.rb +84 -4
- data/spec/ldpath_transform_spec.rb +9 -0
- data/spec/spec_helper.rb +5 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: feb1911da55e6e56d33cb8bccea249060b59f7da
|
4
|
+
data.tar.gz: 87eab8d2813362a18c9ff45707325542f45ec657
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 111dbf2d32a03ab3199d622f1ea78c94322a24733e0120c537ed43d2f42c592e650ab72e67f067cf6578d4be2ddcdbfd6756d09369c2e9d8c1fb7757f7624bb2
|
7
|
+
data.tar.gz: 5dc5e8488936d2d14114522cb1880a05e165edc317b6a433b247dff8e235af989419a7fac28b71a8f5741da7a8d0b2b33c3e6d10179a0a3b830461ff748a970e
|
data/Gemfile
CHANGED
data/ldpath.gemspec
CHANGED
data/lib/ldpath/functions.rb
CHANGED
@@ -126,7 +126,6 @@ module Ldpath
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def startsWith uri, context, str, suffix
|
129
|
-
|
130
129
|
Array(str).map { |x| x.start_with? suffix }
|
131
130
|
end
|
132
131
|
|
@@ -136,9 +135,12 @@ module Ldpath
|
|
136
135
|
end
|
137
136
|
|
138
137
|
def isEmpty uri, context, str
|
139
|
-
|
140
138
|
Array(str).map(&:empty?)
|
141
139
|
end
|
140
|
+
|
141
|
+
def predicates uri, context, *args
|
142
|
+
context.query([uri, nil, nil]).map(&:predicate).uniq
|
143
|
+
end
|
142
144
|
|
143
145
|
end
|
144
146
|
end
|
data/lib/ldpath/parser.rb
CHANGED
@@ -32,11 +32,13 @@ module Ldpath
|
|
32
32
|
rule(:star) { str("*") }
|
33
33
|
rule(:not_op) { str("!") }
|
34
34
|
rule(:inverse) { str("^") }
|
35
|
+
rule(:tap) { str("?") }
|
35
36
|
rule(:is) { str "is" }
|
36
37
|
rule(:is_a) { str "is-a" }
|
37
38
|
rule(:func) { str "fn:"}
|
38
39
|
rule(:type) { str "^^" }
|
39
40
|
rule(:lang) { str "@" }
|
41
|
+
rule(:loose) { str("~") }
|
40
42
|
|
41
43
|
# todo: fixme
|
42
44
|
rule(:uri) do
|
@@ -138,14 +140,17 @@ module Ldpath
|
|
138
140
|
self_selector |
|
139
141
|
function_selector |
|
140
142
|
property_selector |
|
143
|
+
loose_property_selector |
|
141
144
|
wildcard_selector |
|
142
145
|
reverse_property_selector |
|
143
146
|
string_constant_selector |
|
144
147
|
recursive_path_selector |
|
145
|
-
grouped_selector
|
148
|
+
grouped_selector |
|
149
|
+
tap_selector
|
146
150
|
)
|
147
151
|
}
|
148
152
|
|
153
|
+
|
149
154
|
rule(:atomic_or_testing_selector) {
|
150
155
|
(testing_selector | atomic_selector)
|
151
156
|
}
|
@@ -207,6 +212,14 @@ module Ldpath
|
|
207
212
|
).repeat >>
|
208
213
|
wsp?
|
209
214
|
}
|
215
|
+
|
216
|
+
# xyz
|
217
|
+
rule(:loose_property_selector) {
|
218
|
+
wsp? >>
|
219
|
+
loose >>
|
220
|
+
wsp? >>
|
221
|
+
uri.as(:loose_property) >> wsp?
|
222
|
+
}
|
210
223
|
|
211
224
|
# xyz
|
212
225
|
rule(:property_selector) {
|
@@ -251,6 +264,15 @@ module Ldpath
|
|
251
264
|
selector >> wsp? >>
|
252
265
|
str(")") >> wsp?
|
253
266
|
}
|
267
|
+
|
268
|
+
rule(:tap_selector) {
|
269
|
+
wsp? >>
|
270
|
+
tap >>
|
271
|
+
str("<") >>
|
272
|
+
identifier.as(:identifier) >>
|
273
|
+
str(">") >>
|
274
|
+
(atomic_selector).as(:tap)
|
275
|
+
}
|
254
276
|
|
255
277
|
# Testing Selectors
|
256
278
|
|
data/lib/ldpath/program.rb
CHANGED
@@ -21,25 +21,38 @@ module Ldpath
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
attr_reader :mappings
|
25
|
-
def initialize mappings
|
24
|
+
attr_reader :mappings, :cache, :loaded
|
25
|
+
def initialize mappings, cache = RDF::Util::Cache.new
|
26
26
|
@mappings ||= mappings
|
27
|
-
@cache =
|
27
|
+
@cache = cache
|
28
|
+
@loaded = {}
|
28
29
|
end
|
29
30
|
|
30
31
|
def loading uri, context
|
31
|
-
if uri.to_s =~ /^http/ and !
|
32
|
-
|
33
|
-
|
32
|
+
if uri.to_s =~ /^http/ and !loaded[uri]
|
33
|
+
context << load_graph(uri)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_graph uri
|
38
|
+
cache[uri] ||= begin
|
39
|
+
Ldpath.logger.debug "[#{self.object_id}] Loading #{uri.inspect}"
|
40
|
+
|
41
|
+
reader_types = RDF::Format.reader_types.reject { |t| t.to_s =~ /html/ }.map do |t|
|
42
|
+
t.to_s =~ /text\/(?:plain|html)/ ? "#{t};q=0.5" : t
|
43
|
+
end
|
44
|
+
|
45
|
+
RDF::Graph.load(uri, headers: { 'Accept' => reader_types.join(", ") }).tap { loaded[uri] = true }
|
34
46
|
end
|
35
47
|
end
|
36
48
|
|
37
49
|
def evaluate uri, context = nil
|
38
50
|
h = {}
|
39
|
-
context ||=
|
51
|
+
context ||= load_graph(uri.to_s)
|
40
52
|
|
41
53
|
mappings.each do |m|
|
42
|
-
h[m.name]
|
54
|
+
h[m.name] ||= []
|
55
|
+
h[m.name] += case m.selector
|
43
56
|
when Selector
|
44
57
|
m.selector.evaluate(self, uri, context).map do |x|
|
45
58
|
next x unless m.field_type
|
@@ -50,7 +63,11 @@ module Ldpath
|
|
50
63
|
end
|
51
64
|
end
|
52
65
|
|
53
|
-
h
|
66
|
+
h.merge(meta)
|
67
|
+
end
|
68
|
+
|
69
|
+
def meta
|
70
|
+
@meta ||= {}
|
54
71
|
end
|
55
72
|
|
56
73
|
def func_call fname, uri, context, *arguments
|
data/lib/ldpath/selectors.rb
CHANGED
@@ -21,9 +21,9 @@ module Ldpath
|
|
21
21
|
class FunctionSelector < Selector
|
22
22
|
attr_reader :fname, :arguments
|
23
23
|
|
24
|
-
def initialize fname, arguments
|
24
|
+
def initialize fname, arguments = []
|
25
25
|
@fname = fname
|
26
|
-
@arguments = arguments
|
26
|
+
@arguments = Array(arguments)
|
27
27
|
end
|
28
28
|
|
29
29
|
def evaluate program, uris, context
|
@@ -37,7 +37,7 @@ module Ldpath
|
|
37
37
|
i
|
38
38
|
end
|
39
39
|
end
|
40
|
-
program.func_call fname, uri, context,
|
40
|
+
program.func_call fname, uri, context, args
|
41
41
|
end.flatten.compact
|
42
42
|
end
|
43
43
|
end
|
@@ -53,6 +53,21 @@ module Ldpath
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
class LoosePropertySelector < Selector
|
57
|
+
attr_reader :property
|
58
|
+
def initialize property
|
59
|
+
@property = property
|
60
|
+
end
|
61
|
+
|
62
|
+
def evaluate_one uri, context
|
63
|
+
return PropertySelector.new(property).evaluate_one(uri_context) unless defined? RDF::Reasoner
|
64
|
+
|
65
|
+
context.query([uri, nil, nil]).select do |result|
|
66
|
+
result.predicate.entail(:subPropertyOf).include? property
|
67
|
+
end.map(&:object)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
56
71
|
class WildcardSelector < Selector
|
57
72
|
def evaluate_one uri, context
|
58
73
|
context.query([uri, nil, nil]).map(&:object)
|
@@ -121,4 +136,25 @@ module Ldpath
|
|
121
136
|
end
|
122
137
|
end
|
123
138
|
|
139
|
+
class TapSelector < Selector
|
140
|
+
attr_reader :identifier, :tap
|
141
|
+
def initialize identifier, tap
|
142
|
+
@identifier = identifier
|
143
|
+
@tap = tap
|
144
|
+
end
|
145
|
+
|
146
|
+
def evaluate program, uris, context
|
147
|
+
program.meta[identifier] = tap.evaluate(program, uris, context).map { |x| RDF::Literal.new(x.to_s).canonicalize.object }
|
148
|
+
|
149
|
+
Array(uris).map do |uri|
|
150
|
+
loading program, uri, context
|
151
|
+
evaluate_one uri, context
|
152
|
+
end.flatten.compact
|
153
|
+
end
|
154
|
+
|
155
|
+
def evaluate_one uri, context
|
156
|
+
uri
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
124
160
|
end
|
data/lib/ldpath/transform.rb
CHANGED
@@ -53,6 +53,10 @@ module Ldpath
|
|
53
53
|
SelfSelector.new
|
54
54
|
end
|
55
55
|
|
56
|
+
rule(fname: simple(:fname)) do
|
57
|
+
FunctionSelector.new fname.to_s
|
58
|
+
end
|
59
|
+
|
56
60
|
rule(fname: simple(:fname), arglist: subtree(:arglist)) do
|
57
61
|
FunctionSelector.new fname.to_s, arglist
|
58
62
|
end
|
@@ -60,6 +64,10 @@ module Ldpath
|
|
60
64
|
rule(property: simple(:property)) do
|
61
65
|
PropertySelector.new property
|
62
66
|
end
|
67
|
+
|
68
|
+
rule(loose_property: simple(:property)) do
|
69
|
+
LoosePropertySelector.new property
|
70
|
+
end
|
63
71
|
|
64
72
|
rule(wildcard: simple(:wilcard)) do
|
65
73
|
WildcardSelector.new
|
@@ -85,6 +93,10 @@ module Ldpath
|
|
85
93
|
|
86
94
|
RecursivePathSelector.new properties[:delegate], repeat
|
87
95
|
end
|
96
|
+
|
97
|
+
rule(identifier: simple(:identifier), tap: subtree(:tap)) do
|
98
|
+
TapSelector.new identifier.to_s, tap
|
99
|
+
end
|
88
100
|
|
89
101
|
### Test Selectors
|
90
102
|
|
data/lib/ldpath/version.rb
CHANGED
data/lib/ldpath.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "ldpath/version"
|
2
2
|
require 'linkeddata'
|
3
|
+
require 'logger'
|
3
4
|
|
4
5
|
module Ldpath
|
5
6
|
require 'ldpath/field_mapping'
|
@@ -14,5 +15,19 @@ module Ldpath
|
|
14
15
|
def evaluate program, uri, context
|
15
16
|
Ldpath::Program.parse(program).evaluate(uri, context)
|
16
17
|
end
|
18
|
+
|
19
|
+
def logger
|
20
|
+
@logger ||= begin
|
21
|
+
if defined? Rails
|
22
|
+
Rails.logger
|
23
|
+
else
|
24
|
+
Logger.new(STDERR)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger= logger
|
30
|
+
@logger = logger
|
31
|
+
end
|
17
32
|
end
|
18
33
|
end
|
data/spec/ldpath_parser_spec.rb
CHANGED
@@ -143,6 +143,14 @@ describe Ldpath::Parser do
|
|
143
143
|
it "function_selector" do
|
144
144
|
subject.selector.parse('fn:concat(foaf:givename," ",foaf:surname)')
|
145
145
|
end
|
146
|
+
|
147
|
+
it "tap_selector" do
|
148
|
+
subject.selector.parse('?<a><info:a>')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "loose_selector" do
|
152
|
+
subject.selector.parse('~<info:a>')
|
153
|
+
end
|
146
154
|
end
|
147
155
|
|
148
156
|
describe "integration tests" do
|
data/spec/ldpath_program_spec.rb
CHANGED
@@ -76,7 +76,8 @@ EOF
|
|
76
76
|
subject do
|
77
77
|
Ldpath::Program.parse <<-EOF
|
78
78
|
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
79
|
-
|
79
|
+
ab = fn:concat("a", "b") ;
|
80
|
+
title = fn:concat(dcterms:title, dcterms:description) ;
|
80
81
|
first_a = fn:first("a", "b") ;
|
81
82
|
last_b = fn:last("a", "b") ;
|
82
83
|
EOF
|
@@ -85,15 +86,19 @@ EOF
|
|
85
86
|
let(:object) { RDF::URI.new("info:a") }
|
86
87
|
|
87
88
|
let(:graph) do
|
88
|
-
RDF::Graph.new
|
89
|
+
graph = RDF::Graph.new
|
90
|
+
graph << [object, RDF::DC.title, "Hello, world!"]
|
91
|
+
graph << [object, RDF::DC.description, "Description"]
|
92
|
+
|
93
|
+
graph
|
89
94
|
end
|
90
95
|
|
91
96
|
it "should work" do
|
92
97
|
result = subject.evaluate object, graph
|
93
|
-
expect(result["
|
98
|
+
expect(result["ab"]).to match_array "ab"
|
99
|
+
expect(result["title"]).to match_array "Hello, world!Description"
|
94
100
|
expect(result["first_a"]).to match_array "a"
|
95
101
|
expect(result["last_b"]).to match_array "b"
|
96
|
-
|
97
102
|
end
|
98
103
|
end
|
99
104
|
|
@@ -112,4 +117,79 @@ EOF
|
|
112
117
|
expect(result["title"]).to match_array "Huw Stephens"
|
113
118
|
end
|
114
119
|
end
|
120
|
+
|
121
|
+
describe "Predicate function" do
|
122
|
+
subject do
|
123
|
+
Ldpath::Program.parse <<-EOF
|
124
|
+
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
125
|
+
predicates = <http://xmlns.com/foaf/0.1/primaryTopic> / fn:predicates() :: xsd:string ;
|
126
|
+
EOF
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should work" do
|
130
|
+
result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5.rdf")
|
131
|
+
expect(result["predicates"]).to include "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://purl.org/ontology/po/pid", "http://purl.org/dc/elements/1.1/title"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "tap selector" do
|
136
|
+
let(:object) { RDF::URI.new("info:a") }
|
137
|
+
let(:child) { RDF::URI.new("info:b") }
|
138
|
+
let(:grandchild) { RDF::URI.new("info:c") }
|
139
|
+
|
140
|
+
let(:graph) do
|
141
|
+
graph = RDF::Graph.new
|
142
|
+
|
143
|
+
graph << [object, RDF::DC.title, "Object"]
|
144
|
+
graph << [child, RDF::DC.title, "Child"]
|
145
|
+
graph << [object, RDF::DC.hasPart, child]
|
146
|
+
|
147
|
+
graph
|
148
|
+
end
|
149
|
+
|
150
|
+
subject do
|
151
|
+
Ldpath::Program.parse <<-EOF
|
152
|
+
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
153
|
+
title = dcterms:title :: xsd:string ;
|
154
|
+
child_title = dcterms:hasPart / dcterms:title :: xsd:string ;
|
155
|
+
child_title_with_tap = dcterms:hasPart / ?<tap>fn:predicates() / dcterms:title :: xsd:string ;
|
156
|
+
EOF
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should work" do
|
160
|
+
result = subject.evaluate object, graph
|
161
|
+
expect(result["child_title_with_tap"]).to eq result["child_title"]
|
162
|
+
expect(result["tap"]).to eq ["http://purl.org/dc/terms/title"]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "loose selector" do
|
167
|
+
let(:object) { RDF::URI.new("info:a") }
|
168
|
+
let(:child) { RDF::URI.new("info:b") }
|
169
|
+
let(:grandchild) { RDF::URI.new("info:c") }
|
170
|
+
|
171
|
+
let(:graph) do
|
172
|
+
graph = RDF::Graph.new
|
173
|
+
|
174
|
+
graph << [object, RDF::DC.title, "Object"]
|
175
|
+
graph << [child, RDF::DC.title, "Child"]
|
176
|
+
graph << [object, RDF::DC.hasPart, child]
|
177
|
+
|
178
|
+
graph
|
179
|
+
end
|
180
|
+
|
181
|
+
subject do
|
182
|
+
Ldpath::Program.parse <<-EOF
|
183
|
+
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
184
|
+
@prefix dc: <http://purl.org/dc/elements/1.1/> ;
|
185
|
+
title = dcterms:title :: xsd:string ;
|
186
|
+
title_with_loose = ~dc:title :: xsd:string ;
|
187
|
+
EOF
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should work" do
|
191
|
+
result = subject.evaluate object, graph
|
192
|
+
expect(result["title_with_loose"]).to eq result["title"]
|
193
|
+
end
|
194
|
+
end
|
115
195
|
end
|
@@ -38,6 +38,15 @@ describe Ldpath::Transform do
|
|
38
38
|
subject.apply parser.parse("xyz = (info:a){2,} ;\n")
|
39
39
|
end
|
40
40
|
|
41
|
+
it "should transform tap selectors" do
|
42
|
+
subject.apply parser.parse("xyz = ?<x>info:a ;\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should transform loose property selectors" do
|
46
|
+
subject.apply parser.parse("xyz = ~info:a ;\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
|
41
50
|
it "should transform namespaces" do
|
42
51
|
subject.apply parser.parse("@prefix foaf: <http://xmlns.com/foaf/0.1/>")
|
43
52
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ldpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Beer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdf-reasoner
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
description:
|
84
98
|
email:
|
85
99
|
- cabeer@stanford.edu
|
@@ -132,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
146
|
version: '0'
|
133
147
|
requirements: []
|
134
148
|
rubyforge_project:
|
135
|
-
rubygems_version: 2.
|
149
|
+
rubygems_version: 2.4.5
|
136
150
|
signing_key:
|
137
151
|
specification_version: 4
|
138
152
|
summary: Ruby implementation of LDPath
|