file_pipeline 0.0.6 → 0.0.7
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.
- checksums.yaml +4 -4
- data/README.rdoc +12 -10
- data/lib/file_pipeline/errors/failed_modification_error.rb +45 -13
- data/lib/file_pipeline/versioned_file.rb +42 -75
- data/lib/file_pipeline/versions/history.rb +106 -0
- data/lib/file_pipeline/versions.rb +22 -0
- data/lib/file_pipeline.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b25bf4205819b6d0df2fcbb9a879c7855fc2b0a3cb973774049f44a7d6965b8
|
4
|
+
data.tar.gz: 1191020063c4bb7669e9dfd88a03d539c7b081cd2f422decd87ac6bca288c86e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ccb8dabb09322d7c3b6b258c8e4e06edb3a7774e36c1fc26421794b8c53915b219a85c8c9bf07da2bf203cd949a8fc484a1db1cb8ddf6d8443a5c2ba724d4ff
|
7
|
+
data.tar.gz: 3e5a2ec367ab3a2d7280c9d6daaa41f6e3cadcba9b1b73bfdb891d4fef781bade2e4e5ffe970aee76e175ce43ea3ae82d967367f18b29f59dbffec180825262e
|
data/README.rdoc
CHANGED
@@ -54,7 +54,7 @@ instructions on how to create custom operations).
|
|
54
54
|
==== Basic set up with default operations
|
55
55
|
|
56
56
|
To define an operation, pass the class name of the operation in underscore
|
57
|
-
notation
|
57
|
+
notation without the containing module name, and any options to
|
58
58
|
{#define_operation}[rdoc-ref:FilePipeline::Pipeline#define_operation].
|
59
59
|
|
60
60
|
The example below adds an instance of
|
@@ -87,8 +87,9 @@ call <tt>#define_operation</tt> with the desired operations and options.
|
|
87
87
|
|
88
88
|
When file operations are to be used that are not included in the gem, place
|
89
89
|
the source files for the class definitions in one or more directories and
|
90
|
-
initialize the Pipeline object with the
|
91
|
-
be added to the
|
90
|
+
initialize the Pipeline object with the paths to those directories. The
|
91
|
+
directories will be added to the
|
92
|
+
{source directories}[rdoc-ref:FilePipeline.source_directories].
|
92
93
|
|
93
94
|
Directories are added to the source directories in reverse order, so that
|
94
95
|
directories added later will have precedence when searching source files. The
|
@@ -103,7 +104,7 @@ finally in the included default operations.
|
|
103
104
|
|
104
105
|
The basename for source files _must_ be the class name in underscore notation
|
105
106
|
without the containing module name. If, for example, the operation is
|
106
|
-
<tt>FileOperations::MyOperation</tt>, the source file basename
|
107
|
+
<tt>FileOperations::MyOperation</tt>, the source file basename has to be
|
107
108
|
<tt>'my_operation.rb'</tt>
|
108
109
|
|
109
110
|
my_pipeline = FilePipeline::Pipeline.new('~/custom_operations',
|
@@ -146,7 +147,7 @@ VersionedFile provides access to a files metadata via the
|
|
146
147
|
{#metadata}[rdoc-ref:FilePipeline::VersionedFile#metadata] method of the
|
147
148
|
versioned file instance.
|
148
149
|
|
149
|
-
|
150
|
+
Metadata for the original file, the current (latest) or an arbitrary version can
|
150
151
|
be accessed:
|
151
152
|
|
152
153
|
image = FilePipeline::VersionedFile.new('~/image.jpg')
|
@@ -167,12 +168,13 @@ versions available, pass the <tt>:for_version</tt> option with the symbol
|
|
167
168
|
|
168
169
|
Some file operations can comprise metadata; many image processing libraries
|
169
170
|
will not preserve all _Exif_ tags and their values when converting images to
|
170
|
-
a different format, but only write a
|
171
|
-
|
171
|
+
a different format, but only write a subset of tags to the file they create.
|
172
|
+
In these cases, the
|
172
173
|
{ExifRestoration}[rdoc-ref:FilePipeline::FileOperations::ExifRestoration]
|
173
|
-
operation can be used to try to restore the tags that have been discarded
|
174
|
-
|
175
|
-
not write back to the file
|
174
|
+
operation can be used to try to restore the tags that have been discarded. The
|
175
|
+
operation uses Exiftool to write tags, and Exiftool will not write all tags.
|
176
|
+
It will store any tags and their values that it could not write back to the file
|
177
|
+
and return them as captured data.
|
176
178
|
|
177
179
|
Likewise, if the
|
178
180
|
{ExifRedaction}[rdoc-ref:FilePipeline::FileOperations::ExifRedaction] is applied
|
@@ -8,32 +8,64 @@ module FilePipeline
|
|
8
8
|
# The file opration that caused the error.
|
9
9
|
attr_reader :info
|
10
10
|
|
11
|
-
#
|
11
|
+
# Returns a new instance.
|
12
|
+
#
|
13
|
+
# ===== Arguments
|
14
|
+
#
|
15
|
+
# * +msg+ - error message for the exception. If none provided, the
|
16
|
+
# instance will be initialized with the #default_message.
|
17
|
+
#
|
18
|
+
# ===== Options
|
19
|
+
#
|
20
|
+
# * <tt>info</tt> - a FileOperations::Results object or an object.
|
21
|
+
# * <tt>file</tt> - path to the file thas was being processed.
|
12
22
|
def initialize(msg = nil, info: nil, file: nil)
|
13
23
|
@file = file
|
14
24
|
@info = info
|
15
|
-
|
16
|
-
if info.respond_to?(:operation) && info.respond_to?(:log)
|
17
|
-
msg ||= "#{@info.operation&.name} with options"\
|
18
|
-
" #{@info.operation&.options} failed on #{file}."
|
19
|
-
if original_error
|
20
|
-
msg += "\nException raised by the operation:"\
|
21
|
-
" #{original_error.inspect}. Backtrace:\n"
|
22
|
-
msg += original_backtrace if original_backtrace
|
23
|
-
end
|
24
|
-
else
|
25
|
-
msg ||= 'Operation failed' unless info
|
26
|
-
end
|
25
|
+
msg ||= default_message
|
27
26
|
super msg
|
28
27
|
end
|
29
28
|
|
29
|
+
# Returns the backtrace of the error that caused the exception.
|
30
30
|
def original_backtrace
|
31
31
|
original_error&.backtrace&.join("\n")
|
32
32
|
end
|
33
33
|
|
34
|
+
# Returns the error that caused the exception.
|
34
35
|
def original_error
|
35
36
|
@info.log.find { |item| item.is_a? Exception }
|
36
37
|
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Appends the backtrace of the error that caused the exception to the
|
42
|
+
# #default_message.
|
43
|
+
def append_backtrace(str)
|
44
|
+
return str + "\n" unless original_backtrace
|
45
|
+
|
46
|
+
str + " Backtrace:\n#{original_backtrace}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Appends the message of the error that caused the exception to the
|
50
|
+
# #default_message.
|
51
|
+
def append_error(str)
|
52
|
+
return str unless original_error
|
53
|
+
|
54
|
+
str += "\nException raised by the operation:"\
|
55
|
+
" #{original_error.inspect}."
|
56
|
+
append_backtrace str
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns a String with the #message for +self+.
|
60
|
+
def default_message
|
61
|
+
if info&.respond_to?(:operation) && info&.respond_to?(:log)
|
62
|
+
msg = "#{info.operation&.name} with options"\
|
63
|
+
" #{info.operation&.options} failed on #{@file}."
|
64
|
+
append_error msg
|
65
|
+
else
|
66
|
+
'Operation failed'
|
67
|
+
end
|
68
|
+
end
|
37
69
|
end
|
38
70
|
end
|
39
71
|
end
|
@@ -19,6 +19,35 @@ module FilePipeline
|
|
19
19
|
# by #finalize is not replacing the original.
|
20
20
|
attr_reader :target_suffix
|
21
21
|
|
22
|
+
extend Forwardable
|
23
|
+
|
24
|
+
# Returns a two-dimesnional array, where each nested array has two items;
|
25
|
+
# the file operation object and data captured by the operartion (if any).
|
26
|
+
#
|
27
|
+
# <tt>[[description_object, data_or_nil], ...]</tt>
|
28
|
+
delegate captured_data: :history
|
29
|
+
|
30
|
+
# Returns any data captured by <tt>operation_name</tt>.
|
31
|
+
#
|
32
|
+
# If multiple instances of one operation class have modified the file,
|
33
|
+
# pass any +options+ the specific instance of the operation was initialized
|
34
|
+
# with as the optional second argument.
|
35
|
+
delegate captured_data_for: :history
|
36
|
+
|
37
|
+
# Returns an array with all data captured by operations with +tag+.
|
38
|
+
#
|
39
|
+
# Tags are defined in FileOperations::CapturedDataTags
|
40
|
+
delegate captured_data_with: :history
|
41
|
+
|
42
|
+
# Returns an array of triplets (arryas with three items each): the name of
|
43
|
+
# the file operation class (a string), options (a hash), and the actual log
|
44
|
+
# (an array).
|
45
|
+
delegate log: :history
|
46
|
+
|
47
|
+
# Returns an array with paths to the version files of +self+ (excluding
|
48
|
+
# #original).
|
49
|
+
delegate versions: :history
|
50
|
+
|
22
51
|
# Returns a new instance with +file+ as the #original.
|
23
52
|
#
|
24
53
|
# ===== Arguments
|
@@ -41,23 +70,10 @@ module FilePipeline
|
|
41
70
|
|
42
71
|
@original = file
|
43
72
|
@basename = File.basename(file, '.*')
|
44
|
-
@history =
|
73
|
+
@history = Versions::History.new
|
45
74
|
@directory = nil
|
46
75
|
@target_suffix = target_suffix
|
47
|
-
|
48
|
-
|
49
|
-
# Copies the file with path _src_ to <em>/dir/filename</em>.
|
50
|
-
def self.copy(src, dir, filename)
|
51
|
-
dest = FilePipeline.path(dir, filename)
|
52
|
-
FileUtils.cp src, dest
|
53
|
-
dest
|
54
|
-
end
|
55
|
-
|
56
|
-
# Moves the file with path _src_ to <em>/dir/filename</em>.
|
57
|
-
def self.move(src, dir, filename)
|
58
|
-
dest = FilePipeline.path(dir, filename)
|
59
|
-
FileUtils.mv src, dest
|
60
|
-
dest
|
76
|
+
history[original] = nil
|
61
77
|
end
|
62
78
|
|
63
79
|
# Adds a new version to #history and returns _self_.
|
@@ -80,37 +96,6 @@ module FilePipeline
|
|
80
96
|
raise e
|
81
97
|
end
|
82
98
|
|
83
|
-
# Returns a two-dimesnional array, where each nested array has two items;
|
84
|
-
# the file operation object and data captured by the operartion (if any).
|
85
|
-
#
|
86
|
-
# <tt>[[description_object, data_or_nil], ...]</tt>
|
87
|
-
def captured_data
|
88
|
-
filter_history :data
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns any data captured by <tt>operation_name</tt>.
|
92
|
-
#
|
93
|
-
# If multiple instances of one operation class have modified the file,
|
94
|
-
# pass any +options+ the specific instance of the operation was initialized
|
95
|
-
# with as the optional second argument.
|
96
|
-
def captured_data_for(operation_name, **options)
|
97
|
-
raw_data = captured_data.filter do |operation, _|
|
98
|
-
operation.name == operation_name &&
|
99
|
-
options.all? { |k, v| operation.options[k] == v }
|
100
|
-
end
|
101
|
-
raw_data.map(&:last)
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns an array with all data captured by operations with +tag+ has.
|
105
|
-
#
|
106
|
-
# Tags are defined in FileOperations::CapturedDataTags
|
107
|
-
def captured_data_with(tag)
|
108
|
-
return unless changed?
|
109
|
-
|
110
|
-
captured_data.select { |operation, _| operation.captured_data_tag == tag }
|
111
|
-
.map(&:last)
|
112
|
-
end
|
113
|
-
|
114
99
|
# Returns +true+ if there are #versions (file has been modified).
|
115
100
|
#
|
116
101
|
# *Warning:* It will also return +true+ if the file has been cloned.
|
@@ -122,7 +107,7 @@ module FilePipeline
|
|
122
107
|
# the file to history, but no FileOperations::Results.
|
123
108
|
def clone
|
124
109
|
filename = FilePipeline.new_basename + current_extension
|
125
|
-
clone_file =
|
110
|
+
clone_file = Versions.copy(current, directory, filename)
|
126
111
|
self << clone_file
|
127
112
|
end
|
128
113
|
|
@@ -161,19 +146,11 @@ module FilePipeline
|
|
161
146
|
yield(self) if block_given?
|
162
147
|
filename = overwrite ? replacing_trarget : preserving_taget
|
163
148
|
FileUtils.rm original if overwrite
|
164
|
-
@original =
|
149
|
+
@original = Versions.copy(current, original_dir, filename)
|
165
150
|
ensure
|
166
151
|
reset
|
167
152
|
end
|
168
153
|
|
169
|
-
# Returns an array of triplets (arryas with three items each): the name of
|
170
|
-
# the file operation class (a string), options (a hash), and the actual log
|
171
|
-
# (an array).
|
172
|
-
def log
|
173
|
-
filter_history(:log)
|
174
|
-
.map { |operation, info| [operation.name, operation.options, info] }
|
175
|
-
end
|
176
|
-
|
177
154
|
# Returns the Exif metadata
|
178
155
|
#
|
179
156
|
# ===== Options
|
@@ -186,10 +163,12 @@ module FilePipeline
|
|
186
163
|
#--
|
187
164
|
# TODO: when file is not an image file, this should return other metadata
|
188
165
|
# than exif.
|
189
|
-
# TODO: implement the option to return metadata for a specif version index
|
190
166
|
#++
|
191
167
|
def metadata(for_version: :current)
|
192
|
-
|
168
|
+
if %i[current original].include? for_version
|
169
|
+
file = public_send(for_version)
|
170
|
+
end
|
171
|
+
file ||= for_version
|
193
172
|
read_exif(file).first
|
194
173
|
end
|
195
174
|
|
@@ -218,29 +197,15 @@ module FilePipeline
|
|
218
197
|
# Returns a hash into which all captured data from file operations with the
|
219
198
|
# FileOperations::CapturedDataTags::DROPPED_EXIF_DATA has been merged.
|
220
199
|
def recovered_metadata
|
200
|
+
return unless changed?
|
221
201
|
captured_data_with(FileOperations::CapturedDataTags::DROPPED_EXIF_DATA)
|
222
202
|
&.reduce({}) { |recovered, data| recovered.merge data }
|
223
203
|
end
|
224
204
|
|
225
|
-
# Returns an array with paths to the version files of +self+ (excluding
|
226
|
-
# #original).
|
227
|
-
def versions
|
228
|
-
history.keys
|
229
|
-
end
|
230
|
-
|
231
205
|
alias touch clone
|
232
206
|
|
233
207
|
private
|
234
208
|
|
235
|
-
# item = :data or :log
|
236
|
-
def filter_history(item)
|
237
|
-
history.inject([]) do |results, (_, info)|
|
238
|
-
next results unless info.respond_to?(item) && info.public_send(item)
|
239
|
-
|
240
|
-
results << [info.operation, info.public_send(item)]
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
209
|
# Returns the filename for a target file that will not overwrite the
|
245
210
|
# original.
|
246
211
|
def preserving_taget
|
@@ -256,16 +221,18 @@ module FilePipeline
|
|
256
221
|
# Deletes the work directory and resets #versions
|
257
222
|
def reset
|
258
223
|
FileUtils.rm_r directory, force: true
|
259
|
-
|
224
|
+
history.clear!
|
260
225
|
end
|
261
226
|
|
262
227
|
# Validates if file exists and has been stored in #directory.
|
263
228
|
def validate(file)
|
229
|
+
return current unless file
|
230
|
+
|
264
231
|
raise Errors::MissingVersionFileError, file: file unless File.exist? file
|
265
232
|
|
266
233
|
return file if File.dirname(file) == directory
|
267
234
|
|
268
|
-
|
235
|
+
Versions.move file, directory, File.basename(file)
|
269
236
|
end
|
270
237
|
|
271
238
|
# Creates the directory containing all version files. Directory name is
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FilePipeline
|
4
|
+
module Versions
|
5
|
+
# History objects keep track of a VersionedFile instances versions names and
|
6
|
+
# any associated logs or data for each version.
|
7
|
+
class History
|
8
|
+
# Returns a new instance.
|
9
|
+
def initialize
|
10
|
+
@entries = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Retrieves the _results_ object for the <tt>version_name</tt>.
|
14
|
+
def [](version_name)
|
15
|
+
@entries[version_name]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Associates the +results+ with the <tt>version_name</tt>.
|
19
|
+
def []=(version_name, results)
|
20
|
+
entry = @entries.fetch version_name, []
|
21
|
+
entry << results
|
22
|
+
@entries[version_name] = entry.compact
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a two-dimensional array, where each nested array has two items:
|
26
|
+
# * the file operation object
|
27
|
+
# * data captured by the operartion (if any).
|
28
|
+
#
|
29
|
+
# <tt>[[file_operation_object, data_or_nil], ...]</tt>
|
30
|
+
def captured_data
|
31
|
+
filter :data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns any data captured by <tt>operation_name</tt>.
|
35
|
+
#
|
36
|
+
# If multiple instances of one operation class have modified the file,
|
37
|
+
# pass any +options+ the specific instance of the operation was
|
38
|
+
# initialized with as the optional second argument.
|
39
|
+
def captured_data_for(operation_name, **options)
|
40
|
+
return if empty?
|
41
|
+
|
42
|
+
captured_data.filter { |op, _| matches? op, operation_name, options }
|
43
|
+
.map(&:last)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns an array with all data captured by operations with +tag+.
|
47
|
+
# Returns an empty array if there is no data for +tag+.
|
48
|
+
#
|
49
|
+
# Tags are defined in FileOperations::CapturedDataTags
|
50
|
+
def captured_data_with(tag)
|
51
|
+
captured_data.filter { |op, _| op.captured_data_tag == tag }
|
52
|
+
.map(&:last)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Clears all history entries (version names and associated results).
|
56
|
+
def clear!
|
57
|
+
@entries.clear
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns +true+ if +self+ has no entries (version names and associated
|
61
|
+
# results), +true+ otherwise.
|
62
|
+
def empty?
|
63
|
+
@entries.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns an array of triplets (arryas with three items each):
|
67
|
+
# * Name of the file operation class (String).
|
68
|
+
# * Options for the file operation instance (Hash).
|
69
|
+
# * The log (Array).
|
70
|
+
def log
|
71
|
+
filter(:log).map { |op, results| [op.name, op.options, results] }
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns a two-dimensional Array where every nested Array will consist
|
75
|
+
# of the version name (file path) at index +0+ and +nil+ or an Array with
|
76
|
+
# all _results_ objects for the version at index +1+:
|
77
|
+
#
|
78
|
+
# <tt>[version_name, [results1, ...]]</tt>
|
79
|
+
def to_a
|
80
|
+
@entries.to_a
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns an array with paths to the version files of +self+ (excluding
|
84
|
+
# #original).
|
85
|
+
def versions
|
86
|
+
@entries.keys
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# Filters entries in self by +item+ (<tt>:log</tt> or <tt>:data</tt>).
|
92
|
+
def filter(item)
|
93
|
+
@entries.values.flatten.select(&item).map do |results|
|
94
|
+
[results.operation, results.public_send(item)]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns +true+ if +name+ matches the _name_ attribute of +operation+ and
|
99
|
+
# +options+ matches the options the operation instance is initialized
|
100
|
+
# with.
|
101
|
+
def matches?(operation, name, opts)
|
102
|
+
operation.name == name && opts.all? { |k, v| operation.options[k] == v }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'versions/history'
|
4
|
+
|
5
|
+
module FilePipeline
|
6
|
+
# Module that contains classes to work with VersionedFile.
|
7
|
+
module Versions
|
8
|
+
# Copies the file with path _src_ to <em>/dir/filename</em>.
|
9
|
+
def self.copy(src, dir, filename)
|
10
|
+
dest = FilePipeline.path(dir, filename)
|
11
|
+
FileUtils.cp src, dest
|
12
|
+
dest
|
13
|
+
end
|
14
|
+
|
15
|
+
# Moves the file with path _src_ to <em>/dir/filename</em>.
|
16
|
+
def self.move(src, dir, filename)
|
17
|
+
dest = FilePipeline.path(dir, filename)
|
18
|
+
FileUtils.mv src, dest
|
19
|
+
dest
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/file_pipeline.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_pipeline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Stein
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_exiftool
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.0.16
|
41
|
-
description: The file_pipeline gem provides a framework
|
41
|
+
description: The file_pipeline gem provides a framework for nondestructive application
|
42
42
|
of file operation batches to files.
|
43
43
|
email: loveablelobster@fastmail.fm
|
44
44
|
executables: []
|
@@ -65,6 +65,8 @@ files:
|
|
65
65
|
- lib/file_pipeline/file_operations/results.rb
|
66
66
|
- lib/file_pipeline/pipeline.rb
|
67
67
|
- lib/file_pipeline/versioned_file.rb
|
68
|
+
- lib/file_pipeline/versions.rb
|
69
|
+
- lib/file_pipeline/versions/history.rb
|
68
70
|
homepage: https://github.com/loveablelobster/file_pipeline
|
69
71
|
licenses:
|
70
72
|
- MIT
|
@@ -77,7 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
79
|
requirements:
|
78
80
|
- - ">="
|
79
81
|
- !ruby/object:Gem::Version
|
80
|
-
version: '
|
82
|
+
version: '2.6'
|
81
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
84
|
requirements:
|
83
85
|
- - ">="
|