moab-versioning 4.3.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/moab.rb +2 -1
  3. data/lib/moab/bagger.rb +6 -1
  4. data/lib/moab/config.rb +40 -7
  5. data/lib/moab/deposit_bag_validator.rb +19 -14
  6. data/lib/moab/exceptions.rb +2 -0
  7. data/lib/moab/file_group.rb +6 -3
  8. data/lib/moab/file_group_difference.rb +3 -0
  9. data/lib/moab/file_group_difference_subset.rb +2 -0
  10. data/lib/moab/file_instance.rb +3 -0
  11. data/lib/moab/file_instance_difference.rb +2 -0
  12. data/lib/moab/file_inventory.rb +4 -0
  13. data/lib/moab/file_inventory_difference.rb +2 -0
  14. data/lib/moab/file_manifestation.rb +3 -0
  15. data/lib/moab/file_signature.rb +7 -2
  16. data/lib/moab/signature_catalog.rb +3 -3
  17. data/lib/moab/signature_catalog_entry.rb +2 -0
  18. data/lib/moab/stanford.rb +2 -0
  19. data/lib/moab/storage_object.rb +6 -0
  20. data/lib/moab/storage_object_validator.rb +22 -8
  21. data/lib/moab/storage_object_version.rb +7 -0
  22. data/lib/moab/storage_repository.rb +48 -6
  23. data/lib/moab/storage_services.rb +9 -0
  24. data/lib/moab/utc_time.rb +2 -0
  25. data/lib/moab/verification_result.rb +4 -3
  26. data/lib/moab/version_metadata.rb +2 -0
  27. data/lib/moab/version_metadata_entry.rb +2 -0
  28. data/lib/moab/version_metadata_event.rb +2 -0
  29. data/lib/serializer.rb +2 -0
  30. data/lib/serializer/manifest.rb +2 -0
  31. data/lib/serializer/serializable.rb +5 -0
  32. data/lib/stanford/active_fedora_object.rb +2 -0
  33. data/lib/stanford/content_inventory.rb +4 -0
  34. data/lib/stanford/dor_metadata.rb +2 -0
  35. data/lib/stanford/moab_storage_directory.rb +4 -2
  36. data/lib/stanford/storage_object_validator.rb +2 -0
  37. data/lib/stanford/storage_repository.rb +4 -0
  38. data/lib/stanford/storage_services.rb +2 -0
  39. metadata +18 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd9a6b4c49a9ab93e011a23004c0c21b74878ff7dc46c29b022c56b83627c3bb
4
- data.tar.gz: 065bb99748c0e06d5f3fafebc9b75552e1585709e170d27b27a5f14cb7b1db85
3
+ metadata.gz: dcb99d73bd625e8cbba0201f1dea7f6ae4925806df623e2a1e52198827f5b1c7
4
+ data.tar.gz: cb53aea7e39eabf83f8f80e0d05b70fe4a73e4376e0a6e054fb912b1225460f1
5
5
  SHA512:
6
- metadata.gz: 2efdbe79de69d26b41de7de0052ade6e3c8cf1a8651e6e05d093b889cb0de0ac47061663951bef33082012719b3f5774ff37ced11ef210a8f7a67cfbc7bbb7b2
7
- data.tar.gz: cd9518df71844ea61f4b036d08d51e2c86456c28492404265b8bd68d8510db1556ac359abd3ae95736011431ebab6bbe4a804530875e060b278dd54a9e57aff5
6
+ metadata.gz: af674dbff0e829b11da52850800fd2b3365e4ebc27d6629cefe7a71de0961bab884e7fb406be515a93a6387e48c5eb90a170144177fef9655331b9517732c298
7
+ data.tar.gz: d858888aad9e8557b33471f02c600e94217eba5ac213f27469fd7cc745f79752c9699e53c58d007f9c6fd39202d17f5e14da1a5761994309b2e5047ca76e0731
data/lib/moab.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Moab is a module that provides a distintive namespace for the collection of classes it contains.
2
4
  #
3
5
  # ====Data Model
@@ -33,7 +35,6 @@ module Moab
33
35
  end
34
36
 
35
37
  require 'serializer'
36
- require 'confstruct/configuration'
37
38
  require 'moab/config'
38
39
  require 'moab/utc_time'
39
40
  require 'moab/file_signature'
data/lib/moab/bagger.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A class used to create a BagIt package from a version inventory and a set of source files.
3
5
  # The {#fill_bag} method is called with a package_mode parameter that specifies
@@ -141,6 +143,7 @@ module Moab
141
143
  def deposit_group(group_id, source_dir)
142
144
  group = bag_inventory.group(group_id)
143
145
  return nil? if group.nil? || group.files.empty?
146
+
144
147
  target_dir = bag_pathname.join('data', group_id)
145
148
  group.path_list.each do |relative_path|
146
149
  source = source_dir.join(relative_path)
@@ -158,6 +161,7 @@ module Moab
158
161
  def reconstuct_group(group_id, storage_object_dir)
159
162
  group = bag_inventory.group(group_id)
160
163
  return nil? if group.nil? || group.files.empty?
164
+
161
165
  target_dir = bag_pathname.join('data', group_id)
162
166
  group.files.each do |file|
163
167
  catalog_entry = signature_catalog.signature_hash[file.signature]
@@ -260,6 +264,7 @@ module Moab
260
264
  shell_execute(tar_cmd.sub('--force-local', ''))
261
265
  end
262
266
  raise(MoabRuntimeError, "Unable to create tarfile #{tar_pathname}") unless tar_pathname.exist?
267
+
263
268
  true
264
269
  end
265
270
 
@@ -273,7 +278,7 @@ module Moab
273
278
  stdout
274
279
  else
275
280
  msg = "Shell command failed: [#{command}] caused by <STDERR = #{stderr}>"
