assembly-objectfile 1.10.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfe0d362cd776d4099d57530dc6c502e8760eb49953dfa93d755016b98c54d6a
4
- data.tar.gz: c1f0da284aa258aa89375b6d7b92dd7847b3e87b27712c2802e29157b86b6d9c
3
+ metadata.gz: e964d66148904c190829abd7d9c65d09459405f184a48a2350602d1f4c6b6a5f
4
+ data.tar.gz: 85fca1341b29f0c3f5b3858b419e0273754de1a47140b5ae36d2cbf2a77feea4
5
5
  SHA512:
6
- metadata.gz: dfce4baa7f4d0cd52944195661ba94b6af1010fce66d714eb7c7b54778681fd5041d92d5f2fb82561c20048f76e4c313050afd880d7eb8b0c6eafb0fd6aedb67
7
- data.tar.gz: c936f71be1c89887f76a9e3c66a37b690730f40a4bcc01605dcd2610d961f85d44eb110b91f40754346ef46482ad481a1aa6a76a2d9e866de42782cb344115b3
6
+ metadata.gz: f2cf693279f7c43392f92b3dd8bf28df4baca673276c3c96208b420c6ec26415b37b9498149a0ee6fe8ff4606046768582107f1e71b66199f04463b8f5dec918
7
+ data.tar.gz: fcdc3f9041410416893e8ba1258c677a9eb0f6ede6eb833deb74f9dcb30e005d226d4486419a6fc2a1ae24b9e0ceda579e1acb7f189cf022af822fc32e275fa6
@@ -1,12 +1,10 @@
1
- ## Why was this change made?
1
+ ## Why was this change made? 🤔
2
2
 
3
3
 
4
4
 
5
- ## How was this change tested?
5
+ ## How was this change tested? 🤨
6
6
 
