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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +8 -1
  3. data/.standard.yml +1 -0
  4. data/Gemfile +5 -5
  5. data/README.md +1 -1
  6. data/Rakefile +4 -2
  7. data/VERSION +1 -1
  8. data/bin/standardrb +16 -0
  9. data/iiif-presentation.gemspec +23 -23
  10. data/lib/iiif/hash_behaviours.rb +29 -33
  11. data/lib/iiif/ordered_hash.rb +33 -33
  12. data/lib/iiif/presentation/abstract_resource.rb +17 -22
  13. data/lib/iiif/presentation/annotation.rb +9 -11
  14. data/lib/iiif/presentation/annotation_list.rb +8 -10
  15. data/lib/iiif/presentation/canvas.rb +11 -13
  16. data/lib/iiif/presentation/collection.rb +7 -9
  17. data/lib/iiif/presentation/image_resource.rb +33 -35
  18. data/lib/iiif/presentation/layer.rb +8 -10
  19. data/lib/iiif/presentation/manifest.rb +9 -12
  20. data/lib/iiif/presentation/range.rb +8 -10
  21. data/lib/iiif/presentation/resource.rb +5 -7
  22. data/lib/iiif/presentation/sequence.rb +8 -11
  23. data/lib/iiif/presentation/service.rb +1 -2
  24. data/lib/iiif/presentation.rb +7 -7
  25. data/lib/iiif/service.rb +121 -102
  26. data/lib/iiif/v3/abstract_resource.rb +127 -130
  27. data/lib/iiif/v3/presentation/annotation.rb +20 -21
  28. data/lib/iiif/v3/presentation/annotation_collection.rb +7 -9
  29. data/lib/iiif/v3/presentation/annotation_page.rb +14 -15
  30. data/lib/iiif/v3/presentation/canvas.rb +21 -22
  31. data/lib/iiif/v3/presentation/choice.rb +14 -15
  32. data/lib/iiif/v3/presentation/collection.rb +7 -8
  33. data/lib/iiif/v3/presentation/image_resource.rb +21 -22
  34. data/lib/iiif/v3/presentation/manifest.rb +18 -19
  35. data/lib/iiif/v3/presentation/nav_place.rb +125 -29
  36. data/lib/iiif/v3/presentation/range.rb +10 -10
  37. data/lib/iiif/v3/presentation/resource.rb +4 -5
  38. data/lib/iiif/v3/presentation/sequence.rb +10 -11
  39. data/lib/iiif/v3/presentation/service.rb +12 -13
  40. data/lib/iiif/v3/presentation.rb +8 -8
  41. data/spec/integration/iiif/presentation/image_resource_spec.rb +54 -58
  42. data/spec/integration/iiif/service_spec.rb +76 -77
  43. data/spec/integration/iiif/v3/abstract_resource_spec.rb +72 -73
  44. data/spec/integration/iiif/v3/presentation/image_resource_spec.rb +53 -56
  45. data/spec/spec_helper.rb +56 -64
  46. data/spec/unit/iiif/hash_behaviours_spec.rb +384 -387
  47. data/spec/unit/iiif/ordered_hash_spec.rb +86 -91
  48. data/spec/unit/iiif/presentation/abstract_resource_spec.rb +64 -70
  49. data/spec/unit/iiif/presentation/annotation_list_spec.rb +1 -3
  50. data/spec/unit/iiif/presentation/annotation_spec.rb +1 -3
  51. data/spec/unit/iiif/presentation/canvas_spec.rb +11 -14
  52. data/spec/unit/iiif/presentation/collection_spec.rb +26 -33
  53. data/spec/unit/iiif/presentation/image_resource_spec.rb +4 -6
  54. data/spec/unit/iiif/presentation/layer_spec.rb +16 -20
  55. data/spec/unit/iiif/presentation/manifest_spec.rb +45 -48
  56. data/spec/unit/iiif/presentation/range_spec.rb +18 -22
  57. data/spec/unit/iiif/presentation/resource_spec.rb +3 -6
  58. data/spec/unit/iiif/presentation/sequence_spec.rb +58 -63
  59. data/spec/unit/iiif/presentation/shared_examples/abstract_resource_only_keys.rb +4 -10
  60. data/spec/unit/iiif/presentation/shared_examples/any_type_keys.rb +5 -9
  61. data/spec/unit/iiif/presentation/shared_examples/array_only_keys.rb +9 -17
  62. data/spec/unit/iiif/presentation/shared_examples/int_only_keys.rb +6 -14
  63. data/spec/unit/iiif/presentation/shared_examples/string_only_keys.rb +6 -13
  64. data/spec/unit/iiif/service_spec.rb +8 -13
  65. data/spec/unit/iiif/v3/abstract_resource_define_methods_for_spec.rb +39 -37
  66. data/spec/unit/iiif/v3/abstract_resource_spec.rb +124 -131
  67. data/spec/unit/iiif/v3/presentation/annotation_collection_spec.rb +14 -17
  68. data/spec/unit/iiif/v3/presentation/annotation_page_spec.rb +71 -69
  69. data/spec/unit/iiif/v3/presentation/annotation_spec.rb +249 -233
  70. data/spec/unit/iiif/v3/presentation/canvas_spec.rb +211 -193
  71. data/spec/unit/iiif/v3/presentation/choice_spec.rb +81 -77
  72. data/spec/unit/iiif/v3/presentation/collection_spec.rb +24 -29
  73. data/spec/unit/iiif/v3/presentation/image_resource_spec.rb +70 -71
  74. data/spec/unit/iiif/v3/presentation/manifest_spec.rb +248 -235
  75. data/spec/unit/iiif/v3/presentation/nav_place_spec.rb +249 -49
  76. data/spec/unit/iiif/v3/presentation/range_spec.rb +28 -29
  77. data/spec/unit/iiif/v3/presentation/resource_spec.rb +83 -82
  78. data/spec/unit/iiif/v3/presentation/sequence_spec.rb +125 -119
  79. data/spec/unit/iiif/v3/presentation/service_spec.rb +123 -124
  80. data/spec/unit/iiif/v3/presentation/shared_examples/abstract_resource_only_keys.rb +4 -8
  81. data/spec/unit/iiif/v3/presentation/shared_examples/any_type_keys.rb +5 -7
  82. data/spec/unit/iiif/v3/presentation/shared_examples/array_only_keys.rb +9 -13
  83. data/spec/unit/iiif/v3/presentation/shared_examples/hash_only_keys.rb +9 -13
  84. data/spec/unit/iiif/v3/presentation/shared_examples/int_only_keys.rb +6 -10
  85. data/spec/unit/iiif/v3/presentation/shared_examples/numeric_only_keys.rb +6 -10
  86. data/spec/unit/iiif/v3/presentation/shared_examples/string_only_keys.rb +6 -10
  87. data/spec/unit/iiif/v3/presentation/shared_examples/uri_only_keys.rb +9 -13
  88. metadata +26 -65