276
- msg << " STDOUT = #{stdout}" if stdout && stdout.length.positive?
281
+ msg << " STDOUT = #{stdout}" if stdout&.length&.positive?
277
282
  raise(MoabStandardError, msg)
278
283
  end
279
284
  rescue SystemCallError => e
data/lib/moab/config.rb CHANGED
@@ -1,10 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
- # @return [Confstruct::Configuration] the configuration data
3
- Config = Confstruct::Configuration.new do
4
- storage_roots nil
5
- storage_trunk nil
6
- deposit_trunk nil
7
- path_method :druid_tree
8
- checksum_algos [:md5, :sha1, :sha256]
4
+ # A place to store configuration for the gem
5
+ class Configuration
6
+ def initialize
7
+ @path_method = :druid_tree
8
+ @checksum_algos = [:md5, :sha1, :sha256]
9
+ end
10
+
11
+ def configure(&block)
12
+ instance_eval(&block)
13
+ end
14
+
15
+ def storage_roots(new_value = nil)
16
+ @storage_roots = new_value if new_value
17
+ @storage_roots
18
+ end
19
+
20
+ def storage_trunk(new_value = nil)
21
+ @storage_trunk = new_value if new_value
22
+ @storage_trunk
23
+ end
24
+
25
+ def deposit_trunk(new_value = nil)
26
+ @deposit_trunk = new_value if new_value
27
+ @deposit_trunk
28
+ end
29
+
30
+ def path_method(new_value = nil)
31
+ @path_method = new_value if new_value
32
+ @path_method
33
+ end
34
+
35
+ def checksum_algos(new_value = nil)
36
+ @checksum_algos = new_value if new_value
37
+ @checksum_algos
38
+ end
9
39
  end
40
+
41
+ # @return [Moab::Configuration] the configuration data
42
+ Config = Configuration.new
10
43
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # Given a deposit bag, ensures the contents valid for becoming a StorageObjectVersion
3
5
  # this is a Shameless Green implementation, combining code from:
@@ -30,23 +32,23 @@ module Moab
30
32
  VERSION_MISSING_FROM_FILE => "Version xml file %{version_file} missing data at %{xpath} containing version id"
31
33
  }.freeze
32
34
 
33
- REQUIRED_MANIFEST_CHECKSUM_TYPE = 'sha256'.freeze
35
+ REQUIRED_MANIFEST_CHECKSUM_TYPE = 'sha256'
34
36
  RECOGNIZED_CHECKSUM_ALGORITHMS = %i[md5 sha1 sha256 sha384 sha512].freeze
35
37
 
36
- TAGMANIFEST = 'tagmanifest'.freeze
37
- MANIFEST = 'manifest'.freeze
38
- DATA_DIR_BASENAME = 'data'.freeze
39
- BAG_INFO_TXT_BASENAME = 'bag-info.txt'.freeze
40
- VERSION_ADDITIONS_BASENAME = 'versionAdditions.xml'.freeze
41
- VERSION_INVENTORY_BASENAME = 'versionInventory.xml'.freeze
42
- VERSION_METADATA_PATH = "#{DATA_DIR_BASENAME}/metadata/versionMetadata.xml".freeze
38
+ TAGMANIFEST = 'tagmanifest'
39
+ MANIFEST = 'manifest'
40
+ DATA_DIR_BASENAME = 'data'
41
+ BAG_INFO_TXT_BASENAME = 'bag-info.txt'
42
+ VERSION_ADDITIONS_BASENAME = 'versionAdditions.xml'
43
+ VERSION_INVENTORY_BASENAME = 'versionInventory.xml'
44
+ VERSION_METADATA_PATH = "#{DATA_DIR_BASENAME}/metadata/versionMetadata.xml"
43
45
 