7
-
8
-
9
- ## Which documentation and/or configurations were updated?
7
+ ⚡ ⚠ If this change has cross service impact, ***run [integration tests](https://github.com/sul-dlss/infrastructure-integration-test) that do accessioning*** and/or test in [stage|qa] environment, in addition to specs. ⚡
10
8
 
11
9
 
12
10
 
data/.rubocop_todo.yml CHANGED
@@ -1,33 +1,11 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2021-01-08 23:41:37 UTC using RuboCop version 1.8.0.
3
+ # on 2021-04-26 18:43:37 UTC using RuboCop version 1.11.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1
10
- # Cop supports --auto-correct.
11
- # Configuration parameters: EnforcedStyleAlignWith, Severity.
12
- # SupportedStylesAlignWith: start_of_line, begin
13
- Layout/BeginEndAlignment:
14
- Exclude:
15
- - 'lib/assembly-objectfile/object_fileable.rb'
16
-
17
- # Offense count: 1
18
- # Cop supports --auto-correct.
19
- # Configuration parameters: AllowAliasSyntax, AllowedMethods.
20
- # AllowedMethods: alias_method, public, protected, private
21
- Layout/EmptyLinesAroundAttributeAccessor:
22
- Exclude:
23
- - 'lib/assembly-objectfile/object_fileable.rb'
24
-
25
- # Offense count: 1
26
- # Cop supports --auto-correct.
27
- Layout/RescueEnsureAlignment:
28
- Exclude:
29
- - 'lib/assembly-objectfile/object_fileable.rb'
30
-
31
9
  # Offense count: 1
32
10
  Lint/UselessAssignment:
33
11
  Exclude:
@@ -36,38 +14,38 @@ Lint/UselessAssignment:
36
14
  # Offense count: 3
37
15
  # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
38
16
  Metrics/AbcSize:
39
- Max: 52
17
+ Max: 55
40
18
 
41
19
  # Offense count: 1
42
20
  # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
43
21
  # IgnoredMethods: refine
44
22
  Metrics/BlockLength:
45
- Max: 26
23
+ Max: 27
46
24
 
47
25
  # Offense count: 2
48
26
  # Configuration parameters: IgnoredMethods.
49
27
  Metrics/CyclomaticComplexity:
50
- Max: 13
28
+ Max: 14
51
29
 
52
30
  # Offense count: 4
53
31
  # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
54
32
  Metrics/MethodLength:
55
- Max: 30
33
+ Max: 31
56
34
 
57
35
  # Offense count: 1
58
36
  # Configuration parameters: CountComments, CountAsOne.
59
37
  Metrics/ModuleLength:
60
- Max: 117
38
+ Max: 120
61
39
 
62
40
  # Offense count: 1
63
41
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
64
42
  Metrics/ParameterLists:
65
- Max: 11
43
+ Max: 12
66
44
 
67
45
  # Offense count: 2
68
46
  # Configuration parameters: IgnoredMethods.
69
47
  Metrics/PerceivedComplexity:
70
- Max: 14
48
+ Max: 15
71
49
 
72
50
  # Offense count: 1
73
51
  # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, Regex, IgnoreExecutableScripts, AllowedAcronyms.
@@ -87,7 +65,7 @@ Naming/PredicateName:
87
65
  - 'spec/**/*'
88
66
  - 'lib/assembly-objectfile/object_fileable.rb'
89
67
 
90
- # Offense count: 8
68
+ # Offense count: 9
91
69
  # Configuration parameters: Max.
92
70
  RSpec/ExampleLength:
93
71
  Exclude:
@@ -101,13 +79,13 @@ RSpec/FilePath:
101
79
  - 'spec/content_metadata_spec.rb'
102
80
  - 'spec/object_file_spec.rb'
103
81
 
104
- # Offense count: 71
82
+ # Offense count: 74
105
83
  # Configuration parameters: AssignmentOnly.
106
84
  RSpec/InstanceVariable:
107
85
  Exclude:
108
86
  - 'spec/object_file_spec.rb'
109
87
 
110
- # Offense count: 38
88
+ # Offense count: 40
111
89
  RSpec/MultipleExpectations:
112
90
  Max: 29
113
91
 
@@ -132,29 +110,7 @@ Style/CommentedKeyword:
132
110
  Exclude:
133
111
  - 'lib/assembly-objectfile/content_metadata.rb'
134
112
 
135
- # Offense count: 2
136
- # Cop supports --auto-correct.
137
- Style/KeywordParametersOrder:
138
- Exclude:
139
- - 'lib/assembly-objectfile/content_metadata/file.rb'
140
- - 'lib/assembly-objectfile/content_metadata/file_set.rb'
141
-
142
- # Offense count: 1
143
- # Cop supports --auto-correct.
144
- Style/RedundantAssignment:
145
- Exclude:
146
- - 'lib/assembly-objectfile/content_metadata.rb'
147
-
148
- # Offense count: 5
149
- # Cop supports --auto-correct.
150
- Style/StringConcatenation:
151
- Exclude:
152
- - 'config/boot.rb'
153
- - 'lib/assembly-objectfile.rb'
154
- - 'lib/assembly-objectfile/object_file.rb'
155
- - 'spec/spec_helper.rb'
156
-
157
- # Offense count: 113
113
+ # Offense count: 122
158
114
  # Cop supports --auto-correct.
159
115
  # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
160
116
  # URISchemes: http, https
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ source 'http://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in .gemspec
6
6
  gemspec
7
+
8
+ gem 'byebug'
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  s.require_paths = ['lib']
22
22
 
23
- s.required_ruby_version = '~> 2.5'
23
+ s.required_ruby_version = '>= 2.5', '< 4'
24
24
 
25
25
  s.add_dependency 'activesupport', '>= 5.2.0'
26
26
  s.add_dependency 'deprecation'
@@ -13,12 +13,14 @@ module Assembly
13
13
  # Represents a configuration for generating the content metadata
14
14
  class Config < Dry::Struct
15
15
  STYLES = %w[image file book map 3d document webarchive-seed].freeze
16
+ READING_ORDERS = %w[ltr rtl].freeze
16
17
  attribute :auto_labels, Types::Strict::Bool.default(true)
17
18
  attribute :flatten_folder_structure, Types::Strict::Bool.default(false)
18
19
  attribute :add_file_attributes, Types::Strict::Bool.default(false)
19
20
  attribute :add_exif, Types::Strict::Bool.default(false)
20
21
  attribute :file_attributes, Types::Strict::Hash.default({}.freeze)
21
22
  attribute :type, Types::Strict::String.enum(*STYLES)
23
+ attribute :reading_order, Types::Strict::String.default('ltr').enum(*READING_ORDERS)
22
24
  end
23
25
  end
24
26
  end
@@ -35,7 +35,7 @@ module Assembly
35
35
  @style = style
36
36
  end
37
37
 
38
- delegate :sha1, :md5, :provider_md5, :provider_sha1, :mimetype, :filesize, :image?, to: :file
38
+ delegate :sha1, :md5, :provider_md5, :provider_sha1, :mimetype, :filesize, :image?, :valid_image?, to: :file
39
39
 
40
40
  def file_id(common_path:, flatten_folder_structure:)
41
41
  # set file id attribute, first check the relative_path parameter on the object, and if it is set, just use that
@@ -15,6 +15,8 @@ module Assembly
15
15
 
16
16
  Nokogiri::XML::Builder.new do |xml|
17
17
  xml.contentMetadata(objectId: druid.to_s, type: config.type) do
18
+ xml.bookData(readingOrder: config.reading_order) if config.type == 'book'
19
+
18
20
  filesets.each_with_index do |fileset, index| # iterate over all the resources
19
21
  # start a new resource element
20
22
  sequence = index + 1
@@ -29,19 +31,19 @@ module Assembly
29
31
  resource_label = fileset.label_from_file(default: default_label)
30
32
 
31
33
  xml.label(resource_label) unless resource_label.empty?
32
- fileset.files.each do |obj| # iterate over all the files in a resource
33
- xml_file_params = { id: obj.file_id(common_path: common_path, flatten_folder_structure: config.flatten_folder_structure) }
34
- xml_file_params.merge!(obj.file_attributes(config.file_attributes)) if config.add_file_attributes
35
- xml_file_params.merge!(mimetype: obj.mimetype, size: obj.filesize) if config.add_exif
34
+ fileset.files.each do |cm_file| # iterate over all the files in a resource
35
+ xml_file_params = { id: cm_file.file_id(common_path: common_path, flatten_folder_structure: config.flatten_folder_structure) }
36
+ xml_file_params.merge!(cm_file.file_attributes(config.file_attributes)) if config.add_file_attributes
37
+ xml_file_params.merge!(mimetype: cm_file.mimetype, size: cm_file.filesize) if config.add_exif
36
38
 
37
39
  xml.file(xml_file_params) do
38
40
  if config.add_exif # add exif info if the user requested it
39
- xml.checksum(obj.sha1, type: 'sha1')
40
- xml.checksum(obj.md5, type: 'md5')
41
- xml.imageData(obj.image_data) if obj.image? # add image data for an image
42
- elsif obj.provider_md5 || obj.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
43
- xml.checksum(obj.provider_sha1, type: 'sha1') if obj.provider_sha1
44
- xml.checksum(obj.provider_md5, type: 'md5') if obj.provider_md5
41
+ xml.checksum(cm_file.sha1, type: 'sha1')
42
+ xml.checksum(cm_file.md5, type: 'md5')
43
+ xml.imageData(cm_file.image_data) if cm_file.valid_image? # add image data for an image
44
+ elsif cm_file.provider_md5 || cm_file.provider_sha1 # if we did not add exif info, see if there are user supplied checksums to add
45
+ xml.checksum(cm_file.provider_sha1, type: 'sha1') if cm_file.provider_sha1
46
+ xml.checksum(cm_file.provider_md5, type: 'md5') if cm_file.provider_md5
45
47
  end
46
48
  end
47
49
  end
@@ -52,13 +52,15 @@ module Assembly
52
52
  # :flatten_folder_structure = optional - Will remove *all* folder structure when genearting file IDs (e.g. DPG subfolders like '00','05' will be removed) when generating file IDs. This is useful if the folder structure is flattened when staging files (like for DPG).
53
53
  # The default is false. If set to true, will override the "preserve_common_paths" parameter.
54
54
  # :auto_labels = optional - Will add automated resource labels (e.g. "File 1") when labels are not provided by the user. The default is true.
55
+ # See https://consul.stanford.edu/pages/viewpage.action?spaceKey=chimera&title=DOR+content+types%2C+resource+types+and+interpretive+metadata for next two settings
56
+ # :reading_order = optional - only valid for simple_book, can be 'rtl' or 'ltr'. The default is 'ltr'.
55
57
  # Example:
56
58
  # Assembly::ContentMetadata.create_content_metadata(:druid=>'druid:nx288wh8889',:style=>:simple_image,:objects=>object_files,:add_file_attributes=>false)
57
59
  def self.create_content_metadata(druid:, objects:, auto_labels: true,
58
60
  add_exif: false, bundle: :default, style: :simple_image,
59
61
  add_file_attributes: false, file_attributes: {},
60
62
  preserve_common_paths: false, flatten_folder_structure: false,
61
- include_root_xml: nil)
63
+ include_root_xml: nil, reading_order: 'ltr')
62
64
 
