contracts 0.16.1 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Contracts
2
4
  # Handles class and instance methods addition
3
5
  # Represents single such method
4
6
  class MethodHandler
5
7
  METHOD_REFERENCE_FACTORY = {
6
8
  :class_methods => SingletonMethodReference,
7
- :instance_methods => MethodReference
9
+ :instance_methods => MethodReference,
8
10
  }
9
11
 
10
12
  RAW_METHOD_STRATEGY = {
11
13
  :class_methods => lambda { |target, name| target.method(name) },
12
- :instance_methods => lambda { |target, name| target.instance_method(name) }
14
+ :instance_methods => lambda { |target, name| target.instance_method(name) },
13
15
  }
14
16
 
15
17
  # Creates new instance of MethodHandler
@@ -78,11 +80,13 @@ module Contracts
78
80
 
79
81
  def pattern_matching?
80
82
  return @_pattern_matching if defined?(@_pattern_matching)
83
+
81
84
  @_pattern_matching = decorated_methods.any? { |x| x.method != method_reference }
82
85
  end
83
86
 
84
87
  def mark_pattern_matching_decorators
85
88
  return unless pattern_matching?
89
+
86
90
  decorated_methods.each(&:pattern_match!)
87
91
  end
88
92
 
@@ -107,13 +111,13 @@ module Contracts
107
111
  current_engine = engine
108
112
 
109
113
  # We are gonna redefine original method here
110
- method_reference.make_definition(target) do |*args, &blk|
114
+ method_reference.make_definition(target) do |*args, **kargs, &blk|
111
115
  engine = current_engine.nearest_decorated_ancestor
112
116
 
113
117
  # If we weren't able to find any ancestor that has decorated methods
114
118
  # FIXME : this looks like untested code (commenting it out doesn't make specs red)
115
119
  unless engine
116
- fail "Couldn't find decorator for method " + self.class.name + ":#{name}.\nDoes this method look correct to you? If you are using contracts from rspec, rspec wraps classes in it's own class.\nLook at the specs for contracts.ruby as an example of how to write contracts in this case."
120
+ fail "Couldn't find decorator for method #{self.class.name}:#{name}.\nDoes this method look correct to you? If you are using contracts from rspec, rspec wraps classes in it's own class.\nLook at the specs for contracts.ruby as an example of how to write contracts in this case."
117
121
  end
118
122
 
119
123
  # Fetch decorated methods out of the contracts engine
@@ -130,17 +134,20 @@ module Contracts
130
134
  last_error = nil
131
135
 
132
136
  decorated_methods.each do |decorated_method|
133
- result = decorated_method.call_with_inner(true, self, *args, &blk)
137
+ result = decorated_method.call_with_inner(true, self, *args, **kargs, &blk)
134
138
  return result unless result.is_a?(ParamContractError)
139
+
135
140
  last_error = result
136
141
  end
137
142
 
138
143
  begin
139
- if ::Contract.failure_callback(last_error.data, false)
140
- decorated_methods.last.call_with_inner(false, self, *args, &blk)
144
+ if ::Contract.failure_callback(last_error&.data, use_pattern_matching: false)
145
+ decorated_methods.last.call_with_inner(false, self, *args, **kargs, &blk)
141
146
  end
147
+ # rubocop:disable Naming/RescuedExceptionsVariableName
142
148
  rescue expected_error => final_error
143
149
  raise final_error.to_contract_error
150
+ # rubocop:enable Naming/RescuedExceptionsVariableName
144
151
  end
145
152
  end
146
153
  end
@@ -173,7 +180,8 @@ https://github.com/egonSchiele/contracts.ruby/issues
173
180
 
174
181
  return if matched.empty?
175
182
 
176
- fail ContractError.new(%{
183
+ fail ContractError.new(
184
+ %{
177
185
  It looks like you are trying to use pattern-matching, but
178
186
  multiple definitions for function '#{method_name}' have the same
179
187
  contract for input parameters:
@@ -181,7 +189,9 @@ contract for input parameters:
181
189
  #{(matched + [decorator]).map(&:to_s).join("\n")}
182
190
 
183
191
  Each definition needs to have a different contract for the parameters.
184
- }, {})
192
+ },
193
+ {},
194
+ )
185
195
  end