44
46
  REQUIRED_BAG_FILES = [
45
47
  DATA_DIR_BASENAME,
46
- 'bagit.txt'.freeze,
48
+ 'bagit.txt',
47
49
  BAG_INFO_TXT_BASENAME,
48
- "#{MANIFEST}-#{REQUIRED_MANIFEST_CHECKSUM_TYPE}.txt".freeze,
49
- "#{TAGMANIFEST}-#{REQUIRED_MANIFEST_CHECKSUM_TYPE}.txt".freeze,
50
+ "#{MANIFEST}-#{REQUIRED_MANIFEST_CHECKSUM_TYPE}.txt",
51
+ "#{TAGMANIFEST}-#{REQUIRED_MANIFEST_CHECKSUM_TYPE}.txt",
50
52
  VERSION_ADDITIONS_BASENAME,
51
53
  VERSION_INVENTORY_BASENAME,
52
54
  VERSION_METADATA_PATH
@@ -64,6 +66,7 @@ module Moab
64
66
  def validation_errors
65
67
  return [single_error_hash(BAG_DIR_NOT_FOUND, bag_dir: deposit_bag_pathname)] unless deposit_bag_pathname.exist?
66
68
  return result_array unless required_bag_files_exist?
69
+
67
70
  verify_version
68
71
  verify_tagmanifests
69
72
  verify_payload_size
@@ -112,6 +115,7 @@ module Moab
112
115
  doc = Nokogiri::XML(File.open(pathname.to_s), &:strict)
113
116
  version_id = doc.xpath(xpath).last.text unless doc.xpath(xpath).empty?
114
117
  return version_id.to_i if version_id
118
+
115
119
  err_data = {
116
120
  version_file: pathname,
117
121
  xpath: xpath
@@ -129,6 +133,7 @@ module Moab
129
133
 
130
134
  def verify_version_from_xml_file(file_pathname, found)
131
135
  return if found == expected_new_version
136
+
132
137
  err_data = {
133
138
  file_pathname: file_pathname,
134
139
  new_version: expected_new_version,
@@ -251,6 +256,7 @@ module Moab
251
256
  end
252
257
  end
253
258
  return if diff_hash.empty?
259
+
254
260
  err_data = {
255
261
  manifest_type: manifest_type,
256
262
  diffs: diff_hash
@@ -266,9 +272,7 @@ module Moab
266
272
  checksum_types_to_compare.each do |type|
267
273
  left_checksum = left_checksums[type]
268
274
  right_checksum = right_checksums[type]
269
- if left_checksum != right_checksum
270
- diff_hash[type] = { left_label => left_checksum, right_label => right_checksum }
271
- end
275
+ diff_hash[type] = { left_label => left_checksum, right_label => right_checksum } if left_checksum != right_checksum
272
276
  end
273
277
  diff_hash.empty? ? nil : diff_hash
274
278
  end
@@ -277,6 +281,7 @@ module Moab
277
281
  sizes_from_bag_info_file = bag_info_payload_size
278
282
  generated_sizes = generated_payload_size
279
283
  return if sizes_from_bag_info_file == generated_sizes
284
+
280
285
  err_data = {
281
286
  bag_info_sizes: sizes_from_bag_info_file,
282
287
  generated_sizes: generated_sizes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  class MoabRuntimeError < RuntimeError; end
3
5
  class MoabStandardError < StandardError; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A container for a standard subset of a digital objects {FileManifestation} objects
3
5
  # Used to segregate depositor content from repository metadata files
@@ -161,9 +163,11 @@ module Moab
161
163
  # @return [Boolean] Test whether the given path is contained within the {#base_directory}
162
164
  def is_descendent_of_base?(pathname)
163
165
  raise(MoabRuntimeError, "base_directory has not been set") if @base_directory.nil?
166
+
164
167
  is_descendent = false
165
168
  pathname.expand_path.ascend { |ancestor| is_descendent ||= (ancestor == @base_directory) }
166
169
  raise(MoabRuntimeError, "#{pathname} is not a descendent of #{@base_directory}") unless is_descendent
170
+
167
171
  is_descendent
168
172
  end
169
173
 
@@ -203,6 +207,7 @@ module Moab
203
207
  validated ||= is_descendent_of_base?(pathname)
204
208
  pathname.children.sort.each do |child|
205
209
  next if child.basename.to_s == '.DS_Store'
210
+
206
211
  if child.directory?
207
212
  harvest_directory(child, recursive, validated) if recursive
208
213
  else
@@ -222,9 +227,7 @@ module Moab
222
227
  instance = FileInstance.new.instance_from_file(pathname, @base_directory)
223
228
  if @signatures_from_bag && @signatures_from_bag[pathname]
224
229
  signature = @signatures_from_bag[pathname]
225
- unless signature.complete?
226
- signature = signature.normalized_signature(pathname)
227
- end
230
+ signature = signature.normalized_signature(pathname) unless signature.complete?
228
231
  else
229
232
  signature = FileSignature.new.signature_from_file(pathname)
230
233
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # Performs analysis and reports the differences between two matching {FileGroup} objects.
3
5
  # The descending elements of the report hold a detailed breakdown of file-level differences, organized by change type.
@@ -132,6 +134,7 @@ module Moab
132
134
 
133
135
  def subsets=(array)
134
136
  return unless array
137
+
135
138
  array.each { |subset| subset_hash[subset.change.to_sym] = subset }
136
139
  end
137
140
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A container for reporting a set of file-level differences of the type specified by the change attribute
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # The file path and last modification date properties of a file
3
5
  #
@@ -52,6 +54,7 @@ module Moab
52
54
  # @return [Boolean] Returns true if self and other have the same path.
53
55
  def eql?(other)
54
56
  return false unless other.respond_to?(:path) # Cannot equal an incomparable type!
57
+
55
58
  path == other.path
56
59
  end
57
60
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A container for recording difference information at the file level
3
5
  # * If there was no change, the change type is set to <i>identical</i>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A structured container for recording information about a collection of related files.
3
5
  #
@@ -132,9 +134,11 @@ module Moab
132
134
  file_group = group(group_id)
133
135
  errmsg = "group #{group_id} not found for #{digital_object_id} - #{version_id}"
134
136
  raise FileNotFoundException, errmsg if file_group.nil?
137
+
135
138
  file_signature = file_group.path_hash[file_id]
136
139
  errmsg = "#{group_id} file #{file_id} not found for #{digital_object_id} - #{version_id}"
137
140
  raise FileNotFoundException, errmsg if file_signature.nil?
141
+
138
142
  file_signature
139
143
  end
140
144
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # Compares two {FileInventory} instances based primarily on file signatures and secondarily on file pathnames.
3
5
  # Although the usual use will be to compare the content of 2 different temporal versions of the same object,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A container for a file signature and all the physical file instances that have that signature
3
5
  # This element has one child {FileSignature} element, and one or more {FileInstance} elements
@@ -75,6 +77,7 @@ module Moab
75
77
  # @return [Boolean] True if {FileManifestation} objects have same content
76
78
  def ==(other)
77
79
  return false unless other.respond_to?(:signature) && other.respond_to?(:instances) # Cannot equal an incomparable type!
80
+
78
81
  (signature == other.signature) && (instances == other.instances)
79
82
  end
80
83
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # The fixity properties of a file, used to determine file content equivalence regardless of filename.
3
5
  # Placing this data in a class by itself facilitates using file size together with the MD5 and SHA1 checksums
@@ -128,10 +130,12 @@ module Moab
128
130
  def eql?(other)
129
131
  return false unless other.respond_to?(:size) && other.respond_to?(:checksums)
130
132
  return false if size.to_i != other.size.to_i
133
+
131
134
  self_checksums = checksums
132
135
  other_checksums = other.checksums
133
136
  matching_keys = self_checksums.keys & other_checksums.keys
134
137
  return false if matching_keys.empty?
138
+
135
139
  matching_keys.each do |key|
136
140
  return false if self_checksums[key] != other_checksums[key]
137
141
  end
@@ -176,6 +180,7 @@ module Moab
176
180
  def normalized_signature(pathname)
177
181
  sig_from_file = FileSignature.new.signature_from_file(pathname)
178
182
  return sig_from_file if eql?(sig_from_file)
183
+
179
184
  # The full signature from file is consistent with current values, or...
180
185
  # One or more of the fixity values is inconsistent, so raise an exception
181
186
  raise(MoabRuntimeError, "Signature inconsistent between inventory and file for #{pathname}: #{diff(sig_from_file).inspect}")
@@ -185,8 +190,8 @@ module Moab
185
190
  def self.checksum_names_for_type
186
191
  {
187
192
  md5: ['MD5'],
188
- sha1: ['SHA-1', 'SHA1'],
189
- sha256: ['SHA-256', 'SHA256']
193
+ sha1: %w[SHA-1 SHA1],
194
+ sha256: %w[SHA-256 SHA256]
190
195
  }
191
196
  end
192
197
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A digital object's Signature Catalog is derived from an filtered aggregation of the file inventories
3
5
  # of a digital object's set of versions. (see {#update})
@@ -181,9 +183,7 @@ module Moab
181
183
  version_inventory.groups.each do |group|
182
184
  group_addtions = FileGroup.new(:group_id => group.group_id)
183
185
  group.files.each do |file|
184
- unless @signature_hash.key?(file.signature)
185
- group_addtions.add_file_instance(file.signature, file.instances[0])
186
- end
186
+ group_addtions.add_file_instance(file.signature, file.instances[0]) unless @signature_hash.key?(file.signature)
187
187
  end
188
188
  version_additions.groups << group_addtions unless group_addtions.files.empty?
189
189
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A file-level entry in a digital object's {SignatureCatalog}.
3
5
  # It has a child {FileSignature} element that identifies the file's contents (the bytestream)
data/lib/moab/stanford.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'moab'
2
4
  require 'stanford/content_inventory'
3
5
  require 'stanford/dor_metadata'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A class to represent a digital object's repository storage location
3
5
  # and methods for
@@ -113,6 +115,7 @@ module Moab
113
115
  storage_filepath = @object_pathname.join(catalog_filepath)
114
116
  errmsg = "#{catalog_filepath} missing from storage location #{storage_filepath}"
115
117
  raise FileNotFoundException, errmsg unless storage_filepath.exist?
118
+
116
119
  storage_filepath
117
120
  end
118
121
 
@@ -127,6 +130,7 @@ module Moab
127
130
  def version_id_list
128
131
  list = []
129
132
  return list unless @object_pathname.exist?
133
+
130
134
  @object_pathname.children.each do |dirname|
131
135
  vnum = dirname.basename.to_s
132
136
  list << vnum[1..-1].to_i if vnum =~ /^v(\d+)$/
@@ -163,6 +167,7 @@ module Moab
163
167
  if version_inventory.version_id != (current_version_id + 1)
164
168
  raise(MoabRuntimeError, "version mismatch - current: #{current_version_id} new: #{version_inventory.version_id}")
165
169
  end
170
+
166
171
  true
167
172
  end
168
173
 
@@ -188,6 +193,7 @@ module Moab
188
193
  # * Current version + 1 is used for creation of a new version
189
194
  def storage_object_version(version_id)
190
195
  raise(MoabRuntimeError, "Version ID not specified") unless version_id
196
+
191
197
  StorageObjectVersion.new(self, version_id)
192
198
  end
193
199
 
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Moab
4
6
  # Given a druid path, are the contents actually a well-formed Moab?
5
7
  # Shameless green: repetitious code included.
6
8
  class StorageObjectValidator
7
- METADATA_DIR = "metadata".freeze
8
- CONTENT_DIR = "content".freeze
9
+ METADATA_DIR = "metadata"
10
+ CONTENT_DIR = "content"
9
11
  EXPECTED_DATA_SUB_DIRS = [CONTENT_DIR, METADATA_DIR].freeze
10
12
  IMPLICIT_DIRS = ['.', '..'].freeze # unlike Find.find, Dir.entries returns the current/parent dirs
11
- DATA_DIR = "data".freeze
12
- MANIFESTS_DIR = 'manifests'.freeze
13
+ DATA_DIR = "data"
14
+ MANIFESTS_DIR = 'manifests'
13
15
  EXPECTED_VERSION_SUB_DIRS = [DATA_DIR, MANIFESTS_DIR].freeze
14
16
  MANIFEST_INVENTORY_PATH = File.join(MANIFESTS_DIR, "manifestInventory.xml").freeze
15
17
  SIGNATURE_CATALOG_PATH = File.join(MANIFESTS_DIR, "signatureCatalog.xml").freeze
@@ -90,6 +92,7 @@ module Moab
90
92
  def check_sequential_version_dirs
91
93
  version_directories.each_with_index do |dir_name, index|
92
94
  next if dir_name[1..-1].to_i == index + 1 # version numbering starts at 1, array indexing at 0
95
+
93
96
  return [result_hash(VERSIONS_NOT_IN_ORDER, version_directories)]
94
97
  end
95
98
  []
@@ -113,6 +116,7 @@ module Moab
113
116
  return expected_version_sub_dirs(version_path, version) if count == EXPECTED_VERSION_SUB_DIRS.size
114
117
  return found_unexpected(version_sub_dirs, version, EXPECTED_VERSION_SUB_DIRS) if count > EXPECTED_VERSION_SUB_DIRS.size
115
118
  return missing_dir(version_sub_dirs, version, EXPECTED_VERSION_SUB_DIRS) if count < EXPECTED_VERSION_SUB_DIRS.size
119
+
116
120
  []
117
121
  end
118
122
 
@@ -122,15 +126,20 @@ module Moab
122
126
  data_sub_dirs = directory_entries(data_dir_path)
123
127
  errors.concat check_data_sub_dirs(version, data_sub_dirs)
124
128
  errors.concat check_metadata_dir_files_only(version_path) if errors.empty?
125
- errors.concat check_optional_content_dir(version_path, allow_content_subdirs) if data_sub_dirs.include?('content') && errors.empty?
129
+ if data_sub_dirs.include?('content') && errors.empty?
130
+ errors.concat check_optional_content_dir(version_path, allow_content_subdirs)
131
+ end
126
132
  errors
127
133
  end
128
134
 
129
135
  def check_data_sub_dirs(version, data_sub_dirs)
130
136
  return found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS) if data_sub_dirs.size > EXPECTED_DATA_SUB_DIRS.size
137
+
131
138
  errors = []
132
139
  errors.concat missing_dir(data_sub_dirs, version, [METADATA_DIR]) unless data_sub_dirs.include?(METADATA_DIR)
133
- errors.concat found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS) unless data_sub_dirs.to_set.subset?(EXPECTED_DATA_SUB_DIRS.to_set)
140
+ unless data_sub_dirs.to_set.subset?(EXPECTED_DATA_SUB_DIRS.to_set)
141
+ errors.concat found_unexpected(data_sub_dirs, version, EXPECTED_DATA_SUB_DIRS)
142
+ end
134
143
  errors
135
144
  end
136
145
 
@@ -139,7 +148,9 @@ module Moab
139
148
  content_dir_path = File.join(version_path, DATA_DIR, CONTENT_DIR)
140
149
  errors << result_hash(NO_FILES_IN_CONTENT_DIR, basename(version_path)) if directory_entries(content_dir_path).empty?
141
150
  content_sub_dir = contains_sub_dir?(content_dir_path)
142
- errors << result_hash(CONTENT_SUB_DIRS_DETECTED, version: basename(version_path), dir: content_sub_dir) if content_sub_dir && !allow_content_subdirs
151
+ if content_sub_dir && !allow_content_subdirs
152
+ errors << result_hash(CONTENT_SUB_DIRS_DETECTED, version: basename(version_path), dir: content_sub_dir)
153
+ end
143
154
  if allow_content_subdirs && contains_sub_dir?(content_dir_path) && contains_forbidden_content_sub_dir?(content_dir_path)
144
155
  errors << result_hash(BAD_SUB_DIR_IN_CONTENT_DIR, basename(version_path))
145
156
  end
@@ -159,7 +170,9 @@ module Moab
159
170
  metadata_dir_path = File.join(version_path, DATA_DIR, METADATA_DIR)
160
171
  errors << result_hash(NO_FILES_IN_METADATA_DIR, basename(version_path)) if directory_entries(metadata_dir_path).empty?
161
172
  metadata_sub_dir = contains_sub_dir?(metadata_dir_path)
162
- errors << result_hash(METADATA_SUB_DIRS_DETECTED, version: basename(version_path), dir: metadata_sub_dir) if metadata_sub_dir
173
+ if metadata_sub_dir
174
+ errors << result_hash(METADATA_SUB_DIRS_DETECTED, version: basename(version_path), dir: metadata_sub_dir)
175
+ end
163
176
  errors
164
177
  end
165
178
 
@@ -228,6 +241,7 @@ module Moab
228
241
 
229
242
  def check_required_manifest_files(dir, version)
230
243
  return [result_hash(NO_FILES_IN_MANIFEST_DIR, version)] unless contains_file?(File.join(dir, MANIFESTS_DIR))
244
+
231
245
  errors = []
232
246
  errors << result_hash(NO_MANIFEST_INVENTORY, version) unless File.exist?(File.join(dir, MANIFEST_INVENTORY_PATH))
233
247
  errors << result_hash(NO_SIGNATURE_CATALOG, version) unless File.exist?(File.join(dir, SIGNATURE_CATALOG_PATH))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A class to represent a version subdirectory within an object's home directory in preservation storage
3
5
  # ====Data Model
@@ -68,6 +70,7 @@ module Moab
68
70
  def find_filepath(file_category, file_id)
69
71
  this_version_filepath = file_pathname(file_category, file_id)
70
72
  return this_version_filepath if this_version_filepath.exist?
73
+
71
74
  if file_category == 'manifest'
72
75
  msg = "manifest file #{file_id} not found for #{@storage_object.digital_object_id} - #{@version_id}"
73
76
  raise FileNotFoundException, msg
@@ -109,6 +112,7 @@ module Moab
109
112
  def file_inventory(type)
110
113
  if version_id > 0
111
114
  return @inventory_cache[type] if @inventory_cache.key?(type)
115
+
112
116
  @inventory_cache[type] = FileInventory.read_xml_file(@version_pathname.join('manifests'), type)
113
117
  else
114
118
  groups = %w[content metadata].collect { |id| FileGroup.new(:group_id => id) }
@@ -136,6 +140,7 @@ module Moab
136
140
  # @return [void] Create the version subdirectory and move files into it
137
141
  def ingest_bag_data(bag_dir)
138
142
  raise(MoabRuntimeError, "Version already exists: #{@version_pathname}") if @version_pathname.exist?
143
+
139
144
  @version_pathname.join('manifests').mkpath
140
145
  bag_dir = Pathname(bag_dir)
141
146
  ingest_dir(bag_dir.join('data'), @version_pathname.join('data'))
@@ -150,6 +155,7 @@ module Moab
150
155
  # @return [void] recursively link or copy the source directory contents to the target directory
151
156
  def ingest_dir(source_dir, target_dir, use_links = true)
152
157
  raise(MoabRuntimeError, "cannot copy - target already exists: #{target_dir.expand_path}") if target_dir.exist?
158
+
153
159
  target_dir.mkpath
154
160
  source_dir.children.each do |child|
155
161
  if child.directory?
@@ -321,6 +327,7 @@ module Moab
321
327
  # @return [null] Deactivate this object version by moving it to another directory. (Used by restore operation)
322
328
  def deactivate(timestamp)
323
329
  return unless @version_pathname.exist?
330
+
324
331
  timestamp_pathname = @version_pathname.parent.join(timestamp.utc.iso8601.gsub(/[-:]/, ''))
325
332
  timestamp_pathname.mkpath
326
333
  demote_pathame = timestamp_pathname.join(@version_pathname.basename)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A class to represent the SDR repository store
3
5
  #
@@ -19,8 +21,10 @@ module Moab
19
21
  def storage_roots
20
22
  unless defined?(@storage_roots)
21
23
  raise(MoabRuntimeError, "Moab::Config.storage_roots not found in config file") if Moab::Config.storage_roots.nil?
24
+
22
25
  @storage_roots = [Moab::Config.storage_roots].flatten.collect { |filesystem| Pathname(filesystem) }
23
26
  raise(MoabRuntimeError, "Moab::Config.storage_roots empty") if @storage_roots.empty?
27
+
24
28
  @storage_roots.each { |root| raise(MoabRuntimeError, "Storage root #{root} not found on system") unless root.exist? }
25
29
  end
26
30
  @storage_roots
@@ -30,7 +34,8 @@ module Moab
30
34
  def storage_trunk
31
35
  unless defined?(@storage_trunk)
32
36
  raise(MoabRuntimeError, "Moab::Config.storage_trunk not found in config file") if Moab::Config.storage_trunk.nil?
33
- @storage_trunk = Moab::Config.storage_trunk
37
+
38
+ @storage_trunk = Moab::Config.storage_trunk
34
39
  end
35
40
  @storage_trunk
36
41
  end
@@ -50,7 +55,7 @@ module Moab
50
55
  unless defined?(@deposit_trunk)
51
56
  # do not raise error. this parameter will be ignored if missing
52
57
  # raise "Moab::Config.deposit_trunk not found in config file" if Moab::Config.deposit_trunk.nil?
53
- @deposit_trunk = Moab::Config.deposit_trunk
58
+ @deposit_trunk = Moab::Config.deposit_trunk
54
59
  end
55
60
  @deposit_trunk
56
61
  end
@@ -71,6 +76,7 @@ module Moab
71
76
  storage_roots.each do |root|
72
77
  root_trunk = root.join(storage_trunk)
73
78
  raise(MoabRuntimeError, "Storage area not found at #{root_trunk}") unless root_trunk.exist?
79
+
74
80
  root_trunk_branch = root_trunk.join(branch)
75
81
  return root if root_trunk_branch.exist?
76
82
  end
@@ -80,6 +86,7 @@ module Moab
80
86
  storage_roots.each do |root|
81
87
  root_trunk = root.join(deposit_trunk)
82
88
  raise(MoabRuntimeError, "Deposit area not found at #{root_trunk}") unless root_trunk.exist?
89
+
83
90
  root_trunk_branch = root_trunk.join(branch)
84
91
  return root if root_trunk_branch.exist?
85
92
  end
@@ -93,10 +100,35 @@ module Moab
93
100
  # @return [StorageObject] The representation of a digitial object's storage directory, which might not exist yet.
94
101
  def find_storage_object(object_id, include_deposit = false)
95
102
  root = find_storage_root(object_id, include_deposit)
96
- storage_pathname = root.join(storage_trunk, storage_branch(object_id))
97
- storage_object = StorageObject.new(object_id, storage_pathname)
98
- storage_object.storage_root = root
99
- storage_object
103
+ create_storage_object(object_id, root)
104
+ end
105
+
106
+ # @param object_id [String] The identifier of the digital object
107
+ # @param include_deposit [Boolean] specifies whether to look in deposit areas for objects in process of initial ingest
108
+ # @return [Array<StorageObject>] Representations of a digitial object's storage directories, or an empty array if none found.
109
+ def search_storage_objects(object_id, include_deposit = false)
110
+ storage_objects = []
111
+ # Search for the object's home directory in the storage areas
112
+ branch = storage_branch(object_id)
113
+ storage_roots.each do |root|
114
+ root_trunk = root.join(storage_trunk)
115
+ raise(MoabRuntimeError, "Storage area not found at #{root_trunk}") unless root_trunk.exist?
116
+
117
+ root_trunk_branch = root_trunk.join(branch)
118
+ storage_objects << create_storage_object(object_id, root) if root_trunk_branch.exist?
119
+ end
120
+ # Search for the object's directory in the deposit areas
121
+ if include_deposit && deposit_trunk
122
+ branch = deposit_branch(object_id)
123
+ storage_roots.each do |root|
124
+ root_trunk = root.join(deposit_trunk)
125
+ raise(MoabRuntimeError, "Deposit area not found at #{root_trunk}") unless root_trunk.exist?
126
+
127
+ root_trunk_branch = root_trunk.join(branch)
128
+ storage_objects << create_storage_object(object_id, root) if root_trunk_branch.exist?
129
+ end
130
+ end
131
+ storage_objects
100
132
  end
101
133
 
102
134
  # @param object_id [String] The identifier of the digital object whose size is desired
@@ -118,6 +150,7 @@ module Moab
118
150
  storage_object = find_storage_object(object_id)
119
151
  unless storage_object.object_pathname.exist?
120
152
  raise ObjectNotFoundException, "No storage object found for #{object_id}" unless create
153
+
121
154
  storage_object.object_pathname.mkpath
122
155
  end
123
156
  storage_object
@@ -129,5 +162,14 @@ module Moab
129
162
  def store_new_object_version(druid, bag_pathname)
130
163
  storage_object(druid, create = true).ingest_bag(bag_pathname)
131
164
  end
165
+
166
+ private
167
+
168
+ def create_storage_object(object_id, root)
169
+ storage_pathname = root.join(storage_trunk, storage_branch(object_id))
170
+ storage_object = StorageObject.new(object_id, storage_pathname)
171
+ storage_object.storage_root = root
172
+ storage_object
173
+ end
132
174
  end
133
175
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # An interface class to support access to SDR storage via a RESTful server
3
5
  #
@@ -41,6 +43,13 @@ module Moab
41
43
  @@repository.find_storage_object(object_id, include_deposit)
42
44
  end
43
45
 
46
+ # @param object_id [String] The identifier of the digital object
47
+ # @param [Object] include_deposit
48
+ # @return [Array<StorageObject>] Representations of a digitial object's storage directories, or an empty array if none found.
49
+ def self.search_storage_objects(object_id, include_deposit = false)
50
+ @@repository.search_storage_objects(object_id, include_deposit)
51
+ end
52
+
44
53
  # @param object_id [String] The identifier of the digital object whose size is desired
45
54
  # @param include_deposit [Boolean] specifies whether to look in deposit areas for objects in process of initial ingest
46
55
  # @return [Integer] the size occupied on disk by the storage object, in bytes. this is the entire moab (all versions).
data/lib/moab/utc_time.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # Timestamp conversion methods.
3
5
  class UtcTime
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A recursive "Tree" type object for verifications
3
5
  class VerificationResult
@@ -52,10 +54,9 @@ module Moab
52
54
  # @return [Hash] The verification result serialized to a hash
53
55
  def to_hash(verbose = false, level = 0)
54
56
  hash = { 'verified' => verified }
55
- if verbose || !verified
56
- hash['details'] = details || subentities_to_hash(verbose, level)
57
- end
57
+ hash['details'] = details || subentities_to_hash(verbose, level) if verbose || !verified
58
58
  return hash if level > 0
59
+
59
60
  { entity => hash }
60
61
  end
61
62
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # The descriptive information about a digital object's collection of versions
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # The descriptive attributes of a digital object version.
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Moab
2
4
  # A container element to record object version lifecycle events with timestamps
3
5
  #
data/lib/serializer.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Serializer is a module containing classes whose methods faciliate serialization
2
4
  # of data fields to various formats. To obtain those benefits, a dependent class
3
5
  # should inherit from {Serializable} or {Manifest}
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Serializer
2
4
  # Subclass of {Serializable} that adds methods for marshalling/unmarshalling data
3
5
  # to a persistent XML file format.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Serializer
2
4
  # Some utility methods to faciliate serialization of data fields to Hash, JSON, or YAML shared by all subclasses.
3
5
  # This class assumes that HappyMapper is used for declaration of fields to be serialized.
@@ -21,6 +23,7 @@ module Serializer
21
23
  opts.each do |key, value|
22
24
  errmsg = "#{key} is not a variable name in #{self.class.name}"
23
25
  raise(Moab::MoabRuntimeError, errmsg) unless variable_names.include?(key.to_s) || key == :test
26
+
24
27
  instance_variable_set("@#{key}", value)
25
28
  end
26
29
  end
@@ -68,6 +71,7 @@ module Serializer
68
71
  # @return [String] For the current object instance, return the string to use as a hash key
69
72
  def key
70
73
  return send(key_name) if key_name
74
+
71
75
  nil
72
76
  end
73
77
 
@@ -117,6 +121,7 @@ module Serializer
117
121
  # @return [Hash] Generate a hash containing the differences between two objects of the same type
118
122
  def diff(other)
119
123
  raise(Moab::MoabRuntimeError, "Cannot compare different classes") if self.class != other.class
124
+
120
125
  left = other.to_hash
121
126
  right = to_hash
122
127
  if key.nil? || other.key.nil?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stanford
2
4
  # Utility Class for extracting content or other information from a Fedora Instance
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stanford
2
4
  # Stanford-specific utility methods for transforming contentMetadata to versionInventory and doing comparisons
3
5
  #
@@ -127,6 +129,7 @@ module Stanford
127
129
  def validate_content_metadata(content_metadata)
128
130
  result = validate_content_metadata_details(content_metadata)
129
131
  raise Moab::InvalidMetadataException, result[0] + " ..." unless result.empty?
132
+
130
133
  true
131
134
  end
132
135
 
@@ -176,6 +179,7 @@ module Stanford
176
179
  def remediate_content_metadata(content_metadata, content_group)
177
180
  return nil if content_metadata.nil?
178
181
  return content_metadata if content_group.nil? || content_group.files.empty?
182
+
179
183
  signature_for_path = content_group.path_hash
180
184
  @type_for_name = Moab::FileSignature.checksum_type_for_name
181
185
  @names_for_type = Moab::FileSignature.checksum_names_for_type
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stanford
2
4
  # Stanford-specific utility methods for interfacing with DOR metadata files
3
5
  #
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'find'
2
4
 
3
5
  module Stanford
4
6
  ##
5
7
  # methods for dealing with a directory which stores Moab objects
6
8
  class MoabStorageDirectory
7
- DRUID_TREE_REGEXP = '[[:lower:]]{2}/\\d{3}/[[:lower:]]{2}/\\d{4}'.freeze
8
- DRUID_REGEXP = '[[:lower:]]{2}\\d{3}[[:lower:]]{2}\\d{4}'.freeze
9
+ DRUID_TREE_REGEXP = '[[:lower:]]{2}/\\d{3}/[[:lower:]]{2}/\\d{4}'
10
+ DRUID_REGEXP = '[[:lower:]]{2}\\d{3}[[:lower:]]{2}\\d{4}'
9
11
 
10
12
  def self.find_moab_paths(storage_dir)
11
13
  Find.find(storage_dir) do |path|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stanford
2
4
  # druids are Stanford specific entities
3
5
  class StorageObjectValidator < Moab::StorageObjectValidator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'druid-tools'
2
4
 
3
5
  module Stanford
@@ -32,9 +34,11 @@ module Stanford
32
34
  # Note: this seems an odd place to do druid validation, but leaving it here for now
33
35
  syntax_msg = "Identifier has invalid suri syntax: #{object_id}"
34
36
  raise(Moab::InvalidSuriSyntaxError, syntax_msg + " nil or empty") if object_id.to_s.empty?
37
+
35
38
  identifier = object_id.split(':')[-1]
36
39
  raise(Moab::InvalidSuriSyntaxError, syntax_msg) if identifier.to_s.empty?
37
40
  raise(Moab::InvalidSuriSyntaxError, syntax_msg) unless DruidTools::Druid.valid?(identifier, true)
41
+
38
42
  DruidTools::Druid.new(identifier, true).tree.join(File::SEPARATOR)
39
43
  end
40
44
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stanford
2
4
  # An interface class to support access to SDR storage via a RESTful server
3
5
  class StorageServices < Moab::StorageServices
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moab-versioning
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Weber
@@ -11,24 +11,24 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-11-15 00:00:00.000000000 Z
14
+ date: 2020-01-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
- name: confstruct
17
+ name: druid-tools
18
18
  requirement: !ruby/object:Gem::Requirement
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: '0'
22
+ version: 1.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '0'
29
+ version: 1.0.0
30
30
  - !ruby/object:Gem::Dependency
31
- name: nokogiri
31
+ name: json
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - ">="
@@ -42,7 +42,7 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: '0'
44
44
  - !ruby/object:Gem::Dependency
45
- name: nokogiri-happymapper
45
+ name: nokogiri
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
@@ -56,7 +56,7 @@ dependencies:
56
56
  - !ruby/object:Gem::Version
57
57
  version: '0'
58
58
  - !ruby/object:Gem::Dependency
59
- name: json
59
+ name: nokogiri-happymapper
60
60
  requirement: !ruby/object:Gem::Requirement
61
61
  requirements:
62
62
  - - ">="
@@ -70,21 +70,7 @@ dependencies:
70
70
  - !ruby/object:Gem::Version
71
71
  version: '0'
72
72
  - !ruby/object:Gem::Dependency
73
- name: druid-tools
74
- requirement: !ruby/object:Gem::Requirement
75
- requirements:
76
- - - ">="
77
- - !ruby/object:Gem::Version
78
- version: 1.0.0
79
- type: :runtime
80
- prerelease: false
81
- version_requirements: !ruby/object:Gem::Requirement
82
- requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- version: 1.0.0
86
- - !ruby/object:Gem::Dependency
87
- name: equivalent-xml
73
+ name: coveralls
88
74
  requirement: !ruby/object:Gem::Requirement
89
75
  requirements:
90
76
  - - ">="
@@ -98,7 +84,7 @@ dependencies:
98
84
  - !ruby/object:Gem::Version
99
85
  version: '0'
100
86
  - !ruby/object:Gem::Dependency
101
- name: rake
87
+ name: equivalent-xml
102
88
  requirement: !ruby/object:Gem::Requirement
103
89
  requirements:
104
90
  - - ">="
@@ -112,7 +98,7 @@ dependencies:
112
98
  - !ruby/object:Gem::Version
113
99
  version: '0'
114
100
  - !ruby/object:Gem::Dependency
115
- name: rspec
101
+ name: pry-byebug
116
102
  requirement: !ruby/object:Gem::Requirement
117
103
  requirements:
118
104
  - - ">="
@@ -126,7 +112,7 @@ dependencies:
126
112
  - !ruby/object:Gem::Version
127
113
  version: '0'
128
114
  - !ruby/object:Gem::Dependency
129
- name: coveralls
115
+ name: rake
130
116
  requirement: !ruby/object:Gem::Requirement
131
117
  requirements:
132
118
  - - ">="
@@ -140,7 +126,7 @@ dependencies:
140
126
  - !ruby/object:Gem::Version
141
127
  version: '0'
142
128
  - !ruby/object:Gem::Dependency
143
- name: pry-byebug
129
+ name: rspec
144
130
  requirement: !ruby/object:Gem::Requirement
145
131
  requirements:
146
132
  - - ">="
@@ -159,28 +145,28 @@ dependencies:
159
145
  requirements:
160
146
  - - "~>"
161
147
  - !ruby/object:Gem::Version
162
- version: 0.50.0
148
+ version: 0.79.0
163
149
  type: :development
164
150
  prerelease: false
165
151
  version_requirements: !ruby/object:Gem::Requirement
166
152
  requirements:
167
153
  - - "~>"
168
154
  - !ruby/object:Gem::Version
169
- version: 0.50.0
155
+ version: 0.79.0
170
156
  - !ruby/object:Gem::Dependency
171
157
  name: rubocop-rspec
172
158
  requirement: !ruby/object:Gem::Requirement
173
159
  requirements:
174
160
  - - "~>"
175
161
  - !ruby/object:Gem::Version
176
- version: 1.18.0
162
+ version: 1.37.1
177
163
  type: :development
178
164
  prerelease: false
179
165
  version_requirements: !ruby/object:Gem::Requirement
180
166
  requirements:
181
167
  - - "~>"
182
168
  - !ruby/object:Gem::Version
183
- version: 1.18.0
169
+ version: 1.37.1
184
170
  description: Contains classes to process digital object version content and metadata
185
171
  email:
186
172
  - darren.weber@stanford.edu
@@ -237,7 +223,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
237
223
  requirements:
238
224
  - - "~>"
239
225
  - !ruby/object:Gem::Version
240
- version: '2.1'
226
+ version: '2.3'
241
227
  required_rubygems_version: !ruby/object:Gem::Requirement
242
228
  requirements:
243
229
  - - ">="