63
65
  common_path = find_common_path(objects) unless preserve_common_paths # find common paths to all files provided if needed
64
66
 
@@ -68,6 +70,7 @@ module Assembly
68
70
  add_file_attributes: add_file_attributes,
69
71
  file_attributes: file_attributes,
70
72
  add_exif: add_exif,
73
+ reading_order: reading_order,
71
74
  type: object_level_type(style))
72
75
 
73
76
  builder = NokogiriBuilder.build(druid: druid,
@@ -8,7 +8,7 @@ module Assembly
8
8
  module ObjectFileable
9
9
  attr_accessor :file_attributes, :label, :path, :provider_md5, :provider_sha1, :relative_path, :mime_type_order
10
10
 
11
- VALID_MIMETYPE_METHODS = %i[exif file extension].freeze
11
+ VALID_MIMETYPE_METHODS = %i[override exif file extension].freeze
12
12
 
13
13
  # @param [String] path full path to the file to be worked with
14
14
  # @param [Hash<Symbol => Object>] params options used during content metadata generation
@@ -18,7 +18,8 @@ module Assembly
18
18
  # @option params [String] :provider_sha1 pre-computed SHA1 checksum
19
19
  # @option params [String] :relative_path if you want the file ids in the content metadata it can be set, otherwise content metadata will get the full path
20
20
  # @option params [Array] :mime_type_order can be set to the order in which you want mimetypes to be determined
21
- # options are :exif (from exif if exists), :extension (from file extension), and :file (from unix file system command)
21
+ # options are :override (from manual overide mapping if exists), :exif (from exif if exists),
22
+ # :extension (from file extension), and :file (from unix file system command)
22
23
  # the default is defined in the private `default_mime_type_order` method but you can override to set your own order
23
24
  # @example
24
25
  # Assembly::ObjectFile.new('/input/path_to_file.tif')
@@ -127,12 +128,21 @@ module Assembly
127
128
  mimetype = ''
128
129
  mime_type_order.each do |mime_type_method|
129
130
  mimetype = public_send("#{mime_type_method}_mimetype") if VALID_MIMETYPE_METHODS.include?(mime_type_method)
130
- break if !mimetype.nil? && mimetype != ''
131
+ break if mimetype.present?
131
132
  end
132
133
  mimetype
133
134
  end
134
135
  end
135
136
 
137
+ # Returns mimetype information using the manual override mapping (based on a file extension lookup)
138
+ # @return [String] mime type for supplied file if a mapping exists for the file's extension
139
+ # @example
140
+ # source_file = Assembly::ObjectFile.new('/input/path_to_file.json')
141
+ # puts source_file.override_mimetype # 'application/json'
142
+ def override_mimetype
143
+ @override_mimetype ||= Assembly::OVERRIDE_MIMETYPES.fetch(ext.to_sym, '')
144
+ end
145
+
136
146
  # Returns mimetype information using the mime-types gem (based on a file extension lookup)
137
147
  # @return [String] mime type for supplied file
138
148
  # @example
@@ -257,7 +267,7 @@ exif&.mimetype && prefer_exif
257
267
 
258
268
  # prive method defining default preferred ordering of how mimetypes are determined
259
269
  def default_mime_type_order
260
- %i[exif file extension]
270
+ %i[override exif file extension]
261
271
  end
262
272
 
263
273
  # private method to check for file existence before operating on it
@@ -4,6 +4,6 @@
4
4
  module Assembly
5
5
  class ObjectFile
6
6
  # Project version number
7
- VERSION = '1.10.1'
7
+ VERSION = '1.12.0'
8
8
  end
9
9
  end
@@ -14,6 +14,14 @@ module Assembly
14
14
  # by the file command, then a check will be made to see if exif data exists...if so, the mimetype returned by the exif data will be used
15
15
  # if no exif data exists, then the mimetype returned by the unix file command will be used
16
16
  TRUSTED_MIMETYPES = ['text/plain', 'plain/text', 'application/pdf', 'text/html', 'application/xml'].freeze
17
+
18
+ # this is a manual override mapping of file extension to mimetype; if a file with the given extension is found, the mapped
19
+ # mimetype will be returned and no further methods will be used - this is used to force a specific mimetype to be returned for
20
+ # for a given file extension regardless of what exif or the unix file system command returns
21
+ # the mapping format is "extension with period: returned mimetype", e.g. for any .json file, you will always get `application/json`
22
+ OVERRIDE_MIMETYPES = {
23
+ '.json': 'application/json'
24
+ }.freeze
17
25
  end
18
26
 
19
27
  require 'assembly-objectfile/content_metadata'
@@ -8,8 +8,8 @@ RSpec.describe Assembly::ContentMetadata do
8
8
 
9
9
  let(:xml) { Nokogiri::XML(result) }
10
10
 
11
- context 'when style is simple_image' do
12
- context 'when using a single tif and jp2' do
11
+ context 'when style=simple_image' do
12
+ context 'when using a single tif and jp2 with add_exif: true' do
13
13
  it 'generates valid content metadata with exif, adding file attributes' do
14
14
  objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)]
