mutant 0.11.0 → 0.11.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfa3f4386dd2bb68e31b67124aac333cf71d13bb2fec0cf46fea56360475f3f4
4
- data.tar.gz: c1c3284ed18f7e2b268c8536a9103d11b7eb8abb0f3fc73a1890ffc8d461e9e5
3
+ metadata.gz: 70a7ce19bef24f9e278efb7beee74d9ae0eed625f0e4e4a712d9330ac1907339
4
+ data.tar.gz: 814ca08aed382018685010ca642903ea1e4da3226ae4c7c0fb0fae920818be49
5
5
  SHA512:
6
- metadata.gz: a20b1be07d23f2a0939bab498c500cf1707f75c647af84409d5ec42437bdd26aa6d4f89c9f70e558408e1280812da0cbc7cf7758af1c80c499289e3554b0b92d
7
- data.tar.gz: 276e169499aa4b48bc2488178de01b3d3ce1cb4647796bef023491c5d21faaed2d88e1ee61ae012c09d5c86f68ac68cda4a705174cc3cb88dab69e7cc4ea1578
6
+ metadata.gz: 3461d1141fdb8ec16d4262aaf9542ec9db4fc00bc31adf97024803ebd71133de3738c55dd08000f080ae59c8a29a6877eb9758001ea42ff54637a7b09d91e1ac
7
+ data.tar.gz: e03447c1d1d192fa98641fbee718ef3e6440b69a43d88023741635e348df94fe336cd92e716a1d8a9e638fba230530377a98ea413890f97b6654c0e45e88960e
data/LICENSE CHANGED
@@ -5,8 +5,8 @@ END-USER LICENSE AGREEMENT
5
5
  IMPORTANT: THIS SOFTWARE END-USER LICENSE AGREEMENT ("EULA") IS A LEGAL
6
6
  AGREEMENT (“Agreement”) BETWEEN YOU (THE CUSTOMER, EITHER AS AN INDIVIDUAL OR,
7
7
  IF PURCHASED OR OTHERWISE ACQUIRED BY OR FOR AN ENTITY, AS AN ENTITY) AND
8
- CONTRIBUTED SYSTEMS. READ IT CAREFULLY BEFORE COMPLETING THE INSTALLATION
9
- PROCESS AND USING SIDEKIQ PRO AND RELATED SOFTWARE COMPONENTS (“SOFTWARE”).
8
+ SCHIRP DSO LTD. READ IT CAREFULLY BEFORE COMPLETING THE INSTALLATION
9
+ PROCESS AND USING MUTANT AND RELATED SOFTWARE COMPONENTS (“SOFTWARE”).
10
10
 
11
11
  IT PROVIDES A LICENSE TO USE THE SOFTWARE AND CONTAINS WARRANTY INFORMATION
12
12
  AND LIABILITY DISCLAIMERS. BY INSTALLING AND USING THE SOFTWARE, YOU ARE
@@ -71,6 +71,10 @@ module Mutant
71
71
 
72
72
  hooks.run(:env_infection_pre, env)
73
73
 
74
+ config.environment_variables.each do |key, value|
75
+ world.environment_variables[key] = value
76
+ end
77
+
74
78
  config.includes.each(&world.load_path.public_method(:<<))
75
79
  config.requires.each(&world.kernel.public_method(:require))
76
80
 
@@ -62,6 +62,7 @@ module Mutant
62
62
  set(matcher: @config.matcher.add(attribute, value))
63
63
  end
64
64
 
65
+ # rubocop:disable Metrics/MethodLength
65
66
  def add_environment_options(parser)
66
67
  parser.separator('Environment:')
67
68
  parser.on('--zombie', 'Run mutant zombified') do
@@ -73,7 +74,14 @@ module Mutant
73
74
  parser.on('-r', '--require NAME', 'Require file with NAME') do |name|
74
75
  add(:requires, name)
75
76
  end