186
196
  end
187
197
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Contracts
2
4
  # MethodReference represents original method reference that was
3
5
  # decorated by contracts.ruby. Used for instance methods.
@@ -39,8 +41,8 @@ module Contracts
39
41
 
40
42
  # Calls original method on specified `this` argument with
41
43
  # specified arguments `args` and block `&blk`.
42
- def send_to(this, *args, &blk)
43
- this.send(aliased_name, *args, &blk)
44
+ def send_to(this, *args, **kargs, &blk)
45
+ this.send(aliased_name, *args, **kargs, &blk)
44
46
  end
45
47
 
46
48
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Contracts
2
4
  module Support
3
5
  class << self
@@ -8,7 +10,7 @@ module Contracts
8
10
  if file.nil? || line.nil?
9
11
  ""
10
12
  else
11
- file + ":" + line.to_s
13
+ "#{file}:#{line}"
12
14
  end
13
15
  end
14
16
 
@@ -45,7 +47,7 @@ module Contracts
45
47
  def indent_string(string, amount)
46
48
  string.gsub(
47
49
  /^(?!$)/,
48
- (string[/^[ \t]/] || " ") * amount
50
+ (string[/^[ \t]/] || " ") * amount,
49
51
  )
50
52
  end
51
53
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Contracts
2
4
  module Validators
3
5
  DEFAULT_VALIDATOR_STRATEGIES = {
@@ -9,6 +11,7 @@ module Contracts
9
11
  Array => lambda do |contract|
10
12
  lambda do |arg|
11
13
  return false unless arg.is_a?(Array) && arg.length == contract.length
14
+
12
15
  arg.zip(contract).all? do |_arg, _contract|
13
16
  Contract.valid?(_arg, _contract)
14
17
  end
@@ -19,6 +22,7 @@ module Contracts
19
22
  Hash => lambda do |contract|
20
23
  lambda do |arg|
21
24
  return false unless arg.is_a?(Hash)
25
+
22
26
  contract.keys.all? do |k|
23
27
  Contract.valid?(arg[k], contract[k])
24
28
  end
@@ -59,7 +63,7 @@ module Contracts
59
63
 
60
64
  :default => lambda do |contract|
61
65
  lambda { |arg| contract == arg }
62
- end
66
+ end,
63
67
  }.freeze
64
68
 
65
69
  # Allows to override validator with custom one.
@@ -90,7 +94,7 @@ module Contracts
90
94
  else
91
95
  if contract.respond_to? :valid?
92
96
  :valid
93
- elsif klass == Class || klass == Module
97
+ elsif [Class, Module].include?(klass)
94
98
  :class
95
99
  else
96
100
  :default
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Contracts
2
- VERSION = "0.16.1"
4
+ VERSION = "0.17.1"
3
5
  end
data/lib/contracts.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "contracts/version"
1
4
  require "contracts/attrs"
2
5
  require "contracts/builtin_contracts"
3
6
  require "contracts/decorators"
@@ -50,8 +53,10 @@ class Contract < Contracts::Decorator
50
53
  end
51
54
  end
52
55
 
53
- attr_reader :args_contracts, :ret_contract, :klass, :method
56
+ attr_reader :args_contracts, :kargs_contract, :ret_contract, :klass, :method
57
+
54
58
  def initialize(klass, method, *contracts)
59
+ super(klass, method)
55
60
  unless contracts.last.is_a?(Hash)
56
61
  unless contracts.one?