15
15
  result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, add_file_attributes: true, objects: objects)
@@ -44,46 +44,8 @@ RSpec.describe Assembly::ContentMetadata do
44
44
  expect(xml.xpath('//resource/file/imageData')[1].attributes['width'].value).to eq('100')
45
45
  expect(xml.xpath('//resource/file/imageData')[1].attributes['height'].value).to eq('100')
46
46
  end
47
- end
48
-
49
- context 'when using a single tif and jp2' do
50
- it 'generates valid content metadata with no exif adding specific file attributes for 2 objects, and defaults for 1 object' do
51
- obj1 = Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE)
52
- obj2 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)
53
- obj3 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE2)
54
- obj1.file_attributes = { publish: 'no', preserve: 'no', shelve: 'no' }
55
- obj2.file_attributes = { publish: 'yes', preserve: 'yes', shelve: 'yes' }
56
- objects = [obj1, obj2, obj3]
57
- result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: false, add_file_attributes: true, objects: objects)
58
- expect(result.class).to be String
59
- xml = Nokogiri::XML(result)
60
- expect(xml.errors.size).to eq 0
61
- expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
62
- expect(xml.xpath('//resource').length).to eq 3
63
- expect(xml.xpath('//resource/file').length).to eq 3
64
- expect(xml.xpath('//resource/file/checksum').length).to eq 0
65
- expect(xml.xpath('//resource/file/imageData').length).to eq 0
66
- expect(xml.xpath('//label').length).to eq 3
67
- expect(xml.xpath('//label')[0].text).to match(/Image 1/)
68
- expect(xml.xpath('//label')[1].text).to match(/Image 2/)
69
- expect(xml.xpath('//label')[2].text).to match(/Image 3/)
70
- expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
71
- expect(xml.xpath('//resource')[1].attributes['type'].value).to eq('image')
72
- expect(xml.xpath('//resource')[2].attributes['type'].value).to eq('image')
73
- expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('no') # specificially set in object
74
- expect(xml.xpath('//resource/file')[0].attributes['preserve'].value).to eq('no') # specificially set in object
75
- expect(xml.xpath('//resource/file')[0].attributes['shelve'].value).to eq('no') # specificially set in object
76
- expect(xml.xpath('//resource/file')[1].attributes['publish'].value).to eq('yes') # specificially set in object
77
- expect(xml.xpath('//resource/file')[1].attributes['preserve'].value).to eq('yes') # specificially set in object
78
- expect(xml.xpath('//resource/file')[1].attributes['shelve'].value).to eq('yes') # specificially set in object
79
- expect(xml.xpath('//resource/file')[2].attributes['publish'].value).to eq('yes') # defaults by mimetype
80
- expect(xml.xpath('//resource/file')[2].attributes['preserve'].value).to eq('no') # defaults by mimetype
81
- expect(xml.xpath('//resource/file')[2].attributes['shelve'].value).to eq('yes') # defaults by mimetype
82
- end
83
- end
84
47
 
