diff --git a/lib/iiif/v3/abstract_resource.rb b/lib/iiif/v3/abstract_resource.rb index 76fd0c0..e19755e 100644 --- a/lib/iiif/v3/abstract_resource.rb +++ b/lib/iiif/v3/abstract_resource.rb @@ -347,7 +347,9 @@ def self.from_ordered_hash(hsh, default_klass=IIIF::OrderedHash) hsh.keys.each do |key| new_key = key.underscore == key ? key : key.underscore if new_key == 'service' - new_object[new_key] = IIIF::V3::AbstractResource.from_ordered_hash(hsh[key], IIIF::V3::Presentation::Service) + new_object[new_key] = hsh[key].map do |entry| + IIIF::V3::AbstractResource.from_ordered_hash(entry, IIIF::V3::Presentation::Service) + end elsif new_key == 'body' new_object[new_key] = IIIF::V3::AbstractResource.from_ordered_hash(hsh[key], IIIF::V3::Presentation::Resource) elsif hsh[key].kind_of?(Hash) diff --git a/spec/fixtures/v3/manifests/complete_from_spec.json b/spec/fixtures/v3/manifests/complete_from_spec.json index dc7ab0c..573730d 100644 --- a/spec/fixtures/v3/manifests/complete_from_spec.json +++ b/spec/fixtures/v3/manifests/complete_from_spec.json @@ -28,11 +28,13 @@ "description": "A longer description of this example book. It should give some real information.", "rights": "http://www.example.org/license.html", "attribution": "Provided by Example Organization", - "service": { - "@context": "http://example.org/ns/jsonld/context.json", - "id": "http://example.org/service/example", - "profile": "http://example.org/docs/example-service.html" - }, + "service": [ + { + "@context": "http://example.org/ns/jsonld/context.json", + "id": "http://example.org/service/example", + "profile": "http://example.org/docs/example-service.html" + } + ], "seeAlso": { "id": "http://www.example.org/library/catalog/book1.marc", "format": "application/marc" @@ -67,11 +69,13 @@ "format": "image/jpeg", "height": 2000, "width": 1500, - "service": { - "@context": "http://iiif.io/api/image/2/context.json", - "id": "http://www.example.org/images/book1-page1", - "profile": "http://iiif.io/api/image/2/level1.json" - } + "service": [ + { + "@context": "http://iiif.io/api/image/2/context.json", + "id": "http://www.example.org/images/book1-page1", + "profile": "http://iiif.io/api/image/2/level1.json" + } + ] } } ] @@ -102,25 +106,27 @@ "format": "image/jpeg", "height": 2000, "width": 1500, - "service": { - "@context": "http://iiif.io/api/image/2/context.json", - "id": "http://www.example.org/images/book1-page2", - "profile": "http://iiif.io/api/image/2/level1.json", - "height": 8000, - "width": 6000, - "tiles": [ - { - "width": 512, - "scaleFactors": [ - 1, - 2, - 4, - 8, - 16 - ] - } - ] - } + "service": [ + { + "@context": "http://iiif.io/api/image/2/context.json", + "id": "http://www.example.org/images/book1-page2", + "profile": "http://iiif.io/api/image/2/level1.json", + "height": 8000, + "width": 6000, + "tiles": [ + { + "width": 512, + "scaleFactors": [ + 1, + 2, + 4, + 8, + 16 + ] + } + ] + } + ] }, "target": "http://www.example.org/iiif/book1/canvas/p2" } @@ -153,11 +159,13 @@ "format": "image/jpeg", "height": 2000, "width": 1500, - "service": { - "@context": "http://iiif.io/api/image/2/context.json", - "id": "http://www.example.org/images/book1-page3", - "profile": "http://iiif.io/api/image/2/level1.json" - } + "service": [ + { + "@context": "http://iiif.io/api/image/2/context.json", + "id": "http://www.example.org/images/book1-page3", + "profile": "http://iiif.io/api/image/2/level1.json" + } + ] } } ] diff --git a/spec/fixtures/v3/manifests/minimal.json b/spec/fixtures/v3/manifests/minimal.json index e4db4d4..5f7ca59 100644 --- a/spec/fixtures/v3/manifests/minimal.json +++ b/spec/fixtures/v3/manifests/minimal.json @@ -32,11 +32,13 @@ "format": "image/jpeg", "height": 2000, "width": 1500, - "service": { - "@context": "http://iiif.io/api/image/2/context.json", - "id": "http://www.example.org/images/book1-page1", - "profile": "http://iiif.io/api/image/2/level1.json" - } + "service": [ + { + "@context": "http://iiif.io/api/image/2/context.json", + "id": "http://www.example.org/images/book1-page1", + "profile": "http://iiif.io/api/image/2/level1.json" + } + ] } } ] diff --git a/spec/fixtures/v3/manifests/service_only.json b/spec/fixtures/v3/manifests/service_only.json index f31d7c2..294c2cc 100644 --- a/spec/fixtures/v3/manifests/service_only.json +++ b/spec/fixtures/v3/manifests/service_only.json @@ -6,9 +6,11 @@ "type": "Manifest", "id": "http://www.example.org/iiif/book1/manifest", "label": "Book 1", - "service": { - "@context": "http://example.org/ns/jsonld/context.json", - "id": "http://example.org/service/example", - "profile": "http://example.org/docs/example-service.html" - } + "service": [ + { + "@context": "http://example.org/ns/jsonld/context.json", + "id": "http://example.org/service/example", + "profile": "http://example.org/docs/example-service.html" + } + ] } diff --git a/spec/integration/iiif/v3/abstract_resource_spec.rb b/spec/integration/iiif/v3/abstract_resource_spec.rb index fa8686f..8c5bdd8 100644 --- a/spec/integration/iiif/v3/abstract_resource_spec.rb +++ b/spec/integration/iiif/v3/abstract_resource_spec.rb @@ -47,12 +47,14 @@ "id": "http://example.com/manifest", "type": "Manifest", "label": "My Manifest", - "service": { - "@context": "http://iiif.io/api/image/2/context.json", - "@id":"http://www.example.org/images/book1-page1", - "id":"http://www.example.org/images/book1-page1", - "profile":"http://iiif.io/api/image/2/profiles/level2.json" - }, + "service": [ + { + "@context": "http://iiif.io/api/image/2/context.json", + "@id":"http://www.example.org/images/book1-page1", + "id":"http://www.example.org/images/book1-page1", + "profile":"http://iiif.io/api/image/2/profiles/level2.json" + } + ], "some_other_thing": { "foo" : "bar" }, @@ -95,7 +97,7 @@ it 'turns services into Services' do expected_klass = IIIF::V3::Presentation::Service parsed = described_class.from_ordered_hash(fixture) - expect(parsed['service'].class).to be expected_klass + expect(parsed['service'].map(&:class).uniq).to contain_exactly expected_klass end it 'round-trips' do diff --git a/spec/unit/iiif/v3/presentation/annotation_spec.rb b/spec/unit/iiif/v3/presentation/annotation_spec.rb index 7bea098..e3f837e 100644 --- a/spec/unit/iiif/v3/presentation/annotation_spec.rb +++ b/spec/unit/iiif/v3/presentation/annotation_spec.rb @@ -12,7 +12,7 @@ 'id' => content_id, 'type' => content_type, 'format' => mimetype, - 'service' => image_2_api_service + 'service' => [image_2_api_service] )} describe '#required_keys' do @@ -183,14 +183,16 @@ def initialize(hsh={}) let(:img_mime) { 'image/jpeg' } let(:img_h) { 2000 } let(:img_w) { 1500 } - let(:img_hw_resource) { IIIF::V3::Presentation::ImageResource.new( - 'id' => content_id, - 'type' => img_type, - 'format' => img_mime, - 'height' => img_h, - 'width' => img_w, - 'service' => image_2_api_service - )} + let(:img_hw_resource) do + IIIF::V3::Presentation::ImageResource.new( + 'id' => content_id, + 'type' => img_type, + 'format' => img_mime, + 'height' => img_h, + 'width' => img_w, + 'service' => [image_2_api_service] + ) + end let(:my_anno) { anno = described_class.new anno['id'] = anno_id @@ -209,22 +211,23 @@ def initialize(hsh={}) describe 'and service with height and width and tiles' do let(:tiles_val) { [{"width" => 512, "scaleFactors" => [1,2,4,8,16]}] } - let(:service) { + let(:service) do s = image_2_api_service s['height'] = 8000 s['width'] = 6000 s['tiles'] = tiles_val - s - } + [s] + end it 'validates' do img_hw_resource['service'] = service expect{my_anno.validate}.not_to raise_error end it "body['service'] has expected additional values'" do - expect(my_anno['body']['service']).to eq service - expect(my_anno['body']['service']['height']).to eq 8000 - expect(my_anno['body']['service']['width']).to eq 6000 - expect(my_anno['body']['service']['tiles']).to eq tiles_val + annotation_service = my_anno['body']['service'].first + expect(annotation_service).to eq service.first + expect(annotation_service['height']).to eq 8000 + expect(annotation_service['width']).to eq 6000 + expect(annotation_service['tiles']).to eq tiles_val end end end diff --git a/spec/unit/iiif/v3/presentation/image_resource_spec.rb b/spec/unit/iiif/v3/presentation/image_resource_spec.rb index 980d240..161f755 100644 --- a/spec/unit/iiif/v3/presentation/image_resource_spec.rb +++ b/spec/unit/iiif/v3/presentation/image_resource_spec.rb @@ -131,7 +131,7 @@ 'format' => img_mimetype, 'height' => height, 'width' => width, - 'service' => image_v2_service + 'service' => [image_v2_service] }) } describe 'simpler' do @@ -146,7 +146,7 @@ expect(image_object.format).to eq img_mimetype expect(image_object.height).to eq height expect(image_object.width).to eq width - expect(image_object.service).to eq image_v2_service + expect(image_object.service.first).to eq image_v2_service end end describe 'height and width in service' do @@ -156,27 +156,27 @@ # "format": "image/jpeg", # "height":2000, # "width":1500, - # "service": { + # "service": [{ # "@context": "http://iiif.io/api/image/2/context.json", # "id": "http://example.org/images/book1-page2", # "profile": "http://iiif.io/api/image/2/level1.json", # "height":8000, # "width":6000, # "tiles": [{"width": 512, "scaleFactors": [1,2,4,8,16]}] - # } + # }] # } let(:img_obj) { img = image_object - img.service['height'] = 6666 - img.service['width'] = 9999 - img.service['tiles'] = [{"width" => 512, "scaleFactors" => [1,2,4,8,16]}] + img.service.first['height'] = 6666 + img.service.first['width'] = 9999 + img.service.first['tiles'] = [{"width" => 512, "scaleFactors" => [1,2,4,8,16]}] img } it 'validates' do expect{img_obj.validate}.not_to raise_error end it 'has expected service value' do - service_obj = img_obj.service + service_obj = img_obj.service.first expect(service_obj.class).to eq IIIF::V3::Presentation::Service expect(service_obj.keys.size).to eq 7 expect(service_obj['height']).to eq 6666 diff --git a/spec/unit/iiif/v3/presentation/manifest_spec.rb b/spec/unit/iiif/v3/presentation/manifest_spec.rb index a9274f4..61a73bc 100644 --- a/spec/unit/iiif/v3/presentation/manifest_spec.rb +++ b/spec/unit/iiif/v3/presentation/manifest_spec.rb @@ -176,7 +176,7 @@ def initialize(hsh={}) let!(:thumbnail_image) { IIIF::V3::Presentation::ImageResource.new({ "id" => "https://example.org/image/iiif/abc666_05_0001/full/!400,400/0/default.jpg", "format" => "image/jpeg", - "service" => thumbnail_image_service + "service" => [thumbnail_image_service] })} let!(:manifest_object) { described_class.new({ "id" => "https://example.org/abc666/iiif3/manifest", @@ -189,7 +189,7 @@ def initialize(hsh={}) "items" => [canvas_object], "logo" => { "id" => "https://example.org/logo/full/400,/0/default.jpg", - "service" => logo_service + "service" => [logo_service] }, "seeAlso" => { "id" => "https://example.org/abc666.mods", @@ -242,7 +242,7 @@ def initialize(hsh={}) }, "logo" => { "id" => "https://example.org/logo/full/400,/0/default.jpg", - "service" => logo_service + "service" => [logo_service] }, "seeAlso" => { "id" => "https://example.org/abc666.mods", diff --git a/spec/unit/iiif/v3/presentation/sequence_spec.rb b/spec/unit/iiif/v3/presentation/sequence_spec.rb index 8db010f..ae1de5c 100644 --- a/spec/unit/iiif/v3/presentation/sequence_spec.rb +++ b/spec/unit/iiif/v3/presentation/sequence_spec.rb @@ -177,21 +177,21 @@ def initialize(hsh={}) 'thumbnail' => [{ 'id' => 'http://www.example.org/images/book1-page1/full/80,100/0/default.jpg', 'type' => 'Image', - 'service'=> { + 'service'=> [{ '@context' => 'http://iiif.io/api/image/2/context.json', 'id' => 'http://www.example.org/images/book1-page1', 'profile' => 'http://iiif.io/api/image/2/level1.json' - } + }] }], 'attribution' => 'Provided by Example Organization', 'rights' => [{'id' => 'http://www.example.org/license.html'}], 'logo' => 'http://www.example.org/logos/institution1.jpg', 'see_also' => 'http://www.example.org/library/catalog/book1.xml', - 'service' => { + 'service' => [{ '@context' => 'http://example.org/ns/jsonld/context.json', 'id' => 'http://example.org/service/example', 'profile' => 'http://example.org/docs/example-service.html' - }, + }], 'related' => { 'id' => 'http://www.example.org/videos/video-book1.mpg', 'format' => 'video/mpeg'