77
+ parser.on('--env KEY=VALUE', 'Set environment variable') do |value|
78
+ match = ENV_VARIABLE_KEY_VALUE_REGEXP.match(value) || fail("Invalid env variable: #{value.inspect}")
79
+ set(
80
+ environment_variables: @config.environment_variables.merge(match[:key] => match[:value])
81
+ )
82
+ end
76
83
  end
84
+ # rubocop:enable Metrics/MethodLength
77
85
 
78
86
  def add_integration_options(parser)
79
87
  parser.separator('Integration:')
data/lib/mutant/config.rb CHANGED
@@ -5,9 +5,12 @@ module Mutant
5
5
  #
6
6
  # Does not reference any "external" volatile state. The configuration applied
7
7
  # to current environment is being represented by the Mutant::Env object.
8
+ #
9
+ # rubocop:disable Metrics/ClassLength
8
10
  class Config
9
11
  include Adamantium, Anima.new(
10
12
  :coverage_criteria,
13
+ :environment_variables,
11
14
  :expression_parser,
12
15
  :fail_fast,
13
16
  :hooks,
@@ -48,16 +51,17 @@ module Mutant
48
51
  # rubocop:disable Metrics/MethodLength
49
52
  def merge(other)
50
53
  other.with(
51
- coverage_criteria: coverage_criteria.merge(other.coverage_criteria),
52
- fail_fast: fail_fast || other.fail_fast,
53
- hooks: hooks + other.hooks,
54
- includes: includes + other.includes,
55
- integration: other.integration || integration,
56
- jobs: other.jobs || jobs,
57
- matcher: matcher.merge(other.matcher),
58
- mutation_timeout: other.mutation_timeout || mutation_timeout,
59
- requires: requires + other.requires,
60
- zombie: zombie || other.zombie
54
+ coverage_criteria: coverage_criteria.merge(other.coverage_criteria),
55
+ environment_variables: environment_variables.merge(other.environment_variables),
56
+ fail_fast: fail_fast || other.fail_fast,
57
+ hooks: hooks + other.hooks,
58
+ includes: includes + other.includes,
59
+ integration: other.integration || integration,
60
+ jobs: other.jobs || jobs,
61
+ matcher: matcher.merge(other.matcher),
62
+ mutation_timeout: other.mutation_timeout || mutation_timeout,
63
+ requires: requires + other.requires,
64
+ zombie: zombie || other.zombie
61
65
  )
62
66
  end
63
67
  # rubocop:enable Metrics/AbcSize
@@ -117,6 +121,24 @@ module Mutant
117
121
  )
118
122
  )
119
123
 