57
62
  fail %{
@@ -65,6 +70,9 @@ class Contract < Contracts::Decorator
65
70
 
66
71
  # internally we just convert that return value syntax back to an array
67
72
  @args_contracts = contracts[0, contracts.size - 1] + contracts[-1].keys
73
+ # Extract contract for keyword arguments
74
+ @kargs_contract = args_contracts.find { |c| c.is_a?(Contracts::Builtin::KeywordArgs) }
75
+ args_contracts.delete(kargs_contract) if kargs_contract
68
76
 
69
77
  @ret_contract = contracts[-1].values[0]
70
78
 
@@ -72,6 +80,8 @@ class Contract < Contracts::Decorator
72
80
  Contract.make_validator(contract)
73
81
  end
74
82
 
83
+ @kargs_validator = kargs_contract ? Contract.make_validator(kargs_contract) : nil
84
+
75
85
  @args_contract_index = args_contracts.index do |contract|
76
86
  contract.is_a? Contracts::Args
77
87
  end
@@ -89,21 +99,11 @@ class Contract < Contracts::Decorator
89
99
 
90
100
  # ====
91
101
 
92
- # == @has_options_contract
93
- last_contract = args_contracts.last
94
- penultimate_contract = args_contracts[-2]
95
- @has_options_contract = if @has_proc_contract
96
- penultimate_contract.is_a?(Hash) || penultimate_contract.is_a?(Contracts::Builtin::KeywordArgs)
97
- else
98
- last_contract.is_a?(Hash) || last_contract.is_a?(Contracts::Builtin::KeywordArgs)
99
- end
100
- # ===
101
-
102
102
  @klass, @method = klass, method
103
103
  end
104
104
 
105
- def pretty_contract c
106
- c.is_a?(Class) ? c.name : c.class.name
105
+ def pretty_contract contract
106
+ contract.is_a?(Class) ? contract.name : contract.class.name
107
107
  end
108
108
 
109
109
  def to_s
@@ -130,15 +130,15 @@ class Contract < Contracts::Decorator
130
130
  expected_prefix = "Expected: "
131
131
  expected_value = Contracts::Support.indent_string(
132
132
  Contracts::Formatters::Expected.new(data[:contract]).contract.pretty_inspect,
133
- expected_prefix.length
133
+ expected_prefix.length,
134
134
  ).strip
135
- expected_line = expected_prefix + expected_value + ","
135
+ expected_line = "#{expected_prefix}#{expected_value},"
136
136
 
137
137
  # Actual
138
138
  actual_prefix = "Actual: "
139
139
  actual_value = Contracts::Support.indent_string(
140
140
  data[:arg].pretty_inspect,
141
- actual_prefix.length
141
+ actual_prefix.length,
142
142
  ).strip
143
143
  actual_line = actual_prefix + actual_value
144
144
 
@@ -157,16 +157,19 @@ class Contract < Contracts::Decorator
157
157
  position_value = Contracts::Support.method_position(data[:method])
158
158
  position_line = position_prefix + position_value
159
159
 
160
- header +
161
- "\n" +
160
+ [
161
+ header,
162
162
  Contracts::Support.indent_string(
163
- [expected_line,
164
- actual_line,
165
- value_line,
166
- contract_line,
167
- position_line].join("\n"),
168
- indent_amount
169
- )
163
+ [
164
+ expected_line,
165
+ actual_line,
166
+ value_line,
167
+ contract_line,
168
+ position_line,
169
+ ].join("\n"),
170
+ indent_amount,
171
+ ),
172
+ ].join("\n")
170
173
  end
171
174
 
172
175
  # Callback for when a contract fails. By default it raises
@@ -182,7 +185,7 @@ class Contract < Contracts::Decorator
182
185
  # puts failure_msg(data)
183
186
  # exit
184
187
  # end
185
- def self.failure_callback(data, use_pattern_matching = true)
188
+ def self.failure_callback(data, use_pattern_matching: true)
186
189
  if data[:contracts].pattern_match? && use_pattern_matching
187
190
  return DEFAULT_FAILURE_CALLBACK.call(data)
188
191
  end
@@ -242,20 +245,9 @@ class Contract < Contracts::Decorator
242
245
  # returns true if it appended nil
243
246
  def maybe_append_block! args, blk
244
247
  return false unless @has_proc_contract && !blk &&
245
- (@args_contract_index || args.size < args_contracts.size)
246
- args << nil
247
- true
248
- end
248
+ (@args_contract_index || args.size < args_contracts.size)
249
249
 
250
- # Same thing for when we have named params but didn't pass any in.
251
- # returns true if it appended nil
252
- def maybe_append_options! args, blk
253
- return false unless @has_options_contract
254
- if @has_proc_contract && (args_contracts[-2].is_a?(Hash) || args_contracts[-2].is_a?(Contracts::Builtin::KeywordArgs)) && !args[-2].is_a?(Hash)
255
- args.insert(-2, {})
256
- elsif (args_contracts[-1].is_a?(Hash) || args_contracts[-1].is_a?(Contracts::Builtin::KeywordArgs)) && !args[-1].is_a?(Hash)
257
- args << {}
258
- end
250
+ args << nil
259
251
  true
