iiif-presentation 1.0.0 → 1.2.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 +35 -0
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/README.md +22 -2
- data/VERSION +1 -1
- data/iiif-presentation.gemspec +1 -1
- data/lib/iiif/hash_behaviours.rb +1 -1
- data/lib/iiif/presentation/canvas.rb +4 -0
- data/lib/iiif/presentation/service.rb +12 -0
- data/lib/iiif/presentation.rb +5 -4
- data/lib/iiif/service.rb +40 -105
- data/lib/iiif/v3/abstract_resource.rb +491 -0
- data/lib/iiif/v3/presentation/annotation.rb +74 -0
- data/lib/iiif/v3/presentation/annotation_collection.rb +38 -0
- data/lib/iiif/v3/presentation/annotation_page.rb +53 -0
- data/lib/iiif/v3/presentation/canvas.rb +82 -0
- data/lib/iiif/v3/presentation/choice.rb +51 -0
- data/lib/iiif/v3/presentation/collection.rb +52 -0
- data/lib/iiif/v3/presentation/image_resource.rb +110 -0
- data/lib/iiif/v3/presentation/manifest.rb +82 -0
- data/lib/iiif/v3/presentation/range.rb +39 -0
- data/lib/iiif/v3/presentation/resource.rb +30 -0
- data/lib/iiif/v3/presentation/sequence.rb +66 -0
- data/lib/iiif/v3/presentation/service.rb +51 -0
- data/lib/iiif/v3/presentation.rb +36 -0
- data/spec/fixtures/v3/manifests/complete_from_spec.json +195 -0
- data/spec/fixtures/v3/manifests/minimal.json +49 -0
- data/spec/fixtures/v3/manifests/service_only.json +14 -0
- data/spec/fixtures/vcr_cassettes/pul_loris_cassette.json +1 -1
- data/spec/fixtures/vcr_cassettes/pul_loris_cassette_v3.json +1 -0
- data/spec/integration/iiif/presentation/image_resource_spec.rb +0 -1
- data/spec/integration/iiif/service_spec.rb +17 -32
- data/spec/integration/iiif/v3/abstract_resource_spec.rb +202 -0
- data/spec/integration/iiif/v3/presentation/image_resource_spec.rb +118 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/iiif/presentation/canvas_spec.rb +0 -1
- data/spec/unit/iiif/presentation/manifest_spec.rb +1 -1
- data/spec/unit/iiif/v3/abstract_resource_define_methods_for_spec.rb +78 -0
- data/spec/unit/iiif/v3/abstract_resource_spec.rb +293 -0
- data/spec/unit/iiif/v3/presentation/annotation_collection_spec.rb +36 -0
- data/spec/unit/iiif/v3/presentation/annotation_page_spec.rb +131 -0
- data/spec/unit/iiif/v3/presentation/annotation_spec.rb +389 -0
- data/spec/unit/iiif/v3/presentation/canvas_spec.rb +337 -0
- data/spec/unit/iiif/v3/presentation/choice_spec.rb +120 -0
- data/spec/unit/iiif/v3/presentation/collection_spec.rb +55 -0
- data/spec/unit/iiif/v3/presentation/image_resource_spec.rb +189 -0
- data/spec/unit/iiif/v3/presentation/manifest_spec.rb +370 -0
- data/spec/unit/iiif/v3/presentation/range_spec.rb +54 -0
- data/spec/unit/iiif/v3/presentation/resource_spec.rb +174 -0
- data/spec/unit/iiif/v3/presentation/sequence_spec.rb +222 -0
- data/spec/unit/iiif/v3/presentation/service_spec.rb +220 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/abstract_resource_only_keys.rb +41 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/any_type_keys.rb +31 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/array_only_keys.rb +40 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/hash_only_keys.rb +40 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/int_only_keys.rb +45 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/numeric_only_keys.rb +45 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/string_only_keys.rb +26 -0
- data/spec/unit/iiif/v3/presentation/shared_examples/uri_only_keys.rb +31 -0
- metadata +82 -11
- data/.travis.yml +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a766530b4d9f912c49a41e9c6d5982282671c4188a26b27e5a4fb99176fae90c
|
4
|
+
data.tar.gz: bbb25e477c3563ab2a65ec0de5bfc634acffa93c00e7504992dfe539f0e89ad2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac981b561c8e99f41891f2e5246bf46e6de9766abde2269e5eb46e35baeabb4a74404366b8e83ff2eef4e8656ddcb3e8946cd07bfcf14a96c40ba10b29f2fab7
|
7
|
+
data.tar.gz: 126391967ebc6b1e3db349daed94e3aad1ba43f8083729c49b0c976131f5e3c85f8f507713d0f04721f98c494b0193b761a714f1129b9b044d0dcf181e21e112
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ "main" ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ "main" ]
|
15
|
+
|
16
|
+
permissions:
|
17
|
+
contents: read
|
18
|
+
|
19
|
+
jobs:
|
20
|
+
test:
|
21
|
+
|
22
|
+
runs-on: ubuntu-latest
|
23
|
+
strategy:
|
24
|
+
matrix:
|
25
|
+
ruby-version: ['2.7', '3.0', '3.1', '3.2']
|
26
|
+
|
27
|
+
steps:
|
28
|
+
- uses: actions/checkout@v3
|
29
|
+
- name: Set up Ruby
|
30
|
+
uses: ruby/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
34
|
+
- name: Run tests
|
35
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# O'Sullivan: A Ruby API for working with IIIF Presentation manifests
|
2
2
|
|
3
|
-
[](https://travis-ci.org/iiif-prezi/osullivan)
|
4
3
|
[](https://coveralls.io/github/iiif-prezi/osullivan?branch=development)
|
4
|
+
[](https://badge.fury.io/rb/iiif-presentation)
|
5
5
|
|
6
6
|
|
7
7
|
## Installation
|
@@ -25,6 +25,11 @@ seed = {
|
|
25
25
|
# Any options you add are added to the object
|
26
26
|
manifest = IIIF::Presentation::Manifest.new(seed)
|
27
27
|
|
28
|
+
# sequences array is generated for you, but let's add a sequence object
|
29
|
+
sequence = IIIF::Presentation::Sequence.new()
|
30
|
+
sequence['@id'] = "http://example.com/manifest/seq/"
|
31
|
+
manifest.sequences << sequence
|
32
|
+
|
28
33
|
canvas = IIIF::Presentation::Canvas.new()
|
29
34
|
# All classes act like `ActiveSupport::OrderedHash`es, for the most part.
|
30
35
|
# Use `[]=` to set JSON-LD properties...
|
@@ -35,10 +40,25 @@ canvas.width = 10
|
|
35
40
|
canvas.height = 20
|
36
41
|
canvas.label = 'My Canvas'
|
37
42
|
|
43
|
+
# Add images
|
44
|
+
service = IIIF::Presentation::Resource.new('@context' => 'http://iiif.io/api/image/2/context.json', 'profile' => 'http://iiif.io/api/image/2/level2.json', '@id' => "http://images.exampl.com/loris2/my-image")
|
45
|
+
|
46
|
+
image = IIIF::Presentation::ImageResource.new()
|
47
|
+
i['@id'] = "http://images.exampl.com/loris2/my-image/full/#{canvas.width},#{canvas.height}/0/default.jpg"
|
48
|
+
i.format = "image/jpeg"
|
49
|
+
i.width = canvas.width
|
50
|
+
i.height = canvas.height
|
51
|
+
i.service = service
|
52
|
+
|
53
|
+
images = IIIF::Presentation::Resource.new('@type' => 'oa:Annotation', 'motivation' => 'sc:painting', '@id' => "#{canvas['@id']}/images", 'resource' => i)
|
54
|
+
|
55
|
+
canvas.images << images
|
56
|
+
|
57
|
+
# Add other content resources
|
38
58
|
oc = IIIF::Presentation::Resource.new('@id' => 'http://example.com/content')
|
39
59
|
canvas.other_content << oc
|
40
60
|
|
41
|
-
manifest.sequences << canvas
|
61
|
+
manifest.sequences.first.canvases << canvas
|
42
62
|
|
43
63
|
puts manifest.to_json(pretty: true)
|
44
64
|
```
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/iiif-presentation.gemspec
CHANGED
data/lib/iiif/hash_behaviours.rb
CHANGED
@@ -8,7 +8,7 @@ module IIIF
|
|
8
8
|
# * reject
|
9
9
|
# * replace
|
10
10
|
|
11
|
-
def_delegators :@data, :[], :[]=, :camelize_keys, :delete, :empty?,
|
11
|
+
def_delegators :@data, :[], :[]=, :camelize_keys, :delete, :dig, :empty?,
|
12
12
|
:fetch, :has_key?, :has_value?, :include?, :insert, :insert_after,
|
13
13
|
:insert_before, :key, :key?, :keys, :length, :member?, :shift, :size,
|
14
14
|
:snakeize_keys, :store, :unshift, :value?, :values
|
data/lib/iiif/presentation.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'service')
|
2
2
|
%w{
|
3
|
-
abstract_resource
|
3
|
+
abstract_resource
|
4
4
|
annotation
|
5
5
|
annotation_list
|
6
6
|
canvas
|
@@ -8,9 +8,10 @@ abstract_resource
|
|
8
8
|
layer
|
9
9
|
manifest
|
10
10
|
resource
|
11
|
-
|
12
|
-
sequence
|
13
|
-
|
11
|
+
image_resource
|
12
|
+
sequence
|
13
|
+
service
|
14
|
+
range
|
14
15
|
}.each do |f|
|
15
16
|
require File.join(File.dirname(__FILE__), 'presentation', f)
|
16
17
|
end
|
data/lib/iiif/service.rb
CHANGED
@@ -17,6 +17,7 @@ module IIIF
|
|
17
17
|
def abstract_resource_only_keys; %w{ }; end
|
18
18
|
def hash_only_keys; %w{ }; end
|
19
19
|
def int_only_keys; %w{ }; end
|
20
|
+
def numeric_only_keys; %w{ }; end
|
20
21
|
|
21
22
|
def initialize(hsh={})
|
22
23
|
@data = IIIF::OrderedHash[hsh]
|
@@ -24,6 +25,7 @@ module IIIF
|
|
24
25
|
self.define_methods_for_array_only_keys
|
25
26
|
self.define_methods_for_string_only_keys
|
26
27
|
self.define_methods_for_int_only_keys
|
28
|
+
self.define_methods_for_numeric_only_keys
|
27
29
|
self.define_methods_for_abstract_resource_only_keys
|
28
30
|
self.snakeize_keys
|
29
31
|
end
|
@@ -33,9 +35,9 @@ module IIIF
|
|
33
35
|
# Parse from a file path, string, or existing hash
|
34
36
|
def parse(s)
|
35
37
|
ordered_hash = nil
|
36
|
-
if s.kind_of?(String) && File.
|
38
|
+
if s.kind_of?(String) && File.exist?(s)
|
37
39
|
ordered_hash = IIIF::OrderedHash[JSON.parse(IO.read(s))]
|
38
|
-
elsif s.kind_of?(String) && !File.
|
40
|
+
elsif s.kind_of?(String) && !File.exist?(s)
|
39
41
|
ordered_hash = IIIF::OrderedHash[JSON.parse(s)]
|
40
42
|
elsif s.kind_of?(Hash)
|
41
43
|
ordered_hash = IIIF::OrderedHash[s]
|
@@ -210,7 +212,7 @@ module IIIF
|
|
210
212
|
new_object[new_key] = []
|
211
213
|
hsh[key].each do |member|
|
212
214
|
if new_key == 'service'
|
213
|
-
new_object[new_key] << IIIF::Service.from_ordered_hash(member, IIIF::Service)
|
215
|
+
new_object[new_key] << IIIF::Service.from_ordered_hash(member, IIIF::Presentation::Service)
|
214
216
|
elsif new_key == 'resource'
|
215
217
|
new_object[new_key] << IIIF::Service.from_ordered_hash(hsh[key], IIIF::Presentation::Resource)
|
216
218
|
elsif member.kind_of?(Hash)
|
@@ -221,7 +223,7 @@ module IIIF
|
|
221
223
|
end
|
222
224
|
end
|
223
225
|
elsif new_key == 'service'
|
224
|
-
new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key], IIIF::Service)
|
226
|
+
new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key], IIIF::Presentation::Service)
|
225
227
|
elsif new_key == 'resource'
|
226
228
|
new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key], IIIF::Presentation::Resource)
|
227
229
|
elsif hsh[key].kind_of?(Hash)
|
@@ -255,56 +257,22 @@ module IIIF
|
|
255
257
|
end
|
256
258
|
|
257
259
|
def define_methods_for_any_type_keys
|
260
|
+
define_accessor_methods(*any_type_keys)
|
261
|
+
|
262
|
+
# override the getter defined by define_accessor_methods to avoid returning
|
263
|
+
# an array for empty values.
|
258
264
|
any_type_keys.each do |key|
|
259
|
-
# Setters
|
260
|
-
define_singleton_method("#{key}=") do |arg|
|
261
|
-
self.send('[]=', key, arg)
|
262
|
-
end
|
263
|
-
if key.camelize(:lower) != key
|
264
|
-
define_singleton_method("#{key.camelize(:lower)}=") do |arg|
|
265
|
-
self.send('[]=', key, arg)
|
266
|
-
end
|
267
|
-
end
|
268
|
-
# Getters
|
269
265
|
define_singleton_method(key) do
|
270
266
|
self.send('[]', key)
|
271
267
|
end
|
272
|
-
if key.camelize(:lower) != key
|
273
|
-
define_singleton_method(key.camelize(:lower)) do
|
274
|
-
self.send('[]', key)
|
275
|
-
end
|
276
|
-
end
|
277
268
|
end
|
278
269
|
end
|
279
270
|
|
280
271
|
def define_methods_for_array_only_keys
|
281
|
-
array_only_keys
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
m = "#{key} must be an Array."
|
286
|
-
raise IIIF::Presentation::IllegalValueError, m
|
287
|
-
end
|
288
|
-
self.send('[]=', key, arg)
|
289
|
-
end
|
290
|
-
if key.camelize(:lower) != key
|
291
|
-
define_singleton_method("#{key.camelize(:lower)}=") do |arg|
|
292
|
-
unless arg.kind_of?(Array)
|
293
|
-
m = "#{key} must be an Array."
|
294
|
-
raise IIIF::Presentation::IllegalValueError, m
|
295
|
-
end
|
296
|
-
self.send('[]=', key, arg)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
# Getters
|
300
|
-
define_singleton_method(key) do
|
301
|
-
self[key] ||= []
|
302
|
-
self[key]
|
303
|
-
end
|
304
|
-
if key.camelize(:lower) != key
|
305
|
-
define_singleton_method(key.camelize(:lower)) do
|
306
|
-
self.send('[]', key)
|
307
|
-
end
|
272
|
+
define_accessor_methods(*array_only_keys) do |key, arg|
|
273
|
+
unless arg.kind_of?(Array)
|
274
|
+
m = "#{key} must be an Array."
|
275
|
+
raise IIIF::Presentation::IllegalValueError, m
|
308
276
|
end
|
309
277
|
end
|
310
278
|
end
|
@@ -314,85 +282,53 @@ module IIIF
|
|
314
282
|
abstract_resource_only_keys.each do |hsh|
|
315
283
|
key = hsh[:key]
|
316
284
|
type = hsh[:type]
|
317
|
-
|
318
|
-
|
285
|
+
|
286
|
+
define_accessor_methods(key) do |key, arg|
|
319
287
|
unless arg.kind_of?(type)
|
320
288
|
m = "#{key} must be an #{type}."
|
321
289
|
raise IIIF::Presentation::IllegalValueError, m
|
322
290
|
end
|
323
|
-
self.send('[]=', key, arg)
|
324
|
-
end
|
325
|
-
if key.camelize(:lower) != key
|
326
|
-
define_singleton_method("#{key.camelize(:lower)}=") do |arg|
|
327
|
-
unless arg.kind_of?(type)
|
328
|
-
m = "#{key} must be an #{type}."
|
329
|
-
raise IIIF::Presentation::IllegalValueError, m
|
330
|
-
end
|
331
|
-
self.send('[]=', key, arg)
|
332
|
-
end
|
333
|
-
end
|
334
|
-
# Getters
|
335
|
-
define_singleton_method(key) do
|
336
|
-
self[key] ||= []
|
337
|
-
self[key]
|
338
|
-
end
|
339
|
-
if key.camelize(:lower) != key
|
340
|
-
define_singleton_method(key.camelize(:lower)) do
|
341
|
-
self.send('[]', key)
|
342
|
-
end
|
343
291
|
end
|
344
292
|
end
|
345
293
|
end
|
346
294
|
|
347
|
-
|
348
295
|
def define_methods_for_string_only_keys
|
349
|
-
string_only_keys
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
m = "#{key} must be an String."
|
354
|
-
raise IIIF::Presentation::IllegalValueError, m
|
355
|
-
end
|
356
|
-
self.send('[]=', key, arg)
|
357
|
-
end
|
358
|
-
if key.camelize(:lower) != key
|
359
|
-
define_singleton_method("#{key.camelize(:lower)}=") do |arg|
|
360
|
-
unless arg.kind_of?(String)
|
361
|
-
m = "#{key} must be an String."
|
362
|
-
raise IIIF::Presentation::IllegalValueError, m
|
363
|
-
end
|
364
|
-
self.send('[]=', key, arg)
|
365
|
-
end
|
296
|
+
define_accessor_methods(*string_only_keys) do |key, arg|
|
297
|
+
unless arg.kind_of?(String)
|
298
|
+
m = "#{key} must be an String."
|
299
|
+
raise IIIF::Presentation::IllegalValueError, m
|
366
300
|
end
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def define_methods_for_int_only_keys
|
305
|
+
define_accessor_methods(*int_only_keys) do |key, arg|
|
306
|
+
unless arg.kind_of?(Integer) && arg > 0
|
307
|
+
m = "#{key} must be a positive Integer."
|
308
|
+
raise IIIF::Presentation::IllegalValueError, m
|
371
309
|
end
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def define_methods_for_numeric_only_keys
|
314
|
+
define_accessor_methods(*numeric_only_keys) do |key, arg|
|
315
|
+
unless arg.kind_of?(Numeric) && arg > 0
|
316
|
+
m = "#{key} must be a positive Integer or Float."
|
317
|
+
raise IIIF::Presentation::IllegalValueError, m
|
376
318
|
end
|
377
319
|
end
|
378
320
|
end
|
379
321
|
|
380
|
-
def
|
381
|
-
|
322
|
+
def define_accessor_methods(*keys, &validation)
|
323
|
+
keys.each do |key|
|
382
324
|
# Setter
|
383
325
|
define_singleton_method("#{key}=") do |arg|
|
384
|
-
|
385
|
-
m = "#{key} must be a positive Integer."
|
386
|
-
raise IIIF::Presentation::IllegalValueError, m
|
387
|
-
end
|
326
|
+
validation.call(key, arg) if block_given?
|
388
327
|
self.send('[]=', key, arg)
|
389
328
|
end
|
390
329
|
if key.camelize(:lower) != key
|
391
330
|
define_singleton_method("#{key.camelize(:lower)}=") do |arg|
|
392
|
-
|
393
|
-
m = "#{key} must be a positive Integer."
|
394
|
-
raise IIIF::Presentation::IllegalValueError, m
|
395
|
-
end
|
331
|
+
validation.call(key, arg) if block_given?
|
396
332
|
self.send('[]=', key, arg)
|
397
333
|
end
|
398
334
|
end
|
@@ -408,6 +344,5 @@ module IIIF
|
|
408
344
|
end
|
409
345
|
end
|
410
346
|
end
|
411
|
-
|
412
347
|
end
|
413
348
|
end
|