ldpath 1.0.1 → 1.1.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 +4 -4
- data/.travis.yml +3 -1
- data/CHANGELOG.md +5 -0
- data/README.md +8 -2
- data/ldpath.gemspec +3 -2
- data/lib/ldpath.rb +7 -1
- data/lib/ldpath/loaders.rb +5 -0
- data/lib/ldpath/loaders/direct.rb +11 -0
- data/lib/ldpath/loaders/graph.rb +9 -0
- data/lib/ldpath/loaders/linked_data_fragment.rb +25 -0
- data/lib/ldpath/program.rb +14 -4
- data/lib/ldpath/result.rb +1 -7
- data/lib/ldpath/tests.rb +5 -2
- data/lib/ldpath/version.rb +1 -1
- data/spec/ldpath_program_spec.rb +53 -13
- metadata +27 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2392ccdedd0caa14ab3a6a9be74043156d66cda1
|
4
|
+
data.tar.gz: 25c171de64758510a076c32ee3fce37434707deb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fb33a6e0fe7af743f164ea41cee703c8a36f95ea216258297afd256b62e90da5d0b82c8c3aaf98eac4892118d6665abd647d68ff2f471874eb57cb108b0b924
|
7
|
+
data.tar.gz: 9b2f191ee2bdf62d775d3110d07752914a00b4b4aa48d9886b16d6d84acd6c702e25367760f61a87b5776b7d1766ee9446334e4a871d82b8ddddab995e2a52a3
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,8 @@ This is a ruby implementation of [LDPath](http://marmotta.apache.org/ldpath/lang
|
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
+
### Required gem installation
|
12
|
+
|
11
13
|
Add this line to your application's Gemfile:
|
12
14
|
|
13
15
|
gem 'ldpath'
|
@@ -20,6 +22,10 @@ Or install it yourself as:
|
|
20
22
|
|
21
23
|
$ gem install ldpath
|
22
24
|
|
25
|
+
### Additional gem installations
|
26
|
+
|
27
|
+
To support RDF serializations, you will need to either install the [linkeddata gem](https://github.com/ruby-rdf/linkeddata) which installs a large set of RDF serializations or, in order to have a smaller dependency footprint, install gems for only the serializations your plan to use in your app. The list of serializations are in the [README](https://github.com/ruby-rdf/linkeddata/blob/develop/README.md#features) for the linkeddata gem.
|
28
|
+
|
23
29
|
## Usage
|
24
30
|
|
25
31
|
```ruby
|
@@ -35,10 +41,10 @@ uri = RDF::URI.new "info:a"
|
|
35
41
|
context = RDF::Graph.new << [uri, RDF::Vocab::DC.title, "Some Title"]
|
36
42
|
|
37
43
|
program = Ldpath::Program.parse my_program
|
38
|
-
output = program.evaluate uri, context
|
44
|
+
output = program.evaluate uri, context: context
|
39
45
|
# => { ... }
|
40
46
|
```
|
41
|
-
|
47
|
+
|
42
48
|
## Compatibility
|
43
49
|
|
44
50
|
* Ruby 2.5 or the latest 2.4 version is recommended. Later versions may also work.
|
data/ldpath.gemspec
CHANGED
@@ -18,10 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_dependency "parslet"
|
21
|
-
spec.add_dependency "
|
21
|
+
spec.add_dependency "rdf", '~> 3.0'
|
22
|
+
spec.add_dependency "nokogiri", "~> 1.8"
|
22
23
|
|
23
24
|
# spec.add_development_dependency "bixby", "~> 1.0.0"
|
24
|
-
spec.add_development_dependency "bundler", "~>
|
25
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
25
26
|
spec.add_development_dependency "byebug"
|
26
27
|
spec.add_development_dependency "rake"
|
27
28
|
spec.add_development_dependency "rspec"
|
data/lib/ldpath.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require "ldpath/version"
|
2
|
-
require 'linkeddata'
|
3
2
|
require 'logger'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'rdf'
|
5
|
+
# require rdf/ntriples may not be necessary, may only really be necessary
|
6
|
+
# for ldpath_program_spec.rb tests, but I'm not certain, and I don't think it hurts
|
7
|
+
# to do it here.
|
8
|
+
require 'rdf/ntriples'
|
4
9
|
|
5
10
|
module Ldpath
|
6
11
|
require 'ldpath/field_mapping'
|
@@ -11,6 +16,7 @@ module Ldpath
|
|
11
16
|
require 'ldpath/functions'
|
12
17
|
require 'ldpath/program'
|
13
18
|
require 'ldpath/result'
|
19
|
+
require 'ldpath/loaders'
|
14
20
|
|
15
21
|
class << self
|
16
22
|
attr_writer :logger
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Ldpath::Loaders::Direct
|
2
|
+
def load(uri)
|
3
|
+
Ldpath.logger.debug "Loading #{uri.inspect}"
|
4
|
+
|
5
|
+
reader_types = RDF::Format.reader_types.reject { |t| t.to_s =~ /html/ }.map do |t|
|
6
|
+
t.to_s =~ %r{text/(?:plain|html)} ? "#{t};q=0.5" : t
|
7
|
+
end
|
8
|
+
|
9
|
+
RDF::Graph.load(uri, headers: { 'Accept' => reader_types.join(", ") })
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
class Ldpath::Loaders::LinkedDataFragment
|
4
|
+
NEXT_PAGE = RDF::URI('http://www.w3.org/ns/hydra/core#nextPage')
|
5
|
+
|
6
|
+
def initialize(endpoint)
|
7
|
+
@endpoint = endpoint
|
8
|
+
end
|
9
|
+
|
10
|
+
def load(uri)
|
11
|
+
Ldpath.logger.debug "Loading LDF data for #{uri.inspect}"
|
12
|
+
|
13
|
+
graph = RDF::Graph.new
|
14
|
+
request_uri = RDF::URI("#{@endpoint}?subject=#{CGI::escape(uri)}")
|
15
|
+
|
16
|
+
while request_uri
|
17
|
+
Ldpath.logger.debug " -- querying #{request_uri}"
|
18
|
+
request_graph = RDF::Graph.load(request_uri)
|
19
|
+
graph.insert_statements(request_graph)
|
20
|
+
request_uri = request_graph.first_object([request_uri, NEXT_PAGE, nil])
|
21
|
+
end
|
22
|
+
|
23
|
+
graph
|
24
|
+
end
|
25
|
+
end
|
data/lib/ldpath/program.rb
CHANGED
@@ -26,11 +26,14 @@ module Ldpath
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
attr_reader :mappings, :prefixes, :filters
|
30
|
-
def initialize(mappings,
|
29
|
+
attr_reader :mappings, :prefixes, :filters, :default_loader, :loaders
|
30
|
+
def initialize(mappings, default_loader: Ldpath::Loaders::Direct.new, prefixes: {}, filters: [], loaders: {})
|
31
31
|
@mappings ||= mappings
|
32
|
-
@
|
33
|
-
@
|
32
|
+
@default_loader = default_loader
|
33
|
+
@loaders = loaders
|
34
|
+
@prefixes = prefixes
|
35
|
+
@filters = filters
|
36
|
+
|
34
37
|
end
|
35
38
|
|
36
39
|
def evaluate(uri, context: nil, limit_to_context: false)
|
@@ -41,5 +44,12 @@ module Ldpath
|
|
41
44
|
|
42
45
|
result.to_hash
|
43
46
|
end
|
47
|
+
|
48
|
+
def load(uri)
|
49
|
+
loader = loaders.find { |k, v| uri =~ k }&.last
|
50
|
+
loader ||= default_loader
|
51
|
+
|
52
|
+
loader.load(uri)
|
53
|
+
end
|
44
54
|
end
|
45
55
|
end
|
data/lib/ldpath/result.rb
CHANGED
@@ -22,13 +22,7 @@ module Ldpath
|
|
22
22
|
|
23
23
|
def load_graph(uri)
|
24
24
|
cache[uri] ||= begin
|
25
|
-
|
26
|
-
|
27
|
-
reader_types = RDF::Format.reader_types.reject { |t| t.to_s =~ /html/ }.map do |t|
|
28
|
-
t.to_s =~ %r{text/(?:plain|html)} ? "#{t};q=0.5" : t
|
29
|
-
end
|
30
|
-
|
31
|
-
RDF::Graph.load(uri, headers: { 'Accept' => reader_types.join(", ") }).tap { loaded[uri] = true }
|
25
|
+
program.load(uri).tap { loaded[uri] = true }
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
data/lib/ldpath/tests.rb
CHANGED
@@ -8,11 +8,14 @@ module Ldpath
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def evaluate(program, uris, context)
|
11
|
+
return to_enum(:evaluate, program, uris, context) unless block_given?
|
12
|
+
|
11
13
|
entries = delegate.evaluate program, uris, context
|
12
14
|
entries.select do |uri|
|
13
|
-
enum_wrap(test.evaluate(program, uri, context)).any? do |x|
|
15
|
+
result = enum_wrap(test.evaluate(program, uri, context)).any? do |x|
|
14
16
|
x
|
15
17
|
end
|
18
|
+
yield uri if result
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
@@ -26,7 +29,7 @@ module Ldpath
|
|
26
29
|
def evaluate(_program, uri, _context)
|
27
30
|
return unless uri.literal?
|
28
31
|
|
29
|
-
uri if (lang == "none" && !uri.has_language?) || uri.language == lang
|
32
|
+
uri if (lang.to_s == "none" && !uri.has_language?) || uri.language.to_s == lang.to_s
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
data/lib/ldpath/version.rb
CHANGED
data/spec/ldpath_program_spec.rb
CHANGED
@@ -7,11 +7,13 @@ describe Ldpath::Program do
|
|
7
7
|
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
8
8
|
title = dcterms:title :: xsd:string ;
|
9
9
|
parent_title = dcterms:isPartOf / dcterms:title :: xsd:string ;
|
10
|
+
parent_title_en = dcterms:isPartOf / dcterms:title[@en] :: xsd:string ;
|
10
11
|
titles = dcterms:title | (dcterms:isPartOf / dcterms:title) | (^dcterms:isPartOf / dcterms:title) :: xsd:string ;
|
11
12
|
no_titles = dcterms:title & (dcterms:isPartOf / dcterms:title) & (^dcterms:isPartOf / dcterms:title) :: xsd:string ;
|
12
13
|
self = . :: xsd:string ;
|
13
14
|
wildcard = * ::xsd:string ;
|
14
15
|
child_title = ^dcterms:isPartOf / dcterms:title :: xsd:string ;
|
16
|
+
child_description_en = ^dcterms:isPartOf / dcterms:description[@en] :: xsd:string ;
|
15
17
|
recursive = (dcterms:isPartOf)* ;
|
16
18
|
en_description = dcterms:description[@en] ;
|
17
19
|
conditional = dcterms:isPartOf[dcterms:title] ;
|
@@ -46,16 +48,18 @@ EOF
|
|
46
48
|
graph << [parent, RDF::Vocab::DC.title, "Parent title"]
|
47
49
|
graph << [child, RDF::Vocab::DC.isPartOf, object]
|
48
50
|
graph << [child, RDF::Vocab::DC.title, "Child title"]
|
51
|
+
graph << [parent, RDF::Vocab::DC.title, RDF::Literal.new("Parent English!", language: "en")]
|
52
|
+
graph << [parent, RDF::Vocab::DC.title, RDF::Literal.new("Parent French!", language: "fr")]
|
49
53
|
graph << [parent, RDF::Vocab::DC.isPartOf, grandparent]
|
50
54
|
|
51
55
|
result = subject.evaluate object, context: graph
|
52
|
-
|
53
56
|
expect(result["title"]).to match_array "Hello, world!"
|
54
|
-
expect(result["parent_title"]).to match_array "Parent title"
|
57
|
+
expect(result["parent_title"]).to match_array ["Parent title", "Parent English!", "Parent French!"]
|
58
|
+
expect(result["parent_title_en"]).to match_array "Parent English!"
|
55
59
|
expect(result["self"]).to match_array(object)
|
56
60
|
expect(result["wildcard"]).to include "Hello, world!", parent
|
57
61
|
expect(result["child_title"]).to match_array "Child title"
|
58
|
-
expect(result["titles"]).to match_array ["Hello, world!", "Parent title", "Child title"]
|
62
|
+
expect(result["titles"]).to match_array ["Hello, world!", "Parent title", "Child title", "Parent English!", "Parent French!"]
|
59
63
|
expect(result["no_titles"]).to be_empty
|
60
64
|
expect(result["recursive"]).to match_array [parent, grandparent]
|
61
65
|
expect(result["en_description"].first.to_s).to eq "English!"
|
@@ -185,20 +189,56 @@ EOF
|
|
185
189
|
|
186
190
|
describe "Data loading" do
|
187
191
|
subject do
|
188
|
-
Ldpath::Program.parse <<-EOF
|
189
|
-
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
190
|
-
title = foaf:primaryTopic / dc:title :: xsd:string ;
|
191
|
-
EOF
|
192
|
+
Ldpath::Program.parse <<-EOF, context
|
193
|
+
@prefix dcterms : <http://purl.org/dc/terms/> ;
|
194
|
+
title = foaf:primaryTopic / dc:title :: xsd:string ;
|
195
|
+
EOF
|
192
196
|
end
|
197
|
+
let(:context) { {} }
|
193
198
|
|
194
|
-
|
195
|
-
|
196
|
-
|
199
|
+
context 'with direct loading' do
|
200
|
+
let(:context) { { default_loader: Ldpath::Loaders::Direct.new }}
|
201
|
+
|
202
|
+
before do
|
203
|
+
stub_request(:get, 'http://www.bbc.co.uk/programmes/b0081dq5')
|
204
|
+
.to_return(status: 200, body: webmock_fixture('bbc_b0081dq5.nt'), headers: { 'Content-Type' => 'application/n-triples' })
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should work" do
|
208
|
+
result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5")
|
209
|
+
expect(result["title"]).to match_array "Huw Stephens"
|
210
|
+
end
|
197
211
|
end
|
198
212
|
|
199
|
-
|
200
|
-
|
201
|
-
|
213
|
+
context 'with an existing graph' do
|
214
|
+
let(:graph) { RDF::Graph.new }
|
215
|
+
let(:graph_loader) { Ldpath::Loaders::Graph.new graph: graph }
|
216
|
+
let(:context) { { default_loader: graph_loader }}
|
217
|
+
|
218
|
+
before do
|
219
|
+
graph << [RDF::URI('http://www.bbc.co.uk/programmes/b0081dq5'), RDF::URI('http://xmlns.com/foaf/0.1/primaryTopic'), RDF::URI('info:some_uri')]
|
220
|
+
graph << [RDF::URI('info:some_uri'), RDF::URI('http://purl.org/dc/elements/1.1/title'), 'Local Huw Stephens']
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should work" do
|
224
|
+
result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5")
|
225
|
+
expect(result["title"]).to match_array "Local Huw Stephens"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'with linked data fragments' do
|
230
|
+
let(:graph_loader) { Ldpath::Loaders::LinkedDataFragment.new('http://example.com/ldf') }
|
231
|
+
let(:context) { { default_loader: graph_loader }}
|
232
|
+
|
233
|
+
before do
|
234
|
+
stub_request(:get, 'http://example.com/ldf?subject=http://www.bbc.co.uk/programmes/b0081dq5')
|
235
|
+
.to_return(status: 200, body: webmock_fixture('bbc_b0081dq5.nt'), headers: { 'Content-Type' => 'application/n-triples' })
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should work" do
|
239
|
+
result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5")
|
240
|
+
expect(result["title"]).to match_array "Huw Stephens"
|
241
|
+
end
|
202
242
|
end
|
203
243
|
end
|
204
244
|
|
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: 1.0
|
4
|
+
version: 1.1.0
|
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: 2020-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -25,33 +25,47 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rdf
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '3.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.8'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '2.0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '2.0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: byebug
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -176,6 +190,10 @@ files:
|
|
176
190
|
- lib/ldpath.rb
|
177
191
|
- lib/ldpath/field_mapping.rb
|
178
192
|
- lib/ldpath/functions.rb
|
193
|
+
- lib/ldpath/loaders.rb
|
194
|
+
- lib/ldpath/loaders/direct.rb
|
195
|
+
- lib/ldpath/loaders/graph.rb
|
196
|
+
- lib/ldpath/loaders/linked_data_fragment.rb
|
179
197
|
- lib/ldpath/parser.rb
|
180
198
|
- lib/ldpath/program.rb
|
181
199
|
- lib/ldpath/result.rb
|