iiif_manifest 0.4.0 → 1.1.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 (54) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +51 -0
  3. data/.coveralls.yml +1 -0
  4. data/.github_changelog_generator +2 -0
  5. data/.gitignore +0 -0
  6. data/.rspec +0 -0
  7. data/.rubocop.yml +15 -5
  8. data/.rubocop_todo.yml +44 -51
  9. data/CHANGELOG.md +118 -0
  10. data/CODE_OF_CONDUCT.md +36 -49
  11. data/CODE_OF_CONDUCT.old.md +49 -0
  12. data/CONTRIBUTING.md +161 -0
  13. data/Gemfile +0 -0
  14. data/LICENSE +0 -0
  15. data/README.md +76 -18
  16. data/Rakefile +0 -0
  17. data/SUPPORT.md +5 -0
  18. data/iiif_manifest.gemspec +6 -6
  19. data/lib/iiif_manifest.rb +1 -0
  20. data/lib/iiif_manifest/display_image.rb +0 -0
  21. data/lib/iiif_manifest/iiif_collection.rb +6 -4
  22. data/lib/iiif_manifest/iiif_endpoint.rb +0 -0
  23. data/lib/iiif_manifest/manifest_builder.rb +0 -0
  24. data/lib/iiif_manifest/manifest_builder/canvas_builder.rb +0 -0
  25. data/lib/iiif_manifest/manifest_builder/canvas_builder_factory.rb +0 -0
  26. data/lib/iiif_manifest/manifest_builder/child_manifest_builder_factory.rb +0 -0
  27. data/lib/iiif_manifest/manifest_builder/composite_builder.rb +0 -0
  28. data/lib/iiif_manifest/manifest_builder/composite_builder_factory.rb +0 -0
  29. data/lib/iiif_manifest/manifest_builder/deep_canvas_builder_factory.rb +3 -3
  30. data/lib/iiif_manifest/manifest_builder/iiif_service.rb +0 -0
  31. data/lib/iiif_manifest/manifest_builder/image_builder.rb +0 -0
  32. data/lib/iiif_manifest/manifest_builder/image_service_builder.rb +0 -0
  33. data/lib/iiif_manifest/manifest_builder/record_property_builder.rb +15 -16
  34. data/lib/iiif_manifest/manifest_builder/resource_builder.rb +0 -0
  35. data/lib/iiif_manifest/manifest_builder/sequence_builder.rb +0 -0
  36. data/lib/iiif_manifest/manifest_builder/structure_builder.rb +0 -0
  37. data/lib/iiif_manifest/manifest_factory.rb +0 -0
  38. data/lib/iiif_manifest/manifest_service_locator.rb +2 -2
  39. data/lib/iiif_manifest/v3.rb +13 -0
  40. data/lib/iiif_manifest/v3/display_content.rb +20 -0
  41. data/lib/iiif_manifest/v3/manifest_builder.rb +61 -0
  42. data/lib/iiif_manifest/v3/manifest_builder/body_builder.rb +61 -0
  43. data/lib/iiif_manifest/v3/manifest_builder/canvas_builder.rb +77 -0
  44. data/lib/iiif_manifest/v3/manifest_builder/choice_builder.rb +47 -0
  45. data/lib/iiif_manifest/v3/manifest_builder/content_builder.rb +38 -0
  46. data/lib/iiif_manifest/v3/manifest_builder/iiif_service.rb +239 -0
  47. data/lib/iiif_manifest/v3/manifest_builder/image_service_builder.rb +35 -0
  48. data/lib/iiif_manifest/v3/manifest_builder/record_property_builder.rb +100 -0
  49. data/lib/iiif_manifest/v3/manifest_builder/structure_builder.rb +87 -0
  50. data/lib/iiif_manifest/v3/manifest_factory.rb +38 -0
  51. data/lib/iiif_manifest/v3/manifest_service_locator.rb +148 -0
  52. data/lib/iiif_manifest/version.rb +1 -1
  53. metadata +47 -29
  54. data/.travis.yml +0 -4