@@ -1,29 +1,22 @@
1
- require 'set'
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 = 'foo'
5
+ ex = "foo"
10
6
  subject.send("#{prop}=", ex)
11
7
  expect(subject[prop]).to eq ex
12
8
  end
13
- it 'raises an exception when attempting to set it to something other than a String' do
14
- expect { subject.send("#{prop}=", ['Foo']) }.to raise_error IIIF::Presentation::IllegalValueError
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 "#{prop}" do
14
+ describe prop.to_s do
19
15
  it "gets #{prop}" do
20
- ex = 'bar'
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
- describe 'self#get_descendant_class_by_jld_type' do
4
- before do
5
- class DummyClass < IIIF::Service
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
- after do
13
- Object.send(:remove_const, :DummyClass)
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([DummyClass, IIIF::Presentation::Collection])
22
- klass = described_class.get_descendant_class_by_jld_type('sc:Collection')
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 = 'Ignore'
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{ array my_array }
5
+ super + %w[array my_array]
6
6
  end
7
+
7
8
  def hash_only_keys
8
- super + %w{ hash my_hash }
9
+ super + %w[hash my_hash]
9
10
  end
11
+
10
12
  def int_only_keys
11
- super + %w{ int my_int }
13
+ super + %w[int my_int]
12
14
  end
15
+
13
16
  def numeric_only_keys
14
- super + %w{ num my_num }
17
+ super + %w[num my_num]
15
18
  end
19
+
16
20
  def uri_only_keys
17
- super + %w{ uri my_uri }
21
+ super + %w[uri my_uri]
18
22
  end
19
23
 