85
- context 'when using a single tif and jp2' do
86
- it 'generates valid content metadata with exif, overriding file labels' do
48
+ it 'generates valid content metadata, overriding file labels' do
87
49
  objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE, label: 'Sample tif label!'), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE, label: 'Sample jp2 label!')]
88
50
  result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, add_file_attributes: true, objects: objects)
89
51
  expect(result.class).to be String
@@ -119,6 +81,42 @@ RSpec.describe Assembly::ContentMetadata do
119
81
  end
120
82
  end
121
83
 
84
+ context 'when using a single tif and jp2 with add_exif: false' do
85
+ it 'generates valid content metadata adding specific file attributes for 2 objects, and defaults for 1 object' do
86
+ obj1 = Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE)
87
+ obj2 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)
88
+ obj3 = Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE2)
89
+ obj1.file_attributes = { publish: 'no', preserve: 'no', shelve: 'no' }
90
+ obj2.file_attributes = { publish: 'yes', preserve: 'yes', shelve: 'yes' }
91
+ objects = [obj1, obj2, obj3]
92
+ result = described_class.create_content_metadata(druid: TEST_DRUID, add_exif: false, add_file_attributes: true, objects: objects)
93
+ expect(result.class).to be String
94
+ xml = Nokogiri::XML(result)
95
+ expect(xml.errors.size).to eq 0
96
+ expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
97
+ expect(xml.xpath('//resource').length).to eq 3
98
+ expect(xml.xpath('//resource/file').length).to eq 3
99
+ expect(xml.xpath('//resource/file/checksum').length).to eq 0
100
+ expect(xml.xpath('//resource/file/imageData').length).to eq 0
101
+ expect(xml.xpath('//label').length).to eq 3
102
+ expect(xml.xpath('//label')[0].text).to match(/Image 1/)
103
+ expect(xml.xpath('//label')[1].text).to match(/Image 2/)
104
+ expect(xml.xpath('//label')[2].text).to match(/Image 3/)
105
+ expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
106
+ expect(xml.xpath('//resource')[1].attributes['type'].value).to eq('image')
107
+ expect(xml.xpath('//resource')[2].attributes['type'].value).to eq('image')
108
+ expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('no') # specificially set in object
109
+ expect(xml.xpath('//resource/file')[0].attributes['preserve'].value).to eq('no') # specificially set in object
110
+ expect(xml.xpath('//resource/file')[0].attributes['shelve'].value).to eq('no') # specificially set in object
111
+ expect(xml.xpath('//resource/file')[1].attributes['publish'].value).to eq('yes') # specificially set in object
112
+ expect(xml.xpath('//resource/file')[1].attributes['preserve'].value).to eq('yes') # specificially set in object
113
+ expect(xml.xpath('//resource/file')[1].attributes['shelve'].value).to eq('yes') # specificially set in object
114
+ expect(xml.xpath('//resource/file')[2].attributes['publish'].value).to eq('yes') # defaults by mimetype
115
+ expect(xml.xpath('//resource/file')[2].attributes['preserve'].value).to eq('no') # defaults by mimetype
116
+ expect(xml.xpath('//resource/file')[2].attributes['shelve'].value).to eq('yes') # defaults by mimetype
117
+ end
118
+ end
119
+
122
120
  context 'when using a single tif and jp2' do
