-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V3 annotation, annotationPage and choice object improvements #30
Changes from all commits
4a6be8e
e095e4a
360e2c7
42ceb1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,27 @@ module V3 | |
module Presentation | ||
class AnnotationPage < IIIF::V3::AbstractResource | ||
|
||
TYPE = 'AnnotationPage' | ||
TYPE = 'AnnotationPage'.freeze | ||
|
||
def required_keys | ||
super + %w{ id } | ||
end | ||
|
||
def prohibited_keys | ||
super + CONTENT_RESOURCE_PROPERTIES + | ||
%w{ first last total nav_date viewing_direction start_canvas content_annotations } | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking through the 3.0 (alpha) spec, I couldn't find e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
def uri_only_keys | ||
super + %w{ id } | ||
end | ||
|
||
def array_only_keys; | ||
super + %w{ items }; | ||
super + %w{ items } | ||
end | ||
|
||
def legal_viewing_hint_values | ||
super + %w{ none } | ||
end | ||
|
||
def initialize(hsh={}) | ||
|
@@ -20,9 +33,20 @@ def initialize(hsh={}) | |
|
||
def validate | ||
super | ||
# TODO: Each member or resources must be a kind of Annotation | ||
end | ||
|
||
unless self['id'] =~ /^https?:/ | ||
err_msg = "id must be an http(s) URI for #{self.class}" | ||
raise IIIF::V3::Presentation::IllegalValueError, err_msg | ||
end | ||
|
||
items = self['items'] | ||
if items && items.any? | ||
unless items.all? { |entry| entry.instance_of?(IIIF::V3::Presentation::Annotation) } | ||
err_msg = 'All entries in the items list must be a IIIF::V3::Presentation::Annotation' | ||
raise IIIF::V3::Presentation::IllegalValueError, err_msg | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,131 @@ | ||
describe IIIF::V3::Presentation::AnnotationPage do | ||
|
||
describe "#{described_class}.define_methods_for_array_only_keys" do | ||
it_behaves_like 'it has the appropriate methods for array-only keys v3' | ||
describe '#required_keys' do | ||
it 'id' do | ||
expect(subject.required_keys).to include('id') | ||
end | ||
end | ||
|
||
describe '#prohibited_keys' do | ||
it 'contains the expected key names' do | ||
keys = described_class::CONTENT_RESOURCE_PROPERTIES + | ||
%w{ | ||
first | ||
last | ||
total | ||
nav_date | ||
viewing_direction | ||
start_canvas | ||
content_annotations | ||
} | ||
expect(subject.prohibited_keys).to include(*keys) | ||
end | ||
end | ||
|
||
describe '#uri_only_keys' do | ||
it 'id' do | ||
expect(subject.uri_only_keys).to include('id') | ||
end | ||
end | ||
|
||
describe '#array_only_keys' do | ||
it 'items' do | ||
expect(subject.array_only_keys).to include('items') | ||
end | ||
end | ||
|
||
describe '#legal_viewing_hint_values' do | ||
it 'contains none' do | ||
expect(subject.legal_viewing_hint_values).to contain_exactly('none') | ||
end | ||
end | ||
|
||
describe '#initialize' do | ||
it 'sets type to AnnotationPage by default' do | ||
expect(subject['type']).to eq 'AnnotationPage' | ||
end | ||
it 'allows subclasses to override type' do | ||
subclass = Class.new(described_class) do | ||
def initialize(hsh={}) | ||
hsh = { 'type' => 'a:SubClass' } | ||
super(hsh) | ||
end | ||
end | ||
sub = subclass.new | ||
expect(sub['type']).to eq 'a:SubClass' | ||
end | ||
it 'allows type to be passed in' do | ||
ap = described_class.new('type' => 'bar') | ||
expect(ap.type).to eq 'bar' | ||
end | ||
end | ||
|
||
describe '#validate' do | ||
it 'raises IllegalValueError if id is not URI' do | ||
exp_err_msg = "id value must be a String containing a URI for #{described_class}" | ||
subject['id'] = 'foo' | ||
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg) | ||
end | ||
it 'raises IllegalValueError if id is not http(s)' do | ||
subject['id'] = 'ftp://www.example.org' | ||
exp_err_msg = "id must be an http(s) URI for #{described_class}" | ||
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg) | ||
end | ||
it 'raises IllegalValueError for items entry that is not an Annotation' do | ||
subject['id'] = 'http://example.com/iiif3/annotation_page/666' | ||
subject['items'] = [IIIF::V3::Presentation::ImageResource.new, IIIF::V3::Presentation::Annotation.new] | ||
exp_err_msg = "All entries in the items list must be a IIIF::V3::Presentation::Annotation" | ||
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg) | ||
end | ||
end | ||
|
||
describe 'realistic examples' do | ||
let(:ap_id) { 'http://example.com/iiif3/annotation_page/666' } | ||
let(:anno) { IIIF::V3::Presentation::Annotation.new( | ||
'id' => 'http://example.com/anno/666', | ||
'target' => 'http://example.com/canvas/abc' | ||
)} | ||
|
||
describe 'stanford (purl code)' do | ||
let(:anno_page) { | ||
anno_page = described_class.new | ||
anno_page['id'] = ap_id | ||
anno_page.items << anno | ||
anno_page | ||
} | ||
it 'validates' do | ||
expect{anno_page.validate}.not_to raise_error | ||
end | ||
it 'has expected required values' do | ||
expect(anno_page.id).to eq ap_id | ||
expect(anno_page['type']).to eq 'AnnotationPage' | ||
end | ||
it 'has expected additional values' do | ||
expect(anno_page.items).to eq [anno] | ||
end | ||
end | ||
|
||
describe 'two items' do | ||
let(:anno2) { IIIF::V3::Presentation::Annotation.new( | ||
'id' => 'http://example.com/anno/333', | ||
'target' => 'http://example.com/canvas/abc' | ||
)} | ||
let(:anno_page) { | ||
anno_page = described_class.new | ||
anno_page['id'] = ap_id | ||
anno_page.items = [anno, anno2] | ||
anno_page | ||
} | ||
it 'validates' do | ||
expect{anno_page.validate}.not_to raise_error | ||
end | ||
it 'has expected required values' do | ||
expect(anno_page.id).to eq ap_id | ||
expect(anno_page['type']).to eq 'AnnotationPage' | ||
end | ||
it 'has expected additional values' do | ||
expect(anno_page.items).to eq [anno, anno2] | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not seeing
target
anywhere in the Presentation 3.0 API JSON-examples. Where does this come from?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Annotation itself isn't in the 3.0 API; it has its own spec: http://www.openannotation.org/spec/core/ In the spec it is
hasTarget
but our JSON expresses it astarget
I learned about Annotations for the Triannon linked data project I did a while ago; but mostly I looked at examples -- our purl, Tom Crane's, etc.