File without changes
@@ -195,13 +195,13 @@ module IIIFManifest
195
195
 
196
196
  class InjectedFactory
197
197
  attr_reader :factory, :hash_args
198
- def initialize(factory, hash_args)
198
+ def initialize(factory, **hash_args)
199
199
  @hash_args = hash_args
200
200
  @factory = factory
201
201
  end
202
202
 
203
203
  def new(*args)
204
- factory.new(*args, hash_args)
204
+ factory.new(*args, **hash_args)
205
205
  end
206
206
  end
207
207
  end
@@ -0,0 +1,13 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/module'
3
+ require 'active_support/core_ext/object'
4
+
5
+ module IIIFManifest
6
+ module V3
7
+ extend ActiveSupport::Autoload
8
+ autoload :ManifestBuilder
9
+ autoload :ManifestFactory
10
+ autoload :ManifestServiceLocator
11
+ autoload :DisplayContent
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class DisplayContent
4
+ attr_reader :url, :width, :height, :duration, :iiif_endpoint, :format, :type,
5
+ :label, :auth_service
6
+ def initialize(url, type:, width: nil, height: nil, duration: nil, label: nil,
7
+ format: nil, iiif_endpoint: nil, auth_service: nil)
8
+ @url = url
9
+ @type = type
10
+ @width = width
11
+ @height = height
12
+ @duration = duration
13
+ @label = label
14
+ @format = format
15
+ @iiif_endpoint = iiif_endpoint
16
+ @auth_service = auth_service
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,61 @@
1
+ require_relative 'manifest_builder/iiif_service'
2
+ require_relative 'manifest_builder/canvas_builder'
3
+ require_relative 'manifest_builder/record_property_builder'
4
+ require_relative 'manifest_builder/choice_builder'
5
+ require_relative 'manifest_builder/content_builder'
6
+ require_relative 'manifest_builder/body_builder'
7
+ require_relative 'manifest_builder/structure_builder'
8
+ require_relative 'manifest_builder/image_service_builder'
9
+
10
+ module IIIFManifest
11
+ module V3
12
+ class ManifestBuilder
13
+ class << self
14
+ # Utility method to wrap the obj into a IIIF V3 compliant language map as needed.
15
+ def language_map(obj)
16
+ return nil if obj.blank?
17
+ return obj if valid_language_map?(obj)
18
+ obj_to_language_map(obj)
19
+ end
20
+
21
+ def valid_language_map?(obj)
22
+ obj.is_a?(Hash) && obj.all? do |k, v|
23
+ k.is_a?(String) && v.is_a?(Array) && v.all? { |o| o.is_a?(String) }
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def obj_to_language_map(obj)
30
+ return nil unless obj.is_a?(String) || (obj.is_a?(Array) && obj.all? { |o| o.is_a?(String) })
31
+ { '@none' => Array(obj) }
32
+ end
33
+ end
34
+
35
+ attr_reader :work,
36
+ :builders,
37
+ :top_record_factory
38
+ def initialize(work, builders:, top_record_factory:)
39
+ @work = work
40
+ @builders = builders
41
+ @top_record_factory = top_record_factory
42
+ end
43
+
44
+ def apply(collection)
45
+ collection['manifests'] ||= []
46
+ collection['manifests'] << to_h
47
+ collection
48
+ end
49
+
50
+ def to_h
51
+ @to_h ||= builders.new(work).apply(top_record)
52
+ end
53
+
54
+ private
55
+
56
+ def top_record
57
+ top_record_factory.new
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class BodyBuilder
5
+ attr_reader :display_content, :iiif_body_factory, :image_service_builder_factory
6
+ def initialize(display_content, iiif_body_factory:, image_service_builder_factory:)
7
+ @display_content = display_content
8
+ @iiif_body_factory = iiif_body_factory
9
+ @image_service_builder_factory = image_service_builder_factory
10
+ end
11
+
12
+ def apply(annotation)
13
+ build_body
14
+ image_service_builder.apply(body) if iiif_endpoint
15
+ apply_auth_service if auth_service
16
+ annotation.body = body
17
+ end
18
+
19
+ private
20
+
21
+ def build_body
22
+ body['id'] = display_content.url
23
+ body['type'] = body_type
24
+ body['height'] = display_content.height if display_content.try(:height).present?
25
+ body['width'] = display_content.width if display_content.try(:width).present?
26
+ body['duration'] = display_content.duration if display_content.try(:duration).present?
27
+ body['format'] = display_content.format if display_content.try(:format).present?
28
+ body['label'] = ManifestBuilder.language_map(display_content.label) if display_content.try(:label).present?
29
+ end
30
+
31
+ def body
32
+ @body ||= iiif_body_factory.new
33
+ end
34
+
35
+ def body_type
36
+ display_content.try(:type) || 'Image'
37
+ end
38
+
39
+ def iiif_endpoint
40
+ display_content.try(:iiif_endpoint)
41
+ end
42
+
43
+ def image_service_builder
44
+ image_service_builder_factory.new(iiif_endpoint)
45
+ end
46
+
47
+ def auth_service
48
+ display_content.try(:auth_service)
49
+ end
50
+
51
+ def apply_auth_service
52
+ body.service = if body['service'].blank?
53
+ [auth_service]
54
+ else
55
+ body['service'] + [auth_service]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,77 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class CanvasBuilder
5
+ attr_reader :record, :parent, :iiif_canvas_factory, :content_builder,
6
+ :choice_builder, :iiif_annotation_page_factory
7
+
8
+ def initialize(record,
9
+ parent,
10
+ iiif_canvas_factory:,
11
+ content_builder:,
12
+ choice_builder:,
13
+ iiif_annotation_page_factory:)
14
+ @record = record
15
+ @parent = parent
16
+ @iiif_canvas_factory = iiif_canvas_factory
17
+ @content_builder = content_builder
18
+ @choice_builder = choice_builder
19
+ @iiif_annotation_page_factory = iiif_annotation_page_factory
20
+ apply_record_properties
21
+ # Presentation 2.x approach
22
+ attach_image if display_image
23
+ # Presentation 3.0 approach
24
+ attach_content if display_content
25
+ end
26
+
27
+ def canvas
28
+ @canvas ||= iiif_canvas_factory.new
29
+ end
30
+
31
+ def path
32
+ path = "#{parent.manifest_url}/canvas/#{record.id}"
33
+ path << "##{record.media_fragment}" if record.respond_to?(:media_fragment) && record.media_fragment.present?
34
+ path
35
+ end
36
+
37
+ def apply(items)
38
+ return items if canvas.items.blank?
39
+ items << canvas
40
+ end
41
+
42
+ private
43
+
44
+ def display_image
45
+ record.display_image if record.respond_to?(:display_image)
46
+ end
47
+
48
+ def display_content
49
+ Array.wrap(record.display_content) if record.respond_to?(:display_content) && record.display_content.present?
50
+ end
51
+
52
+ def apply_record_properties
53
+ canvas['id'] = path
54
+ canvas.label = ManifestBuilder.language_map(record.to_s) if record.to_s.present?
55
+ annotation_page['id'] = "#{path}/annotation_page/#{annotation_page.index}"
56
+ canvas.items = [annotation_page]
57
+ end
58
+
59
+ def annotation_page
60
+ @annotation_page ||= iiif_annotation_page_factory.new
61
+ end
62
+
63
+ def attach_image
64
+ content_builder.new(display_image).apply(canvas)
65
+ end
66
+
67
+ def attach_content
68
+ if display_content.size == 1
69
+ content_builder.new(display_content.first).apply(canvas)
70
+ else
71
+ choice_builder.new(display_content).apply(canvas)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,47 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class ChoiceBuilder
5
+ attr_reader :display_content, :iiif_annotation_factory, :body_builder_factory, :iiif_choice_factory
6
+ def initialize(display_content, iiif_annotation_factory:, body_builder_factory:, iiif_choice_factory:)
7
+ @display_content = display_content
8
+ @iiif_annotation_factory = iiif_annotation_factory
9
+ @body_builder_factory = body_builder_factory
10
+ @iiif_choice_factory = iiif_choice_factory
11
+ build_choice
12
+ end
13
+
14
+ def apply(canvas)
15
+ annotation['target'] = canvas['id']
16
+ canvas['width'] = choice.items.first['width']
17
+ canvas['height'] = choice.items.first['height']
18
+ canvas['duration'] = choice.items.first['duration']
19
+ annotation.body = choice
20
+ # Assume first item in canvas is an annotation page
21
+ canvas.items.first.items += [annotation]
22
+ end
23
+
24
+ private
25
+
26
+ def build_choice
27
+ display_content.each do |content|
28
+ content_body = body_builder(content).apply(iiif_annotation_factory.new)
29
+ choice.items += [content_body]
30
+ end
31
+ end
32
+
33
+ def body_builder(content)
34
+ body_builder_factory.new(content)
35
+ end
36
+
37
+ def annotation
38
+ @annotation ||= iiif_annotation_factory.new
39
+ end
40
+
41
+ def choice
42
+ @choice ||= iiif_choice_factory.new
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class ContentBuilder
5
+ attr_reader :display_content, :iiif_annotation_factory, :body_builder_factory
6
+ def initialize(display_content, iiif_annotation_factory:, body_builder_factory:)
7
+ @display_content = display_content
8
+ @iiif_annotation_factory = iiif_annotation_factory
9
+ @body_builder_factory = body_builder_factory
10
+ build_resource
11
+ end
12
+
13
+ def apply(canvas)
14
+ annotation['target'] = canvas['id']
15
+ canvas['width'] = annotation.body['width']
16
+ canvas['height'] = annotation.body['height']
17
+ canvas['duration'] = annotation.body['duration']
18
+ # Assume first item in canvas is an annotation page
19
+ canvas.items.first.items += [annotation]
20
+ end
21
+
22
+ private
23
+
24
+ def build_resource
25
+ body_builder.apply(annotation)
26
+ end
27
+
28
+ def body_builder
29
+ body_builder_factory.new(display_content)
30
+ end
31
+
32
+ def annotation
33
+ @annotation ||= iiif_annotation_factory.new
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,239 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class IIIFService < IIIFManifest::ManifestBuilder::IIIFService
5
+ end
6
+
7
+ class IIIFManifest < IIIFService
8
+ def label
9
+ inner_hash['label']
10
+ end
11
+
12
+ def label=(label)
13
+ inner_hash['label'] = label
14
+ end
15
+
16
+ def summary
17
+ inner_hash['summary']
18
+ end
19
+
20
+ def summary=(summary)
21
+ return unless summary.present?
22
+ inner_hash['summary'] = summary
23
+ end
24
+
25
+ def behavior=(behavior)
26
+ return unless behavior.present?
27
+ inner_hash['behavior'] = behavior
28
+ end
29
+
30
+ def viewing_direction=(viewing_direction)
31
+ return unless viewing_direction.present?
32
+ inner_hash['viewingDirection'] = viewing_direction
33
+ end
34
+
35
+ def viewingDirection
36
+ inner_hash['viewingDirection']
37
+ end
38
+
39
+ def items
40
+ inner_hash['items'] ||= []
41
+ end
42
+
43
+ def items=(items)
44
+ inner_hash['items'] = items
45
+ end
46
+
47
+ def metadata=(metadata)
48
+ inner_hash['metadata'] = metadata
49
+ end
50
+
51
+ def service
52
+ inner_hash['service'] || []
53
+ end
54
+
55
+ def service=(service)
56
+ inner_hash['service'] = service
57
+ end
58
+
59
+ def see_also=(see_also)
60
+ inner_hash['seeAlso'] = see_also
61
+ end
62
+
63
+ def rendering=(rendering)
64
+ inner_hash['rendering'] = rendering
65
+ end
66
+
67
+ def rights=(rights)
68
+ inner_hash['rights'] = rights
69
+ end
70
+
71
+ def homepage=(homepage)
72
+ inner_hash['homepage'] = homepage
73
+ end
74
+
75
+ def initial_attributes
76
+ {
77
+ '@context' => [
78
+ 'http://www.w3.org/ns/anno.jsonld',
79
+ 'http://iiif.io/api/presentation/3/context.json'
80
+ ],
81
+ 'type' => 'Manifest'
82
+ }
83
+ end
84
+
85
+ class Collection < IIIFManifest
86
+ def initial_attributes
87
+ {
88
+ '@context' => [
89
+ 'http://www.w3.org/ns/anno.jsonld',
90
+ 'http://iiif.io/api/presentation/3/context.json'
91
+ ],
92
+ 'type' => 'Collection'
93
+ }
94
+ end
95
+
96
+ def viewing_direction=(_viewing_direction)
97
+ raise NotImplementedError
98
+ end
99
+
100
+ def viewingDirection
101
+ raise NotImplementedError
102
+ end
103
+ end
104
+
105
+ class Canvas < IIIFService
106
+ def label
107
+ inner_hash['label']
108
+ end
109
+
110
+ def label=(label)
111
+ inner_hash['label'] = label
112
+ end
113
+
114
+ def items
115
+ inner_hash['items'] ||= []
116
+ end
117
+
118
+ def items=(items)
119
+ inner_hash['items'] = items
120
+ end
121
+
122
+ def initial_attributes
123
+ {
124
+ 'type' => 'Canvas'
125
+ }
126
+ end
127
+ end
128
+
129
+ class Range < IIIFService
130
+ def initial_attributes
131
+ {
132
+ 'type' => 'Range'
133
+ }
134
+ end
135
+ end
136
+
137
+ class Body < IIIFService
138
+ def service=(service)
139
+ inner_hash['service'] = service
140
+ end
141
+
142
+ def initial_attributes
143
+ {
144
+ }
145
+ end
146
+ end
147
+
148
+ class Choice < IIIFService
149
+ def items
150
+ inner_hash['items'] ||= []
151
+ end
152
+
153
+ def items=(items)
154
+ inner_hash['items'] = items
155
+ end
156
+
157
+ def initial_attributes
158
+ {
159
+ 'type' => 'Choice',
160
+ 'choiceHint' => 'user'
161
+ }
162
+ end
163
+ end
164
+
165
+ class AnnotationPage < IIIFService
166
+ def items
167
+ inner_hash['items'] ||= []
168
+ end
169
+
170
+ def items=(items)
171
+ inner_hash['items'] = items
172
+ end
173
+
174
+ def index
175
+ @index ||= SecureRandom.uuid
176
+ end
177
+
178
+ def initial_attributes
179
+ {
180
+ 'type' => 'AnnotationPage'
181
+ }
182
+ end
183
+ end
184
+
185
+ class Annotation < IIIFService
186
+ def body=(body)
187
+ inner_hash['body'] = body
188
+ end
189
+
190
+ def body
191
+ inner_hash['body']
192
+ end
193
+
194
+ def initial_attributes
195
+ {
196
+ 'type' => 'Annotation',
197
+ 'motivation' => 'painting'
198
+ }
199
+ end
200
+ end
201
+
202
+ class SearchService < IIIFService
203
+ def service=(service)
204
+ inner_hash['service'] = service
205
+ end
206
+
207
+ def search_service=(search_service)
208
+ inner_hash['id'] = search_service
209
+ end
210
+
211
+ def initial_attributes
212
+ {
213
+ '@context' => 'http://iiif.io/api/search/1/context.json',
214
+ 'profile' => 'http://iiif.io/api/search/1/search',
215
+ 'label' => 'Search within this manifest'
216
+ }
217
+ end
218
+ end
219
+
220
+ class AutocompleteService < IIIFService
221
+ def autocomplete_service
222
+ inner_hash['id']
223
+ end
224
+
225
+ def autocomplete_service=(autocomplete_service)
226
+ inner_hash['id'] = autocomplete_service
227
+ end
228
+
229
+ def initial_attributes
230
+ {
231
+ 'profile' => 'http://iiif.io/api/search/1/autocomplete',
232
+ 'label' => 'Get suggested words in this manifest'
233
+ }
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end