inst-jobs 3.1.7 → 3.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +4 -2
- data/db/migrate/20200825011002_add_strand_order_override.rb +2 -1
- data/db/migrate/20210809145804_add_n_strand_index.rb +2 -1
- data/lib/delayed/backend/active_record.rb +8 -3
- data/lib/delayed/backend/base.rb +5 -2
- data/lib/delayed/cli.rb +3 -2
- data/lib/delayed/lifecycle.rb +1 -1
- data/lib/delayed/log_tailer.rb +2 -2
- data/lib/delayed/message_sending.rb +7 -4
- data/lib/delayed/performable_method.rb +20 -16
- data/lib/delayed/periodic.rb +1 -1
- data/lib/delayed/settings.rb +2 -0
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/work_queue/parent_process/server.rb +2 -2
- data/lib/delayed/worker/process_helper.rb +4 -4
- data/lib/delayed/worker.rb +6 -6
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b84071f5e26623586c13f855f5ce616786a61fa18ebae0a4640cfd48ab2a63c
|
4
|
+
data.tar.gz: c2c386ac0864c1ac08173eb4960ccdf1f7b89184799c59f7d1b427b4330c548d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 898a6eb496ec26e653ba3a360cd1e820aaba1a04b3768a265976b5d3ed9150e38795f25fdb1adfb89c69f930ec6bb92d2388e36685685abac0209c1e534e2f36
|
7
|
+
data.tar.gz: 26c8af5d1a05624a0ffd161f8d49fa5c81a205f974849577a0d7fa9c84735c48e0269d7078a038fb2e9865aeae294378b12656c0d5359c3d80bbc31429acf0b7
|
@@ -9,7 +9,8 @@ class AddIdToGetDelayedJobsIndex < ActiveRecord::Migration[4.2]
|
|
9
9
|
|
10
10
|
def up
|
11
11
|
rename_index :delayed_jobs, "get_delayed_jobs_index", "get_delayed_jobs_index_old"
|
12
|
-
add_index :delayed_jobs,
|
12
|
+
add_index :delayed_jobs,
|
13
|
+
%i[queue priority run_at id],
|
13
14
|
algorithm: :concurrently,
|
14
15
|
where: "locked_at IS NULL AND next_in_strand",
|
15
16
|
name: "get_delayed_jobs_index"
|
@@ -18,7 +19,8 @@ class AddIdToGetDelayedJobsIndex < ActiveRecord::Migration[4.2]
|
|
18
19
|
|
19
20
|
def down
|
20
21
|
rename_index :delayed_jobs, "get_delayed_jobs_index", "get_delayed_jobs_index_old"
|
21
|
-
add_index :delayed_jobs,
|
22
|
+
add_index :delayed_jobs,
|
23
|
+
%i[priority run_at queue],
|
22
24
|
algorithm: :concurrently,
|
23
25
|
where: "locked_at IS NULL AND next_in_strand",
|
24
26
|
name: "get_delayed_jobs_index"
|
@@ -10,7 +10,8 @@ class AddStrandOrderOverride < ActiveRecord::Migration[4.2]
|
|
10
10
|
def up
|
11
11
|
add_column :delayed_jobs, :strand_order_override, :integer, default: 0, null: false
|
12
12
|
add_column :failed_jobs, :strand_order_override, :integer, default: 0, null: false
|
13
|
-
add_index :delayed_jobs,
|
13
|
+
add_index :delayed_jobs,
|
14
|
+
%i[strand strand_order_override id],
|
14
15
|
algorithm: :concurrently,
|
15
16
|
where: "strand IS NOT NULL",
|
16
17
|
name: "next_in_strand_index"
|
@@ -4,7 +4,8 @@ class AddNStrandIndex < ActiveRecord::Migration[5.2]
|
|
4
4
|
disable_ddl_transaction!
|
5
5
|
|
6
6
|
def change
|
7
|
-
add_index :delayed_jobs,
|
7
|
+
add_index :delayed_jobs,
|
8
|
+
%i[strand next_in_strand id],
|
8
9
|
name: "n_strand_index",
|
9
10
|
where: "strand IS NOT NULL",
|
10
11
|
algorithm: :concurrently
|
@@ -115,7 +115,7 @@ module Delayed
|
|
115
115
|
# but we don't need to lock when inserting into Delayed::Failed
|
116
116
|
if values["strand"] && instance_of?(Job)
|
117
117
|
fn_name = connection.quote_table_name("half_md5_as_bigint")
|
118
|
-
quoted_strand = connection.quote(Rails.version < "7.0" ? values["strand"] : values["strand"].value)
|
118
|
+
quoted_strand = connection.quote((Rails.version < "7.0") ? values["strand"] : values["strand"].value)
|
119
119
|
sql = "SELECT pg_advisory_xact_lock(#{fn_name}(#{quoted_strand})); #{sql}"
|
120
120
|
end
|
121
121
|
result = connection.execute(sql, "#{self.class} Create")
|
@@ -253,7 +253,7 @@ module Delayed
|
|
253
253
|
offset = 0,
|
254
254
|
query = nil)
|
255
255
|
scope = scope_for_flavor(flavor, query)
|
256
|
-
order = flavor.to_s == "future" ? "run_at" : "id desc"
|
256
|
+
order = (flavor.to_s == "future") ? "run_at" : "id desc"
|
257
257
|
scope.order(order).limit(limit).offset(offset).to_a
|
258
258
|
end
|
259
259
|
|
@@ -607,7 +607,12 @@ module Delayed
|
|
607
607
|
end
|
608
608
|
|
609
609
|
def requeue!
|
610
|
-
attrs = attributes.except("id",
|
610
|
+
attrs = attributes.except("id",
|
611
|
+
"last_error",
|
612
|
+
"locked_at",
|
613
|
+
"failed_at",
|
614
|
+
"locked_by",
|
615
|
+
"original_job_id",
|
611
616
|
"requeued_job_id")
|
612
617
|
self.class.transaction do
|
613
618
|
job = nil
|
data/lib/delayed/backend/base.rb
CHANGED
@@ -62,6 +62,9 @@ module Delayed
|
|
62
62
|
kwargs[:singleton] = singleton
|
63
63
|
|
64
64
|
raise ArgumentError, "Only one of strand or n_strand can be used" if strand && n_strand
|
65
|
+
if (strand || n_strand) && run_at && run_at > Job.db_time_now + Settings.stranded_run_at_grace_period
|
66
|
+
raise ArgumentError, "Do not use run_at with strand; you may inadvertently clog the strand"
|
67
|
+
end
|
65
68
|
|
66
69
|
# If two parameters are given to n_strand, the first param is used
|
67
70
|
# as the strand name for looking up the Setting, while the second
|
@@ -113,7 +116,7 @@ module Delayed
|
|
113
116
|
# effectively balancing the load during queueing
|
114
117
|
# overwritten in ActiveRecord::Job to use triggers to balance at run time
|
115
118
|
def n_strand_options(strand_name, num_strands)
|
116
|
-
strand_num = num_strands > 1 ? rand(num_strands) + 1 : 1
|
119
|
+
strand_num = (num_strands > 1) ? rand(num_strands) + 1 : 1
|
117
120
|
strand_name += ":#{strand_num}" if strand_num > 1
|
118
121
|
{ strand: strand_name }
|
119
122
|
end
|
@@ -214,7 +217,7 @@ module Delayed
|
|
214
217
|
def failed?
|
215
218
|
failed_at
|
216
219
|
end
|
217
|
-
|
220
|
+
alias_method :failed, :failed?
|
218
221
|
|
219
222
|
def expired?
|
220
223
|
expires_at && (self.class.db_time_now >= expires_at)
|
data/lib/delayed/cli.rb
CHANGED
@@ -49,7 +49,7 @@ module Delayed
|
|
49
49
|
daemon.daemonize!
|
50
50
|
start
|
51
51
|
when nil
|
52
|
-
puts option_parser.
|
52
|
+
puts option_parser.help
|
53
53
|
else
|
54
54
|
raise("Unknown command: #{command.inspect}")
|
55
55
|
end
|
@@ -82,7 +82,8 @@ module Delayed
|
|
82
82
|
opts.on("-c", "--config [CONFIG_PATH]", "Use alternate config file (default #{@options[:config_file]})") do |c|
|
83
83
|
@options[:config_file] = c
|
84
84
|
end
|
85
|
-
opts.on("-p",
|
85
|
+
opts.on("-p",
|
86
|
+
"--pid [PID_PATH]",
|
86
87
|
"Use alternate folder for PID files (default #{@options[:pid_folder]})") do |p|
|
87
88
|
@options[:pid_folder] = p
|
88
89
|
end
|
data/lib/delayed/lifecycle.rb
CHANGED
@@ -46,7 +46,7 @@ module Delayed
|
|
46
46
|
missing_callback(event) unless @callbacks.key?(event)
|
47
47
|
|
48
48
|
unless EVENTS[event].size == args.size
|
49
|
-
raise ArgumentError, "Callback #{event} expects #{EVENTS[event].size} parameter(s): #{EVENTS[event].join(
|
49
|
+
raise ArgumentError, "Callback #{event} expects #{EVENTS[event].size} parameter(s): #{EVENTS[event].join(", ")}"
|
50
50
|
end
|
51
51
|
|
52
52
|
@callbacks[event].execute(*args, &block)
|
data/lib/delayed/log_tailer.rb
CHANGED
@@ -5,8 +5,8 @@ module Delayed
|
|
5
5
|
def run
|
6
6
|
if Rails.logger.respond_to?(:log_path)
|
7
7
|
log_path = Rails.logger.log_path
|
8
|
-
elsif Rails.logger.instance_variable_get(
|
9
|
-
log_path = Rails.logger.instance_variable_get(
|
8
|
+
elsif Rails.logger.instance_variable_get(:@logdev).try(:instance_variable_get, "@dev").try(:path)
|
9
|
+
log_path = Rails.logger.instance_variable_get(:@logdev).instance_variable_get(:@dev).path
|
10
10
|
else
|
11
11
|
return
|
12
12
|
end
|
@@ -19,7 +19,7 @@ module Delayed
|
|
19
19
|
@object.protected_methods.exclude?(method) &&
|
20
20
|
@object.private_methods.exclude?(method)
|
21
21
|
|
22
|
-
sender_is_object = @sender
|
22
|
+
sender_is_object = @sender.equal?(@object)
|
23
23
|
sender_is_class = @sender.is_a?(@object.class)
|
24
24
|
|
25
25
|
# even if the call is async, if the call is _going_ to generate an error, we make it synchronous
|
@@ -54,8 +54,10 @@ module Delayed
|
|
54
54
|
|
55
55
|
if ::Delayed::Job != ::Delayed::Backend::ActiveRecord::Job || connection != ::Delayed::Job.connection
|
56
56
|
connection.after_transaction_commit do
|
57
|
-
::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object,
|
58
|
-
|
57
|
+
::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object,
|
58
|
+
method,
|
59
|
+
args: args,
|
60
|
+
kwargs: kwargs,
|
59
61
|
on_failure: on_failure,
|
60
62
|
on_permanent_failure: on_permanent_failure,
|
61
63
|
sender: @sender),
|
@@ -65,7 +67,8 @@ module Delayed
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
result = ::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object,
|
70
|
+
result = ::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object,
|
71
|
+
method,
|
69
72
|
args: args,
|
70
73
|
kwargs: kwargs,
|
71
74
|
on_failure: on_failure,
|
@@ -1,7 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Delayed
|
4
|
-
PerformableMethod = Struct.new(:object,
|
4
|
+
PerformableMethod = Struct.new(:object,
|
5
|
+
:method, # rubocop:disable Lint/StructNewOverride
|
6
|
+
:args,
|
7
|
+
:kwargs,
|
8
|
+
:fail_cb,
|
9
|
+
:permanent_fail_cb,
|
10
|
+
:sender,
|
11
|
+
:sender_is_object,
|
12
|
+
:sender_is_class) do
|
5
13
|
def initialize(object, method, args: [], kwargs: {}, on_failure: nil, on_permanent_failure: nil, sender: nil)
|
6
14
|
raise NoMethodError, "undefined method `#{method}' for #{object.inspect}" unless object.respond_to?(method, true)
|
7
15
|
|
@@ -11,13 +19,8 @@ module Delayed
|
|
11
19
|
self.method = method.to_sym
|
12
20
|
self.fail_cb = on_failure
|
13
21
|
self.permanent_fail_cb = on_permanent_failure
|
14
|
-
self.
|
15
|
-
|
16
|
-
YAML.load(YAML.dump(sender))
|
17
|
-
rescue
|
18
|
-
# if for some reason you can't dump the sender, just drop it
|
19
|
-
self.sender = nil
|
20
|
-
end
|
22
|
+
self.sender_is_object = sender.equal?(object)
|
23
|
+
self.sender_is_class = sender.is_a?(object.class)
|
21
24
|
end
|
22
25
|
|
23
26
|
def display_name
|
@@ -32,14 +35,15 @@ module Delayed
|
|
32
35
|
def perform
|
33
36
|
kwargs = self.kwargs || {}
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
# back-compat for jobs queued before we assigned these in initialize
|
39
|
+
self.sender_is_object = sender.equal?(object) if sender_is_object.nil?
|
40
|
+
self.sender_is_class = sender.is_a?(object.class) if sender_is_class.nil?
|
37
41
|
|
38
|
-
if
|
42
|
+
if sender_is_object || (sender_is_class && object.protected_methods.include?(method))
|
39
43
|
if kwargs.empty?
|
40
|
-
object.
|
44
|
+
object.__send__(method, *args)
|
41
45
|
else
|
42
|
-
object.
|
46
|
+
object.__send__(method, *args, **kwargs)
|
43
47
|
end
|
44
48
|
elsif kwargs.empty?
|
45
49
|
object.public_send(method, *args)
|
@@ -59,9 +63,9 @@ module Delayed
|
|
59
63
|
def deep_de_ar_ize(arg)
|
60
64
|
case arg
|
61
65
|
when Hash
|
62
|
-
"{#{arg.map { |k, v| "#{deep_de_ar_ize(k)} => #{deep_de_ar_ize(v)}" }.join(
|
66
|
+
"{#{arg.map { |k, v| "#{deep_de_ar_ize(k)} => #{deep_de_ar_ize(v)}" }.join(", ")}}"
|
63
67
|
when Array
|
64
|
-
"[#{arg.map { |a| deep_de_ar_ize(a) }.join(
|
68
|
+
"[#{arg.map { |a| deep_de_ar_ize(a) }.join(", ")}]"
|
65
69
|
when ActiveRecord::Base
|
66
70
|
"#{arg.class}.find(#{arg.id})"
|
67
71
|
else
|
@@ -73,7 +77,7 @@ module Delayed
|
|
73
77
|
obj_name = object.is_a?(ActiveRecord::Base) ? "#{object.class}.find(#{object.id}).#{method}" : display_name
|
74
78
|
kgs = kwargs || {}
|
75
79
|
kwargs_str = kgs.map { |(k, v)| ", #{k}: #{deep_de_ar_ize(v)}" }.join
|
76
|
-
"#{obj_name}(#{args.map { |a| deep_de_ar_ize(a) }.join(
|
80
|
+
"#{obj_name}(#{args.map { |a| deep_de_ar_ize(a) }.join(", ")}#{kwargs_str})"
|
77
81
|
end
|
78
82
|
end
|
79
83
|
end
|
data/lib/delayed/periodic.rb
CHANGED
data/lib/delayed/settings.rb
CHANGED
@@ -26,6 +26,7 @@ module Delayed
|
|
26
26
|
:sleep_delay,
|
27
27
|
:sleep_delay_stagger,
|
28
28
|
:slow_exit_timeout,
|
29
|
+
:stranded_run_at_grace_period,
|
29
30
|
:worker_health_check_type,
|
30
31
|
:worker_health_check_config,
|
31
32
|
:worker_procname_prefix
|
@@ -132,6 +133,7 @@ module Delayed
|
|
132
133
|
self.fetch_batch_size = 5
|
133
134
|
self.select_random_from_batch = false
|
134
135
|
self.silence_periodic_log = false
|
136
|
+
self.stranded_run_at_grace_period = 10
|
135
137
|
|
136
138
|
self.num_strands = ->(_strand_name) {}
|
137
139
|
self.default_job_options = -> { {} }
|
data/lib/delayed/version.rb
CHANGED
@@ -163,7 +163,7 @@ module Delayed
|
|
163
163
|
forced_latency: forced_latency
|
164
164
|
)
|
165
165
|
logger.debug(
|
166
|
-
"Fetched and locked #{response.values.flatten.size} new jobs for workers (#{response.keys.join(
|
166
|
+
"Fetched and locked #{response.values.flatten.size} new jobs for workers (#{response.keys.join(", ")})."
|
167
167
|
)
|
168
168
|
response.each do |(worker_name, locked_jobs)|
|
169
169
|
if worker_name == prefetch_owner
|
@@ -267,7 +267,7 @@ module Delayed
|
|
267
267
|
end
|
268
268
|
|
269
269
|
def prefetch_owner
|
270
|
-
"prefetch:#{Socket.gethostname rescue
|
270
|
+
"prefetch:#{Socket.gethostname rescue "X"}"
|
271
271
|
end
|
272
272
|
|
273
273
|
def parent_exited?
|
@@ -9,9 +9,9 @@ module Delayed
|
|
9
9
|
ALIVE_CHECK_LINUX = '[ -d "/proc/$WORKER_PID" ]'
|
10
10
|
ALIVE_CHECK_MAC = "ps -p $WORKER_PID > /dev/null"
|
11
11
|
ALIVE_CHECK = RUBY_PLATFORM.include?("darwin") ? ALIVE_CHECK_MAC : ALIVE_CHECK_LINUX
|
12
|
-
SCRIPT_TEMPLATE =
|
13
|
-
WORKER_PID="
|
14
|
-
ORIGINAL_MTIME="
|
12
|
+
SCRIPT_TEMPLATE = <<~SH
|
13
|
+
WORKER_PID="%{pid}" # an example, filled from ruby when the check is created
|
14
|
+
ORIGINAL_MTIME="%{mtime}" # an example, filled from ruby when the check is created
|
15
15
|
|
16
16
|
if #{ALIVE_CHECK}; then
|
17
17
|
CURRENT_MTIME=$(#{STAT})
|
@@ -26,7 +26,7 @@ module Delayed
|
|
26
26
|
else
|
27
27
|
exit 255 # The process is no more, trigger a "critical" state.
|
28
28
|
fi
|
29
|
-
|
29
|
+
SH
|
30
30
|
|
31
31
|
def self.mtime(pid)
|
32
32
|
if RUBY_PLATFORM.include?("darwin")
|
data/lib/delayed/worker.rb
CHANGED
@@ -77,7 +77,7 @@ module Delayed
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def name
|
80
|
-
@name ||= "#{Socket.gethostname rescue
|
80
|
+
@name ||= "#{Socket.gethostname rescue "X"}:#{id}"
|
81
81
|
end
|
82
82
|
|
83
83
|
def process_name=(new_name)
|
@@ -100,7 +100,7 @@ module Delayed
|
|
100
100
|
def start
|
101
101
|
logger.info "Starting worker"
|
102
102
|
self.process_name =
|
103
|
-
"start:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority ||
|
103
|
+
"start:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || "max"}"
|
104
104
|
@self_pipe = IO.pipe
|
105
105
|
work_queue.init
|
106
106
|
|
@@ -170,7 +170,7 @@ module Delayed
|
|
170
170
|
|
171
171
|
self.class.lifecycle.run_callbacks(:loop, self) do
|
172
172
|
self.process_name =
|
173
|
-
"pop:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority ||
|
173
|
+
"pop:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || "max"}"
|
174
174
|
job = self.class.lifecycle.run_callbacks(:pop, self) do
|
175
175
|
work_queue.get_and_lock_next_available(name, config)
|
176
176
|
end
|
@@ -196,7 +196,7 @@ module Delayed
|
|
196
196
|
end
|
197
197
|
else
|
198
198
|
self.process_name =
|
199
|
-
"wait:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority ||
|
199
|
+
"wait:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || "max"}"
|
200
200
|
sleep(Settings.sleep_delay + (rand * Settings.sleep_delay_stagger)) unless exit?
|
201
201
|
end
|
202
202
|
end
|
@@ -220,7 +220,7 @@ module Delayed
|
|
220
220
|
end
|
221
221
|
job.destroy
|
222
222
|
end
|
223
|
-
logger.info("Completed #{log_job(job, :short)} #{format(
|
223
|
+
logger.info("Completed #{log_job(job, :short)} #{format("%.0fms", (runtime * 1000))}")
|
224
224
|
end
|
225
225
|
rescue ::Delayed::RetriableError => e
|
226
226
|
can_retry = job.attempts + 1 < job.inferred_max_attempts
|
@@ -279,7 +279,7 @@ module Delayed
|
|
279
279
|
previous_tmpdir = ENV.fetch("TMPDIR", nil)
|
280
280
|
|
281
281
|
self.class.running_job(job) do
|
282
|
-
dir = Dir.mktmpdir("job-#{job.id}-#{name.gsub(/[^\w.]/,
|
282
|
+
dir = Dir.mktmpdir("job-#{job.id}-#{name.gsub(/[^\w.]/, ".")}-")
|
283
283
|
begin
|
284
284
|
ENV["TMPDIR"] = dir
|
285
285
|
yield
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst-jobs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-05-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -285,33 +285,19 @@ dependencies:
|
|
285
285
|
- !ruby/object:Gem::Version
|
286
286
|
version: '3.10'
|
287
287
|
- !ruby/object:Gem::Dependency
|
288
|
-
name: rubocop
|
288
|
+
name: rubocop-inst
|
289
289
|
requirement: !ruby/object:Gem::Requirement
|
290
290
|
requirements:
|
291
291
|
- - "~>"
|
292
292
|
- !ruby/object:Gem::Version
|
293
|
-
version: '1
|
293
|
+
version: '1'
|
294
294
|
type: :development
|
295
295
|
prerelease: false
|
296
296
|
version_requirements: !ruby/object:Gem::Requirement
|
297
297
|
requirements:
|
298
298
|
- - "~>"
|
299
299
|
- !ruby/object:Gem::Version
|
300
|
-
version: '1
|
301
|
-
- !ruby/object:Gem::Dependency
|
302
|
-
name: rubocop-performance
|
303
|
-
requirement: !ruby/object:Gem::Requirement
|
304
|
-
requirements:
|
305
|
-
- - "~>"
|
306
|
-
- !ruby/object:Gem::Version
|
307
|
-
version: 1.12.0
|
308
|
-
type: :development
|
309
|
-
prerelease: false
|
310
|
-
version_requirements: !ruby/object:Gem::Requirement
|
311
|
-
requirements:
|
312
|
-
- - "~>"
|
313
|
-
- !ruby/object:Gem::Version
|
314
|
-
version: 1.12.0
|
300
|
+
version: '1'
|
315
301
|
- !ruby/object:Gem::Dependency
|
316
302
|
name: rubocop-rails
|
317
303
|
requirement: !ruby/object:Gem::Requirement
|