260
252
  end
261
253
 
@@ -30,7 +30,7 @@ RSpec.describe "Contracts:" do
30
30
  end
31
31
 
32
32
  describe "Num:" do
33
- it "should pass for Fixnums" do
33
+ it "should pass for Integers" do
34
34
  passes { @o.double(2) }
35
35
  end
36
36
 
@@ -376,10 +376,6 @@ RSpec.describe "Contracts:" do
376
376
  fails { @o.hash_keywordargs(:hash => nil) }
377
377
  fails { @o.hash_keywordargs(:hash => 1) }
378
378
  end
379
-
380
- it "should pass if a method is overloaded with non-KeywordArgs" do
381
- passes { @o.person_keywordargs("name", 10) }
382
- end
383
379
  end
384
380
 
385
381
  describe "Optional:" do
@@ -405,15 +401,15 @@ RSpec.describe "Contracts:" do
405
401
  end
406
402
 
407
403
  context "given a fulfilled contract" do
408
- it { expect(@o.gives_max_value(:panda => 1, :bamboo => 2)).to eq(2) }
409
- it { expect(@o.pretty_gives_max_value(:panda => 1, :bamboo => 2)).to eq(2) }
404
+ it { expect(@o.gives_max_value({ :panda => 1, :bamboo => 2 })).to eq(2) }
405
+ it { expect(@o.pretty_gives_max_value({ :panda => 1, :bamboo => 2 })).to eq(2) }
410
406
  end
411
407
 
412
408
  context "given an unfulfilled contract" do
413
- it { fails { @o.gives_max_value(:panda => "1", :bamboo => "2") } }
409
+ it { fails { @o.gives_max_value({ :panda => "1", :bamboo => "2" }) } }
414
410
  it { fails { @o.gives_max_value(nil) } }
415
411
  it { fails { @o.gives_max_value(1) } }
416
- it { fails { @o.pretty_gives_max_value(:panda => "1", :bamboo => "2") } }
412
+ it { fails { @o.pretty_gives_max_value({ :panda => "1", :bamboo => "2" }) } }
417
413
  end
418
414
 
419
415
  describe "#to_s" do
@@ -430,25 +426,25 @@ RSpec.describe "Contracts:" do
430
426
  describe "StrictHash:" do
431
427
  context "when given an exact correct input" do
432
428
  it "does not raise an error" do
433
- passes { @o.strict_person(:name => "calvin", :age => 10) }
429
+ passes { @o.strict_person({ :name => "calvin", :age => 10 }) }
434
430
  end
435
431
  end
436
432
 
437
433
  context "when given an input with correct keys but wrong types" do
438
434
  it "raises an error" do
439
- fails { @o.strict_person(:name => "calvin", :age => "10") }
435
+ fails { @o.strict_person({ :name => "calvin", :age => "10" }) }
440
436
  end
441
437
  end
442
438
 
443
439
  context "when given an input with missing keys" do
444
440
  it "raises an error" do
445
- fails { @o.strict_person(:name => "calvin") }
441
+ fails { @o.strict_person({ :name => "calvin" }) }
446
442
  end
447
443
  end
448
444
 
449
445
  context "when given an input with extra keys" do
450
446
  it "raises an error" do
451
- fails { @o.strict_person(:name => "calvin", :age => 10, :soft => true) }
447
+ fails { @o.strict_person({ :name => "calvin", :age => 10, :soft => true }) }
452
448
  end
453
449
  end
454
450
 
@@ -349,19 +349,19 @@ RSpec.describe "Contracts:" do
349
349
 
350
350
  describe "Hashes" do
351
351
  it "should pass for exact correct input" do
352
- expect { @o.person(:name => "calvin", :age => 10) }.to_not raise_error
352
+ expect { @o.person({ :name => "calvin", :age => 10 }) }.to_not raise_error
353
353
  end
354
354
 
355
355
  it "should pass even if some keys don't have contracts" do
