iiif-presentation 1.4.2 → 1.5.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/.github/workflows/ruby.yml +8 -1
- data/.standard.yml +1 -0
- data/Gemfile +5 -5
- data/README.md +1 -1
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/bin/standardrb +16 -0
- data/iiif-presentation.gemspec +23 -23
- data/lib/iiif/hash_behaviours.rb +29 -33
- data/lib/iiif/ordered_hash.rb +33 -33
- data/lib/iiif/presentation/abstract_resource.rb +17 -22
- data/lib/iiif/presentation/annotation.rb +9 -11
- data/lib/iiif/presentation/annotation_list.rb +8 -10
- data/lib/iiif/presentation/canvas.rb +11 -13
- data/lib/iiif/presentation/collection.rb +7 -9
- data/lib/iiif/presentation/image_resource.rb +33 -35
- data/lib/iiif/presentation/layer.rb +8 -10
- data/lib/iiif/presentation/manifest.rb +9 -12
- data/lib/iiif/presentation/range.rb +8 -10
- data/lib/iiif/presentation/resource.rb +5 -7
- data/lib/iiif/presentation/sequence.rb +8 -11
- data/lib/iiif/presentation/service.rb +1 -2
- data/lib/iiif/presentation.rb +7 -7
- data/lib/iiif/service.rb +121 -102
- data/lib/iiif/v3/abstract_resource.rb +127 -130
- data/lib/iiif/v3/presentation/annotation.rb +20 -21
- data/lib/iiif/v3/presentation/annotation_collection.rb +7 -9
- data/lib/iiif/v3/presentation/annotation_page.rb +14 -15
- data/lib/iiif/v3/presentation/canvas.rb +21 -22
- data/lib/iiif/v3/presentation/choice.rb +14 -15
- data/lib/iiif/v3/presentation/collection.rb +7 -8
- data/lib/iiif/v3/presentation/image_resource.rb +21 -22
- data/lib/iiif/v3/presentation/manifest.rb +18 -19
- data/lib/iiif/v3/presentation/nav_place.rb +125 -29
- data/lib/iiif/v3/presentation/range.rb +10 -10
- data/lib/iiif/v3/presentation/resource.rb +4 -5
- data/lib/iiif/v3/presentation/sequence.rb +10 -11
- data/lib/iiif/v3/presentation/service.rb +12 -13
- data/lib/iiif/v3/presentation.rb +8 -8
- data/spec/integration/iiif/presentation/image_resource_spec.rb +54 -58
- data/spec/integration/iiif/service_spec.rb +76 -77
- data/spec/integration/iiif/v3/abstract_resource_spec.rb +72 -73
- data/spec/integration/iiif/v3/presentation/image_resource_spec.rb +53 -56
- data/spec/spec_helper.rb +56 -64
- data/spec/unit/iiif/hash_behaviours_spec.rb +384 -387
- data/spec/unit/iiif/ordered_hash_spec.rb +86 -91
- data/spec/unit/iiif/presentation/abstract_resource_spec.rb +64 -70
- data/spec/unit/iiif/presentation/annotation_list_spec.rb +1 -3
- data/spec/unit/iiif/presentation/annotation_spec.rb +1 -3
- data/spec/unit/iiif/presentation/canvas_spec.rb +11 -14
- data/spec/unit/iiif/presentation/collection_spec.rb +26 -33
- data/spec/unit/iiif/presentation/image_resource_spec.rb +4 -6
- data/spec/unit/iiif/presentation/layer_spec.rb +16 -20
- data/spec/unit/iiif/presentation/manifest_spec.rb +45 -48
- data/spec/unit/iiif/presentation/range_spec.rb +18 -22
- data/spec/unit/iiif/presentation/resource_spec.rb +3 -6
- data/spec/unit/iiif/presentation/sequence_spec.rb +58 -63
- data/spec/unit/iiif/presentation/shared_examples/abstract_resource_only_keys.rb +4 -10
- data/spec/unit/iiif/presentation/shared_examples/any_type_keys.rb +5 -9
- data/spec/unit/iiif/presentation/shared_examples/array_only_keys.rb +9 -17
- data/spec/unit/iiif/presentation/shared_examples/int_only_keys.rb +6 -14
- data/spec/unit/iiif/presentation/shared_examples/string_only_keys.rb +6 -13
- data/spec/unit/iiif/service_spec.rb +8 -13
- data/spec/unit/iiif/v3/abstract_resource_define_methods_for_spec.rb +39 -37
- data/spec/unit/iiif/v3/abstract_resource_spec.rb +124 -131
- data/spec/unit/iiif/v3/presentation/annotation_collection_spec.rb +14 -17
- data/spec/unit/iiif/v3/presentation/annotation_page_spec.rb +71 -69
- data/spec/unit/iiif/v3/presentation/annotation_spec.rb +249 -233
- data/spec/unit/iiif/v3/presentation/canvas_spec.rb +211 -193
- data/spec/unit/iiif/v3/presentation/choice_spec.rb +81 -77
- data/spec/unit/iiif/v3/presentation/collection_spec.rb +24 -29
- data/spec/unit/iiif/v3/presentation/image_resource_spec.rb +70 -71
- data/spec/unit/iiif/v3/presentation/manifest_spec.rb +248 -235
- data/spec/unit/iiif/v3/presentation/nav_place_spec.rb +249 -49
- data/spec/unit/iiif/v3/presentation/range_spec.rb +28 -29
- data/spec/unit/iiif/v3/presentation/resource_spec.rb +83 -82
- data/spec/unit/iiif/v3/presentation/sequence_spec.rb +125 -119
- data/spec/unit/iiif/v3/presentation/service_spec.rb +123 -124
- data/spec/unit/iiif/v3/presentation/shared_examples/abstract_resource_only_keys.rb +4 -8
- data/spec/unit/iiif/v3/presentation/shared_examples/any_type_keys.rb +5 -7
- data/spec/unit/iiif/v3/presentation/shared_examples/array_only_keys.rb +9 -13
- data/spec/unit/iiif/v3/presentation/shared_examples/hash_only_keys.rb +9 -13
- data/spec/unit/iiif/v3/presentation/shared_examples/int_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/numeric_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/string_only_keys.rb +6 -10
- data/spec/unit/iiif/v3/presentation/shared_examples/uri_only_keys.rb +9 -13
- metadata +26 -65
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
shared_examples 'it has the appropriate methods for string-only keys' do
|
|
4
|
-
|
|
1
|
+
shared_examples "it has the appropriate methods for string-only keys" do
|
|
5
2
|
described_class.new.string_only_keys.each do |prop|
|
|
6
|
-
|
|
7
3
|
describe "#{prop}=" do
|
|
8
4
|
it "sets #{prop}" do
|
|
9
|
-
ex =
|
|
5
|
+
ex = "foo"
|
|
10
6
|
subject.send("#{prop}=", ex)
|
|
11
7
|
expect(subject[prop]).to eq ex
|
|
12
8
|
end
|
|
13
|
-
it
|
|
14
|
-
expect { subject.send("#{prop}=", [
|
|
9
|
+
it "raises an exception when attempting to set it to something other than a String" do
|
|
10
|
+
expect { subject.send("#{prop}=", ["Foo"]) }.to raise_error IIIF::Presentation::IllegalValueError
|
|
15
11
|
end
|
|
16
12
|
end
|
|
17
13
|
|
|
18
|
-
describe
|
|
14
|
+
describe prop.to_s do
|
|
19
15
|
it "gets #{prop}" do
|
|
20
|
-
ex =
|
|
16
|
+
ex = "bar"
|
|
21
17
|
subject[prop] = ex
|
|
22
18
|
expect(subject.send(prop)).to eq ex
|
|
23
19
|
end
|
|
24
20
|
end
|
|
25
|
-
|
|
26
21
|
end
|
|
27
|
-
|
|
28
22
|
end
|
|
29
|
-
|
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
describe IIIF::Service do
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
TYPE = "sc:Collection"
|
|
2
|
+
describe "self#get_descendant_class_by_jld_type" do
|
|
3
|
+
let(:dummy_class) do
|
|
4
|
+
Class.new(IIIF::Service) do
|
|
5
|
+
const_set(:TYPE, "sc:Collection")
|
|
7
6
|
def self.singleton_class?
|
|
8
7
|
true
|
|
9
8
|
end
|
|
10
9
|
end
|
|
11
10
|
end
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
15
|
-
it 'gets the right class' do
|
|
16
|
-
klass = described_class.get_descendant_class_by_jld_type('sc:Canvas')
|
|
11
|
+
it "gets the right class" do
|
|
12
|
+
klass = described_class.get_descendant_class_by_jld_type("sc:Canvas")
|
|
17
13
|
expect(klass).to be IIIF::Presentation::Canvas
|
|
18
14
|
end
|
|
19
15
|
context "when there are singleton classes which are returned" do
|
|
20
16
|
it "gets the right class" do
|
|
21
|
-
allow(IIIF::Service).to receive(:descendants).and_return([
|
|
22
|
-
klass = described_class.get_descendant_class_by_jld_type(
|
|
17
|
+
allow(IIIF::Service).to receive(:descendants).and_return([dummy_class, IIIF::Presentation::Collection])
|
|
18
|
+
klass = described_class.get_descendant_class_by_jld_type("sc:Collection")
|
|
23
19
|
expect(klass).to be IIIF::Presentation::Collection
|
|
24
20
|
end
|
|
25
21
|
end
|
|
26
22
|
end
|
|
27
|
-
|
|
28
23
|
end
|
|
@@ -1,78 +1,80 @@
|
|
|
1
1
|
class AbstractResourceSubClass < IIIF::V3::AbstractResource
|
|
2
|
-
TYPE =
|
|
2
|
+
TYPE = "Ignore"
|
|
3
3
|
# need a property here for type of key not already initialized in AbstractResource
|
|
4
4
|
def array_only_keys
|
|
5
|
-
super + %w
|
|
5
|
+
super + %w[array my_array]
|
|
6
6
|
end
|
|
7
|
+
|
|
7
8
|
def hash_only_keys
|
|
8
|
-
super + %w
|
|
9
|
+
super + %w[hash my_hash]
|
|
9
10
|
end
|
|
11
|
+
|
|
10
12
|
def int_only_keys
|
|
11
|
-
super + %w
|
|
13
|
+
super + %w[int my_int]
|
|
12
14
|
end
|
|
15
|
+
|
|
13
16
|
def numeric_only_keys
|
|
14
|
-
super + %w
|
|
17
|
+
super + %w[num my_num]
|
|
15
18
|
end
|
|
19
|
+
|
|
16
20
|
def uri_only_keys
|
|
17
|
-
super + %w
|
|
21
|
+
super + %w[uri my_uri]
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
def initialize(
|
|
21
|
-
|
|
22
|
-
super(hsh)
|
|
24
|
+
def initialize(_hsh = {})
|
|
25
|
+
super({"type" => "a:SubClass"})
|
|
23
26
|
end
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
describe AbstractResourceSubClass do
|
|
27
|
-
|
|
28
30
|
describe "*define_methods_for_any_type_keys" do
|
|
29
31
|
# shared_example expects fixed_values; these are roughly based on Stanford purl code
|
|
30
32
|
# (see https://github.com/sul-dlss/purl/blob/master/app/models/iiif3_presentation_manifest.rb)
|
|
31
33
|
let(:fixed_values) do
|
|
32
34
|
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
"label" => "foo",
|
|
36
|
+
"description" => "bar",
|
|
37
|
+
"thumbnail" => IIIF::V3::Presentation::ImageResource.new(
|
|
38
|
+
"type" => "Image",
|
|
39
|
+
"id" => "http://example.org/full/!400,400/0/default.jpg",
|
|
40
|
+
"format" => "image/jpeg"
|
|
41
|
+
),
|
|
42
|
+
"attribution" => ["foo"],
|
|
43
|
+
"logo" => {
|
|
44
|
+
"id" => "https://example.org/default.jpg",
|
|
45
|
+
"service" => IIIF::V3::Presentation::Service.new(
|
|
46
|
+
"@context" => "http://iiif.io/api/image/2/context.json",
|
|
47
|
+
"@id" => "http://example.org/1",
|
|
48
|
+
"id" => "http://example.org/1",
|
|
49
|
+
"profile" => "http://example.org/whatever"
|
|
48
50
|
)
|
|
49
51
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
"see_also" => {
|
|
53
|
+
"id" => "http://example.org/whatever",
|
|
54
|
+
"format" => "application/mods+xml"
|
|
53
55
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
"related" => ["no", "idea"],
|
|
57
|
+
"within" => {"foo" => "bar"}
|
|
56
58
|
}
|
|
57
59
|
end
|
|
58
|
-
it_behaves_like
|
|
60
|
+
it_behaves_like "it has the appropriate methods for any-type keys v3"
|
|
59
61
|
end
|
|
60
62
|
describe "*define_methods_for_array_only_keys" do
|
|
61
|
-
it_behaves_like
|
|
63
|
+
it_behaves_like "it has the appropriate methods for array-only keys v3"
|
|
62
64
|
end
|
|
63
65
|
describe "*define_methods_for_hash_only_keys" do
|
|
64
|
-
it_behaves_like
|
|
66
|
+
it_behaves_like "it has the appropriate methods for hash-only keys v3"
|
|
65
67
|
end
|
|
66
68
|
describe "*define_methods_for_int_only_keys" do
|
|
67
|
-
it_behaves_like
|
|
69
|
+
it_behaves_like "it has the appropriate methods for integer-only keys v3"
|
|
68
70
|
end
|
|
69
71
|
describe "*define_methods_for_numeric_only_keys" do
|
|
70
|
-
it_behaves_like
|
|
72
|
+
it_behaves_like "it has the appropriate methods for numeric-only keys v3"
|
|
71
73
|
end
|
|
72
74
|
describe "*define_methods_for_string_only_keys" do
|
|
73
|
-
it_behaves_like
|
|
75
|
+
it_behaves_like "it has the appropriate methods for string-only keys v3"
|
|
74
76
|
end
|
|
75
77
|
describe "*define_methods_for_uri_only_keys" do
|
|
76
|
-
it_behaves_like
|
|
78
|
+
it_behaves_like "it has the appropriate methods for uri-only keys v3"
|
|
77
79
|
end
|
|
78
80
|
end
|
|
@@ -1,285 +1,278 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require_relative
|
|
1
|
+
require "active_support/inflector"
|
|
2
|
+
require "json"
|
|
3
|
+
require_relative "../../../../lib/iiif/hash_behaviours"
|
|
4
4
|
|
|
5
5
|
describe IIIF::V3::AbstractResource do
|
|
6
|
-
|
|
7
|
-
let(:
|
|
8
|
-
let(:manifest_from_spec_path) { File.join(fixtures_dir, 'v3/manifests/complete_from_spec.json') }
|
|
6
|
+
let(:fixtures_dir) { File.join(File.dirname(__FILE__), "../../../fixtures") }
|
|
7
|
+
let(:manifest_from_spec_path) { File.join(fixtures_dir, "v3/manifests/complete_from_spec.json") }
|
|
9
8
|
let(:abstract_resource_subclass) do
|
|
10
9
|
Class.new(IIIF::V3::AbstractResource) do
|
|
11
10
|
include IIIF::HashBehaviours
|
|
12
11
|
|
|
13
|
-
def initialize(hsh={})
|
|
14
|
-
hsh[
|
|
15
|
-
super
|
|
12
|
+
def initialize(hsh = {})
|
|
13
|
+
hsh["type"] = "a:SubClass" unless hsh.has_key?("type")
|
|
14
|
+
super
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def required_keys
|
|
19
|
-
super + %w
|
|
18
|
+
super + %w[id]
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def prohibited_keys
|
|
23
|
-
super + %w
|
|
22
|
+
super + %w[verboten]
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def legal_viewing_hint_values
|
|
27
|
-
%w
|
|
26
|
+
%w[viewing_hint1 viewing_hint2]
|
|
28
27
|
end
|
|
29
28
|
end
|
|
30
29
|
end
|
|
31
30
|
subject do
|
|
32
31
|
instance = abstract_resource_subclass.new
|
|
33
|
-
instance[
|
|
32
|
+
instance["id"] = "http://example.com/prefix/manifest/123"
|
|
34
33
|
instance
|
|
35
34
|
end
|
|
36
35
|
|
|
37
|
-
describe
|
|
38
|
-
it
|
|
39
|
-
expect(subject.required_keys).to eq %w
|
|
36
|
+
describe "#required_keys" do
|
|
37
|
+
it "accumulate" do
|
|
38
|
+
expect(subject.required_keys).to eq %w[type id]
|
|
40
39
|
end
|
|
41
40
|
end
|
|
42
41
|
|
|
43
|
-
describe
|
|
44
|
-
it
|
|
42
|
+
describe "#initialize" do
|
|
43
|
+
it "raises an error if you try to instantiate AbstractResource" do
|
|
45
44
|
expect { IIIF::V3::AbstractResource.new }.to raise_error(RuntimeError)
|
|
46
45
|
end
|
|
47
|
-
it
|
|
48
|
-
expect(subject[
|
|
46
|
+
it "sets type" do
|
|
47
|
+
expect(subject["type"]).to eq "a:SubClass"
|
|
49
48
|
end
|
|
50
|
-
it
|
|
49
|
+
it "can take any old hash" do
|
|
51
50
|
hsh = JSON.parse(IO.read(manifest_from_spec_path))
|
|
52
51
|
new_instance = abstract_resource_subclass.new(hsh)
|
|
53
|
-
expect(new_instance[
|
|
52
|
+
expect(new_instance["label"]["en"]).to include "Book 1"
|
|
54
53
|
end
|
|
55
54
|
end
|
|
56
55
|
|
|
57
|
-
describe
|
|
58
|
-
it
|
|
56
|
+
describe "#validate" do
|
|
57
|
+
it "raises MissingRequiredKeyError if required key is missing" do
|
|
59
58
|
subject.required_keys.each { |k| subject.delete(k) }
|
|
60
59
|
expect { subject.validate }.to raise_error IIIF::V3::Presentation::MissingRequiredKeyError
|
|
61
60
|
end
|
|
62
|
-
it
|
|
63
|
-
subject[
|
|
61
|
+
it "raises ProhibitedKeyError if prohibited key is present" do
|
|
62
|
+
subject["verboten"] = 666
|
|
64
63
|
exp_err_msg = "verboten is a prohibited key in #{subject.class}"
|
|
65
64
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::ProhibitedKeyError, exp_err_msg)
|
|
66
65
|
end
|
|
67
|
-
it
|
|
68
|
-
subject[
|
|
66
|
+
it "raises IllegalValueError for bad viewing_direction" do
|
|
67
|
+
subject["viewing_direction"] = "foo"
|
|
69
68
|
exp_err_msg = "viewingDirection must be one of #{subject.legal_viewing_direction_values}"
|
|
70
69
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
71
70
|
end
|
|
72
|
-
describe
|
|
73
|
-
it
|
|
74
|
-
subject[
|
|
71
|
+
describe "viewing_hint" do
|
|
72
|
+
it "can be a uri" do
|
|
73
|
+
subject["viewing_hint"] = "https://example.org/viewiing_hint"
|
|
75
74
|
expect { subject.validate }.not_to raise_error
|
|
76
75
|
end
|
|
77
|
-
it
|
|
78
|
-
subject[
|
|
76
|
+
it "can be a member of legal_viewing_hint_values" do
|
|
77
|
+
subject["viewing_hint"] = subject.legal_viewing_hint_values.first
|
|
79
78
|
expect { subject.validate }.not_to raise_error
|
|
80
79
|
end
|
|
81
|
-
it
|
|
82
|
-
subject[
|
|
80
|
+
it "raises IllegalValueError for bad viewing_hint" do
|
|
81
|
+
subject["viewing_hint"] = "foo"
|
|
83
82
|
exp_err_msg = "viewingHint for #{subject.class} must be one or more of #{subject.legal_viewing_hint_values} or a URI"
|
|
84
83
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
85
84
|
end
|
|
86
|
-
it
|
|
87
|
-
subject[
|
|
85
|
+
it "can have multiple values" do
|
|
86
|
+
subject["viewing_hint"] = [subject.legal_viewing_hint_values.first, subject.legal_viewing_hint_values.last]
|
|
88
87
|
expect { subject.validate }.not_to raise_error
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
|
-
describe
|
|
92
|
-
it
|
|
93
|
-
subject[
|
|
90
|
+
describe "metadata" do
|
|
91
|
+
it "raises IllegalValueError for entry that is not a Hash" do
|
|
92
|
+
subject["metadata"] = ["error"]
|
|
94
93
|
exp_err_msg = "metadata must be an Array with Hash members"
|
|
95
94
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
96
95
|
end
|
|
97
96
|
it 'does not raise error for entry that contains exactly "label" and "value"' do
|
|
98
|
-
subject[
|
|
97
|
+
subject["metadata"] = [{"label" => "bar", "value" => "foo"}]
|
|
99
98
|
expect { subject.validate }.not_to raise_error
|
|
100
99
|
end
|
|
101
100
|
it 'raises IllegalValueError for entry that does not contain exactly "label" and "value"' do
|
|
102
|
-
subject[
|
|
101
|
+
subject["metadata"] = [{"label" => "bar", "bar" => "foo"}]
|
|
103
102
|
exp_err_msg = "metadata members must be a Hash of keys 'label' and 'value'"
|
|
104
103
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
105
104
|
end
|
|
106
105
|
end
|
|
107
|
-
describe
|
|
108
|
-
let
|
|
109
|
-
let
|
|
110
|
-
it
|
|
111
|
-
subject[
|
|
106
|
+
describe "thumbnail" do
|
|
107
|
+
let(:exp_basic_err_msg) { "thumbnail must be an Array with Hash or ImageResource members" }
|
|
108
|
+
let(:exp_keys_msg) { 'thumbnail members must include keys "id" and "type"' }
|
|
109
|
+
it "raises IllegalValueError for entry that is not a Hash or ImageResource object" do
|
|
110
|
+
subject["thumbnail"] = ["error"]
|
|
112
111
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_basic_err_msg)
|
|
113
112
|
end
|
|
114
113
|
it 'does not raise error for entry Hash with "id" and "type"' do
|
|
115
|
-
subject[
|
|
114
|
+
subject["thumbnail"] = [{"id" => "bar", "type" => "foo", "random" => "xxx"}]
|
|
116
115
|
expect { subject.validate }.not_to raise_error
|
|
117
116
|
end
|
|
118
117
|
it 'raises IllegalValueError for entry Hash that does not contain "id" and "type"' do
|
|
119
|
-
subject[
|
|
118
|
+
subject["thumbnail"] = [{"id" => "bar"}]
|
|
120
119
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_keys_msg)
|
|
121
120
|
end
|
|
122
121
|
it 'does not raise error for entry ImageResource with "id"' do
|
|
123
|
-
subject[
|
|
122
|
+
subject["thumbnail"] = [IIIF::V3::Presentation::ImageResource.new({"id" => "bar", "label" => "xxx"})]
|
|
124
123
|
expect { subject.validate }.not_to raise_error
|
|
125
124
|
end
|
|
126
|
-
it
|
|
127
|
-
subject[
|
|
125
|
+
it "raises IllegalValueError for entry ImageResource without id" do
|
|
126
|
+
subject["thumbnail"] = [IIIF::V3::Presentation::ImageResource.new]
|
|
128
127
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_keys_msg)
|
|
129
128
|
end
|
|
130
129
|
end
|
|
131
|
-
describe
|
|
132
|
-
it
|
|
133
|
-
subject[
|
|
130
|
+
describe "nav_date" do
|
|
131
|
+
it "does not raise error for value of form YYYY-MM-DDThh:mm:ssZ" do
|
|
132
|
+
subject["nav_date"] = "1991-01-02T13:04:27Z"
|
|
134
133
|
expect { subject.validate }.not_to raise_error
|
|
135
134
|
end
|
|
136
|
-
it
|
|
137
|
-
subject[
|
|
138
|
-
exp_err_msg =
|
|
135
|
+
it "raises IllegalValueError for value not of form YYYY-MM-DDThh:mm:ssZ" do
|
|
136
|
+
subject["nav_date"] = "1991-01-02T13:04:27+0500"
|
|
137
|
+
exp_err_msg = "nav_date must be of form YYYY-MM-DDThh:mm:ssZ"
|
|
139
138
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
140
139
|
end
|
|
141
140
|
end
|
|
142
141
|
|
|
143
|
-
describe
|
|
144
|
-
it
|
|
145
|
-
subject[
|
|
142
|
+
describe "rights" do
|
|
143
|
+
it "raises IllegalValueError for entry that is not a string" do
|
|
144
|
+
subject["rights"] = ["error"]
|
|
146
145
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError)
|
|
147
146
|
end
|
|
148
147
|
|
|
149
|
-
it
|
|
150
|
-
subject[
|
|
148
|
+
it "does not raise error for entry that is string" do
|
|
149
|
+
subject["rights"] = "http://example.org/rights"
|
|
151
150
|
expect { subject.validate }.not_to raise_error
|
|
152
151
|
end
|
|
153
152
|
end
|
|
154
153
|
|
|
155
|
-
describe
|
|
156
|
-
it
|
|
157
|
-
subject[
|
|
154
|
+
describe "rendering" do
|
|
155
|
+
it "raises IllegalValueError for entry that is not a Hash" do
|
|
156
|
+
subject["rendering"] = ["error"]
|
|
158
157
|
exp_err_msg = "rendering must be an Array with Hash members"
|
|
159
158
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
160
159
|
end
|
|
161
160
|
it 'does not raise error for entry with "label" and "format"' do
|
|
162
|
-
subject[
|
|
161
|
+
subject["rendering"] = [{"label" => "bar", "format" => "foo", "random" => "xxx"}]
|
|
163
162
|
expect { subject.validate }.not_to raise_error
|
|
164
163
|
end
|
|
165
164
|
it 'raises IllegalValueError for entry that does not contain "label" and "format"' do
|
|
166
|
-
subject[
|
|
165
|
+
subject["rendering"] = [{"label" => "bar"}]
|
|
167
166
|
exp_err_msg = 'rendering members must be a Hash including keys "label" and "format"'
|
|
168
167
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
169
168
|
end
|
|
170
169
|
end
|
|
171
|
-
describe
|
|
172
|
-
it
|
|
173
|
-
subject.startCanvas =
|
|
170
|
+
describe "startCanvas" do
|
|
171
|
+
it "raises IllegalValueError for entry that is not URI" do
|
|
172
|
+
subject.startCanvas = "foo"
|
|
174
173
|
exp_err_msg = "startCanvas value must be a String containing a URI for #{subject.class}"
|
|
175
174
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, exp_err_msg)
|
|
176
175
|
end
|
|
177
176
|
end
|
|
178
177
|
end
|
|
179
178
|
|
|
180
|
-
describe
|
|
181
|
-
it
|
|
179
|
+
describe "A nested object (e.g. self['metadata'])" do
|
|
180
|
+
it "returns [] if not set" do
|
|
182
181
|
expect(subject.metadata).to eq([])
|
|
183
182
|
end
|
|
184
|
-
it
|
|
183
|
+
it "is not in #to_ordered_hash at all if we access it but do not append to it" do
|
|
185
184
|
subject.metadata # touch it
|
|
186
185
|
expect(subject.metadata).to eq([])
|
|
187
|
-
expect(subject.to_ordered_hash.has_key?(
|
|
186
|
+
expect(subject.to_ordered_hash.has_key?("metadata")).to be_falsey
|
|
188
187
|
end
|
|
189
|
-
it
|
|
188
|
+
it "gets structured as we'd expect" do
|
|
190
189
|
subject.metadata << {
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
"label" => "Author",
|
|
191
|
+
"value" => "Anne Author"
|
|
193
192
|
}
|
|
194
193
|
subject.metadata << {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
{
|
|
198
|
-
{
|
|
194
|
+
"label" => "Published",
|
|
195
|
+
"value" => [
|
|
196
|
+
{"@value" => "Paris, circa 1400", "@language" => "en"},
|
|
197
|
+
{"@value" => "Paris, environ 14eme siecle", "@language" => "fr"}
|
|
199
198
|
]
|
|
200
199
|
}
|
|
201
|
-
expect(subject.metadata[0][
|
|
202
|
-
expect(subject.metadata[1][
|
|
203
|
-
expect(subject.metadata[1][
|
|
200
|
+
expect(subject.metadata[0]["label"]).to eq("Author")
|
|
201
|
+
expect(subject.metadata[1]["value"].length).to eq(2)
|
|
202
|
+
expect(subject.metadata[1]["value"].reverse.find { |e| e["@language"] == "fr" }["@value"]).to eq("Paris, environ 14eme siecle")
|
|
204
203
|
end
|
|
205
204
|
|
|
206
|
-
it
|
|
205
|
+
it "roundtrips" do
|
|
207
206
|
subject.metadata << {
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
"label" => "Author",
|
|
208
|
+
"value" => "Anne Author"
|
|
210
209
|
}
|
|
211
210
|
subject.metadata << {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
{
|
|
211
|
+
"label" => "Published",
|
|
212
|
+
"value" => [
|
|
213
|
+
{"@value" => "Paris, circa 1400", "@language" => "en"},
|
|
214
|
+
{"@value" => "Paris, environ 14eme siecle", "@language" => "fr"}
|
|
216
215
|
]
|
|
217
216
|
}
|
|
218
|
-
File.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
parsed
|
|
222
|
-
expect(parsed[
|
|
223
|
-
|
|
224
|
-
expect(parsed['metadata'][1]['value'].select { |e| e['@language'] == 'fr'}.last['@value']).to eq('Paris, environ 14eme siecle')
|
|
225
|
-
File.delete('/tmp/osullivan-spec.json')
|
|
217
|
+
File.write("/tmp/osullivan-spec.json", subject.to_json)
|
|
218
|
+
parsed = subject.class.parse("/tmp/osullivan-spec.json")
|
|
219
|
+
expect(parsed["metadata"][0]["label"]).to eq("Author")
|
|
220
|
+
expect(parsed["metadata"][1]["value"].length).to eq(2)
|
|
221
|
+
expect(parsed["metadata"][1]["value"].reverse.find { |e| e["@language"] == "fr" }["@value"]).to eq("Paris, environ 14eme siecle")
|
|
222
|
+
File.delete("/tmp/osullivan-spec.json")
|
|
226
223
|
end
|
|
227
224
|
end
|
|
228
225
|
|
|
229
|
-
describe
|
|
230
|
-
describe
|
|
231
|
-
before(:each) { subject.delete(
|
|
232
|
-
it
|
|
233
|
-
expect(subject.has_key?(
|
|
234
|
-
expect(subject.to_ordered_hash.has_key?(
|
|
235
|
-
end
|
|
236
|
-
it
|
|
237
|
-
expect(subject.has_key?(
|
|
238
|
-
expect(subject.to_ordered_hash(include_context: false).has_key?(
|
|
239
|
-
end
|
|
240
|
-
it
|
|
241
|
-
different_ctxt =
|
|
242
|
-
subject[
|
|
226
|
+
describe "#to_ordered_hash" do
|
|
227
|
+
describe "adds the @context" do
|
|
228
|
+
before(:each) { subject.delete("@context") }
|
|
229
|
+
it "by default" do
|
|
230
|
+
expect(subject.has_key?("@context")).to be_falsey
|
|
231
|
+
expect(subject.to_ordered_hash.has_key?("@context")).to be_truthy
|
|
232
|
+
end
|
|
233
|
+
it "unless you say not to" do
|
|
234
|
+
expect(subject.has_key?("@context")).to be_falsey
|
|
235
|
+
expect(subject.to_ordered_hash(include_context: false).has_key?("@context")).to be_falsey
|
|
236
|
+
end
|
|
237
|
+
it "or it's already there" do
|
|
238
|
+
different_ctxt = "http://example.org/context"
|
|
239
|
+
subject["@context"] = different_ctxt
|
|
243
240
|
oh = subject.to_ordered_hash
|
|
244
|
-
expect(oh[
|
|
241
|
+
expect(oh["@context"]).to eq different_ctxt
|
|
245
242
|
end
|
|
246
243
|
end
|
|
247
244
|
|
|
248
|
-
describe
|
|
245
|
+
describe "runs the validations" do
|
|
249
246
|
let(:error) { IIIF::V3::Presentation::MissingRequiredKeyError }
|
|
250
|
-
before(:each) { subject.delete(
|
|
251
|
-
it
|
|
247
|
+
before(:each) { subject.delete("id") }
|
|
248
|
+
it "raises exceptions" do
|
|
252
249
|
expect { subject.to_ordered_hash }.to raise_error error
|
|
253
250
|
end
|
|
254
|
-
it
|
|
251
|
+
it "unless you tell it not to" do
|
|
255
252
|
expect { subject.to_ordered_hash(force: true) }.to_not raise_error
|
|
256
253
|
end
|
|
257
254
|
end
|
|
258
255
|
end
|
|
259
256
|
|
|
260
|
-
describe
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
TYPE
|
|
257
|
+
describe "*get_descendant_class_by_jld_type" do
|
|
258
|
+
let(:dummy_class) do
|
|
259
|
+
Class.new(IIIF::V3::AbstractResource) do
|
|
260
|
+
const_set(:TYPE, "Collection")
|
|
264
261
|
def self.singleton_class?
|
|
265
262
|
true
|
|
266
263
|
end
|
|
267
264
|
end
|
|
268
265
|
end
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
end
|
|
272
|
-
it 'gets the right class' do
|
|
273
|
-
klass = described_class.get_descendant_class_by_jld_type('Canvas')
|
|
266
|
+
it "gets the right class" do
|
|
267
|
+
klass = described_class.get_descendant_class_by_jld_type("Canvas")
|
|
274
268
|
expect(klass).to eq IIIF::V3::Presentation::Canvas
|
|
275
269
|
end
|
|
276
270
|
context "when there are singleton classes which are returned" do
|
|
277
271
|
it "gets the right class" do
|
|
278
|
-
allow(IIIF::V3::AbstractResource).to receive(:descendants).and_return([
|
|
279
|
-
klass = described_class.get_descendant_class_by_jld_type(
|
|
272
|
+
allow(IIIF::V3::AbstractResource).to receive(:descendants).and_return([dummy_class, IIIF::V3::Presentation::Collection])
|
|
273
|
+
klass = described_class.get_descendant_class_by_jld_type("Collection")
|
|
280
274
|
expect(klass).to eq IIIF::V3::Presentation::Collection
|
|
281
275
|
end
|
|
282
276
|
end
|
|
283
277
|
end
|
|
284
|
-
|
|
285
278
|
end
|