qa-ldf 0.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 +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +21 -0
- data/.travis.yml +15 -0
- data/.yardopts +9 -0
- data/CONTRIBUTING.md +109 -0
- data/Gemfile +18 -0
- data/Guardfile +27 -0
- data/LICENSE +14 -0
- data/README.md +42 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/config/ldf.yml +15 -0
- data/lib/qa/ldf.rb +43 -0
- data/lib/qa/ldf/authorities.rb +1 -0
- data/lib/qa/ldf/authorities/lc_names.rb +31 -0
- data/lib/qa/ldf/authority.rb +104 -0
- data/lib/qa/ldf/client.rb +39 -0
- data/lib/qa/ldf/configuration.rb +67 -0
- data/lib/qa/ldf/empty_search_service.rb +18 -0
- data/lib/qa/ldf/json_mapper.rb +35 -0
- data/lib/qa/ldf/model.rb +49 -0
- data/lib/qa/ldf/spec.rb +3 -0
- data/lib/qa/ldf/spec/authority.rb +112 -0
- data/lib/qa/ldf/spec/model.rb +9 -0
- data/lib/qa/ldf/spec/search_service.rb +30 -0
- data/lib/qa/ldf/version.rb +34 -0
- data/qa-ldf.gemspec +35 -0
- data/spec/contracts/qa_loc_as_search_service_spec.rb +38 -0
- data/spec/qa/ldf/authorities/lc_names_spec.rb +52 -0
- data/spec/qa/ldf/authority_spec.rb +29 -0
- data/spec/qa/ldf/client_spec.rb +23 -0
- data/spec/qa/ldf/configuration_spec.rb +93 -0
- data/spec/qa/ldf/empty_search_service_spec.rb +11 -0
- data/spec/qa/ldf/json_mapper_spec.rb +22 -0
- data/spec/qa/ldf/model_spec.rb +53 -0
- data/spec/qa/ldf_spec.rb +43 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/cache_server.rb +25 -0
- data/spec/support/fake_client.rb +31 -0
- data/spec/support/fake_search_service.rb +40 -0
- data/spec/support/shared_examples/ld_cache_client.rb +35 -0
- metadata +232 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'qa/authorities/loc'
|
3
|
+
|
4
|
+
# We need to guarantee `Loc.subauthority_for('names')` behaves like a search
|
5
|
+
# service
|
6
|
+
describe Qa::Authorities::Loc do
|
7
|
+
subject(:search_service) { described_class.subauthority_for('names') }
|
8
|
+
before do
|
9
|
+
# an empty response for 'tove'
|
10
|
+
stub_request(:get, 'http://id.loc.gov/search/?format=json&'\
|
11
|
+
'q=tove&q=cs:http://id.loc.gov/authorities/names')
|
12
|
+
.with(headers: { 'Accept' => 'application/json' })
|
13
|
+
.to_return(status: 200, body: '[]', headers: {})
|
14
|
+
|
15
|
+
# real responses from fixtures
|
16
|
+
search_config.each do |search|
|
17
|
+
stub_request(:get, 'http://id.loc.gov/search/?format=json' \
|
18
|
+
"&q=#{search[:query]}&q=cs:" \
|
19
|
+
'http://id.loc.gov/authorities/names')
|
20
|
+
.with(headers: { 'Accept' => 'application/json' })
|
21
|
+
.to_return(status: 200, body: search[:body], headers: {})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:search_config) do
|
26
|
+
[
|
27
|
+
{ query: 'moomin', body: '[]', result: [] }, # an empty body
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:searches) do
|
32
|
+
search_config.each_with_object({}) do |search, hsh|
|
33
|
+
hsh[search[:query]] = search[:result]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like 'an ldf search service'
|
38
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF::LCNames do
|
4
|
+
it_behaves_like 'an ldf authority'
|
5
|
+
|
6
|
+
subject(:authority) do
|
7
|
+
auth = described_class.new
|
8
|
+
|
9
|
+
auth.client = FakeClient.new do |client|
|
10
|
+
client.graph = RDF::Graph.new
|
11
|
+
client.graph.insert(*statements)
|
12
|
+
client.label = ldf_label
|
13
|
+
end
|
14
|
+
|
15
|
+
auth
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:ldf_label) { 'Marble Island (Nunavut)' }
|
19
|
+
let(:ldf_uri) { 'http://id.loc.gov/authorities/subjects/sh2004002557' }
|
20
|
+
|
21
|
+
let(:statements) do
|
22
|
+
[RDF::Statement(RDF::URI(ldf_uri),
|
23
|
+
RDF::Vocab::SKOS.prefLabel,
|
24
|
+
RDF::Literal(ldf_label))]
|
25
|
+
end
|
26
|
+
|
27
|
+
before do
|
28
|
+
# mock empty responses for all queries;
|
29
|
+
# see spec/contracts/qa_loc_as_search_service.rb for lc search service tests
|
30
|
+
stub_request(:get, 'http://id.loc.gov/search/?format=json&' \
|
31
|
+
'q=cs:http://id.loc.gov/authorities/names')
|
32
|
+
.with(headers: { 'Accept' => 'application/json' })
|
33
|
+
.to_return(status: 200, body: '[]', headers: {})
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#search_service' do
|
37
|
+
it 'hits the upstream loc endpoint by default' do
|
38
|
+
query = 'a query'
|
39
|
+
url = 'http://id.loc.gov/search/?format=json' \
|
40
|
+
"&q=#{query}&q=cs:http://id.loc.gov/authorities/names"
|
41
|
+
expect(a_request(:get, url))
|
42
|
+
|
43
|
+
authority.search_service.search(query)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#dataset' do
|
48
|
+
it 'defaults to :lcnames' do
|
49
|
+
expect(described_class.new.dataset).to eq :lcnames
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF::Authority do
|
4
|
+
it_behaves_like 'an ldf authority'
|
5
|
+
|
6
|
+
subject(:authority) do
|
7
|
+
auth = described_class.new
|
8
|
+
|
9
|
+
auth.client = FakeClient.new do |client|
|
10
|
+
client.graph = RDF::Graph.new << statement
|
11
|
+
client.label = ldf_label
|
12
|
+
end
|
13
|
+
|
14
|
+
auth
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:ldf_label) { 'Marble Island (Nunavut)' }
|
18
|
+
let(:ldf_uri) { 'http://id.loc.gov/authorities/subjects/sh2004002557' }
|
19
|
+
|
20
|
+
let(:statement) do
|
21
|
+
[RDF::URI(ldf_uri), RDF::Vocab::SKOS.prefLabel, RDF::Literal(ldf_label)]
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#dataset' do
|
25
|
+
it 'defaults an empty string symbol' do
|
26
|
+
expect(described_class.new.dataset).to eq :''
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
##
|
3
|
+
# @todo: Stub LDF behavior at this point. Add integration/contract tests for
|
4
|
+
# this interface.
|
5
|
+
describe Qa::LDF::Client do
|
6
|
+
subject(:client) { described_class.new }
|
7
|
+
|
8
|
+
let(:uri) { 'http://id.loc.gov/authorities/subjects/sh2004002557' }
|
9
|
+
let(:graph_stub) { RDF::Graph.new << [RDF::URI(uri), RDF.type, RDF.Property] }
|
10
|
+
|
11
|
+
before do
|
12
|
+
# stub the external request, this behavior is owned by the server,
|
13
|
+
# we just allow it to make the request
|
14
|
+
stub_request(:get, uri)
|
15
|
+
.to_return(status: 200,
|
16
|
+
body: graph_stub.dump(:ntriples),
|
17
|
+
headers: { 'Content-Type' =>
|
18
|
+
RDF::Format.for(:ntriples).content_type })
|
19
|
+
end
|
20
|
+
|
21
|
+
include_context 'with cache server'
|
22
|
+
it_behaves_like 'an ld cache client'
|
23
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF::Configuration do
|
4
|
+
subject(:config) { described_class.instance }
|
5
|
+
|
6
|
+
shared_context 'with configuration' do
|
7
|
+
before { config.configure!(**options) }
|
8
|
+
after { config.reset! }
|
9
|
+
|
10
|
+
let(:options) do
|
11
|
+
{ option: :moomin }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#[]' do
|
16
|
+
include_context 'with configuration'
|
17
|
+
|
18
|
+
it 'gives nil for unconfigured options' do
|
19
|
+
expect(config[:fake]).to be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'accesses options' do
|
23
|
+
options.each { |k, v| expect(config[k]).to eq v }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#configure!' do
|
28
|
+
it 'configures the options' do
|
29
|
+
expect { config.configure!(key: :value) }
|
30
|
+
.to change { config[:key] }.from(nil).to(:value)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'overrides the options' do
|
34
|
+
config.configure!(key: :value)
|
35
|
+
|
36
|
+
expect { config.configure!(key: :new_value) }
|
37
|
+
.to change { config[:key] }.from(:value).to(:new_value)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'overrides options not in new config' do
|
41
|
+
config.configure!(key: :value)
|
42
|
+
|
43
|
+
expect { config.configure!(new_key: :new_value) }
|
44
|
+
.to change { config[:key] }.from(:value).to(nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'yields itself' do
|
48
|
+
expect { |b| config.configure!(&b) }.to yield_with_args(config)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'yields configured self' do
|
52
|
+
options = { key1: :value, key2: :value }
|
53
|
+
|
54
|
+
config.configure!(**options) { |c| expect(c.to_h).to eq options }
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns self' do
|
58
|
+
expect(config.configure!).to eql config
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#each' do
|
63
|
+
include_context 'with configuration'
|
64
|
+
|
65
|
+
it 'enumerates the options hash' do
|
66
|
+
expect(config.each).to contain_exactly(*options.each)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#reset!' do
|
71
|
+
include_context 'with configuration'
|
72
|
+
|
73
|
+
it 'resets options hash' do
|
74
|
+
expect { config.reset! }.to change { config.to_a }.to be_empty
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#to_a' do
|
79
|
+
include_context 'with configuration'
|
80
|
+
|
81
|
+
it 'returns the configured options as an array' do
|
82
|
+
expect(config.to_a).to eq options.to_a
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#to_h' do
|
87
|
+
include_context 'with configuration'
|
88
|
+
|
89
|
+
it 'returns the configured options as a hash' do
|
90
|
+
expect(config.to_h).to eq options
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'qa/ldf/empty_search_service'
|
4
|
+
|
5
|
+
describe Qa::LDF::EmptySearchService do
|
6
|
+
it_behaves_like 'an ldf search service'
|
7
|
+
|
8
|
+
subject(:search_service) { described_class.new }
|
9
|
+
|
10
|
+
let(:searches) { { '-NonSensE\ !QUERY' => [], 'Bărăganul (Romania)' => [] } }
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF::JsonMapper do
|
4
|
+
subject(:mapper) { described_class.new }
|
5
|
+
|
6
|
+
let(:uri) { 'http://example.com/moomin' }
|
7
|
+
let(:label) { RDF::Literal('Moomin') }
|
8
|
+
|
9
|
+
let(:graph) do
|
10
|
+
RDF::Graph.new << [RDF::URI(uri), RDF::Vocab::SKOS.prefLabel, label]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#map_resource' do
|
14
|
+
it 'maps with an id' do
|
15
|
+
expect(mapper.map_resource(uri, graph)[:id]).to eq uri
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'maps with a label' do
|
19
|
+
expect(mapper.map_resource(uri, graph)[:label]).to eq label
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF::Model do
|
4
|
+
define :be_term do |expected|
|
5
|
+
match { |actual| expect(actual.to_term).to eq expected }
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:id) { 'http://example.com/authority/moomin' }
|
9
|
+
let(:label) { 'moomin' }
|
10
|
+
|
11
|
+
describe '.from_graph' do
|
12
|
+
let(:graph) do
|
13
|
+
graph = RDF::Graph.new
|
14
|
+
graph.insert(*statements)
|
15
|
+
graph
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:statements) do
|
19
|
+
[RDF::Statement(RDF::URI(id), RDF::Vocab::SKOS.prefLabel, label),
|
20
|
+
RDF::Statement(RDF::URI(id), RDF::Vocab::DC.title, 'Moomin Papa'),
|
21
|
+
RDF::Statement(RDF::Node.new, RDF::Vocab::DC.title, 'Moomin Papa')]
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'builds a model with the id as uri' do
|
25
|
+
expect(described_class.from_graph(uri: id, graph: graph))
|
26
|
+
.to be_term RDF::URI(id)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'builds a model with the label as label' do
|
30
|
+
expect(described_class.from_graph(uri: id, graph: graph))
|
31
|
+
.to have_attributes rdf_label: a_collection_containing_exactly(label)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'contains passed graph' do
|
35
|
+
expect(described_class.from_graph(uri: id, graph: graph).statements)
|
36
|
+
.to include(*statements)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.from_qa_result' do
|
41
|
+
let(:json_hash) { { id: id, label: label, papa: 'moomin papa' } }
|
42
|
+
|
43
|
+
it 'builds a model with the id as uri' do
|
44
|
+
expect(described_class.from_qa_result(qa_result: json_hash))
|
45
|
+
.to be_term RDF::URI(id)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'builds a model with the label as label' do
|
49
|
+
expect(described_class.from_qa_result(qa_result: json_hash))
|
50
|
+
.to have_attributes rdf_label: a_collection_containing_exactly(label)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/qa/ldf_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Qa::LDF do
|
4
|
+
subject(:mod) { described_class }
|
5
|
+
|
6
|
+
it 'has a version' do
|
7
|
+
expect(mod::VERSION.to_str).to be_a String
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#version' do
|
11
|
+
it 'returns VERISON' do
|
12
|
+
expect(mod.version).to eql mod::VERSION
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.config' do
|
17
|
+
it 'defaults to an empty config' do
|
18
|
+
expect(mod.config).not_to be_any
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when configured' do
|
22
|
+
before { mod.configure!(**options) }
|
23
|
+
|
24
|
+
let(:options) { { opt: :value, opt2: :value2 } }
|
25
|
+
|
26
|
+
it 'returns the configuration instance' do
|
27
|
+
expect(mod.config.to_h).to eq options
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#configure!' do
|
33
|
+
it 'dispatches arguments to the configuration instance' do
|
34
|
+
opts = { opt: :value }
|
35
|
+
block = proc {}
|
36
|
+
|
37
|
+
expect(Qa::LDF::Configuration.instance)
|
38
|
+
.to receive(:configure!).with(**opts, &block).once
|
39
|
+
|
40
|
+
mod.configure!(**opts, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'pry' unless ENV['CI']
|
6
|
+
require 'webmock/rspec'
|
7
|
+
|
8
|
+
require 'qa/ldf'
|
9
|
+
require 'qa/ldf/spec'
|
10
|
+
|
11
|
+
Dir['./spec/support/**/*.rb'].each { |f| require f }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.color = true
|
15
|
+
config.tty = true
|
16
|
+
|
17
|
+
config.formatter = :progress
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'sham_rack'
|
2
|
+
|
3
|
+
require 'linked_data_fragments/cache_server'
|
4
|
+
require 'linked_data_fragments/repository'
|
5
|
+
|
6
|
+
shared_context 'with cache server' do
|
7
|
+
let(:server_endpoint) { 'http://ldcache.example.com/' }
|
8
|
+
|
9
|
+
before(:context) do
|
10
|
+
server_endpoint = 'ldcache.example.com'
|
11
|
+
|
12
|
+
ShamRack
|
13
|
+
.at(server_endpoint)
|
14
|
+
.mount(LinkedDataFragments::CacheServer::APPLICATION)
|
15
|
+
|
16
|
+
Qa::LDF.configure! do |config|
|
17
|
+
config[:endpoint] = "http://#{server_endpoint}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:context) do
|
22
|
+
ShamRack.reset
|
23
|
+
Qa::LDF::Configuration.instance.reset!
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'support/shared_examples/ld_cache_client'
|
2
|
+
|
3
|
+
require 'rdf'
|
4
|
+
require 'rdf/vocab/skos'
|
5
|
+
|
6
|
+
##
|
7
|
+
# A fake version of `Qa::LDF::Client`.
|
8
|
+
class FakeClient
|
9
|
+
attr_accessor :label, :graph
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
yield self if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(uri:, dataset: :'')
|
16
|
+
graph ||= RDF::Graph.new
|
17
|
+
# Use dataset just to satisfy rubocop.
|
18
|
+
# Is there a better config setting for this; exclude this cop from fakes?
|
19
|
+
graph =
|
20
|
+
graph.dup <<
|
21
|
+
[RDF::URI(uri), RDF::Vocab::SKOS.prefLabel, label || "#{dataset}: moomin"]
|
22
|
+
graph
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe FakeClient do
|
27
|
+
subject(:client) { described_class.new }
|
28
|
+
|
29
|
+
let(:uri) { 'http://id.loc.gov/authorities/subjects/sh2004002557' }
|
30
|
+
it_behaves_like 'an ld cache client'
|
31
|
+
end
|