123
121
  it 'generates valid content metadata with exif, overriding file labels for one, and skipping auto labels for the others or for where the label is set but is blank' do
124
122
  objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE, label: 'Sample tif label!'), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE), Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE, label: '')]
@@ -331,9 +329,29 @@ RSpec.describe Assembly::ContentMetadata do
331
329
  end
332
330
  end
333
331
  end
332
+
333
+ context 'when using a single svg with add_exif: true' do
334
+ subject(:result) { described_class.create_content_metadata(druid: TEST_DRUID, add_exif: true, auto_labels: false, add_file_attributes: true, objects: objects) }
335
+
336
+ let(:objects) { [Assembly::ObjectFile.new(TEST_SVG_INPUT_FILE)] }
337
+
338
+ it 'generates no imageData node' do
339
+ xml = Nokogiri::XML(result)
340
+ expect(xml.errors.size).to eq 0
341
+ expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('image')
342
+ expect(xml.xpath('//resource/file').length).to eq 1
343
+ expect(xml.xpath('//resource/file')[0]['mimetype']).to eq 'image/svg+xml'
344
+ expect(xml.xpath('//resource/file')[0]['publish']).to eq('no')
345
+ expect(xml.xpath('//resource/file')[0]['preserve']).to eq('yes')
346
+ expect(xml.xpath('//resource/file')[0]['shelve']).to eq('no')
347
+ expect(xml.xpath("//resource[@sequence='1']/file").length).to eq 1
348
+ expect(xml.xpath('//imageData')).not_to be_present
349
+ expect(xml.xpath('//resource')[0].attributes['type'].value).to eq('image')
350
+ end
351
+ end
334
352
  end
335
353
 
336
- context 'when style is webarchive-seed' do
354
+ context 'when style=webarchive-seed' do
337
355
  context 'when using a jp2' do
338
356
  it 'generates valid content metadata with exif, adding file attributes' do
339
357
  objects = [Assembly::ObjectFile.new(TEST_JP2_INPUT_FILE)]
@@ -342,6 +360,7 @@ RSpec.describe Assembly::ContentMetadata do
342
360
  xml = Nokogiri::XML(result)
343
361
  expect(xml.errors.size).to eq 0
344
362
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('webarchive-seed')
363
+ expect(xml.xpath('//bookData').length).to eq 0
345
364
  expect(xml.xpath('//resource').length).to eq 1
346
365
  expect(xml.xpath('//resource/file').length).to eq 1
347
366
  expect(xml.xpath('//resource/file/checksum').length).to eq 2
@@ -375,6 +394,7 @@ RSpec.describe Assembly::ContentMetadata do
375
394
  xml = Nokogiri::XML(result)
376
395
  expect(xml.errors.size).to eq 0
377
396
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('map')
397
+ expect(xml.xpath('//bookData').length).to eq 0
378
398
  expect(xml.xpath('//resource/file').length).to eq 2
379
399
  expect(xml.xpath('//resource/file')[0].attributes['mimetype']).to be_nil
380
400
  expect(xml.xpath('//resource/file')[0].attributes['publish'].value).to eq('yes')
@@ -404,6 +424,7 @@ RSpec.describe Assembly::ContentMetadata do
404
424
  expect(xml.errors.size).to eq 0
405
425
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
406
426
  expect(xml.xpath('//contentMetadata')[0].attributes['objectId'].value).to eq(TEST_DRUID.to_s)
427
+ expect(xml.xpath('//bookData')[0].attributes['readingOrder'].value).to eq('ltr')
407
428
  expect(xml.xpath('//resource').length).to eq 4
408
429
  expect(xml.xpath('//resource/file').length).to eq 6
409
430
  expect(xml.xpath("//resource[@sequence='1']/file")[0].attributes['id'].value).to eq('oo000oo0001_00_001.tif')
@@ -428,20 +449,21 @@ RSpec.describe Assembly::ContentMetadata do
428
449
  end
429
450
  end
430
451
 
431
- context "when item has a 'druid:' prefix. Using two tifs, two associated jp2s, two associated pdfs and one lingering PDF using bundle=dpg" do
452
+ context "when item has a 'druid:' prefix and specified book order. Using two tifs, two associated jp2s, two associated pdfs and one lingering PDF using bundle=dpg" do
432
453
  it 'generates valid content metadata with flattening folder structure' do
433
454
  objects = [Assembly::ObjectFile.new(TEST_DPG_TIF), Assembly::ObjectFile.new(TEST_DPG_JP),
434
455
  Assembly::ObjectFile.new(TEST_DPG_PDF), Assembly::ObjectFile.new(TEST_DPG_TIF2),
435
456
  Assembly::ObjectFile.new(TEST_DPG_JP2), Assembly::ObjectFile.new(TEST_DPG_PDF2),
436
457
  Assembly::ObjectFile.new(TEST_DPG_SPECIAL_PDF1)]
