iiif_manifest 0.4.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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