iiif-presentation 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +2 -2
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/README.md +22 -1
- data/VERSION +1 -1
- data/iiif-presentation.gemspec +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 +38 -103
- 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 +78 -7
@@ -0,0 +1,195 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"http://iiif.io/api/presentation/3/context.json",
|
4
|
+
"http://www.w3.org/ns/anno.jsonld"
|
5
|
+
],
|
6
|
+
"id": "http://www.example.org/iiif/book1/manifest",
|
7
|
+
"type": "Manifest",
|
8
|
+
"label": { "en": [ "Book 1" ] },
|
9
|
+
"metadata": [
|
10
|
+
{
|
11
|
+
"label": "Author",
|
12
|
+
"value": "Anne Author"
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"label": "Published",
|
16
|
+
"value": [
|
17
|
+
{
|
18
|
+
"@value": "Paris, circa 1400",
|
19
|
+
"@language": "en"
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"@value": "Paris, environ 14eme siecle",
|
23
|
+
"@language": "fr"
|
24
|
+
}
|
25
|
+
]
|
26
|
+
}
|
27
|
+
],
|
28
|
+
"description": "A longer description of this example book. It should give some real information.",
|
29
|
+
"rights": "http://www.example.org/license.html",
|
30
|
+
"attribution": "Provided by Example Organization",
|
31
|
+
"service": {
|
32
|
+
"@context": "http://example.org/ns/jsonld/context.json",
|
33
|
+
"id": "http://example.org/service/example",
|
34
|
+
"profile": "http://example.org/docs/example-service.html"
|
35
|
+
},
|
36
|
+
"seeAlso": {
|
37
|
+
"id": "http://www.example.org/library/catalog/book1.marc",
|
38
|
+
"format": "application/marc"
|
39
|
+
},
|
40
|
+
"within": "http://www.example.org/collections/books/",
|
41
|
+
"sequences": [
|
42
|
+
{
|
43
|
+
"id": "http://www.example.org/iiif/book1/sequence/normal",
|
44
|
+
"type": "Sequence",
|
45
|
+
"label": "Current Page Order",
|
46
|
+
"viewingDirection": "left-to-right",
|
47
|
+
"viewingHint": "paged",
|
48
|
+
"canvases": [
|
49
|
+
{
|
50
|
+
"id": "http://www.example.org/iiif/book1/canvas/p1",
|
51
|
+
"type": "Canvas",
|
52
|
+
"label": "p. 1",
|
53
|
+
"height": 1000,
|
54
|
+
"width": 750,
|
55
|
+
"content": [
|
56
|
+
{
|
57
|
+
"id": "http://www.example.org/iiif/book1/page/p1",
|
58
|
+
"type": "AnnotationPage",
|
59
|
+
"items": [
|
60
|
+
{
|
61
|
+
"type": "Annotation",
|
62
|
+
"motivation": "painting",
|
63
|
+
"target": "http://www.example.org/iiif/book1/canvas/p1",
|
64
|
+
"body": {
|
65
|
+
"id": "http://www.example.org/iiif/book1/res/page1.jpg",
|
66
|
+
"type": "Image",
|
67
|
+
"format": "image/jpeg",
|
68
|
+
"height": 2000,
|
69
|
+
"width": 1500,
|
70
|
+
"service": {
|
71
|
+
"@context": "http://iiif.io/api/image/2/context.json",
|
72
|
+
"id": "http://www.example.org/images/book1-page1",
|
73
|
+
"profile": "http://iiif.io/api/image/2/level1.json"
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
]
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"id": "http://www.example.org/iiif/book1/page/p666",
|
81
|
+
"type": "AnnotationPage"
|
82
|
+
}
|
83
|
+
]
|
84
|
+
},
|
85
|
+
{
|
86
|
+
"id": "http://www.example.org/iiif/book1/canvas/p2",
|
87
|
+
"type": "Canvas",
|
88
|
+
"label": "p. 2",
|
89
|
+
"height": 1000,
|
90
|
+
"width": 750,
|
91
|
+
"content": [
|
92
|
+
{
|
93
|
+
"id": "http://www.example.org/iiif/book1/page/p1",
|
94
|
+
"type": "AnnotationPage",
|
95
|
+
"items": [
|
96
|
+
{
|
97
|
+
"type": "Annotation",
|
98
|
+
"motivation": "painting",
|
99
|
+
"body": {
|
100
|
+
"id": "http://www.example.org/images/book1-page2/full/1500,2000/0/default.jpg",
|
101
|
+
"type": "Image",
|
102
|
+
"format": "image/jpeg",
|
103
|
+
"height": 2000,
|
104
|
+
"width": 1500,
|
105
|
+
"service": {
|
106
|
+
"@context": "http://iiif.io/api/image/2/context.json",
|
107
|
+
"id": "http://www.example.org/images/book1-page2",
|
108
|
+
"profile": "http://iiif.io/api/image/2/level1.json",
|
109
|
+
"height": 8000,
|
110
|
+
"width": 6000,
|
111
|
+
"tiles": [
|
112
|
+
{
|
113
|
+
"width": 512,
|
114
|
+
"scaleFactors": [
|
115
|
+
1,
|
116
|
+
2,
|
117
|
+
4,
|
118
|
+
8,
|
119
|
+
16
|
120
|
+
]
|
121
|
+
}
|
122
|
+
]
|
123
|
+
}
|
124
|
+
},
|
125
|
+
"target": "http://www.example.org/iiif/book1/canvas/p2"
|
126
|
+
}
|
127
|
+
]
|
128
|
+
},
|
129
|
+
{
|
130
|
+
"id": "http://www.example.org/iiif/book1/list/p2",
|
131
|
+
"type": "AnnotationPage"
|
132
|
+
}
|
133
|
+
]
|
134
|
+
},
|
135
|
+
{
|
136
|
+
"id": "http://www.example.org/iiif/book1/canvas/p3",
|
137
|
+
"type": "Canvas",
|
138
|
+
"label": "p. 3",
|
139
|
+
"height": 1000,
|
140
|
+
"width": 750,
|
141
|
+
"content": [
|
142
|
+
{
|
143
|
+
"id": "http://www.example.org/iiif/book1/page/p1",
|
144
|
+
"type": "AnnotationPage",
|
145
|
+
"items": [
|
146
|
+
{
|
147
|
+
"type": "Annotation",
|
148
|
+
"motivation": "painting",
|
149
|
+
"target": "http://www.example.org/iiif/book1/canvas/p3",
|
150
|
+
"body": {
|
151
|
+
"id": "http://www.example.org/iiif/book1/res/page3.jpg",
|
152
|
+
"type": "Image",
|
153
|
+
"format": "image/jpeg",
|
154
|
+
"height": 2000,
|
155
|
+
"width": 1500,
|
156
|
+
"service": {
|
157
|
+
"@context": "http://iiif.io/api/image/2/context.json",
|
158
|
+
"id": "http://www.example.org/images/book1-page3",
|
159
|
+
"profile": "http://iiif.io/api/image/2/level1.json"
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
]
|
164
|
+
},
|
165
|
+
{
|
166
|
+
"id": "http://www.example.org/iiif/book1/page/p333",
|
167
|
+
"type": "AnnotationPage"
|
168
|
+
}
|
169
|
+
]
|
170
|
+
}
|
171
|
+
]
|
172
|
+
}
|
173
|
+
],
|
174
|
+
"structures": [
|
175
|
+
{
|
176
|
+
"id": "http://www.example.org/iiif/book1/range/r1",
|
177
|
+
"type": "Range",
|
178
|
+
"label": "Introduction",
|
179
|
+
"members": [
|
180
|
+
{
|
181
|
+
"id": "http://www.example.org/iiif/book1/canvas/p1",
|
182
|
+
"type": "Canvas"
|
183
|
+
},
|
184
|
+
{
|
185
|
+
"id": "http://www.example.org/iiif/book1/canvas/p2",
|
186
|
+
"type": "Canvas"
|
187
|
+
},
|
188
|
+
{
|
189
|
+
"id": "http://www.example.org/iiif/book1/canvas/p3#xywh=0,0,750,300",
|
190
|
+
"type": "Canvas"
|
191
|
+
}
|
192
|
+
]
|
193
|
+
}
|
194
|
+
]
|
195
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"http://iiif.io/api/presentation/3/context.json",
|
4
|
+
"http://www.w3.org/ns/anno.jsonld"
|
5
|
+
],
|
6
|
+
"type": "Manifest",
|
7
|
+
"id": "http://www.example.org/iiif/book1/manifest",
|
8
|
+
"label": "Book 1",
|
9
|
+
"sequences": [
|
10
|
+
{
|
11
|
+
"id": "http://www.example.org/iiif/book1/sequence/normal",
|
12
|
+
"label": "Current Page Order",
|
13
|
+
"canvases": [
|
14
|
+
{
|
15
|
+
"id": "http://www.example.org/iiif/book1/canvas/p1",
|
16
|
+
"type": "Canvas",
|
17
|
+
"label": "p. 1",
|
18
|
+
"height": 1000,
|
19
|
+
"width": 750,
|
20
|
+
"content": [
|
21
|
+
{
|
22
|
+
"id": "http://www.example.org/iiif/book1/page/p1",
|
23
|
+
"type": "AnnotationPage",
|
24
|
+
"items": [
|
25
|
+
{
|
26
|
+
"type": "Annotation",
|
27
|
+
"motivation": "painting",
|
28
|
+
"target": "http://www.example.org/iiif/book1/canvas/p1",
|
29
|
+
"body": {
|
30
|
+
"id": "http://www.example.org/iiif/book1/res/page1.jpg",
|
31
|
+
"type": "Image",
|
32
|
+
"format": "image/jpeg",
|
33
|
+
"height": 2000,
|
34
|
+
"width": 1500,
|
35
|
+
"service": {
|
36
|
+
"@context": "http://iiif.io/api/image/2/context.json",
|
37
|
+
"id": "http://www.example.org/images/book1-page1",
|
38
|
+
"profile": "http://iiif.io/api/image/2/level1.json"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
]
|
43
|
+
}
|
44
|
+
]
|
45
|
+
}
|
46
|
+
]
|
47
|
+
}
|
48
|
+
]
|
49
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"@context": [
|
3
|
+
"http://iiif.io/api/presentation/3/context.json",
|
4
|
+
"http://www.w3.org/ns/anno.jsonld"
|
5
|
+
],
|
6
|
+
"type": "Manifest",
|
7
|
+
"id": "http://www.example.org/iiif/book1/manifest",
|
8
|
+
"label": "Book 1",
|
9
|
+
"service": {
|
10
|
+
"@context": "http://example.org/ns/jsonld/context.json",
|
11
|
+
"id": "http://example.org/service/example",
|
12
|
+
"profile": "http://example.org/docs/example-service.html"
|
13
|
+
}
|
14
|
+
}
|
@@ -1 +1 @@
|
|
1
|
-
{"http_interactions":[{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v1.0.1"]}},"response":{"status":{"code":200,"message":"OK"},"headers":{"date":["Wed, 17 Jun 2020 19:38:19 GMT"],"server":["Apache/2.4.18 (Ubuntu)"],"link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\",<http://iiif.io/api/image/2/context.json>;rel=\"http://www.w3.org/ns/json-ld#context\";type=\"application/ld+json\""],"access-control-allow-origin":["*"],"access-control-allow-methods":["GET"],"access-control-allow-headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"last-modified":["Sat, 25 Jan 2020 18:37:32 GMT"],"content-length":["753"],"content-type":["application/json"]},"body":{"encoding":"UTF-8","string":"{\"profile\": [\"http://iiif.io/api/image/2/level2.json\", {\"supports\": [\"canonicalLinkHeader\", \"profileLinkHeader\", \"mirroring\", \"rotationArbitrary\", \"regionSquare\", \"sizeAboveFull\"], \"qualities\": [\"default\", \"bitonal\", \"gray\", \"color\"], \"formats\": [\"jpg\", \"png\", \"gif\", \"webp\"]}], \"tiles\": [{\"width\": 1024, \"scaleFactors\": [1, 2, 4, 8, 16, 32]}], \"protocol\": \"http://iiif.io/api/image\", \"sizes\": [{\"width\": 96, \"height\": 225}, {\"width\": 191, \"height\": 450}, {\"width\": 381, \"height\": 900}, {\"width\": 762, \"height\": 1800}, {\"width\": 1524, \"height\": 3600}, {\"width\": 3047, \"height\": 7200}], \"height\": 7200, \"width\": 3047, \"@context\": \"http://iiif.io/api/image/2/context.json\", \"@id\": \"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2\"}"},"http_version":null},"recorded_at":"Wed, 17 Jun 2020 19:38:19 GMT"},{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/xxxx%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v1.0.1"]}},"response":{"status":{"code":404,"message":"NOT FOUND"},"headers":{"date":["Wed, 17 Jun 2020 19:38:20 GMT"],"server":["Apache/2.4.18 (Ubuntu)"],"link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\""],"access-control-allow-origin":["*"],"access-control-allow-methods":["GET"],"access-control-allow-headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"content-length":["86"],"content-type":["text/plain"]},"body":{"encoding":"UTF-8","string":"Not Found: Source image not found for identifier: xxxx%2F4612422%2F00000001.jp2. (404)"},"http_version":null},"recorded_at":"Wed, 17 Jun 2020 19:38:20 GMT"}],"recorded_with":"VCR 5.1.0"}
|
1
|
+
{"http_interactions":[{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v1.0.1"]}},"response":{"status":{"code":200,"message":"OK"},"headers":{"date":["Wed, 17 Jun 2020 19:38:19 GMT"],"server":["Apache/2.4.18 (Ubuntu)"],"link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\",<http://iiif.io/api/image/2/context.json>;rel=\"http://www.w3.org/ns/json-ld#context\";type=\"application/ld+json\""],"access-control-allow-origin":["*"],"access-control-allow-methods":["GET"],"access-control-allow-headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"last-modified":["Sat, 25 Jan 2020 18:37:32 GMT"],"content-length":["753"],"content-type":["application/json"]},"body":{"encoding":"UTF-8","string":"{\"profile\": [\"http://iiif.io/api/image/2/level2.json\", {\"supports\": [\"canonicalLinkHeader\", \"profileLinkHeader\", \"mirroring\", \"rotationArbitrary\", \"regionSquare\", \"sizeAboveFull\"], \"qualities\": [\"default\", \"bitonal\", \"gray\", \"color\"], \"formats\": [\"jpg\", \"png\", \"gif\", \"webp\"]}], \"tiles\": [{\"width\": 1024, \"scaleFactors\": [1, 2, 4, 8, 16, 32]}], \"protocol\": \"http://iiif.io/api/image\", \"sizes\": [{\"width\": 96, \"height\": 225}, {\"width\": 191, \"height\": 450}, {\"width\": 381, \"height\": 900}, {\"width\": 762, \"height\": 1800}, {\"width\": 1524, \"height\": 3600}, {\"width\": 3047, \"height\": 7200}], \"height\": 7200, \"width\": 3047, \"@context\": \"http://iiif.io/api/image/2/context.json\", \"@id\": \"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2\"}"},"http_version":null},"recorded_at":"Wed, 17 Jun 2020 19:38:19 GMT"},{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/xxxx%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v1.0.1"]}},"response":{"status":{"code":404,"message":"NOT FOUND"},"headers":{"date":["Wed, 17 Jun 2020 19:38:20 GMT"],"server":["Apache/2.4.18 (Ubuntu)"],"link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\""],"access-control-allow-origin":["*"],"access-control-allow-methods":["GET"],"access-control-allow-headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"content-length":["86"],"content-type":["text/plain"]},"body":{"encoding":"UTF-8","string":"Not Found: Source image not found for identifier: xxxx%2F4612422%2F00000001.jp2. (404)"},"http_version":null},"recorded_at":"Wed, 17 Jun 2020 19:38:20 GMT"}],"recorded_with":"VCR 5.1.0"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v0.12.1"],"Accept-Encoding":["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],"Accept":["*/*"]}},"response":{"status":{"code":200,"message":"OK"},"headers":{"Date":["Tue, 27 Jun 2017 22:33:33 GMT"],"Server":["Apache/2.4.18 (Ubuntu)"],"Link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\",<http://iiif.io/api/image/2/context.json>;rel=\"http://www.w3.org/ns/json-ld#context\";type=\"application/ld+json\""],"Access-Control-Allow-Origin":["*"],"Access-Control-Allow-Methods":["GET"],"Access-Control-Allow-Headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"Last-Modified":["Tue, 11 Apr 2017 07:03:53 GMT"],"Content-Length":["753"],"Content-Type":["application/json"]},"body":{"encoding":"UTF-8","string":"{\"profile\": [\"http://iiif.io/api/image/2/level2.json\", {\"supports\": [\"canonicalLinkHeader\", \"profileLinkHeader\", \"mirroring\", \"rotationArbitrary\", \"regionSquare\", \"sizeAboveFull\"], \"qualities\": [\"default\", \"bitonal\", \"gray\", \"color\"], \"formats\": [\"jpg\", \"png\", \"gif\", \"webp\"]}], \"tiles\": [{\"width\": 1024, \"scaleFactors\": [1, 2, 4, 8, 16, 32]}], \"protocol\": \"http://iiif.io/api/image\", \"sizes\": [{\"width\": 96, \"height\": 225}, {\"width\": 191, \"height\": 450}, {\"width\": 381, \"height\": 900}, {\"width\": 762, \"height\": 1800}, {\"width\": 1524, \"height\": 3600}, {\"width\": 3047, \"height\": 7200}], \"height\": 7200, \"width\": 3047, \"@context\": \"http://iiif.io/api/image/2/context.json\", \"@id\": \"https://libimages.princeton.edu/loris/pudl0001%2F4612422%2F00000001.jp2\"}"},"http_version":null},"recorded_at":"Tue, 27 Jun 2017 22:33:33 GMT"},{"request":{"method":"get","uri":"https://libimages.princeton.edu/loris/xxxx%2F4612422%2F00000001.jp2/info.json","body":{"encoding":"US-ASCII","string":""},"headers":{"User-Agent":["Faraday v0.12.1"],"Accept-Encoding":["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],"Accept":["*/*"]}},"response":{"status":{"code":404,"message":"NOT FOUND"},"headers":{"Date":["Tue, 27 Jun 2017 22:33:33 GMT"],"Server":["Apache/2.4.18 (Ubuntu)"],"Link":["<http://iiif.io/api/image/2/level2.json>;rel=\"profile\""],"Access-Control-Allow-Origin":["*"],"Access-Control-Allow-Methods":["GET"],"Access-Control-Allow-Headers":["X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"],"Content-Length":["86"],"Content-Type":["text/plain"]},"body":{"encoding":"UTF-8","string":"Not Found: Source image not found for identifier: xxxx%2F4612422%2F00000001.jp2. (404)"},"http_version":null},"recorded_at":"Tue, 27 Jun 2017 22:33:33 GMT"}],"recorded_with":"VCR 2.9.3"}
|
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
describe IIIF::Service do
|
1
|
+
RSpec.describe IIIF::Service do
|
5
2
|
|
6
3
|
let(:fixtures_dir) { File.join(File.dirname(__FILE__), '../../fixtures') }
|
7
4
|
let(:manifest_from_spec_path) { File.join(fixtures_dir, 'manifests/complete_from_spec.json') }
|
@@ -39,6 +36,7 @@ describe IIIF::Service do
|
|
39
36
|
end
|
40
37
|
|
41
38
|
describe 'self#from_ordered_hash' do
|
39
|
+
subject(:parsed) { described_class.from_ordered_hash(fixture) }
|
42
40
|
let(:fixture) { JSON.parse('{
|
43
41
|
"@context": "http://iiif.io/api/presentation/2/context.json",
|
44
42
|
"@id": "http://example.com/manifest",
|
@@ -87,35 +85,28 @@ describe IIIF::Service do
|
|
87
85
|
}')
|
88
86
|
}
|
89
87
|
it 'doesn\'t raise a NoMethodError when we check the keys' do
|
90
|
-
expect {
|
88
|
+
expect { parsed }.to_not raise_error
|
91
89
|
end
|
90
|
+
|
92
91
|
it 'turns the fixture into a Manifest instance' do
|
93
|
-
|
94
|
-
parsed = described_class.from_ordered_hash(fixture)
|
95
|
-
expect(parsed.class).to be expected_klass
|
92
|
+
expect(parsed).to be_a IIIF::Presentation::Manifest
|
96
93
|
end
|
94
|
+
|
97
95
|
it 'turns keys without "@type" into an OrderedHash' do
|
98
|
-
|
99
|
-
parsed = described_class.from_ordered_hash(fixture)
|
100
|
-
expect(parsed['some_other_thing'].class).to be expected_klass
|
96
|
+
expect(parsed['some_other_thing']).to be_a IIIF::OrderedHash
|
101
97
|
end
|
102
98
|
|
103
99
|
it 'turns services into Services' do
|
104
|
-
|
105
|
-
parsed = described_class.from_ordered_hash(fixture)
|
106
|
-
expect(parsed['service'].class).to be expected_klass
|
100
|
+
expect(parsed['service']).to be_a IIIF::Presentation::Service
|
107
101
|
end
|
108
102
|
|
109
103
|
it 'works with arrays of services' do
|
110
|
-
expected_klass = IIIF::Service
|
111
104
|
fixture['service'] = [fixture['service']]
|
112
|
-
parsed
|
113
|
-
expect(parsed['service'].first.class).to be expected_klass
|
105
|
+
expect(parsed['service'].first).to be_a IIIF::Presentation::Service
|
114
106
|
end
|
115
107
|
|
116
108
|
it 'round-trips' do
|
117
109
|
fp = '/tmp/osullivan-spec.json'
|
118
|
-
parsed = described_class.from_ordered_hash(fixture)
|
119
110
|
File.open(fp,'w') do |f|
|
120
111
|
f.write(parsed.to_json)
|
121
112
|
end
|
@@ -125,31 +116,25 @@ describe IIIF::Service do
|
|
125
116
|
expect(parsed.to_ordered_hash.to_a - from_file.to_ordered_hash.to_a).to eq []
|
126
117
|
expect(from_file.to_ordered_hash.to_a - parsed.to_ordered_hash.to_a).to eq []
|
127
118
|
end
|
119
|
+
|
128
120
|
it 'turns each memeber of "sequences" into an instance of Sequence' do
|
129
|
-
|
130
|
-
parsed = described_class.from_ordered_hash(fixture)
|
131
|
-
parsed['sequences'].each do |s|
|
132
|
-
expect(s.class).to be expected_klass
|
133
|
-
end
|
121
|
+
expect(parsed['sequences']).to all be_a IIIF::Presentation::Sequence
|
134
122
|
end
|
123
|
+
|
135
124
|
it 'turns each member of sequences/canvaes in an instance of Canvas' do
|
136
|
-
expected_klass = IIIF::Presentation::Canvas
|
137
|
-
parsed = described_class.from_ordered_hash(fixture)
|
138
125
|
parsed['sequences'].each do |s|
|
139
|
-
s.canvases.
|
140
|
-
expect(c.class).to be expected_klass
|
141
|
-
end
|
126
|
+
expect(s.canvases).to all be_a IIIF::Presentation::Canvas
|
142
127
|
end
|
143
128
|
end
|
129
|
+
|
144
130
|
it 'turns the keys into snakes' do
|
145
|
-
expect(
|
146
|
-
expect(
|
131
|
+
expect(parsed.has_key?('seeAlso')).to be false
|
132
|
+
expect(parsed.has_key?('see_also')).to be true
|
147
133
|
end
|
134
|
+
|
148
135
|
it 'copies over plain-old key-values' do
|
149
|
-
parsed = described_class.from_ordered_hash(fixture)
|
150
136
|
expect(parsed['label']).to eq 'My Manifest'
|
151
137
|
end
|
152
|
-
|
153
138
|
end
|
154
139
|
|
155
140
|
describe '#to_ordered_hash' do
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe IIIF::V3::AbstractResource do
|
5
|
+
|
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') }
|
8
|
+
|
9
|
+
describe 'self.parse' do
|
10
|
+
it 'works from a file' do
|
11
|
+
s = described_class.parse(manifest_from_spec_path)
|
12
|
+
expect(s['label']['en']).to include 'Book 1'
|
13
|
+
end
|
14
|
+
it 'works from a string of JSON' do
|
15
|
+
file = File.open(manifest_from_spec_path, 'rb')
|
16
|
+
json_string = file.read
|
17
|
+
file.close
|
18
|
+
s = described_class.parse(json_string)
|
19
|
+
expect(s['label']['en']).to include 'Book 1'
|
20
|
+
end
|
21
|
+
describe 'works from a hash' do
|
22
|
+
it 'plain old' do
|
23
|
+
h = JSON.parse(IO.read(manifest_from_spec_path))
|
24
|
+
s = described_class.parse(h)
|
25
|
+
expect(s['label']['en']).to include 'Book 1'
|
26
|
+
end
|
27
|
+
it 'IIIF::OrderedHash' do
|
28
|
+
h = JSON.parse(IO.read(manifest_from_spec_path))
|
29
|
+
oh = IIIF::OrderedHash[h]
|
30
|
+
s = described_class.parse(oh)
|
31
|
+
expect(s['label']['en']).to include 'Book 1'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
it 'turns camels to snakes' do
|
35
|
+
s = described_class.parse(manifest_from_spec_path)
|
36
|
+
expect(s.keys.include?('see_also')).to be_truthy
|
37
|
+
expect(s.keys.include?('seeAlso')).to be_falsey
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'self#from_ordered_hash' do
|
42
|
+
let(:fixture) { JSON.parse('{
|
43
|
+
"@context": [
|
44
|
+
"http://iiif.io/api/presentation/3/context.json",
|
45
|
+
"http://www.w3.org/ns/anno.jsonld"
|
46
|
+
],
|
47
|
+
"id": "http://example.com/manifest",
|
48
|
+
"type": "Manifest",
|
49
|
+
"label": "My Manifest",
|
50
|
+
"service": {
|
51
|
+
"@context": "http://iiif.io/api/image/2/context.json",
|
52
|
+
"@id":"http://www.example.org/images/book1-page1",
|
53
|
+
"id":"http://www.example.org/images/book1-page1",
|
54
|
+
"profile":"http://iiif.io/api/image/2/profiles/level2.json"
|
55
|
+
},
|
56
|
+
"some_other_thing": {
|
57
|
+
"foo" : "bar"
|
58
|
+
},
|
59
|
+
"seeAlso": {
|
60
|
+
"id": "http://www.example.org/library/catalog/book1.marc",
|
61
|
+
"format": "application/marc"
|
62
|
+
},
|
63
|
+
"items": [
|
64
|
+
{
|
65
|
+
"id": "http://example.com/canvas",
|
66
|
+
"type": "Canvas",
|
67
|
+
"width": 10,
|
68
|
+
"height": 20,
|
69
|
+
"label": "My Canvas",
|
70
|
+
"content": [
|
71
|
+
{
|
72
|
+
"id": "http://example.com/content",
|
73
|
+
"type": "AnnotationPage",
|
74
|
+
"motivation": "painting"
|
75
|
+
}
|
76
|
+
]
|
77
|
+
}
|
78
|
+
]
|
79
|
+
}')
|
80
|
+
}
|
81
|
+
it 'doesn\'t raise a NoMethodError when we check the keys' do
|
82
|
+
expect { described_class.from_ordered_hash(fixture) }.to_not raise_error
|
83
|
+
end
|
84
|
+
it 'turns the fixture into a Manifest instance' do
|
85
|
+
expected_klass = IIIF::V3::Presentation::Manifest
|
86
|
+
parsed = described_class.from_ordered_hash(fixture)
|
87
|
+
expect(parsed.class).to be expected_klass
|
88
|
+
end
|
89
|
+
it 'turns keys without "type" into an OrderedHash' do
|
90
|
+
expected_klass = IIIF::OrderedHash
|
91
|
+
parsed = described_class.from_ordered_hash(fixture)
|
92
|
+
expect(parsed['some_other_thing'].class).to be expected_klass
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'turns services into Services' do
|
96
|
+
expected_klass = IIIF::V3::Presentation::Service
|
97
|
+
parsed = described_class.from_ordered_hash(fixture)
|
98
|
+
expect(parsed['service'].class).to be expected_klass
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'round-trips' do
|
102
|
+
fp = '/tmp/osullivan-spec.json'
|
103
|
+
parsed = described_class.from_ordered_hash(fixture)
|
104
|
+
File.open(fp,'w') do |f|
|
105
|
+
f.write(parsed.to_json)
|
106
|
+
end
|
107
|
+
from_file = IIIF::V3::Presentation::Service.parse('/tmp/osullivan-spec.json')
|
108
|
+
File.delete(fp)
|
109
|
+
# is this sufficient?
|
110
|
+
expect(parsed.to_ordered_hash.to_a - from_file.to_ordered_hash.to_a).to eq []
|
111
|
+
expect(from_file.to_ordered_hash.to_a - parsed.to_ordered_hash.to_a).to eq []
|
112
|
+
end
|
113
|
+
it 'turns each member of "items" into an instance of Sequence' do
|
114
|
+
parsed = described_class.from_ordered_hash(fixture)
|
115
|
+
parsed['items'].each do |s|
|
116
|
+
expect(s.class).to be IIIF::V3::Presentation::Canvas
|
117
|
+
end
|
118
|
+
end
|
119
|
+
it 'turns each member of sequences/items into an instance of Canvas' do
|
120
|
+
parsed = described_class.from_ordered_hash(fixture)
|
121
|
+
parsed['items'].each do |s|
|
122
|
+
s.items.each do |c|
|
123
|
+
expect(c.class).to be IIIF::V3::Presentation::Canvas
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
it 'turns the keys into snakes' do
|
128
|
+
expect(described_class.from_ordered_hash(fixture).has_key?('seeAlso')).to be_falsey
|
129
|
+
expect(described_class.from_ordered_hash(fixture).has_key?('see_also')).to be_truthy
|
130
|
+
end
|
131
|
+
it 'copies over plain-old key-values' do
|
132
|
+
parsed = described_class.from_ordered_hash(fixture)
|
133
|
+
expect(parsed['label']).to eq 'My Manifest'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#to_ordered_hash' do
|
138
|
+
let(:logo_uri) { 'http://www.example.org/logos/institution1.jpg' }
|
139
|
+
let(:within_uri) { 'http://www.example.org/collections/books/' }
|
140
|
+
let(:see_also) { 'http://www.example.org/library/catalog/book1.xml' }
|
141
|
+
# NOTE: Using Service to test, as we can't initialize the abstract class
|
142
|
+
let(:instantiated_class) { IIIF::V3::Presentation::Service.new }
|
143
|
+
|
144
|
+
describe 'it puts the json-ld keys at the top' do
|
145
|
+
let(:extra_props) { [
|
146
|
+
['label','foo'],
|
147
|
+
['logo','http://example.com/logo.jpg'],
|
148
|
+
['within','http://example.com/something']
|
149
|
+
] }
|
150
|
+
let(:sorted_ld_keys) {
|
151
|
+
instantiated_class.keys.select { |k| k.start_with?('@') }.sort!
|
152
|
+
}
|
153
|
+
before(:each) {
|
154
|
+
extra_props.reverse.each do |k,v|
|
155
|
+
instantiated_class.unshift(k,v)
|
156
|
+
end
|
157
|
+
}
|
158
|
+
|
159
|
+
it 'by default' do
|
160
|
+
(0..extra_props.length-1).each do |i|
|
161
|
+
expect(instantiated_class.keys[i]).to eq(extra_props[i][0])
|
162
|
+
end
|
163
|
+
oh = instantiated_class.to_ordered_hash
|
164
|
+
(0..sorted_ld_keys.length-1).each do |i|
|
165
|
+
expect(oh.keys[i]).to eq(sorted_ld_keys[i])
|
166
|
+
end
|
167
|
+
end
|
168
|
+
it 'unless you say not to' do
|
169
|
+
(0..extra_props.length-1).each do |i|
|
170
|
+
expect(instantiated_class.keys[i]).to eq(extra_props[i][0])
|
171
|
+
end
|
172
|
+
oh = instantiated_class.to_ordered_hash(sort_json_ld_keys: false)
|
173
|
+
(0..extra_props.length-1).each do |i|
|
174
|
+
expect(oh.keys[i]).to eq(extra_props[i][0])
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'removes empty keys' do
|
180
|
+
it 'if they\'re arrays' do
|
181
|
+
instantiated_class['logo'] = logo_uri
|
182
|
+
instantiated_class['within'] = []
|
183
|
+
ordered_hash = instantiated_class.to_ordered_hash
|
184
|
+
expect(ordered_hash.has_key?('within')).to be_falsey
|
185
|
+
end
|
186
|
+
it 'if they\'re nil' do
|
187
|
+
instantiated_class['logo'] = logo_uri
|
188
|
+
instantiated_class['within'] = nil
|
189
|
+
ordered_hash = instantiated_class.to_ordered_hash
|
190
|
+
expect(ordered_hash.has_key?('within')).to be_falsey
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'converts snake_case keys to camelCase' do
|
195
|
+
instantiated_class['see_also'] = logo_uri
|
196
|
+
instantiated_class['within'] = within_uri
|
197
|
+
ordered_hash = instantiated_class.to_ordered_hash
|
198
|
+
expect(ordered_hash.keys.include?('seeAlso')).to be_truthy
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|