437
458
  test_druid = "druid:#{TEST_DRUID}"
438
- result = described_class.create_content_metadata(druid: test_druid, bundle: :dpg, objects: objects, style: :simple_book, flatten_folder_structure: true)
459
+ result = described_class.create_content_metadata(druid: test_druid, bundle: :dpg, objects: objects, style: :simple_book, flatten_folder_structure: true, reading_order: 'rtl')
439
460
  expect(result.class).to be String
440
461
  expect(result.include?('<?xml')).to be true
441
462
  xml = Nokogiri::XML(result)
442
463
  expect(xml.errors.size).to eq 0
443
464
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
444
465
  expect(xml.xpath('//contentMetadata')[0].attributes['objectId'].value).to eq(test_druid)
466
+ expect(xml.xpath('//bookData')[0].attributes['readingOrder'].value).to eq('rtl')
445
467
  expect(test_druid).to eq("druid:#{TEST_DRUID}")
446
468
  expect(xml.xpath('//resource').length).to eq 3
447
469
  expect(xml.xpath('//resource/file').length).to be 7
@@ -466,6 +488,14 @@ RSpec.describe Assembly::ContentMetadata do
466
488
  end
467
489
  end
468
490
 
491
+ context 'throws an error with invalid reading order' do
492
+ subject(:result) { described_class.create_content_metadata(druid: "druid:#{TEST_DRUID}", bundle: :dpg, objects: [], style: :simple_book, flatten_folder_structure: true, reading_order: 'bogus') }
493
+
494
+ it 'generates valid content metadata with flattening folder structure' do
495
+ expect { result }.to raise_error(Dry::Struct::Error)
496
+ end
497
+ end
498
+
469
499
  context 'when using two tifs' do
470
500
  it 'generates valid content metadata for two tifs of style=simple_book' do
471
501
  objects = [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE), Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE2)]
@@ -493,7 +523,7 @@ RSpec.describe Assembly::ContentMetadata do
493
523
  end
494
524
  end
495
525
 
496
- context 'when using style=book_with_pdf' do
526
+ context 'when style=book_with_pdf' do
497
527
  context 'when using two tiffs and a pdf' do
498
528
  let(:objects) do