356
- expect { @o.person(:name => "calvin", :age => 10, :foo => "bar") }.to_not raise_error
356
+ expect { @o.person({ :name => "calvin", :age => 10, :foo => "bar" }) }.to_not raise_error
357
357
  end
358
358
 
359
359
  it "should fail if a key with a contract on it isn't provided" do
360
- expect { @o.person(:name => "calvin") }.to raise_error(ContractError)
360
+ expect { @o.person({ :name => "calvin" }) }.to raise_error(ContractError)
361
361
  end
362
362
 
363
363
  it "should fail for incorrect input" do
364
- expect { @o.person(:name => 50, :age => 10) }.to raise_error(ContractError)
364
+ expect { @o.person({ :name => 50, :age => 10 }) }.to raise_error(ContractError)
365
365
  end
366
366
  end
367
367
 
@@ -612,16 +612,19 @@ RSpec.describe "Contracts:" do
612
612
 
613
613
  it "should contain to_s representation within a Hash contract" do
614
614
  expect do
615
- @o.hash_complex_contracts(:rigged => "bad")
615
+ @o.hash_complex_contracts({ :rigged => "bad" })
616
616
  end.to raise_error(ContractError, not_s(delim "TrueClass or FalseClass"))
617
617
  end
618
618
 
619
619
  it "should contain to_s representation within a nested Hash contract" do
620
620
  expect do
621
- @o.nested_hash_complex_contracts(:rigged => true,
622
- :contents => {
623
- :kind => 0,
624
- :total => 42 })
621
+ @o.nested_hash_complex_contracts({
622
+ :rigged => true,
623
+ :contents => {
624
+ :kind => 0,
625
+ :total => 42,
626
+ },
627
+ })
625
628
  end.to raise_error(ContractError, not_s(delim "String or Symbol"))
626
629
  end
627
630
 
@@ -100,11 +100,11 @@ class GenericExample
100
100
  end
101
101
  end
102
102
 
103
- Contract ({ :name => String, :age => Fixnum }) => nil
103
+ Contract ({ :name => String, :age => Integer }) => nil
104
104
  def person(data)
105
105
  end
106
106
 
107
- Contract C::StrictHash[{ :name => String, :age => Fixnum }] => nil
107
+ Contract C::StrictHash[{ :name => String, :age => Integer }] => nil
108
108
  def strict_person(data)
109
109
  end
110
110
 
@@ -119,17 +119,12 @@ class GenericExample
119
119
  def nested_hash_complex_contracts(data)
120
120
  end
121
121
 
122
- Contract C::KeywordArgs[:name => String, :age => Fixnum] => nil
123
- def person_keywordargs(data)
124
- end
125
-
126
- # Testing overloaded method
127
- Contract String, Fixnum => nil
128
- def person_keywordargs(name, age)
122
+ Contract C::KeywordArgs[:name => String, :age => Integer] => nil
123
+ def person_keywordargs(name: "name", age: 10)
129
124
  end
130
125
 
131
126
  Contract C::KeywordArgs[:hash => C::HashOf[Symbol, C::Num]] => nil
132
- def hash_keywordargs(data)
127
+ def hash_keywordargs(hash:)
133
128
  end
134
129
 
135
130
  Contract (/foo/) => nil
@@ -534,30 +529,30 @@ class MyBirthday
534
529
  @month = month
535
530
  end
536
531
 
537
- Contract C::None => Fixnum
532
+ Contract C::None => Integer
538
533
  def silly_next_day!
539
534
  self.day += 1
540
535
  end
541
536
 
542
- Contract C::None => Fixnum
537
+ Contract C::None => Integer
543
538
  def silly_next_month!
544
539
  self.month += 1
545
540
  end
546
541
 
547
- Contract C::None => Fixnum
542
+ Contract C::None => Integer
548
543
  def clever_next_day!
549
544
  return clever_next_month! if day == 31
550
545
  self.day += 1
551
546
  end
552
547
 
553
- Contract C::None => Fixnum
548
+ Contract C::None => Integer
554
549
  def clever_next_month!
555
550
  return next_year! if month == 12
556
551
  self.month += 1
557
552
  self.day = 1
558
553
  end
559
554
 
