moab-versioning 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  - - ">="