124
+ # Parse a hash of environment variables
125
+ #
126
+ # @param [Hash<Object,Object>]
127
+ #
128
+ # @return [Either<String,Hash<String,String>]
129
+ #
130
+ def self.parse_environment_variables(hash)
131
+ invalid = hash.keys.reject { |key| key.instance_of?(String) }
132
+ return Either::Left.new("Non string keys: #{invalid}") if invalid.any?
133
+
134
+ invalid = hash.keys.grep_v(ENV_VARIABLE_KEY_REGEXP)
135
+ return Either::Left.new("Invalid keys: #{invalid}") if invalid.any?
136
+
137
+ invalid = hash.values.reject { |value| value.instance_of?(String) }
138
+ return Either::Left.new("Non string values: #{invalid}") if invalid.any?
139
+
140
+ Either::Right.new(hash)
141
+ end
120
142
  TRANSFORM = Transform::Sequence.new(
121
143
  [
122
144
  Transform::Exception.new(SystemCallError, :read.to_proc),
@@ -124,14 +146,23 @@ module Mutant
124
146
  Transform::Hash.new(
125
147
  optional: [
126
148
  Transform::Hash::Key.new('coverage_criteria', ->(value) { CoverageCriteria::TRANSFORM.call(value) }),
127
- Transform::Hash::Key.new('fail_fast', Transform::BOOLEAN),
128
- Transform::Hash::Key.new('hooks', PATHNAME_ARRAY),
129
- Transform::Hash::Key.new('includes', Transform::STRING_ARRAY),
130
- Transform::Hash::Key.new('integration', Transform::STRING),
131
- Transform::Hash::Key.new('jobs', Transform::INTEGER),
132
- Transform::Hash::Key.new('matcher', Matcher::Config::LOADER),
133
- Transform::Hash::Key.new('mutation_timeout', Transform::FLOAT),
134
- Transform::Hash::Key.new('requires', Transform::STRING_ARRAY)
149
+ Transform::Hash::Key.new(
150
+ 'environment_variables',
151
+ Transform::Sequence.new(
152
+ [
153
+ Transform::Primitive.new(Hash),
154
+ Transform::Block.capture(:environment_variables, &method(:parse_environment_variables))
155
+ ]
156
+ )
157
+ ),
158
+ Transform::Hash::Key.new('fail_fast', Transform::BOOLEAN),
159
+ Transform::Hash::Key.new('hooks', PATHNAME_ARRAY),
160
+ Transform::Hash::Key.new('includes', Transform::STRING_ARRAY),
161
+ Transform::Hash::Key.new('integration', Transform::STRING),
162
+ Transform::Hash::Key.new('jobs', Transform::INTEGER),
163
+ Transform::Hash::Key.new('matcher', Matcher::Config::LOADER),
164
+ Transform::Hash::Key.new('mutation_timeout', Transform::FLOAT),
165
+ Transform::Hash::Key.new('requires', Transform::STRING_ARRAY)
135
166
  ],
136
167
  required: []
137
168
  ),
@@ -141,4 +172,5 @@ module Mutant
141
172
 
142
173
  private_constant(:TRANSFORM)
143
174
  end # Config
175
+ # rubocop:enable Metrics/ClassLength
144
176
  end # Mutant
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Expression
5
+ class Descendants < self
6
+ include Anima.new(:const_name)
7
+
8
+ REGEXP = /\Adescendants:(?<const_name>.+)\z/.freeze
9
+
10
+ def syntax
11
+ "descendants:#{const_name}"
12
+ end
13
+
14
+ def matcher
15
+ Matcher::Descendants.new(const_name: const_name)
16
+ end
17
+ end # Descendants
18
+ end # Expression
19
+ end # Mutant
@@ -14,7 +14,7 @@ module Mutant
14
14
  def call(env)
15
15
  matchers.flat_map do |matcher|
16
16
  matcher.call(env)
17
- end
17
+ end.uniq
18
18
  end
19
19
 
20
20
  end # Chain
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Matcher
5
+ # Matcher for all descendants by constant name
6
+ class Descendants < self
7
+ include Anima.new(:const_name)
8
+
9
+ def call(env)
10
+ const = env.world.try_const_get(const_name) or return EMPTY_ARRAY
11
+
12
+ Chain.new(
13
+ matched_scopes(env, const).map { |scope| Scope.new(scope.raw) }
14
+ ).call(env)
15
+ end
16
+
17
+ private
18
+
19
+ def matched_scopes(env, const)
20
+ env.matchable_scopes.select do |scope|
21
+ scope.raw.equal?(const) || const > scope.raw
22
+ end
23
+ end
24
+ end # Descendant
25
+ end # Matcher
26
+ end # Mutant
@@ -21,7 +21,7 @@ module Mutant
21
21
  # @return [Enumerable<Subject>]
22
22
  def call(env)
23
23
  Chain.new(
24
- methods.map { |method| matcher.new(scope, method) }
24
+ methods(env).map { |method| matcher.new(scope, method) }
25
25
  ).call(env)
26
26
  end
27
27
 
@@ -31,17 +31,16 @@ module Mutant
31
31
  self.class::MATCHER
32
32
  end
33
33
 
34
- def methods
34
+ def methods(env)
35
35
  candidate_names.each_with_object([]) do |name, methods|
36
- method = access(name)
37
- methods << method if method.owner.equal?(candidate_scope)
36
+ method = access(env, name)
37
+ methods << method if method&.owner.equal?(candidate_scope)
38
38
  end
39
39
  end
40
- memoize :methods
41
40
 
42
41
  def candidate_names
43
42
  CANDIDATE_NAMES
44
- .map(&candidate_scope.public_method(:public_send))
43
+ .map { |name| candidate_scope.public_send(name, false) }
45
44
  .reduce(:+)
46
45
  .sort
47
46
  end
@@ -55,7 +54,7 @@ module Mutant
55
54
 
56
55
  private
57
56
 
58
- def access(method_name)
57
+ def access(_env, method_name)
59
58
  scope.method(method_name)
60
59
  end
61
60
 
@@ -71,7 +70,7 @@ module Mutant
71
70
 
72
71
  private
73
72
 
74
- def access(method_name)
73
+ def access(_env, method_name)
75
74
  scope.method(method_name)
76
75
  end
77
76
 
@@ -84,11 +83,35 @@ module Mutant
84
83
  class Instance < self
85
84
  MATCHER = Matcher::Method::Instance
86
85
 
86
+ MESSAGE = <<~'MESSAGE'
87
+ Caught an exception while accessing a method with
88
+ #instance_method that is part of #{public,privat,protected}_instance_methods.
89
+
90
+ This is a bug in your ruby implementation its stdlib, libaries our your code.
91
+
92
+ Mutant will ignore this method:
93
+
94
+ Object: %<scope>s
95
+ Method: %<method_name>s
96
+ Exception:
97
+
98
+ %<exception>s
99
+
100
+ See: https://github.com/mbj/mutant/issues/1273
101
+ MESSAGE
102
+
87
103
  private
88
104
 
89
- def access(method_name)
105
+ # rubocop:disable Lint/RescueException
106
+ def access(env, method_name)
90
107
  scope.instance_method(method_name)
108
+ rescue Exception => exception
109
+ env.warn(
110
+ MESSAGE % { scope: scope, method_name: method_name, exception: exception }
111
+ )
112
+ nil
91
113
  end
114
+ # rubocop:enable Lint/RescueException
92
115
 
93
116
  def candidate_scope
94
117
  scope
@@ -6,6 +6,8 @@ module Mutant
6
6
  # Mutator for arguments node
7
7
  class Arguments < self
8
8
 
9
+ ANONYMOUS_BLOCKARG_PRED = ::Parser::AST::Node.new(:blockarg, [nil]).method(:eql?)
10
+
9
11
  handle(:args)
10
12
 
11
13
  private
@@ -17,15 +19,24 @@ module Mutant
17
19
  end
18
20
 
19
21
  def emit_argument_presence
20
- emit_type
22
+ emit_type unless removed_block_arg?(EMPTY_ARRAY)
21
23
 
22
24
  Util::Array::Presence.call(children).each do |children|
23
- unless children.one? && n_mlhs?(children.first)
25
+ unless removed_block_arg?(children) || (children.one? && n_mlhs?(children.first))
24
26
  emit_type(*children)
25
27
  end
26
28
  end
27
29
  end
28
30
 
31
+ def removed_block_arg?(children)
32
+ anonymous_block_arg? && children.none?(&ANONYMOUS_BLOCKARG_PRED)
33
+ end
34
+
35
+ def anonymous_block_arg?
36
+ children.any?(&ANONYMOUS_BLOCKARG_PRED)
37
+ end
38
+ memoize :anonymous_block_arg?
39
+
29
40
  def emit_argument_mutations
30
41
  children.each_with_index do |child, index|
31
42
  Mutator.mutate(child).each do |mutant|
@@ -12,6 +12,7 @@ module Mutant
12
12
  private
13
13
 
14
14
  def dispatch
15
+ return unless argument
15
16
  emit_argument_mutations
16
17
  emit_symbol_to_proc_mutations
17
18
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.0'
5
+ VERSION = '0.11.4'
6
6
  end # Mutant
data/lib/mutant/world.rb CHANGED
@@ -5,6 +5,7 @@ module Mutant
5
5
  class World
6
6
  include Adamantium, Anima.new(
7
7
  :condition_variable,
8
+ :environment_variables,
8
9
  :gem,
9
10
  :gem_method,
10
11
  :io,
@@ -49,6 +50,19 @@ module Mutant
49
50
  end
50
51
  end
51
52
 
53
+ # Try const get
54
+ #
55
+ # @param [String]
56
+ #
57
+ # @return [Class|Module|nil]
58
+ #
59
+ # rubocop:disable Lint/SuppressedException
60
+ def try_const_get(name)
61
+ kernel.const_get(name)
62
+ rescue NameError
63
+ end
64
+ # rubocop:enable Lint/SuppressedException
65
+
52
66
  # Deadline
53
67
  #
54
68
  # @param [Float, nil] allowed_time
data/lib/mutant.rb CHANGED
@@ -38,6 +38,11 @@ module Mutant
38
38
  EMPTY_ARRAY = [].freeze
39
39
  EMPTY_HASH = {}.freeze
40
40
  SCOPE_OPERATOR = '::'
41
+
42
+ env_key = /[a-zA-Z_\d]+/
43
+
44
+ ENV_VARIABLE_KEY_VALUE_REGEXP = /\A(?<key>#{env_key}+)=(?<value>.*)\z/.freeze
45
+ ENV_VARIABLE_KEY_REGEXP = /\A#{env_key}\z/.freeze
41
46
  end # Mutant
42
47
 
43
48
  require 'mutant/procto'
@@ -164,23 +169,25 @@ require 'mutant/subject/method/instance'
164
169
  require 'mutant/subject/method/singleton'
165
170
  require 'mutant/subject/method/metaclass'
166
171
  require 'mutant/matcher'
167
- require 'mutant/matcher/config'
168
172
  require 'mutant/matcher/chain'
173
+ require 'mutant/matcher/config'
174
+ require 'mutant/matcher/descendants'
175
+ require 'mutant/matcher/filter'
169
176
  require 'mutant/matcher/method'
170
- require 'mutant/matcher/method/singleton'
171
- require 'mutant/matcher/method/metaclass'
172
177
  require 'mutant/matcher/method/instance'
178
+ require 'mutant/matcher/method/metaclass'
179
+ require 'mutant/matcher/method/singleton'
173
180
  require 'mutant/matcher/methods'
174
181
  require 'mutant/matcher/namespace'
175
- require 'mutant/matcher/scope'
176
- require 'mutant/matcher/filter'
177
182
  require 'mutant/matcher/null'
183
+ require 'mutant/matcher/scope'
178
184
  require 'mutant/matcher/static'
179
185
  require 'mutant/expression'
180
- require 'mutant/expression/parser'
186
+ require 'mutant/expression/descendants'
181
187
  require 'mutant/expression/method'
182
188
  require 'mutant/expression/methods'
183
189
  require 'mutant/expression/namespace'
190
+ require 'mutant/expression/parser'
184
191
  require 'mutant/test'
185
192
  require 'mutant/timer'
186
193
  require 'mutant/integration'
@@ -234,46 +241,49 @@ require 'mutant/license/subscription/commercial'
234
241
 
235
242
  module Mutant
236
243
  WORLD = World.new(
237
- condition_variable: ConditionVariable,
238
- gem: Gem,
239
- gem_method: method(:gem),
240
- io: IO,
241
- json: JSON,
242
- kernel: Kernel,
243
- load_path: $LOAD_PATH,
244
- marshal: Marshal,
245
- mutex: Mutex,
246
- object_space: ObjectSpace,
247
- open3: Open3,
248
- pathname: Pathname,
249
- process: Process,
250
- stderr: $stderr,
251
- stdout: $stdout,
252
- thread: Thread,
253
- timer: Timer.new(Process)
244
+ condition_variable: ConditionVariable,
245
+ environment_variables: ENV,
246
+ gem: Gem,
247
+ gem_method: method(:gem),
248
+ io: IO,
249
+ json: JSON,
250
+ kernel: Kernel,
251
+ load_path: $LOAD_PATH,
252
+ marshal: Marshal,
253
+ mutex: Mutex,
254
+ object_space: ObjectSpace,
255
+ open3: Open3,
256
+ pathname: Pathname,
257
+ process: Process,
258
+ stderr: $stderr,
259
+ stdout: $stdout,
260
+ thread: Thread,
261
+ timer: Timer.new(Process)
254
262
  )
255
263
 
256
264
  # Reopen class to initialize constant to avoid dep circle
257
265
  class Config
258
266
  DEFAULT = new(
259
- coverage_criteria: Config::CoverageCriteria::EMPTY,
260
- expression_parser: Expression::Parser.new([
267
+ coverage_criteria: Config::CoverageCriteria::EMPTY,
268
+ expression_parser: Expression::Parser.new([
269
+ Expression::Descendants,
261
270
  Expression::Method,
262
271
  Expression::Methods,
263
272
  Expression::Namespace::Exact,
264
273
  Expression::Namespace::Recursive
265
274
  ]),
266
- fail_fast: false,
267
- hooks: EMPTY_ARRAY,
268
- includes: EMPTY_ARRAY,
269
- integration: nil,
270
- isolation: Mutant::Isolation::Fork.new(WORLD),
271
- jobs: nil,
272
- matcher: Matcher::Config::DEFAULT,
273
- mutation_timeout: nil,
274
- reporter: Reporter::CLI.build(WORLD.stdout),
275
- requires: EMPTY_ARRAY,
276
- zombie: false
275
+ fail_fast: false,
276
+ environment_variables: EMPTY_HASH,
277
+ hooks: EMPTY_ARRAY,
278
+ includes: EMPTY_ARRAY,
279
+ integration: nil,
280
+ isolation: Mutant::Isolation::Fork.new(WORLD),
281
+ jobs: nil,
282
+ matcher: Matcher::Config::DEFAULT,
283
+ mutation_timeout: nil,
284
+ reporter: Reporter::CLI.build(WORLD.stdout),
285
+ requires: EMPTY_ARRAY,
286
+ zombie: false
277
287
  )
278
288
  end # Config
279
289
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-18 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
33
+ version: 3.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0
40
+ version: 3.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: regexp_parser
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: 0.6.0
81
+ version: 0.6.4
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: 0.6.0
88
+ version: 0.6.4
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: parallel
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -207,6 +207,7 @@ files:
207
207
  - lib/mutant/context.rb
208
208
  - lib/mutant/env.rb
209
209
  - lib/mutant/expression.rb
210
+ - lib/mutant/expression/descendants.rb
210
211
  - lib/mutant/expression/method.rb
211
212
  - lib/mutant/expression/methods.rb
212
213
  - lib/mutant/expression/namespace.rb
@@ -226,6 +227,7 @@ files:
226
227
  - lib/mutant/matcher.rb
227
228
  - lib/mutant/matcher/chain.rb
228
229
  - lib/mutant/matcher/config.rb
230
+ - lib/mutant/matcher/descendants.rb
229
231
  - lib/mutant/matcher/filter.rb
230
232
  - lib/mutant/matcher/method.rb
231
233
  - lib/mutant/matcher/method/instance.rb
@@ -382,7 +384,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
382
384
  - !ruby/object:Gem::Version
383
385
  version: '0'
384
386
  requirements: []
385
- rubygems_version: 3.1.6
387
+ rubygems_version: 3.3.3
386
388
  signing_key:
387
389
  specification_version: 4
388
390
  summary: ''