560
- Contract C::None => Fixnum
555
+ Contract C::None => Integer
561
556
  def next_year!
562
557
  self.month = 1
563
558
  self.day = 1
@@ -615,7 +610,7 @@ with_enabled_no_contracts do
615
610
  body + "!"
616
611
  end
617
612
 
618
- Contract Fixnum, String => String
613
+ Contract Integer, String => String
619
614
  def on_response(status, body)
620
615
  "error #{status}: #{body}"
621
616
  end
@@ -30,15 +30,15 @@ RSpec.describe Contract do
30
30
  obj = klass.new
31
31
 
32
32
  expect do
33
- obj.something(:a => 35, :b => "hello")
33
+ obj.something({ :a => 35, :b => "hello" })
34
34
  end.to raise_error(ContractError)
35
35
 
36
36
  expect do
37
- obj.something(
37
+ obj.something({
38
38
  :a => 35,
39
39
  :b => "hello",
40
40
  :it_is_a_hash => true
41
- )
41
+ })
42
42
  end.not_to raise_error
43
43
  end
44
44
 
@@ -1,10 +1,10 @@
1
1
  class GenericExample
2
- Contract C::Args[String], { repeat: C::Maybe[C::Num] } => C::ArrayOf[String]
2
+ Contract C::Args[String], C::KeywordArgs[ repeat: C::Maybe[C::Num] ] => C::ArrayOf[String]
3
3
  def splat_then_optional_named(*vals, repeat: 2)
4
4
  vals.map { |v| v * repeat }
5
5
  end
6
6
 
7
- Contract ({foo: C::Nat}) => nil
7
+ Contract C::KeywordArgs[ foo: C::Nat ] => nil
8
8
  def nat_test_with_kwarg(foo: 10)
9
9
  end
10
10
 
@@ -34,7 +34,7 @@ RSpec.describe "Contract validators" do
34
34
 
35
35
  describe "within a hash" do
36
36
  it "should pass for a matching string" do
37
- expect { o.hash_containing_foo(:host => "foo.example.org") }.to_not raise_error
37
+ expect { o.hash_containing_foo({ :host => "foo.example.org" }) }.to_not raise_error
38
38
  end
39
39
  end
40
40
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contracts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aditya Bhargava
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-17 00:00:00.000000000 Z
11
+ date: 2024-10-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This library provides contracts for Ruby. Contracts let you clearly express
14
14
  how your code behaves, and free you from writing tons of boilerplate, defensive
@@ -56,6 +56,7 @@ files:
56
56
  - features/builtin_contracts/hash_of.feature
57
57
  - features/builtin_contracts/int.feature
58
58
  - features/builtin_contracts/keyword_args.feature
59
+ - features/builtin_contracts/keyword_args_with_optional_positional_args.feature
59
60
  - features/builtin_contracts/maybe.feature
60
61
  - features/builtin_contracts/nat.feature
61
62
  - features/builtin_contracts/nat_pos.feature
@@ -111,9 +112,7 @@ homepage: https://github.com/egonSchiele/contracts.ruby
111
112
  licenses:
112
113
  - BSD-2-Clause
113
114
  metadata: {}
114
- post_install_message: "\n 0.16.x will be the supporting Ruby 2.x and be feature
115
- frozen (only fixes will be released)\n For Ruby 3.x use 0.17.x or later (might
116
- not be released yet)\n "
115
+ post_install_message:
117
116
  rdoc_options: []
118
117
  require_paths:
119
118
  - lib
@@ -121,15 +120,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
120
  requirements:
122
121
  - - ">="
123
122
  - !ruby/object:Gem::Version
124
- version: '0'
123
+ version: '3.0'
124
+ - - "<"
125
+ - !ruby/object:Gem::Version
126
+ version: '4'
125
127
  required_rubygems_version: !ruby/object:Gem::Requirement
126
128
  requirements:
127
129
  - - ">="
128
130
  - !ruby/object:Gem::Version
129
131
  version: '0'
130
132
  requirements: []
131
- rubygems_version: 3.0.3
132
- signing_key:
133
+ rubygems_version: 3.4.10
134
+ signing_key:
133
135
  specification_version: 4
134
136
  summary: Contracts for Ruby.
135
137
  test_files: []