iiif-presentation 1.2.0 → 1.4.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/README.md +6 -6
- data/VERSION +1 -1
- data/iiif-presentation.gemspec +1 -0
- data/lib/iiif/presentation/annotation.rb +5 -1
- data/lib/iiif/v3/presentation/nav_place.rb +108 -0
- data/lib/iiif/v3/presentation/range.rb +12 -2
- data/lib/iiif/v3/presentation/sequence.rb +2 -17
- data/lib/iiif/v3/presentation.rb +1 -0
- data/spec/unit/iiif/v3/presentation/nav_place_spec.rb +96 -0
- data/spec/unit/iiif/v3/presentation/range_spec.rb +20 -1
- data/spec/unit/iiif/v3/presentation/sequence_spec.rb +1 -10
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d5fac69b52d8f3510fa40fc221882302736f9b4afe8b55b1330497ab11d8033
|
4
|
+
data.tar.gz: 9156c96e93409320cddde7d86bb78894b6351cd2c291ab6bdca39958d3f27bbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85f3b92e738793e5360cdff614c6f50fd271cb7b1033a6df1de8452603a18b4aa6cb0c6e4c9e5639f0587c6d1666cb47054c4b99894e398ee4a3c1fcfa08bd09
|
7
|
+
data.tar.gz: be3fc1d37352d21c018cffc8c2315d221aadcd00fad0c46847ffe1d68b131b6bc3844abf08ba6bd5cf56c049df706a31e1300c3279fa98b3fb1e43d267a34187
|
data/README.md
CHANGED
@@ -44,13 +44,13 @@ canvas.label = 'My Canvas'
|
|
44
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
45
|
|
46
46
|
image = IIIF::Presentation::ImageResource.new()
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
image['@id'] = "http://images.exampl.com/loris2/my-image/full/#{canvas.width},#{canvas.height}/0/default.jpg"
|
48
|
+
image.format = "image/jpeg"
|
49
|
+
image.width = canvas.width
|
50
|
+
image.height = canvas.height
|
51
|
+
image.service = service
|
52
52
|
|
53
|
-
images = IIIF::Presentation::Resource.new('@type' => 'oa:Annotation', 'motivation' => 'sc:painting', '@id' => "#{canvas['@id']}/images", 'resource' =>
|
53
|
+
images = IIIF::Presentation::Resource.new('@type' => 'oa:Annotation', 'motivation' => 'sc:painting', '@id' => "#{canvas['@id']}/images", 'resource' => image)
|
54
54
|
|
55
55
|
canvas.images << images
|
56
56
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/iiif-presentation.gemspec
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'geo/coord'
|
2
|
+
|
3
|
+
module IIIF
|
4
|
+
module V3
|
5
|
+
module Presentation
|
6
|
+
class NavPlace < IIIF::V3::AbstractResource
|
7
|
+
Rect = Struct.new(:coord1, :coord2)
|
8
|
+
|
9
|
+
COORD_REGEX = /(?:(?<hemisphere>[NSEW])\s*)?(?<degrees>\d+)[°⁰*](?:\s*(?<minutes>\d+)[\'ʹ′])?(?:\s*(?<seconds>\d+)["ʺ″])?(?:\s*(?<hemisphere>[NSEW]))?/
|
10
|
+
def initialize(coordinate_texts:, base_uri:)
|
11
|
+
@coordinate_texts = coordinate_texts
|
12
|
+
@base_uri = base_uri
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Boolean] indicates if coordinate_texts passed in are valid
|
16
|
+
def valid?
|
17
|
+
!(coordinates.nil? || coordinates.empty?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
raise ArgumentError.new('invalid coordinates') unless valid?
|
22
|
+
|
23
|
+
{
|
24
|
+
id: "#{base_uri}/feature-collection/1",
|
25
|
+
type: 'FeatureCollection',
|
26
|
+
features: features
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :coordinate_texts, :base_uri
|
33
|
+
|
34
|
+
def coordinates
|
35
|
+
@coordinates ||= coordinate_texts.map do |coordinate_text|
|
36
|
+
coordinate_parts = coordinate_text.split(%r{ ?--|/})
|
37
|
+
case coordinate_parts.length
|
38
|
+
when 2
|
39
|
+
coord_for(coordinate_parts[0], coordinate_parts[1])
|
40
|
+
when 4
|
41
|
+
rect_for(coordinate_parts)
|
42
|
+
end
|
43
|
+
end.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
def coord_for(long_str, lat_str)
|
47
|
+
long_matcher = long_str.match(COORD_REGEX)
|
48
|
+
lat_matcher = lat_str.match(COORD_REGEX)
|
49
|
+
return unless long_matcher && lat_matcher
|
50
|
+
|
51
|
+
Geo::Coord.new(latd: lat_matcher[:degrees], latm: lat_matcher[:minutes], lats: lat_matcher[:seconds], lath: lat_matcher[:hemisphere],
|
52
|
+
lngd: long_matcher[:degrees], lngm: long_matcher[:minutes], lngs: long_matcher[:seconds], lngh: long_matcher[:hemisphere])
|
53
|
+
end
|
54
|
+
|
55
|
+
def rect_for(coordinate_parts)
|
56
|
+
coord1 = coord_for(coordinate_parts[0], coordinate_parts[2])
|
57
|
+
coord2 = coord_for(coordinate_parts[1], coordinate_parts[3])
|
58
|
+
return if coord1.nil? || coord2.nil?
|
59
|
+
|
60
|
+
Rect.new(coord1, coord2)
|
61
|
+
end
|
62
|
+
|
63
|
+
def features
|
64
|
+
coordinates.map.with_index(1) do |coordinate, index|
|
65
|
+
{
|
66
|
+
id: "#{base_uri}/iiif/feature/#{index}",
|
67
|
+
type: 'Feature',
|
68
|
+
properties: {},
|
69
|
+
geometry: coordinate.is_a?(Rect) ? polygon_geometry(coordinate) : point_geometry(coordinate)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def point_geometry(coord)
|
75
|
+
{
|
76
|
+
type: 'Point',
|
77
|
+
coordinates: [format(coord.lng), format(coord.lat)]
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def polygon_geometry(rect)
|
82
|
+
{
|
83
|
+
type: 'Polygon',
|
84
|
+
coordinates: [
|
85
|
+
[
|
86
|
+
[format(rect.coord1.lng), format(rect.coord1.lat)],
|
87
|
+
[format(rect.coord2.lng), format(rect.coord1.lat)],
|
88
|
+
[format(rect.coord2.lng), format(rect.coord2.lat)],
|
89
|
+
[format(rect.coord1.lng), format(rect.coord2.lat)],
|
90
|
+
[format(rect.coord1.lng), format(rect.coord1.lat)]
|
91
|
+
]
|
92
|
+
]
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [BigDecimal] coordinate value from geocoord gem
|
97
|
+
# @return [String] string formatted with max 6 digits after the decimal point
|
98
|
+
# The to_f ensures removal of scientific notation of BigDecimal before converting to a string.
|
99
|
+
# examples:
|
100
|
+
# input value is BigDecimal("-23.9") or "0.239e2", output value is "-23.9" as string
|
101
|
+
# input value is BigDecimal("23.9424213434") or "0.239424213434e2", output value is "23.942421" as string
|
102
|
+
def format(decimal)
|
103
|
+
decimal.truncate(6).to_f.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -3,8 +3,8 @@ module IIIF
|
|
3
3
|
module Presentation
|
4
4
|
# Ranges are linked or embedded within the manifest in a structures field
|
5
5
|
class Range < Sequence
|
6
|
-
|
7
6
|
TYPE = 'Range'.freeze
|
7
|
+
VALID_ITEM_TYPES = [IIIF::V3::Presentation::Canvas, IIIF::V3::Presentation::Range]
|
8
8
|
|
9
9
|
def required_keys
|
10
10
|
super + %w{ id label }
|
@@ -28,11 +28,21 @@ module IIIF
|
|
28
28
|
|
29
29
|
def validate
|
30
30
|
super
|
31
|
+
validate_list(self['items']) if self['items']
|
32
|
+
validate_list(self['canvases']) if self['canvases']
|
31
33
|
# TODO: Ranges must have URIs and they should be http(s) URIs.
|
32
|
-
# TODO: Values of the members array must be canvas or range
|
33
34
|
# TODO: contentAnnotations: links to AnnotationCollection
|
34
35
|
# TODO: startCanvas: A link from a Sequence or Range to a Canvas that is contained within it
|
35
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def validate_list(canvas_array)
|
41
|
+
return if canvas_array.all? { |entry| VALID_ITEM_TYPES.include?(entry.class) }
|
42
|
+
|
43
|
+
m = "All entries in the (items or canvases) array must be one of #{VALID_ITEM_TYPES.join(', ')}"
|
44
|
+
raise IIIF::V3::Presentation::IllegalValueError, m
|
45
|
+
end
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|
@@ -37,29 +37,14 @@ module IIIF
|
|
37
37
|
# NOTE: allowing 'items' or 'canvases' as Universal Viewer currently only accepts canvases
|
38
38
|
# see https://github.com/sul-dlss/osullivan/issues/27, sul-dlss/purl/issues/167
|
39
39
|
unless (self['items'] && self['items'].any?) ||
|
40
|
-
|
41
|
-
m = 'The (items or canvases) list must have at least one entry
|
40
|
+
(self['canvases'] && self['canvases'].any?)
|
41
|
+
m = 'The (items or canvases) list must have at least one entry.'
|
42
42
|
raise IIIF::V3::Presentation::MissingRequiredKeyError, m
|
43
43
|
end
|
44
|
-
validate_canvas_list(self['items']) if self['items']
|
45
|
-
validate_canvas_list(self['canvases']) if self['canvases']
|
46
|
-
|
47
44
|
# TODO: startCanvas: A link from a Sequence or Range to a Canvas that is contained within it
|
48
45
|
|
49
46
|
# TODO: All external Sequences must have a dereference-able http(s) URI
|
50
47
|
end
|
51
|
-
|
52
|
-
def validate_canvas_list(canvas_array)
|
53
|
-
unless canvas_array.size >= 1
|
54
|
-
m = 'The (items or canvases) list must have at least one entry (and it must be a IIIF::V3::Presentation::Canvas)'
|
55
|
-
raise IIIF::V3::Presentation::MissingRequiredKeyError, m
|
56
|
-
end
|
57
|
-
|
58
|
-
unless canvas_array.all? { |entry| entry.instance_of?(IIIF::V3::Presentation::Canvas) }
|
59
|
-
m = 'All entries in the (items or canvases) list must be a IIIF::V3::Presentation::Canvas'
|
60
|
-
raise IIIF::V3::Presentation::IllegalValueError, m
|
61
|
-
end
|
62
|
-
end
|
63
48
|
end
|
64
49
|
end
|
65
50
|
end
|
data/lib/iiif/v3/presentation.rb
CHANGED
@@ -0,0 +1,96 @@
|
|
1
|
+
describe IIIF::V3::Presentation::NavPlace do
|
2
|
+
let(:subject) { described_class.new(coordinate_texts: coordinate_texts, base_uri: base_uri) }
|
3
|
+
let(:base_uri) { "https://purl.stanford.edu" }
|
4
|
+
let(:invalid_coordinates) { ["bogus", "stuff", "is", "here"] }
|
5
|
+
let(:valid_coordinates) do
|
6
|
+
["W 23°54'00\"--E 53°36'00\"/N 71°19'00\"--N 33°30'00\"",
|
7
|
+
'E 103°48ʹ/S 3°46ʹ).',
|
8
|
+
'X 103°48ʹ/Y 3°46ʹ).',
|
9
|
+
'In decimal degrees: (E 138.0--W 074.0/N 073.0--N 041.2).', # currently invalid therefore doesn't show up in nav_place
|
10
|
+
'23°54′00″W -- 53°36′00″E / 71°19′00″N -- 33°30′00″N'
|
11
|
+
]
|
12
|
+
end
|
13
|
+
let(:nav_place) do
|
14
|
+
{ id: 'https://purl.stanford.edu/feature-collection/1',
|
15
|
+
type: 'FeatureCollection',
|
16
|
+
features: [{ id: 'https://purl.stanford.edu/iiif/feature/1',
|
17
|
+
type: 'Feature',
|
18
|
+
properties: {},
|
19
|
+
geometry: { type: 'Polygon',
|
20
|
+
coordinates: [[['-23.9', '71.316666'],
|
21
|
+
['53.6', '71.316666'],
|
22
|
+
['53.6', '33.5'],
|
23
|
+
['-23.9', '33.5'],
|
24
|
+
['-23.9', '71.316666']]] } },
|
25
|
+
{ id: 'https://purl.stanford.edu/iiif/feature/2',
|
26
|
+
type: 'Feature',
|
27
|
+
properties: {},
|
28
|
+
geometry: { type: 'Point', coordinates: ['103.8', '-3.766666'] } },
|
29
|
+
{ id: 'https://purl.stanford.edu/iiif/feature/3',
|
30
|
+
type: 'Feature',
|
31
|
+
properties: {},
|
32
|
+
geometry: { coordinates: ['103.8', '3.766666'], type: "Point" } },
|
33
|
+
{ id: 'https://purl.stanford.edu/iiif/feature/4',
|
34
|
+
type: 'Feature',
|
35
|
+
properties: {},
|
36
|
+
geometry: { type: 'Polygon',
|
37
|
+
coordinates: [[['-23.9', '71.316666'],
|
38
|
+
['53.6', '71.316666'],
|
39
|
+
['53.6', '33.5'],
|
40
|
+
['-23.9', '33.5'],
|
41
|
+
['-23.9', '71.316666']]] } }
|
42
|
+
] }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#build' do
|
46
|
+
context 'when coordinates are valid' do
|
47
|
+
let(:coordinate_texts) { valid_coordinates }
|
48
|
+
|
49
|
+
it 'returns navPlace' do
|
50
|
+
expect(subject.build).to eq nav_place
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when coordinates are not present' do
|
55
|
+
let(:coordinate_texts) { [] }
|
56
|
+
|
57
|
+
it 'raises ArgumentError' do
|
58
|
+
expect { subject.build }.to raise_error(ArgumentError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when coordinates are invalid' do
|
63
|
+
let(:coordinate_texts) { invalid_coordinates }
|
64
|
+
|
65
|
+
it 'raises ArgumentError' do
|
66
|
+
expect { subject.build }.to raise_error(ArgumentError)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#valid' do
|
72
|
+
context 'when coordinates are valid' do
|
73
|
+
let(:coordinate_texts) { valid_coordinates }
|
74
|
+
|
75
|
+
it 'returns true' do
|
76
|
+
expect(subject.valid?).to be true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when coordinates are not present' do
|
81
|
+
let(:coordinate_texts) { [] }
|
82
|
+
|
83
|
+
it 'returns false' do
|
84
|
+
expect(subject.valid?).to be false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when coordinates are invalid' do
|
89
|
+
let(:coordinate_texts) { invalid_coordinates }
|
90
|
+
|
91
|
+
it 'returns false' do
|
92
|
+
expect(subject.valid?).to be false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -49,6 +49,25 @@ describe IIIF::V3::Presentation::Range do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
describe '#validate' do
|
52
|
+
let(:bad_val_msg) do
|
53
|
+
"All entries in the (items or canvases) array must be one of #{IIIF::V3::Presentation::Range::VALID_ITEM_TYPES.join(', ')}"
|
54
|
+
end
|
55
|
+
describe 'items' do
|
56
|
+
it 'raises IllegalValueError for items entry that is not valid type' do
|
57
|
+
subject['id'] = 'test_range'
|
58
|
+
subject['label'] = { 'en' => ['Test Range'] }
|
59
|
+
subject['items'] = [IIIF::V3::Presentation::Range.new('id' => 'child_range', 'label' => ['Child Label']),
|
60
|
+
IIIF::V3::Presentation::AnnotationPage.new]
|
61
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, bad_val_msg)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe 'canvases' do
|
65
|
+
it 'raises IllegalValueError for canvases entry that is not valid type' do
|
66
|
+
subject['id'] = 'test_range'
|
67
|
+
subject['label'] = { 'en' => ['Test Range'] }
|
68
|
+
subject['canvases'] = [IIIF::V3::Presentation::Canvas.new, IIIF::V3::Presentation::AnnotationPage.new]
|
69
|
+
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, bad_val_msg)
|
70
|
+
end
|
71
|
+
end
|
52
72
|
end
|
53
|
-
|
54
73
|
end
|
@@ -57,8 +57,7 @@ describe IIIF::V3::Presentation::Sequence do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe '#validate' do
|
60
|
-
let(:req_key_msg) { "The (items or canvases) list must have at least one entry
|
61
|
-
let(:bad_val_msg) { "All entries in the (items or canvases) list must be a IIIF::V3::Presentation::Canvas" }
|
60
|
+
let(:req_key_msg) { "The (items or canvases) list must have at least one entry." }
|
62
61
|
it 'raises MissingRequiredKeyError if no items or canvases key' do
|
63
62
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::MissingRequiredKeyError, req_key_msg)
|
64
63
|
end
|
@@ -67,20 +66,12 @@ describe IIIF::V3::Presentation::Sequence do
|
|
67
66
|
subject['items'] = []
|
68
67
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::MissingRequiredKeyError, req_key_msg)
|
69
68
|
end
|
70
|
-
it 'raises IllegalValueError for items entry that is not a Canvas' do
|
71
|
-
subject['items'] = [IIIF::V3::Presentation::Canvas.new, IIIF::V3::Presentation::AnnotationPage.new]
|
72
|
-
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, bad_val_msg)
|
73
|
-
end
|
74
69
|
end
|
75
70
|
describe 'canvases' do
|
76
71
|
it 'raises MissingRequiredKeyError for canvases as empty Array' do
|
77
72
|
subject['items'] = []
|
78
73
|
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::MissingRequiredKeyError, req_key_msg)
|
79
74
|
end
|
80
|
-
it 'raises IllegalValueError for canvases entry that is not a Canvas' do
|
81
|
-
subject['canvases'] = [IIIF::V3::Presentation::Canvas.new, IIIF::V3::Presentation::AnnotationPage.new]
|
82
|
-
expect { subject.validate }.to raise_error(IIIF::V3::Presentation::IllegalValueError, bad_val_msg)
|
83
|
-
end
|
84
75
|
end
|
85
76
|
end
|
86
77
|
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iiif-presentation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Stroop
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: bundler
|
@@ -150,6 +149,20 @@ dependencies:
|
|
150
149
|
- - "~>"
|
151
150
|
- !ruby/object:Gem::Version
|
152
151
|
version: '2.7'
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
name: geo_coord
|
154
|
+
requirement: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
type: :runtime
|
160
|
+
prerelease: false
|
161
|
+
version_requirements: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
153
166
|
description: API for working with IIIF Presentation manifests.
|
154
167
|
email:
|
155
168
|
- jpstroop@gmail.com
|
@@ -192,6 +205,7 @@ files:
|
|
192
205
|
- lib/iiif/v3/presentation/collection.rb
|
193
206
|
- lib/iiif/v3/presentation/image_resource.rb
|
194
207
|
- lib/iiif/v3/presentation/manifest.rb
|
208
|
+
- lib/iiif/v3/presentation/nav_place.rb
|
195
209
|
- lib/iiif/v3/presentation/range.rb
|
196
210
|
- lib/iiif/v3/presentation/resource.rb
|
197
211
|
- lib/iiif/v3/presentation/sequence.rb
|
@@ -238,6 +252,7 @@ files:
|
|
238
252
|
- spec/unit/iiif/v3/presentation/collection_spec.rb
|
239
253
|
- spec/unit/iiif/v3/presentation/image_resource_spec.rb
|
240
254
|
- spec/unit/iiif/v3/presentation/manifest_spec.rb
|
255
|
+
- spec/unit/iiif/v3/presentation/nav_place_spec.rb
|
241
256
|
- spec/unit/iiif/v3/presentation/range_spec.rb
|
242
257
|
- spec/unit/iiif/v3/presentation/resource_spec.rb
|
243
258
|
- spec/unit/iiif/v3/presentation/sequence_spec.rb
|
@@ -254,7 +269,6 @@ homepage: https://github.com/iiif/osullivan
|
|
254
269
|
licenses:
|
255
270
|
- Simplified BSD
|
256
271
|
metadata: {}
|
257
|
-
post_install_message:
|
258
272
|
rdoc_options: []
|
259
273
|
require_paths:
|
260
274
|
- lib
|
@@ -269,8 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
269
283
|
- !ruby/object:Gem::Version
|
270
284
|
version: '0'
|
271
285
|
requirements: []
|
272
|
-
rubygems_version: 3.
|
273
|
-
signing_key:
|
286
|
+
rubygems_version: 3.6.9
|
274
287
|
specification_version: 4
|
275
288
|
summary: API for working with IIIF Presentation manifests.
|
276
289
|
test_files:
|
@@ -316,6 +329,7 @@ test_files:
|
|
316
329
|
- spec/unit/iiif/v3/presentation/collection_spec.rb
|
317
330
|
- spec/unit/iiif/v3/presentation/image_resource_spec.rb
|
318
331
|
- spec/unit/iiif/v3/presentation/manifest_spec.rb
|
332
|
+
- spec/unit/iiif/v3/presentation/nav_place_spec.rb
|
319
333
|
- spec/unit/iiif/v3/presentation/range_spec.rb
|
320
334
|
- spec/unit/iiif/v3/presentation/resource_spec.rb
|
321
335
|
- spec/unit/iiif/v3/presentation/sequence_spec.rb
|