20
- def initialize(hsh={})
21
- hsh = { 'type' => 'a:SubClass' }
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
- 'label' => 'foo',
34
- 'description' => 'bar',
35
- 'thumbnail' => IIIF::V3::Presentation::ImageResource.new(
36
- 'type' => 'Image',
37
- 'id' => "http://example.org/full/!400,400/0/default.jpg",
38
- 'format' => 'image/jpeg'
39
- ),
40
- 'attribution' => ['foo'],
41
- 'logo' => {
42
- 'id' => 'https://example.org/default.jpg',
43
- 'service' => IIIF::V3::Presentation::Service.new(
44
- '@context' => 'http://iiif.io/api/image/2/context.json',
45
- '@id' => 'http://example.org/1',
46
- 'id' => 'http://example.org/1',
47
- 'profile' => 'http://example.org/whatever'
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
- 'see_also' => {
51
- 'id' => 'http://example.org/whatever',
52
- 'format' => 'application/mods+xml'
52
+ "see_also" => {
53
+ "id" => "http://example.org/whatever",
54
+ "format" => "application/mods+xml"
53
55
  },
54
- 'related' => ['no', 'idea'],
55
- 'within' => {'foo' => 'bar'}
56
+ "related" => ["no", "idea"],
57
+ "within" => {"foo" => "bar"}
56
58
  }
57
59
  end
58
- it_behaves_like 'it has the appropriate methods for any-type keys v3'
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 'it has the appropriate methods for array-only keys v3'
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 'it has the appropriate methods for hash-only keys v3'
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 'it has the appropriate methods for integer-only keys v3'
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 'it has the appropriate methods for numeric-only keys v3'
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 'it has the appropriate methods for string-only keys v3'
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 'it has the appropriate methods for uri-only keys v3'
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 'active_support/inflector'
2
- require 'json'
3
- require_relative '../../../../lib/iiif/hash_behaviours'
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(:fixtures_dir) { File.join(File.dirname(__FILE__), '../../../fixtures') }
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['type'] = 'a:SubClass' unless hsh.has_key?('type')
15
- super(hsh)
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{ id }
18
+ super + %w[id]
20
19
  end
21
20
 
22
21
  def prohibited_keys
23
- super + %w{ verboten }
22
+ super + %w[verboten]
24
23
  end
25
24
 
26
25
  def legal_viewing_hint_values
27
- %w{ viewing_hint1 viewing_hint2 }
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['id'] = 'http://example.com/prefix/manifest/123'
32
+ instance["id"] = "http://example.com/prefix/manifest/123"
34
33
  instance
35
34
  end
36
35
 
37
- describe '#required_keys' do
38
- it 'accumulate' do
39
- expect(subject.required_keys).to eq %w{ type id }
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 '#initialize' do
44
- it 'raises an error if you try to instantiate AbstractResource' do
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 'sets type' do
48
- expect(subject['type']).to eq 'a:SubClass'
46
+ it "sets type" do
47
+ expect(subject["type"]).to eq "a:SubClass"
49
48
  end
50
- it 'can take any old hash' do
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['label']['en']).to include 'Book 1'
52
+ expect(new_instance["label"]["en"]).to include "Book 1"
54
53
  end
55
54
  end
56
55
 
57
- describe '#validate' do
58
- it 'raises MissingRequiredKeyError if required key is missing' do
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 'raises ProhibitedKeyError if prohibited key is present' do
63
- subject['verboten'] = 666
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 'raises IllegalValueError for bad viewing_direction' do
68
- subject['viewing_direction'] = 'foo'
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 'viewing_hint' do
73
- it 'can be a uri' do
74
- subject['viewing_hint'] = 'https://example.org/viewiing_hint'
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 'can be a member of legal_viewing_hint_values' do
78
- subject['viewing_hint'] = subject.legal_viewing_hint_values.first
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 'raises IllegalValueError for bad viewing_hint' do
82
- subject['viewing_hint'] = 'foo'
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 'can have multiple values' do
87
- subject['viewing_hint'] = [subject.legal_viewing_hint_values.first, subject.legal_viewing_hint_values.last]
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 'metadata' do
92
- it 'raises IllegalValueError for entry that is not a Hash' do
93
- subject['metadata'] = ['error']
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['metadata'] = [{ 'label' => 'bar', 'value' => 'foo' }]
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['metadata'] = [{ 'label' => 'bar', 'bar' => 'foo' }]
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 'thumbnail' do
108
- let (:exp_basic_err_msg) { "thumbnail must be an Array with Hash or ImageResource members" }
109
- let (:exp_keys_msg) { 'thumbnail members must include keys "id" and "type"' }
110
- it 'raises IllegalValueError for entry that is not a Hash or ImageResource object' do
111
- subject['thumbnail'] = ['error']
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['thumbnail'] = [{ 'id' => 'bar', 'type' => 'foo', 'random' => 'xxx' }]
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['thumbnail'] = [{ 'id' => 'bar' }]
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['thumbnail'] = [IIIF::V3::Presentation::ImageResource.new({ 'id' => 'bar', 'label' => 'xxx' })]
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 'raises IllegalValueError for entry ImageResource without id' do
127
- subject['thumbnail'] = [IIIF::V3::Presentation::ImageResource.new]
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 'nav_date' do
132
- it 'does not raise error for value of form YYYY-MM-DDThh:mm:ssZ' do
133
- subject['nav_date'] = '1991-01-02T13:04:27Z'
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 'raises IllegalValueError for value not of form YYYY-MM-DDThh:mm:ssZ' do
137
- subject['nav_date'] = '1991-01-02T13:04:27+0500'
138
- exp_err_msg = 'nav_date must be of form YYYY-MM-DDThh:mm:ssZ'
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 'rights' do
144
- it 'raises IllegalValueError for entry that is not a string' do
145
- subject['rights'] = ['error']
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 'does not raise error for entry that is string' do
150
- subject['rights'] = 'http://example.org/rights'
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 'rendering' do
156
- it 'raises IllegalValueError for entry that is not a Hash' do
157
- subject['rendering'] = ['error']
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['rendering'] = [{ 'label' => 'bar', 'format' => 'foo', 'random' => 'xxx' }]
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['rendering'] = [{ 'label' => 'bar' }]
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 'startCanvas' do
172
- it 'raises IllegalValueError for entry that is not URI' do
173
- subject.startCanvas = 'foo'
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 'A nested object (e.g. self[\'metadata\'])' do
181
- it 'returns [] if not set' do
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 'is not in #to_ordered_hash at all if we access it but do not append to it' do
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?('metadata')).to be_falsey
186
+ expect(subject.to_ordered_hash.has_key?("metadata")).to be_falsey
188
187
  end