499
529
  [Assembly::ObjectFile.new(TEST_TIF_INPUT_FILE),
@@ -580,6 +610,7 @@ RSpec.describe Assembly::ContentMetadata do
580
610
  xml = Nokogiri::XML(result)
581
611
  expect(xml.errors.size).to eq 0
582
612
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('file')
613
+ expect(xml.xpath('//bookData').length).to eq 0
583
614
  expect(xml.xpath('//resource').length).to eq 4
584
615
  expect(xml.xpath('//resource/file').length).to eq 4
585
616
  expect(xml.xpath('//label').length).to eq 4
@@ -611,6 +642,7 @@ RSpec.describe Assembly::ContentMetadata do
611
642
  it 'generates valid content metadata for two tifs' do
612
643
  expect(xml.errors.size).to eq 0
613
644
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('book')
645
+ expect(xml.xpath('//bookData').length).to eq 1
614
646
  expect(xml.xpath('//resource').length).to eq 2
615
647
  expect(xml.xpath('//resource/file').length).to eq 2
616
648
  expect(xml.xpath('//label').length).to eq 2
@@ -641,6 +673,7 @@ RSpec.describe Assembly::ContentMetadata do
641
673
  it 'generates valid content metadata' do
642
674
  expect(xml.errors.size).to eq 0
643
675
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('document')
676
+ expect(xml.xpath('//bookData').length).to eq 0
644
677
  expect(xml.xpath('//resource').length).to eq 1
645
678
  expect(xml.xpath('//resource/file').length).to eq 1
646
679
  expect(xml.xpath('//label').length).to eq 1
@@ -713,6 +746,7 @@ RSpec.describe Assembly::ContentMetadata do
713
746
  it 'generates valid content metadata' do
714
747
  expect(xml.errors.size).to eq 0
715
748
  expect(xml.xpath('//contentMetadata')[0].attributes['type'].value).to eq('3d')
749
+ expect(xml.xpath('//bookData').length).to eq 0
716
750
  expect(xml.xpath('//resource').length).to eq 4
717
751
  expect(xml.xpath('//resource/file').length).to eq 4
718
752
  expect(xml.xpath('//label').length).to eq 4
@@ -70,6 +70,13 @@ describe Assembly::ObjectFile do
70
70
  expect(@ai.mimetype).to eq('text/plain')
71
71
  end
72
72
 
73
+ it 'overrides the mimetype generators and uses the manual mapping to set the correct mimetype of application/json for a .json file' do
74
+ @ai = described_class.new(TEST_JSON_FILE)
75
+ expect(@ai.exif_mimetype).to be_nil # exif returns nil
76
+ expect(@ai.file_mimetype).to eq('text/plain') # unix file system command returns plain text
77
+ expect(@ai.mimetype).to eq('application/json') # but our configured mapping overrides both and returns application/json
78
+ end
79
+
73
80
  it 'sets the correct mimetype of image/tiff for .tif files' do
74
81
  @ai = described_class.new(TEST_TIF_INPUT_FILE)
75
82
  expect(@ai.mimetype).to eq('image/tiff')
data/spec/spec_helper.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  require 'simplecov'
4
4
  SimpleCov.start
5
5
 
6
- bootfile = File.expand_path("#{File.dirname(__FILE__)}/../config/boot")
7
- require bootfile
6
+ require File.expand_path("#{File.dirname(__FILE__)}/../config/boot")
7
+ require 'byebug'
8
8
 
9
9
  RSpec.configure do |config|
10
10
  config.order = 'random'
@@ -18,6 +18,7 @@ TEST_TIF_INPUT_FILE2 = File.join(TEST_INPUT_DIR, 'test2.tif')
18
18
  TEST_JPEG_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jpg')
19
19
  TEST_JP2_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.jp2')
20
20
  TEST_JP2_INPUT_FILE2 = File.join(TEST_INPUT_DIR, 'test2.jp2')
21
+ TEST_SVG_INPUT_FILE = File.join(TEST_INPUT_DIR, 'test.svg')
21
22
  TEST_JP2_OUTPUT_FILE = File.join(TEST_OUTPUT_DIR, 'test.jp2')
22
23
  TEST_PDF_FILE = File.join(TEST_INPUT_DIR, 'test.pdf')
23
24
 
@@ -54,6 +55,8 @@ TEST_RES3_TEI = File.join(TEST_INPUT_DIR, 'res3_teifile.txt')
54
55
 
55
56
  TEST_FILE_NO_EXIF = File.join(TEST_INPUT_DIR, 'file_with_no_exif.xml')
56
57
 
58
+ TEST_JSON_FILE = File.join(TEST_INPUT_DIR, 'test.json')
59
+
57
60
  TEST_OBJ_FILE = File.join(TEST_INPUT_DIR, 'someobject.obj')
58
61
  TEST_PLY_FILE = File.join(TEST_INPUT_DIR, 'someobject.ply')
59
62
 
@@ -0,0 +1 @@
1
+ {some: 'thing'}
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="507.3" height="508.2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden"><defs><clipPath id="clip0"><rect x="2361" y="213" width="507" height="508"/></clipPath></defs><g clip-path="url(#clip0)" transform="translate(-2361 -213)"><path d="M2361 467C2361 326.72 2474.5 213 2614.5 213 2754.5 213 2868 326.72 2868 467 2868 607.28 2754.5 721 2614.5 721 2474.5 721 2361 607.28 2361 467Z" fill="#BF9000" fill-rule="evenodd"/></g></svg>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: assembly-objectfile
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.1
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Mangiafico
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2021-03-16 00:00:00.000000000 Z
14
+ date: 2022-02-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -263,7 +263,9 @@ files:
263
263
  - spec/test_data/input/someobject.obj
264
264
  - spec/test_data/input/someobject.ply
265
265
  - spec/test_data/input/test.jp2
266
+ - spec/test_data/input/test.json
266
267
  - spec/test_data/input/test.pdf
268
+ - spec/test_data/input/test.svg
267
269
  - spec/test_data/input/test.tif
268
270
  - spec/test_data/input/test2.jp2
269
271
  - spec/test_data/input/test2.tif
@@ -278,16 +280,19 @@ require_paths:
278
280
  - lib
279
281
  required_ruby_version: !ruby/object:Gem::Requirement
280
282
  requirements:
281
- - - "~>"
283
+ - - ">="
282
284
  - !ruby/object:Gem::Version
283
285
  version: '2.5'
286
+ - - "<"
287
+ - !ruby/object:Gem::Version
288
+ version: '4'
284
289
  required_rubygems_version: !ruby/object:Gem::Requirement
285
290
  requirements:
286
291
  - - ">="
287
292
  - !ruby/object:Gem::Version
288
293
  version: '0'
289
294
  requirements: []
290
- rubygems_version: 3.2.14
295
+ rubygems_version: 3.2.32
291
296
  signing_key:
292
297
  specification_version: 4
293
298
  summary: Ruby immplementation of file services needed to prepare objects to be accessioned
@@ -326,7 +331,9 @@ test_files:
326
331
  - spec/test_data/input/someobject.obj
327
332
  - spec/test_data/input/someobject.ply
328
333
  - spec/test_data/input/test.jp2
334
+ - spec/test_data/input/test.json
329
335
  - spec/test_data/input/test.pdf
336
+ - spec/test_data/input/test.svg
330
337
  - spec/test_data/input/test.tif
331
338
  - spec/test_data/input/test2.jp2
332
339
  - spec/test_data/input/test2.tif