Skip to content

Commit

Permalink
Refactoring vocabularies data source
Browse files Browse the repository at this point in the history
Separated out prefix registration function from vocab registration.
Vocabulary lookup is done by the vocabulary URI, not the class, so this
allows us Be able to override the prefix of any vocabulary, not just
those defined locally.

Also added tests (see #88).
  • Loading branch information
cdchapman committed Jan 20, 2022
1 parent 3609c84 commit 6db9472
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 33 deletions.
34 changes: 28 additions & 6 deletions lib/data_sources/vocabularies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ module DataSources
class Vocabularies < Nanoc::DataSource
identifier :vocabularies

class UnknownVocabularyPrefix < ::Nanoc::Core::Error
class UnknownVocabulary < ::Nanoc::Core::TrivialError
def initialize(uri)
super("A vocabulary with the uri “#{uri}” (specified in the site's configuration file) was not found.")
end
end

class UnknownVocabularyPrefix < ::Nanoc::Core::TrivialError
def initialize(prefix)
super("A vocabulary with the prefix “#{prefix}” (specified in the site's configuration file) was not found.")
end
Expand All @@ -23,7 +29,9 @@ def up
LifePreserver::Vocab.constants
.map(&LifePreserver::Vocab.method(:const_get))
.select { |constant| constant.is_a? Class }
register_vocabularies(local_vocabs, @config[:prefix_overrides])
register_vocabularies(local_vocabs)

register_prefixes(@config[:prefix_overrides])

if (categories = @config[:categories])
prefixes = categories.values.flatten
Expand Down Expand Up @@ -152,17 +160,31 @@ def load_extra_metadata(metadata)
# @note called by {#up} when the site is loading.
#
# @param vocabs [Array<RDF::Vocabulary>] Vocabulary classes to register.
# @param prefixes [Hash{Symbol=>String}] Optional prefixes with to register
# the vocabularies.
#
# @return [void]
def register_vocabularies(vocabs, prefixes = {})
def register_vocabularies(vocabs)
Array(vocabs).each do |vocab|
class_name = vocab.__name__.to_s.demodulize
prefix = prefixes[class_name.to_sym] || class_name.downcase
prefix = class_name.downcase
RDF::Vocabulary.register(prefix.to_sym, vocab, class_name: class_name)
end
end

# Register prefixes with the Ruby RDF framework.
#
# @note called by {#up} when the site is loading.
#
# @raise [UnknownVocabulary] if an {RDF::Vocabulary} with the uri specified in
# site config is not found.
# @param prefixes [Hash{String,Symbol=>String}] Mapping of URI=>prefix pairs.
# @return [void]
def register_prefixes(prefixes)
Hash(prefixes).each do |uri, prefix|
vocab = RDF::Vocabulary.find(uri.to_s)
raise UnknownVocabulary.new(uri.to_s) unless vocab
vocab.__prefix__ = prefix.to_sym
end
end
end
end
end
4 changes: 4 additions & 0 deletions nanoc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ data_sources:
- type: vocabularies
items_root: &vocabularies_root /_vocabularies
extra_metadata: 'var/voaf_metadata.yaml'
prefix_overrides:
:https://pentandra.com#: p5web
:https://pentandra.com/company#: p5inc
:https://pentandra.com/blog#: p5blog
categories:
standard: [ cc, ctag, dc, foaf, owl, pav, prov, rdf, rdfs, schema, sh, sioc, skos, xhv ]
business: [ essglobal, fea, org, rov, vcard ]
Expand Down
82 changes: 55 additions & 27 deletions spec/data_sources/vocabularies_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module LifePreserver
module DataSources
class Vocabularies
public :register_vocabularies,
:register_prefixes,
:find_vocab_metadata,
:load_extra_metadata,
:cleanup
Expand All @@ -20,11 +21,10 @@ class Vocabularies
let(:site) { Nanoc::Core::SiteLoader.new.new_from_cwd }

describe '#register_vocabularies' do
subject! { data_source.register_vocabularies(vocabs, prefix_overrides) }
subject! { data_source.register_vocabularies(vocabs) }

let(:example_uri) { 'https://example/ns#' }
let(:vocabs) { [EXAMPLE = Class.new(RDF::Vocabulary(example_uri))] }
let(:prefix_overrides) { {} }
let(:vocabs) { [stub_const('EXAMPLE', Class.new(RDF::Vocabulary(example_uri)))] }

context 'with local vocabularies' do
it 'will register local vocabularies' do
Expand All @@ -40,50 +40,78 @@ class Vocabularies
end
end

context 'with prefix overrides' do
let(:prefix_overrides) { { EXAMPLE: 'ex' } }
context 'with vocab that defines a `name` property' do
let(:vocabs) do
[
stub_const('TEST', Class.new(RDF::Vocabulary('https://test/ns#')) do
property(:name,
comment: 'This is a data property',
label: 'name',
range: 'http://www.w3.org/2001/XMLSchema#string',
type: 'http://www.w3.org/2002/07/owl#DatatypeProperty')
end),
]
end

it 'will register local vocabularies' do
expect(RDF::Vocabulary.find_term(example_uri)).not_to be_nil
it 'will register the correct prefix in the vocab map' do
expect(RDF::Vocabulary.vocab_map.key?(:test)).to be true
end

it 'will register the overridden prefix in the vocab map' do
expect(RDF::Vocabulary.vocab_map.key?(:ex)).to be true
it 'will locate the property using pname' do
expect(RDF::Vocabulary.expand_pname('test:name')).to eq('https://test/ns#name')
end

xit 'will register the overridden prefix as the vocab default' do
expect(RDF::Vocabulary.find_term(example_uri).pname).to start_with('ex:')
it 'will set the correct prefix as the vocab default' do
expect(RDF::Vocabulary.find_term('https://test/ns#name').pname).to eq('test:name')
end
end
end

context 'with vocab that defines a `name` property' do
let(:vocabs) do
[
TEST = Class.new(RDF::Vocabulary('https://test/ns#')) do
property :name,
comment: 'This is a data property',
label: 'name',
range: 'http://www.w3.org/2001/XMLSchema#string',
type: 'http://www.w3.org/2002/07/owl#DatatypeProperty'
end,
]
describe '#register_prefixes' do
subject! { data_source.register_prefixes(prefix_overrides) }

let(:example_uri) { 'https://example/ns#' }
let(:vocab) { stub_const('EXAMPLE', Class.new(RDF::Vocabulary(example_uri))) }

before { RDF::Vocabulary.register(:example, vocab) }

context 'without prefix overrides' do
let(:prefix_overrides) { {} }

it 'will register vocabulary with default prefix' do
expect(RDF::Vocabulary.find_term(example_uri).pname).to start_with('example:')
end
end

it 'will register the correct prefix in the vocab map' do
expect(RDF::Vocabulary.vocab_map.key?(:test)).to be true
context 'with prefix overrides' do
let(:prefix_overrides) { Hash[example_uri, 'ex'] }

it 'will register the overridden prefix in the vocab map' do
expect(RDF::Vocabulary.vocab_map.key?(:ex)).to be true
end

it 'will register the correct prefix as the vocab default' do
expect(RDF::Vocabulary.find_term('https://test/ns#name').pname).to eq('test:name')
it 'will retain the default prefix in the vocab map for backwards lookups' do
expect(RDF::Vocabulary.vocab_map.key?(:example)).to be true
end

it 'will register the overriding prefix as the vocab prefix' do
expect(RDF::Vocabulary.find_term(example_uri).pname).to start_with('ex:')
end

it 'will map to the overriding prefix when given original prefix' do
expect(RDF::Vocabulary.expand_pname('example:').pname).to start_with('ex:')
end
end

context 'with non-existent URIs' do
end
end

describe '#find_vocab_metadata' do
subject(:metadata) { data_source.find_vocab_metadata(vocab, extra_metadata) }

let(:example_uri) { 'https://example/ns#' }
let(:vocab) { EXAMPLE = Class.new(RDF::Vocabulary(example_uri)) }
let(:vocab) { stub_const('EXAMPLE', Class.new(RDF::Vocabulary(example_uri))) }
let(:extra_metadata) { {} }

context 'without extra metadata' do
Expand Down

0 comments on commit 6db9472

Please sign in to comment.