189
- it 'gets structured as we\'d expect' do
188
+ it "gets structured as we'd expect" do
190
189
  subject.metadata << {
191
- 'label' => 'Author',
192
- 'value' => 'Anne Author'
190
+ "label" => "Author",
191
+ "value" => "Anne Author"
193
192
  }
194
193
  subject.metadata << {
195
- 'label' => 'Published',
196
- 'value' => [
197
- {'@value'=> 'Paris, circa 1400', '@language'=>'en'},
198
- {'@value'=> 'Paris, environ 14eme siecle', '@language'=>'fr'}
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]['label']).to eq('Author')
202
- expect(subject.metadata[1]['value'].length).to eq(2)
203
- expect(subject.metadata[1]['value'].select { |e| e['@language'] == 'fr'}.last['@value']).to eq('Paris, environ 14eme siecle')
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 'roundtrips' do
205
+ it "roundtrips" do
207
206
  subject.metadata << {
208
- 'label' => 'Author',
209
- 'value' => 'Anne Author'
207
+ "label" => "Author",
208
+ "value" => "Anne Author"
210
209
  }
211
210
  subject.metadata << {
212
- 'label' => 'Published',
213
- 'value' => [
214
- {'@value'=> 'Paris, circa 1400', '@language'=>'en'},
215
- {'@value'=> 'Paris, environ 14eme siecle', '@language'=>'fr'}
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.open('/tmp/osullivan-spec.json','w') do |f|
219
- f.write(subject.to_json)
220
- end
221
- parsed = subject.class.parse('/tmp/osullivan-spec.json')
222
- expect(parsed['metadata'][0]['label']).to eq('Author')
223
- expect(parsed['metadata'][1]['value'].length).to eq(2)
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 '#to_ordered_hash' do
230
- describe 'adds the @context' do
231
- before(:each) { subject.delete('@context') }
232
- it 'by default' do
233
- expect(subject.has_key?('@context')).to be_falsey
234
- expect(subject.to_ordered_hash.has_key?('@context')).to be_truthy
235
- end
236
- it 'unless you say not to' do
237
- expect(subject.has_key?('@context')).to be_falsey
238
- expect(subject.to_ordered_hash(include_context: false).has_key?('@context')).to be_falsey
239
- end
240
- it 'or it\'s already there' do
241
- different_ctxt = 'http://example.org/context'
242
- subject['@context'] = different_ctxt
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['@context']).to eq different_ctxt
241
+ expect(oh["@context"]).to eq different_ctxt
245
242
  end
246
243
  end
247
244
 
248
- describe 'runs the validations' do
245
+ describe "runs the validations" do
249
246
  let(:error) { IIIF::V3::Presentation::MissingRequiredKeyError }
250
- before(:each) { subject.delete('id') }
251
- it 'raises exceptions' do
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 'unless you tell it not to' do
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 '*get_descendant_class_by_jld_type' do
261
- before do
262
- class DummyClass < IIIF::V3::AbstractResource
263
- TYPE = "Collection"
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
- after do
270
- Object.send(:remove_const, :DummyClass)
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([DummyClass, IIIF::V3::Presentation::Collection])
279
- klass = described_class.get_descendant_class_by_jld_type('Collection')
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