rbbt-util 5.27.13 → 5.28.5
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/lib/rbbt/annotations/util.rb +2 -2
- data/lib/rbbt/hpc.rb +5 -2
- data/lib/rbbt/resource/path.rb +8 -6
- data/lib/rbbt/resource/util.rb +4 -3
- data/lib/rbbt/tsv/change_id.rb +2 -2
- data/lib/rbbt/tsv/parallel/traverse.rb +6 -8
- data/lib/rbbt/tsv/util.rb +20 -12
- data/lib/rbbt/util/misc/inspect.rb +2 -2
- data/lib/rbbt/workflow/integration/cromwell.rb +10 -3
- data/lib/rbbt/workflow/remote_workflow/remote_step.rb +5 -0
- data/lib/rbbt/workflow/step/accessor.rb +5 -4
- data/lib/rbbt/workflow/step/dependencies.rb +2 -2
- data/share/rbbt_commands/app/start +2 -2
- data/share/workflow_config.ru +5 -1
- data/test/rbbt/test_resource.rb +3 -3
- data/test/rbbt/tsv/parallel/test_traverse.rb +21 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dc2c06d6d3e5f783f24a671c0150d6cb2da641d003770ee5315c10118a0ea34
|
4
|
+
data.tar.gz: 0e5cf607bd69452be51bf21d36ceeef49ab3d0cb2821728900547e7db60a03af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d949e77540e01389eb90a757dbf7a499e6aadf237b998b533ffb964fee46bf2ff9c7145c00fa355ce4ff30a1710caab9169bebbf5be22a998c74cc84610c11e
|
7
|
+
data.tar.gz: c2d18ea2d6b45db2878c4a8ae07ac433d1ed365813bf7fe5635c325b743415575998ed6ae3db64d6429719c369ab8be5f263149d9fee8d3ca6edba15b0da1265
|
@@ -74,7 +74,7 @@ module Annotated
|
|
74
74
|
|
75
75
|
object = case
|
76
76
|
when literal_pos
|
77
|
-
values[literal_pos]
|
77
|
+
values[literal_pos].tap{|o| o.force_encoding(Encoding.default_external)}
|
78
78
|
else
|
79
79
|
id.dup
|
80
80
|
end
|
@@ -119,7 +119,7 @@ module Annotated
|
|
119
119
|
fields = AnnotatedArray === annotations ? annotations.annotations : annotations.compact.first.annotations
|
120
120
|
fields << :annotation_types
|
121
121
|
|
122
|
-
when (fields == [:literal] and
|
122
|
+
when (fields == [:literal] and ! annotations.compact.empty?)
|
123
123
|
fields << :literal
|
124
124
|
|
125
125
|
when (fields == [:all] && Annotated === annotations)
|
data/lib/rbbt/hpc.rb
CHANGED
@@ -451,12 +451,15 @@ EOF
|
|
451
451
|
out = CMD.cmd("tail -f '#{fout}'", :pipe => true) if File.exists?(fout) and not tail == :STDERR
|
452
452
|
err = CMD.cmd("tail -f '#{ferr}'", :pipe => true) if File.exists?(ferr)
|
453
453
|
|
454
|
-
Misc.consume_stream(err, true, STDERR) if err
|
455
|
-
Misc.consume_stream(out, true, STDOUT) if out
|
454
|
+
terr = Misc.consume_stream(err, true, STDERR) if err
|
455
|
+
tout = Misc.consume_stream(out, true, STDOUT) if out
|
456
456
|
|
457
457
|
sleep 3 while CMD.cmd("squeue --job #{job}").read.include? job.to_s
|
458
|
+
rescue Aborted
|
458
459
|
ensure
|
459
460
|
begin
|
461
|
+
terr.exit if terr
|
462
|
+
tout.exit if tout
|
460
463
|
err.close if err
|
461
464
|
err.join if err
|
462
465
|
rescue Exception
|
data/lib/rbbt/resource/path.rb
CHANGED
@@ -13,7 +13,7 @@ module Path
|
|
13
13
|
string.resource = resource
|
14
14
|
string.search_paths = search_paths
|
15
15
|
string.search_order = search_order
|
16
|
-
string.libdir = libdir || Path.caller_lib_dir
|
16
|
+
string.libdir = libdir || Path.caller_lib_dir
|
17
17
|
string
|
18
18
|
end
|
19
19
|
|
@@ -52,11 +52,11 @@ module Path
|
|
52
52
|
def join(name)
|
53
53
|
raise "Invalid path: #{ self }" if self.nil?
|
54
54
|
new = if self.empty?
|
55
|
-
self.annotate name.to_s.dup
|
55
|
+
self.annotate name.to_s.dup.chomp
|
56
56
|
else
|
57
|
-
self.annotate File.join(self, name.to_s)
|
57
|
+
self.annotate File.join(self, name.to_s.chomp)
|
58
58
|
end
|
59
|
-
new.original = File.join(self.original, name.to_s) if self.original
|
59
|
+
new.original = File.join(self.original, name.to_s.chomp) if self.original
|
60
60
|
new
|
61
61
|
end
|
62
62
|
|
@@ -76,7 +76,7 @@ module Path
|
|
76
76
|
return [] unless self.exists?
|
77
77
|
found = self.find
|
78
78
|
exp = File.join(found, pattern)
|
79
|
-
paths = Dir.glob(exp).collect{|f|
|
79
|
+
paths = Dir.glob(exp).collect{|f| self.annotate(f) }
|
80
80
|
|
81
81
|
paths.each do |p|
|
82
82
|
p.original = File.join(found.original, p.sub(/^#{found}/, ''))
|
@@ -412,7 +412,9 @@ module Path
|
|
412
412
|
end
|
413
413
|
|
414
414
|
def replace_extension(new_extension = nil, multiple = false)
|
415
|
-
if multiple
|
415
|
+
if String === multiple
|
416
|
+
new_path = self.sub(/(\.[^\.\/]{1,5})(.#{multiple})?$/,'')
|
417
|
+
elsif multiple
|
416
418
|
new_path = self.sub(/(\.[^\.\/]{1,5})+$/,'')
|
417
419
|
else
|
418
420
|
new_path = self.sub(/\.[^\.\/]{1,5}$/,'')
|
data/lib/rbbt/resource/util.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Path
|
2
2
|
|
3
|
-
def self.caller_lib_dir(file = nil, relative_to = 'lib')
|
3
|
+
def self.caller_lib_dir(file = nil, relative_to = ['lib', 'bin'])
|
4
4
|
file = caller.reject{|l|
|
5
5
|
l =~ /rbbt\/(?:resource\.rb|workflow\.rb)/ or
|
6
6
|
l =~ /rbbt\/resource\/path\.rb/ or
|
@@ -9,13 +9,14 @@ module Path
|
|
9
9
|
l =~ /progress-monitor\.rb/
|
10
10
|
}.first.sub(/\.rb[^\w].*/,'.rb') if file.nil?
|
11
11
|
|
12
|
+
relative_to = [relative_to] unless Array === relative_to
|
12
13
|
file = File.expand_path(file)
|
13
|
-
return Path.setup(file) if File.exist? File.join(file,
|
14
|
+
return Path.setup(file) if relative_to.select{|d| File.exist? File.join(file, d)}.any?
|
14
15
|
|
15
16
|
while file != '/'
|
16
17
|
dir = File.dirname file
|
17
18
|
|
18
|
-
return dir if File.exist? File.join(dir,
|
19
|
+
return dir if relative_to.select{|d| File.exist? File.join(dir, d)}.any?
|
19
20
|
|
20
21
|
file = File.dirname file
|
21
22
|
end
|
data/lib/rbbt/tsv/change_id.rb
CHANGED
@@ -58,13 +58,13 @@ module TSV
|
|
58
58
|
|
59
59
|
identifiers, persist_input, compact = Misc.process_options options, :identifiers, :persist, :compact
|
60
60
|
identifiers = tsv.identifier_files.first if identifiers.nil?
|
61
|
-
identifiers = Organism.identifiers(tsv.namespace) if identifiers.nil?
|
61
|
+
identifiers = Organism.identifiers(tsv.namespace) if defined?(Organism) && identifiers.nil? && tsv.namespace && Organism.identifiers(tsv.namespace).exists?
|
62
62
|
identifiers.namespace ||= tsv.namespace
|
63
63
|
|
64
64
|
fields = (identifiers and identifiers.all_fields.include?(field))? [field] : nil
|
65
65
|
#index = identifiers.index :target => format, :fields => fields, :persist => persist_input, :order => true
|
66
66
|
|
67
|
-
grep = Organism.blacklist_genes(tsv.namespace).list if identifiers.namespace
|
67
|
+
grep = Organism.blacklist_genes(tsv.namespace).list if defined?(Organism) && identifiers.namespace && Organism.blacklist_genes(tsv.namespace).exists?
|
68
68
|
if fields.nil?
|
69
69
|
index = identifiers.index(:data_tsv_grep => grep, :data_invert_grep => true, :target => format, :persist => true, :order => true, :unnamed => true, :data_persist => true)
|
70
70
|
else
|
@@ -101,8 +101,8 @@ module TSV
|
|
101
101
|
error = true
|
102
102
|
raise $!
|
103
103
|
ensure
|
104
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
105
104
|
join.call(error) if join
|
105
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -137,8 +137,8 @@ module TSV
|
|
137
137
|
error = true
|
138
138
|
raise $!
|
139
139
|
ensure
|
140
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
141
140
|
join.call(error) if join
|
141
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -177,8 +177,8 @@ module TSV
|
|
177
177
|
error = true
|
178
178
|
raise $!
|
179
179
|
ensure
|
180
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
181
180
|
join.call(error) if join
|
181
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
@@ -219,8 +219,8 @@ module TSV
|
|
219
219
|
error = true
|
220
220
|
raise $!
|
221
221
|
ensure
|
222
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
223
222
|
join.call(error) if join
|
223
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
@@ -273,8 +273,8 @@ module TSV
|
|
273
273
|
error = true
|
274
274
|
raise $!
|
275
275
|
ensure
|
276
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
277
276
|
join.call(error) if join
|
277
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
278
278
|
end
|
279
279
|
end
|
280
280
|
|
@@ -318,8 +318,8 @@ module TSV
|
|
318
318
|
error = true
|
319
319
|
raise $!
|
320
320
|
ensure
|
321
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
322
321
|
join.call(error) if join
|
322
|
+
Log::ProgressBar.remove_bar(bar) if bar
|
323
323
|
end
|
324
324
|
end
|
325
325
|
|
@@ -727,8 +727,6 @@ module TSV
|
|
727
727
|
Log.exception $!
|
728
728
|
abort_stream(into, $!)
|
729
729
|
raise $!
|
730
|
-
ensure
|
731
|
-
Log::ProgressBar.remove_bar(bar) if bar
|
732
730
|
end
|
733
731
|
|
734
732
|
into
|
data/lib/rbbt/tsv/util.rb
CHANGED
@@ -316,22 +316,30 @@ module TSV
|
|
316
316
|
|
317
317
|
def to_single
|
318
318
|
new = {}
|
319
|
-
|
320
|
-
|
321
|
-
through do |k,v|
|
322
|
-
new[k] = v.first.first
|
323
|
-
end
|
324
|
-
when :flat
|
319
|
+
|
320
|
+
if block_given?
|
325
321
|
through do |k,v|
|
326
|
-
new[k] = v
|
322
|
+
new[k] = yield v
|
327
323
|
end
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
324
|
+
else
|
325
|
+
case type
|
326
|
+
when :double
|
327
|
+
through do |k,v|
|
328
|
+
new[k] = v.first.first
|
329
|
+
end
|
330
|
+
when :flat
|
331
|
+
through do |k,v|
|
332
|
+
new[k] = v.first
|
333
|
+
end
|
334
|
+
when :single
|
335
|
+
return self
|
336
|
+
when :list
|
337
|
+
through do |k,v|
|
338
|
+
new[k] = v.first
|
339
|
+
end
|
333
340
|
end
|
334
341
|
end
|
342
|
+
|
335
343
|
self.annotate(new)
|
336
344
|
new.type = :single
|
337
345
|
new.fields = [new.fields.first] if new.fields.length > 1
|
@@ -290,7 +290,7 @@ module Misc
|
|
290
290
|
if obj.exists?
|
291
291
|
if obj.directory?
|
292
292
|
files = obj.glob("**/*")
|
293
|
-
"directory: #{files}"
|
293
|
+
"directory: #{Misc.fingerprint(files)}"
|
294
294
|
else
|
295
295
|
"file: " << obj << "--" << mtime_str(obj)
|
296
296
|
end
|
@@ -401,7 +401,7 @@ module Misc
|
|
401
401
|
|
402
402
|
def self.scan_version_text(text, cmd = nil)
|
403
403
|
cmd = "NOCMDGIVE" if cmd.nil? || cmd.empty?
|
404
|
-
m = text.match(/(?:version.*?|#{cmd}.*?|#{cmd.split(/[-_.]/).first}.*?|v)((?:\d+\.)*\d+(?:-[a-z_]+)?)/i)
|
404
|
+
m = text.match(/(?:version.*?|#{cmd}.*?|#{cmd.to_s.split(/[-_.]/).first}.*?|v)((?:\d+\.)*\d+(?:-[a-z_]+)?)/i)
|
405
405
|
return nil if m.nil?
|
406
406
|
m[1]
|
407
407
|
end
|
@@ -1,13 +1,20 @@
|
|
1
|
-
module
|
1
|
+
module Cromwell
|
2
2
|
|
3
3
|
Rbbt.claim Rbbt.software.opt.jar["cromwell.jar"], :url, "https://github.com/broadinstitute/cromwell/releases/download/48/cromwell-48.jar"
|
4
4
|
Rbbt.claim Rbbt.software.opt.jar["wdltool.jar"], :url, "https://github.com/broadinstitute/wdltool/releases/download/0.14/wdltool-0.14.jar"
|
5
5
|
|
6
|
-
def run_cromwell(file, work_dir, options = {})
|
6
|
+
def self.run_cromwell(file, work_dir, options = {})
|
7
|
+
cromwell_inputs_file = Misc.process_options options, :cromwell_inputs_file
|
7
8
|
jar = Rbbt.software.opt.jar["cromwell.jar"].produce.find
|
8
|
-
|
9
|
+
if cromwell_inputs_file
|
10
|
+
CMD.cmd_log("java -jar '#{jar}' run '#{file}' --workflow-root='#{work_dir}' -i #{cromwell_inputs_file}", options.merge("add_option_dashes" => true))
|
11
|
+
else
|
12
|
+
CMD.cmd_log("java -jar '#{jar}' run '#{file}' --workflow-root='#{work_dir}'", options.merge("add_option_dashes" => true))
|
13
|
+
end
|
9
14
|
end
|
15
|
+
end
|
10
16
|
|
17
|
+
module Workflow
|
11
18
|
def load_cromwell(file)
|
12
19
|
jar = Rbbt.software.opt.jar["wdltool.jar"].produce.find
|
13
20
|
inputs = JSON.load(CMD.cmd("java -jar '#{jar}' inputs '#{file}'"))
|
@@ -340,6 +340,11 @@ class RemoteStep < Step
|
|
340
340
|
@inputs = new_inputs
|
341
341
|
@info = nil
|
342
342
|
end
|
343
|
+
|
344
|
+
def init_info(*args)
|
345
|
+
i = {:status => :waiting, :pid => Process.pid, :path => path}
|
346
|
+
i[:dependencies] = dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
|
347
|
+
end
|
343
348
|
end
|
344
349
|
|
345
350
|
require 'rbbt/workflow/remote_workflow/remote_step/rest'
|
@@ -208,7 +208,7 @@ class Step
|
|
208
208
|
end
|
209
209
|
|
210
210
|
def init_info(force = false)
|
211
|
-
return nil if @exec
|
211
|
+
return nil if @exec || info_file.nil? || (Open.exists?(info_file) && ! force)
|
212
212
|
Open.lock(info_file, :lock => info_lock) do
|
213
213
|
i = {:status => :waiting, :pid => Process.pid, :path => path}
|
214
214
|
i[:dependencies] = dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
|
@@ -437,11 +437,12 @@ class Step
|
|
437
437
|
rec_dependencies = self.rec_dependencies
|
438
438
|
return [] if rec_dependencies.empty?
|
439
439
|
canfail_paths = self.canfail_paths
|
440
|
+
dep = rec_dependencies.select{|d| d.task_name.to_s == 'contamination'}.first
|
440
441
|
dirty_files = rec_dependencies.reject{|dep|
|
441
442
|
(defined?(WorkflowRemoteClient) && WorkflowRemoteClient::RemoteStep === dep) ||
|
442
443
|
! Open.exists?(dep.info_file) ||
|
443
444
|
(dep.path && (Open.exists?(dep.path) || Open.remote?(dep.path))) ||
|
444
|
-
((dep.error? || dep.aborted?
|
445
|
+
((dep.error? || dep.aborted?) && (! dep.recoverable_error? || canfail_paths.include?(dep.path)))
|
445
446
|
}
|
446
447
|
end
|
447
448
|
|
@@ -508,12 +509,12 @@ class Step
|
|
508
509
|
|
509
510
|
def nopid?
|
510
511
|
pid = info[:pid] || Open.exists?(pid_file)
|
511
|
-
! pid && ! (status.nil? || status == :aborted || status == :done || status == :error)
|
512
|
+
! pid && ! (status.nil? || status == :aborted || status == :done || status == :error || status == :cleaned)
|
512
513
|
end
|
513
514
|
|
514
515
|
def aborted?
|
515
516
|
status = self.status
|
516
|
-
status == :aborted || ((status != :noinfo && status != :setup && status != :noinfo) && nopid?)
|
517
|
+
status == :aborted || ((status != :cleaned && status != :noinfo && status != :setup && status != :noinfo) && nopid?)
|
517
518
|
end
|
518
519
|
|
519
520
|
# {{{ INFO
|
@@ -24,7 +24,7 @@ class Step
|
|
24
24
|
Log.medium "Not duplicating stream #{stream_key}"
|
25
25
|
STREAM_CACHE[stream_key] = stream
|
26
26
|
when File
|
27
|
-
if Open.exists?
|
27
|
+
if Open.exists?(current.path)
|
28
28
|
Log.medium "Reopening file #{stream_key}"
|
29
29
|
Open.open(current.path)
|
30
30
|
else
|
@@ -97,7 +97,7 @@ class Step
|
|
97
97
|
end
|
98
98
|
|
99
99
|
job.dup_inputs unless status == 'done' or job.started?
|
100
|
-
job.init_info unless status == '
|
100
|
+
job.init_info(status == 'noinfo') unless status == 'waiting' || status == 'done' || job.started?
|
101
101
|
|
102
102
|
canfail = ComputeDependency === job && job.canfail?
|
103
103
|
end
|
@@ -54,9 +54,9 @@ app = ARGV.shift
|
|
54
54
|
|
55
55
|
ENV["RServe-session"] = options[:RServe_session] || app
|
56
56
|
|
57
|
-
app_dir = Rbbt.etc.app_dir.exists? ? Path.setup(Rbbt.etc.app_dir.read.strip) : Rbbt.apps
|
57
|
+
app_dir = Rbbt.etc.app_dir.exists? ? Path.setup(Rbbt.etc.app_dir.read.strip) : Rbbt.apps
|
58
58
|
|
59
|
-
app_dir = app_dir[app]
|
59
|
+
app_dir = app_dir[app].find
|
60
60
|
|
61
61
|
server = options[:server] || 'puma'
|
62
62
|
Misc.in_dir(app_dir) do
|
data/share/workflow_config.ru
CHANGED
@@ -43,7 +43,11 @@ etc_dir = Rbbt.etc
|
|
43
43
|
load_file etc_dir['app.d/pre.rb'].find
|
44
44
|
|
45
45
|
app.get '/' do
|
46
|
-
|
46
|
+
begin
|
47
|
+
template_render('main', params, 'main', :cache_type => :asynchronous)
|
48
|
+
rescue TemplateMissing
|
49
|
+
redirect to(File.join('/', wf.to_s))
|
50
|
+
end
|
47
51
|
end
|
48
52
|
|
49
53
|
#{{{ BASE
|
data/test/rbbt/test_resource.rb
CHANGED
@@ -69,11 +69,11 @@ class TestTSV < Test::Unit::TestCase
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def test_libdir
|
72
|
-
assert File.exist?
|
73
|
-
assert File.exist?
|
72
|
+
assert File.exist?(TestResource[].share.Rlib["util.R"].find(:lib))
|
73
|
+
assert File.exist?(TestResource[].share.Rlib["util.R"].find)
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
76
|
+
def __test_server
|
77
77
|
require 'rbbt/sources/organism'
|
78
78
|
TmpFile.with_file :extension => 'gz' do |tmp|
|
79
79
|
Organism.get_from_server("Hsa/b37/known_sites/dbsnp_138.vcf.gz", tmp, 'http://rbbt.bsc.es')
|
@@ -202,7 +202,7 @@ class TestTSVParallelThrough < Test::Unit::TestCase
|
|
202
202
|
stream = datafile_test('identifiers').open
|
203
203
|
dumper = TSV::Dumper.new datafile_test('identifiers').tsv_options
|
204
204
|
dumper.init
|
205
|
-
TSV.traverse stream, :head => head, :into => dumper do |k,v|
|
205
|
+
TSV.traverse stream, :head => head, :into => dumper, :bar => true do |k,v|
|
206
206
|
k = k.first
|
207
207
|
[k,v]
|
208
208
|
end
|
@@ -212,6 +212,26 @@ class TestTSVParallelThrough < Test::Unit::TestCase
|
|
212
212
|
assert_equal head, res.size
|
213
213
|
end
|
214
214
|
|
215
|
+
def test_traverse_into_dumper_error_bar
|
216
|
+
require 'rbbt/sources/organism'
|
217
|
+
|
218
|
+
head = 2_000
|
219
|
+
|
220
|
+
stream = datafile_test('identifiers').open
|
221
|
+
dumper = TSV::Dumper.new datafile_test('identifiers').tsv_options
|
222
|
+
dumper.init
|
223
|
+
TSV.traverse stream, :head => head, :into => dumper, :bar => true do |k,v|
|
224
|
+
k = k.first
|
225
|
+
raise
|
226
|
+
[k,v]
|
227
|
+
end
|
228
|
+
|
229
|
+
assert_raise do
|
230
|
+
res = TSV.open(dumper.stream)
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
215
235
|
def test_traverse_into_dumper_threads
|
216
236
|
require 'rbbt/sources/organism'
|
217
237
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbt-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.28.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Vazquez
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|