qa-ldf 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|