mocktail 3.0.0 → 3.0.1

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: bd08e4a44a711e7fc26677b99ebc6c98a841c4513cbb59cf85fe863d25d78b41
4
- data.tar.gz: 796387b2e7d00be4819766f3fd99b6e8169371d9247667562c487150f952a10b
3
+ metadata.gz: 5f97cc51c4c07f73a4d9b5adeeba1d9f6d36c70fa29d6061bb28df91948019c3
4
+ data.tar.gz: a9471b225f4d03664485993c6976e3368c49f7771ac4db11b59c4080153fe8ad
5
5
  SHA512:
6
- metadata.gz: bc861430dcb25e5a77d438e6c86b07cd91486c83884ba2f3ce8ee5c997de7629da11b473ac5347bb73b55bcc87ca28efb3e570ac431f61a4b9252e5abd6453a0
7
- data.tar.gz: 8008dda26649d9a1aa75dc23740181a88daadc3ea1d707059e25f4ffd1a2a0d874e944ae9ae31c1ce7118caccaae5ada68ebfc89bf67b0972dab979ee02542f0
6
+ metadata.gz: 498fbe4ee233f7a248c5898972ed8691a512f17c5d7bed828943467f22a4d9f06fcf354d2155afd26f019685fe5636a3f0ff6ddf186b32914e39d9b0db23e538
7
+ data.tar.gz: 9753fb8c3e5db0e325e32a7f3693e0afd51a2cdfd349a9b690b256f7aa77c4ca5e1739065c5b37c1d89fca0db73ebf8c38270518789977c2c2a770c2e88086f1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 3.0.1
2
+
3
+ * Fix arity validation staying disabled after a `stubs` or `verify` block with
4
+ `ignore_arity: true` raises
5
+ * Fix `ArgumentError: unknown keyword` when a replaced class's `new` or class
6
+ method takes an options hash and is called with brace-less keywords
7
+ [#20](https://github.com/testdouble/mocktail/pull/20)
8
+ * Replaced `new` and class methods with no keyword parameters now accept
9
+ keyword-style calls as a trailing hash, as real Ruby does, instead of raising
10
+ `ArgumentError`
11
+
1
12
  # 3.0.0
2
13
 
3
14
  * **Breaking change** - Drop support for Ruby 3.0, which is EOL
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mocktail (3.0.0)
4
+ mocktail (3.0.1)
5
5
  sorbet-eraser (~> 0.3.1)
6
6
  sorbet-runtime (~> 0.5.9204)
7
7
 
@@ -32,7 +32,7 @@ module Mocktail
32
32
  approved_call_sites = [
33
33
  /fulfills_stubbing.rb:(16|20)/,
34
34
  /validates_arguments.rb:(18|23)/,
35
- /validates_arguments.rb:(21|26)/
35
+ /validates_arguments.rb:(23|28)/
36
36
  ]
37
37
  if internal_call_sites.any? && approved_call_sites.none? { |approved_call_site|
38
38
  internal_call_sites.first&.match?(approved_call_site)
@@ -17,10 +17,13 @@ module Mocktail
17
17
  def self.optional(disable, &blk)
18
18
  return blk.call unless disable
19
19
 
20
+ previous = disabled?
20
21
  disable!
21
- ret = blk.call
22
- enable!
23
- ret
22
+ begin
23
+ blk.call
24
+ ensure
25
+ Thread.current[:mocktail_arity_validation_disabled] = previous
26
+ end
24
27
  end
25
28
 
26
29
  def initialize
@@ -1,3 +1,5 @@
1
+ require_relative "share/folds_keywords_into_options_hash"
2
+
1
3
  module Mocktail
2
4
  class HandlesDryNewCall
3
5
  extend T::Sig
@@ -7,9 +9,12 @@ module Mocktail
7
9
  @logs_call = LogsCall.new
8
10
  @fulfills_stubbing = FulfillsStubbing.new
9
11
  @imitates_type = ImitatesType.new
12
+ @folds_keywords_into_options_hash = FoldsKeywordsIntoOptionsHash.new
10
13
  end
11
14
 
12
15
  def handle(type, args, kwargs, block)
16
+ args, kwargs = @folds_keywords_into_options_hash.fold(type.instance_method(:initialize), args, kwargs)
17
+
13
18
  @validates_arguments.validate(Call.new(
14
19
  original_method: type.instance_method(:initialize),
15
20
  args: args,
@@ -1,9 +1,12 @@
1
+ require_relative "../share/folds_keywords_into_options_hash"
2
+
1
3
  module Mocktail
2
4
  class RedefinesSingletonMethods
3
5
  extend T::Sig
4
6
 
5
7
  def initialize
6
8
  @handles_dry_call = HandlesDryCall.new
9
+ @folds_keywords_into_options_hash = FoldsKeywordsIntoOptionsHash.new
7
10
  end
8
11
 
9
12
  def redefine(type)
@@ -16,10 +19,12 @@ module Mocktail
16
19
 
17
20
  declare_singleton_method_missing_errors!(type)
18
21
  handles_dry_call = @handles_dry_call
22
+ folds_keywords_into_options_hash = @folds_keywords_into_options_hash
19
23
  type_replacement.replacement_methods = type_replacement.original_methods&.map { |original_method|
20
24
  type.singleton_class.send(:undef_method, original_method.name)
21
25
  type.define_singleton_method original_method.name, ->(*args, **kwargs, &block) {
22
26
  if TopShelf.instance.singleton_methods_replaced?(type)
27
+ args, kwargs = folds_keywords_into_options_hash.fold(original_method, args, kwargs)
23
28
  handles_dry_call.handle(Call.new(
24
29
  singleton: true,
25
30
  double: type,
@@ -0,0 +1,22 @@
1
+ module Mocktail
2
+ class FoldsKeywordsIntoOptionsHash
3
+ extend T::Sig
4
+
5
+ KEYWORD_PARAM_TYPES = [:key, :keyreq, :keyrest, :nokey].freeze
6
+
7
+ def initialize
8
+ @grabs_original_method_parameters = GrabsOriginalMethodParameters.new
9
+ end
10
+
11
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
12
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
13
+ # them out, so fold them back in to match what the real method would see
14
+
15
+ def fold(original_method, args, kwargs)
16
+ return [args, kwargs] if kwargs.empty? || original_method.nil?
17
+ return [args, kwargs] if @grabs_original_method_parameters.grab(original_method).any? { |type, _| KEYWORD_PARAM_TYPES.include?(type) }
18
+
19
+ [[*args, kwargs], {}]
20
+ end
21
+ end
22
+ end
@@ -34,7 +34,7 @@ module Mocktail
34
34
  approved_call_sites = [
35
35
  /fulfills_stubbing.rb:(16|20)/,
36
36
  /validates_arguments.rb:(18|23)/,
37
- /validates_arguments.rb:(21|26)/
37
+ /validates_arguments.rb:(23|28)/
38
38
  ]
39
39
  if internal_call_sites.any? && approved_call_sites.none? { |approved_call_site|
40
40
  internal_call_sites.first&.match?(approved_call_site)
@@ -22,10 +22,13 @@ module Mocktail
22
22
  def self.optional(disable, &blk)
23
23
  return blk.call unless disable
24
24
 
25
+ previous = disabled?
25
26
  disable!
26
- ret = blk.call
27
- enable!
28
- ret
27
+ begin
28
+ blk.call
29
+ ensure
30
+ Thread.current[:mocktail_arity_validation_disabled] = previous
31
+ end
29
32
  end
30
33
 
31
34
  sig { void }
@@ -1,5 +1,7 @@
1
1
  # typed: strict
2
2
 
3
+ require_relative "share/folds_keywords_into_options_hash"
4
+
3
5
  module Mocktail
4
6
  class HandlesDryNewCall
5
7
  extend T::Sig
@@ -10,10 +12,13 @@ module Mocktail
10
12
  @logs_call = T.let(LogsCall.new, LogsCall)
11
13
  @fulfills_stubbing = T.let(FulfillsStubbing.new, FulfillsStubbing)
12
14
  @imitates_type = T.let(ImitatesType.new, ImitatesType)
15
+ @folds_keywords_into_options_hash = T.let(FoldsKeywordsIntoOptionsHash.new, FoldsKeywordsIntoOptionsHash)
13
16
  end
14
17
 
15
18
  sig { params(type: T::Class[T.all(T, Object)], args: T::Array[T.anything], kwargs: T::Hash[Symbol, T.anything], block: T.nilable(Proc)).returns(T.anything) }
16
19
  def handle(type, args, kwargs, block)
20
+ args, kwargs = @folds_keywords_into_options_hash.fold(type.instance_method(:initialize), args, kwargs)
21
+
17
22
  @validates_arguments.validate(Call.new(
18
23
  original_method: type.instance_method(:initialize),
19
24
  args: args,
@@ -1,5 +1,7 @@
1
1
  # typed: strict
2
2
 
3
+ require_relative "../share/folds_keywords_into_options_hash"
4
+
3
5
  module Mocktail
4
6
  class RedefinesSingletonMethods
5
7
  extend T::Sig
@@ -7,6 +9,7 @@ module Mocktail
7
9
  sig { void }
8
10
  def initialize
9
11
  @handles_dry_call = T.let(HandlesDryCall.new, HandlesDryCall)
12
+ @folds_keywords_into_options_hash = T.let(FoldsKeywordsIntoOptionsHash.new, FoldsKeywordsIntoOptionsHash)
10
13
  end
11
14
 
12
15
  sig { params(type: T.any(T::Class[T.anything], Module)).void }
@@ -20,10 +23,12 @@ module Mocktail
20
23
 
21
24
  declare_singleton_method_missing_errors!(type)
22
25
  handles_dry_call = @handles_dry_call
26
+ folds_keywords_into_options_hash = @folds_keywords_into_options_hash
23
27
  type_replacement.replacement_methods = type_replacement.original_methods&.map { |original_method|
24
28
  type.singleton_class.send(:undef_method, original_method.name)
25
29
  type.define_singleton_method original_method.name, ->(*args, **kwargs, &block) {
26
30
  if TopShelf.instance.singleton_methods_replaced?(type)
31
+ args, kwargs = folds_keywords_into_options_hash.fold(original_method, args, kwargs)
27
32
  handles_dry_call.handle(Call.new(
28
33
  singleton: true,
29
34
  double: type,
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+
3
+ module Mocktail
4
+ class FoldsKeywordsIntoOptionsHash
5
+ extend T::Sig
6
+
7
+ KEYWORD_PARAM_TYPES = T.let([:key, :keyreq, :keyrest, :nokey].freeze, T::Array[Symbol])
8
+
9
+ sig { void }
10
+ def initialize
11
+ @grabs_original_method_parameters = T.let(GrabsOriginalMethodParameters.new, GrabsOriginalMethodParameters)
12
+ end
13
+
14
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
15
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
16
+ # them out, so fold them back in to match what the real method would see
17
+ sig { params(original_method: T.nilable(T.any(UnboundMethod, Method)), args: T::Array[T.anything], kwargs: T::Hash[Symbol, T.anything]).returns([T::Array[T.anything], T::Hash[Symbol, T.anything]]) }
18
+ def fold(original_method, args, kwargs)
19
+ return [args, kwargs] if kwargs.empty? || original_method.nil?
20
+ return [args, kwargs] if @grabs_original_method_parameters.grab(original_method).any? { |type, _| KEYWORD_PARAM_TYPES.include?(type) }
21
+
22
+ [[*args, kwargs], {}]
23
+ end
24
+ end
25
+ end
@@ -8,5 +8,5 @@ module Mocktail
8
8
  Mocktail.send(:remove_const, :VERSION)
9
9
  end
10
10
 
11
- VERSION = "3.0.0"
11
+ VERSION = "3.0.1"
12
12
  end
@@ -6,5 +6,5 @@ module Mocktail
6
6
  Mocktail.send(:remove_const, :VERSION)
7
7
  end
8
8
 
9
- VERSION = "3.0.0"
9
+ VERSION = "3.0.1"
10
10
  end
@@ -7,15 +7,10 @@
7
7
 
8
8
  # typed: true
9
9
 
10
- # DO NOT EDIT MANUALLY
11
- # This is an autogenerated file for types exported from the `mocktail` gem.
12
- # Please instead update this file by running `bin/tapioca gem mocktail`.
13
-
14
10
  # The Cabinet stores all thread-local state, so anything that goes here
15
11
  # is guaranteed by Mocktail to be local to the currently-running thread
16
12
  #
17
13
  # source://mocktail//lib/mocktail/sorbet/mocktail/typed.rb#3
18
- # The Cabinet stores all thread-local state, so anything that goes here
19
14
  module Mocktail
20
15
  extend ::Mocktail::DSL
21
16
 
@@ -25,8 +20,6 @@ module Mocktail
25
20
  # don't commit code that relies on it!
26
21
  #
27
22
  # source://mocktail//lib/mocktail/sorbet/mocktail.rb#149
28
- # Stores most transactional state about calls & stubbing configurations
29
- # Anything returned by this is undocumented and could change at any time, so
30
23
  sig { returns(::Mocktail::Cabinet) }
31
24
  def cabinet; end
32
25
 
@@ -35,8 +28,6 @@ module Mocktail
35
28
  # calls to that method
36
29
  #
37
30
  # source://mocktail//lib/mocktail/sorbet/mocktail.rb#141
38
- # An alias for Mocktail.explain(double).reference.calls
39
- # Takes an optional second parameter of the method name to filter only
40
31
  sig do
41
32
  params(
42
33
  double: ::Object,
@@ -76,7 +67,6 @@ module Mocktail
76
67
  # stubs its constructor to return that fake the next time klass.new is called
77
68
  #
78
69
  # source://mocktail//lib/mocktail/sorbet/mocktail.rb#63
79
- # Returns an instance of `klass` whose implementation is mocked out AND
80
70
  sig do
81
71
  type_parameters(:T)
82
72
  .params(
@@ -106,7 +96,6 @@ module Mocktail
106
96
  # or included will also fake instance methods
107
97
  #
108
98
  # source://mocktail//lib/mocktail/sorbet/mocktail.rb#111
109
- # Replaces every singleton method on `type` with a fake, and when instantiated
110
99
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
111
100
  def replace(type); end
112
101
 
@@ -207,7 +196,6 @@ class Mocktail::Call < ::T::Struct
207
196
  # to redefine the equality methods to compare the values of the attributes.
208
197
  #
209
198
  # source://mocktail//lib/mocktail/sorbet/mocktail/value/call.rb#27
210
- # Because T::Struct compares with referential equality, we need
211
199
  sig { params(other: T.nilable(T.anything)).returns(T::Boolean) }
212
200
  def ==(other); end
213
201
 
@@ -221,7 +209,6 @@ class Mocktail::Call < ::T::Struct
221
209
 
222
210
  class << self
223
211
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
224
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
225
212
  def inherited(s); end
226
213
  end
227
214
  end
@@ -301,14 +288,6 @@ module Mocktail::Debug
301
288
  # mocked BasicObject
302
289
  #
303
290
  # source://mocktail//lib/mocktail/sorbet/mocktail/debug.rb#20
304
- # It would be easy and bad for the mocktail lib to call something like
305
- # double == other_double
306
- # But if it's a double, that means anyone who stubs that method could change
307
- # the internal behavior of the library in unexpected ways (as happened here:
308
- # https://github.com/testdouble/mocktail/issues/7 )
309
- # For that reason when we run our tests, we also want to blow up if this
310
- # happens unintentionally. This works in conjunction with the test
311
- # MockingMethodfulClassesTest, because it mocks every defined method on the
312
291
  sig { void }
313
292
  def guard_against_mocktail_accidentally_calling_mocks_if_debugging!; end
314
293
  end
@@ -337,8 +316,6 @@ class Mocktail::DeclaresDryClass
337
316
  # mocked methods. YMMV
338
317
  #
339
318
  # source://mocktail//lib/mocktail/sorbet/mocktail/imitates_type/makes_double/declares_dry_class.rb#55
340
- # These have special implementations, but if the user defines
341
- # any of them on the object itself, then they'll be replaced with normal
342
319
  sig do
343
320
  params(
344
321
  dry_class: T::Class[::Object],
@@ -392,7 +369,6 @@ class Mocktail::DemoConfig < ::T::Struct
392
369
 
393
370
  class << self
394
371
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
395
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
396
372
  def inherited(s); end
397
373
  end
398
374
  end
@@ -466,7 +442,6 @@ class Mocktail::Double < ::T::Struct
466
442
 
467
443
  class << self
468
444
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
469
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
470
445
  def inherited(s); end
471
446
  end
472
447
  end
@@ -482,7 +457,6 @@ class Mocktail::DoubleData < ::T::Struct
482
457
 
483
458
  class << self
484
459
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
485
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
486
460
  def inherited(s); end
487
461
  end
488
462
  end
@@ -615,7 +589,6 @@ class Mocktail::FakeMethodData < ::T::Struct
615
589
 
616
590
  class << self
617
591
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
618
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
619
592
  def inherited(s); end
620
593
  end
621
594
  end
@@ -653,6 +626,30 @@ class Mocktail::FindsVerifiableCalls
653
626
  def find(recording, demo_config); end
654
627
  end
655
628
 
629
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#4
630
+ class Mocktail::FoldsKeywordsIntoOptionsHash
631
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#10
632
+ sig { void }
633
+ def initialize; end
634
+
635
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
636
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
637
+ # them out, so fold them back in to match what the real method would see
638
+ #
639
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#18
640
+ sig do
641
+ params(
642
+ original_method: T.nilable(T.any(::Method, ::UnboundMethod)),
643
+ args: T::Array[T.anything],
644
+ kwargs: T::Hash[::Symbol, T.anything]
645
+ ).returns([T::Array[T.anything], T::Hash[::Symbol, T.anything]])
646
+ end
647
+ def fold(original_method, args, kwargs); end
648
+ end
649
+
650
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#7
651
+ Mocktail::FoldsKeywordsIntoOptionsHash::KEYWORD_PARAM_TYPES = T.let(T.unsafe(nil), Array)
652
+
656
653
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/fulfills_stubbing.rb#7
657
654
  class Mocktail::FulfillsStubbing
658
655
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/fulfills_stubbing.rb#11
@@ -706,10 +703,6 @@ class Mocktail::GrabsOriginalMethodParameters
706
703
  # per usual
707
704
  #
708
705
  # source://mocktail//lib/mocktail/sorbet/mocktail/grabs_original_method_parameters.rb#14
709
- # Sorbet wraps the original method in a sig wrapper, so we need to unwrap it.
710
- # The value returned from `owner.instance_method(method_name)` does not have
711
- # the real parameters values available, as they'll have been erased
712
- # If the method isn't wrapped by Sorbet, this will return the #instance_method,
713
706
  sig { params(method: T.nilable(T.any(::Method, ::UnboundMethod))).returns(T::Array[T::Array[::Symbol]]) }
714
707
  def grab(method); end
715
708
 
@@ -731,13 +724,13 @@ class Mocktail::HandlesDryCall
731
724
  def handle(dry_call); end
732
725
  end
733
726
 
734
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#4
727
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#6
735
728
  class Mocktail::HandlesDryNewCall
736
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#8
729
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#10
737
730
  sig { void }
738
731
  def initialize; end
739
732
 
740
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#16
733
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#19
741
734
  sig do
742
735
  params(
743
736
  type: T::Class[T.all(::Object, ::T)],
@@ -901,7 +894,6 @@ class Mocktail::Matchers::Base
901
894
  # single-argument, though, so that's defaulted here and in #insepct
902
895
  #
903
896
  # source://mocktail//lib/mocktail/sorbet/mocktail/matchers/base.rb#15
904
- # Custom matchers can receive any args, kwargs, or block they want. Usually
905
897
  sig { params(expected: ::BasicObject).void }
906
898
  def initialize(expected); end
907
899
 
@@ -943,15 +935,6 @@ end
943
935
  # https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Captor.html
944
936
  #
945
937
  # source://mocktail//lib/mocktail/sorbet/mocktail/matchers/captor.rb#17
946
- # Captors are conceptually complex implementations, but with a simple usage/purpose:
947
- # They are values the user can create and hold onto that will return a matcher
948
- # and then "capture" the value made by the real call, for later analysis & assertion.
949
- # Unlike other matchers, these don't make any useful sense for stubbing, but are
950
- # very useful when asserting complication call verifications
951
- # The fact the user will need the reference outside the verification call is
952
- # why this is a top-level method on Mocktail, and not included in the |m| block
953
- # arg to stubs/verify
954
- # See Mockito, which is the earliest implementation I know of:
955
938
  class Mocktail::Matchers::Captor
956
939
  # source://mocktail//lib/mocktail/sorbet/mocktail/matchers/captor.rb#62
957
940
  sig { void }
@@ -962,8 +945,6 @@ class Mocktail::Matchers::Captor
962
945
  # it needs to think it's being returned whatever parameter is expected
963
946
  #
964
947
  # source://mocktail//lib/mocktail/sorbet/mocktail/matchers/captor.rb#59
965
- # This T.untyped is intentional. Even though a Capture is surely returned,
966
- # in order for a verification demonstration to pass its own type check,
967
948
  sig { returns(T.untyped) }
968
949
  def capture; end
969
950
 
@@ -1170,7 +1151,6 @@ class Mocktail::NoExplanationData < ::T::Struct
1170
1151
 
1171
1152
  class << self
1172
1153
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1173
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1174
1154
  def inherited(s); end
1175
1155
  end
1176
1156
  end
@@ -1192,7 +1172,6 @@ class Mocktail::Params < ::T::Struct
1192
1172
 
1193
1173
  class << self
1194
1174
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1195
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1196
1175
  def inherited(s); end
1197
1176
  end
1198
1177
  end
@@ -1370,23 +1349,23 @@ class Mocktail::RedefinesNew
1370
1349
  def redefine(type); end
1371
1350
  end
1372
1351
 
1373
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#4
1352
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#6
1374
1353
  class Mocktail::RedefinesSingletonMethods
1375
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#8
1354
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#10
1376
1355
  sig { void }
1377
1356
  def initialize; end
1378
1357
 
1379
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#47
1358
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#52
1380
1359
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
1381
1360
  def declare_singleton_method_missing_errors!(type); end
1382
1361
 
1383
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#13
1362
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#16
1384
1363
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
1385
1364
  def redefine(type); end
1386
1365
 
1387
1366
  private
1388
1367
 
1389
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#72
1368
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#77
1390
1369
  sig { params(method: ::Method).returns(T::Boolean) }
1391
1370
  def sorbet_method_hook?(method); end
1392
1371
  end
@@ -1516,20 +1495,6 @@ class Mocktail::RunsSorbetSigBlocksBeforeReplacement
1516
1495
  # It's very fun and confusing and a great time.
1517
1496
  #
1518
1497
  # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/runs_sorbet_sig_blocks_before_replacement.rb#26
1519
- # This is necessary because when Sorbet runs a sig block of a singleton
1520
- # method, it has the net effect of unwrapping/redefining the method. If
1521
- # we try to use Mocktail.replace(Foo) and Foo.bar has a Sorbet sig block,
1522
- # then we'll end up with three "versions" of the same method and no way
1523
- # to keep straight which one == which:
1524
- # A - Foo.bar, as defined in the original class
1525
- # B - Foo.bar, as redefined by RedefinesSingletonMethods
1526
- # C - Foo.bar, as wrapped by sorbet-runtime
1527
- # Initially, Foo.method(:bar) would == C, but after the type
1528
- # replacement, it would == B (with a reference back to C as the original),
1529
- # but after handling a single dry call, our invocation of
1530
- # GrabsOriginalMethodParameters.grab(Foo.method(:bar)) would invoke the
1531
- # Sorbet `sig` block, which has the net effect of redefining the method back
1532
- # to A.
1533
1498
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
1534
1499
  def run(type); end
1535
1500
  end
@@ -1545,7 +1510,6 @@ class Mocktail::Signature < ::T::Struct
1545
1510
 
1546
1511
  class << self
1547
1512
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1548
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1549
1513
  def inherited(s); end
1550
1514
  end
1551
1515
  end
@@ -1591,37 +1555,30 @@ class Mocktail::StringifiesCall
1591
1555
  private
1592
1556
 
1593
1557
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#46
1594
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#47
1595
1558
  sig { params(args: T::Array[::Object]).returns(T.nilable(::String)) }
1596
1559
  def argify(args); end
1597
1560
 
1598
1561
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#29
1599
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#30
1600
1562
  sig { params(call: ::Mocktail::Call, parens: T::Boolean).returns(T.nilable(::String)) }
1601
1563
  def args_to_s(call, parens: T.unsafe(nil)); end
1602
1564
 
1603
1565
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#64
1604
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#65
1605
1566
  sig { params(block: T.nilable(::Proc), anonymous: T::Boolean).returns(T.nilable(::String)) }
1606
1567
  def blockify(block, anonymous:); end
1607
1568
 
1608
1569
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#52
1609
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#53
1610
1570
  sig { params(kwargs: T::Hash[::Symbol, ::Object]).returns(T.nilable(::String)) }
1611
1571
  def kwargify(kwargs); end
1612
1572
 
1613
1573
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#58
1614
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#59
1615
1574
  sig { params(block: T.nilable(::Proc)).returns(T.nilable(::String)) }
1616
1575
  def lambdafy(block); end
1617
1576
 
1618
1577
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#75
1619
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#76
1620
1578
  sig { params(block: ::Proc).returns(::String) }
1621
1579
  def source_locationify(block); end
1622
1580
 
1623
1581
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#80
1624
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#81
1625
1582
  sig { params(path: ::String).returns(::String) }
1626
1583
  def strip_pwd(path); end
1627
1584
  end
@@ -1676,7 +1633,6 @@ class Mocktail::Stubbing < ::T::Struct
1676
1633
 
1677
1634
  class << self
1678
1635
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1679
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1680
1636
  def inherited(s); end
1681
1637
  end
1682
1638
  end
@@ -1689,8 +1645,6 @@ Mocktail::TYPED = T.let(T.unsafe(nil), TrueClass)
1689
1645
  # method replacements carried out with Mocktail.replace(ClassOrModule)
1690
1646
  #
1691
1647
  # source://mocktail//lib/mocktail/sorbet/mocktail/value/top_shelf.rb#7
1692
- # The TopShelf is where we keep all the more global, dangerous state.
1693
- # In particular, this is where Mocktail manages state related to singleton
1694
1648
  class Mocktail::TopShelf
1695
1649
  # source://mocktail//lib/mocktail/sorbet/mocktail/value/top_shelf.rb#19
1696
1650
  sig { void }
@@ -1778,7 +1732,6 @@ class Mocktail::TypeReplacement < ::T::Struct
1778
1732
 
1779
1733
  class << self
1780
1734
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1781
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1782
1735
  def inherited(s); end
1783
1736
  end
1784
1737
  end
@@ -1798,7 +1751,6 @@ class Mocktail::TypeReplacementData < ::T::Struct
1798
1751
 
1799
1752
  class << self
1800
1753
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1801
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1802
1754
  def inherited(s); end
1803
1755
  end
1804
1756
  end
@@ -1814,7 +1766,6 @@ class Mocktail::UnsatisfyingCall < ::T::Struct
1814
1766
 
1815
1767
  class << self
1816
1768
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1817
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1818
1769
  def inherited(s); end
1819
1770
  end
1820
1771
  end
@@ -1846,11 +1797,11 @@ Mocktail::VERSION = T.let(T.unsafe(nil), String)
1846
1797
 
1847
1798
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#4
1848
1799
  class Mocktail::ValidatesArguments
1849
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#32
1800
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#35
1850
1801
  sig { void }
1851
1802
  def initialize; end
1852
1803
 
1853
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#37
1804
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#40
1854
1805
  sig { params(dry_call: ::Mocktail::Call).returns(::NilClass) }
1855
1806
  def validate(dry_call); end
1856
1807
 
data/script/build CHANGED
@@ -33,8 +33,8 @@ require_relative "mocktail/sorbet"
33
33
  RUBY
34
34
 
35
35
  echo "----------> ❷ Generating sorbet sigs via tapioca in sub_projects/rbi_generator"
36
- cd sub_projects/rbi_generator
37
36
  rm -f rbi/mocktail-pregenerated.rbi
37
+ cd sub_projects/rbi_generator
38
38
  rm -f sorbet/rbi/gems/mocktail@*.rbi
39
39
  bundle
40
40
  bundle exec tapioca gem --all --exclude=tapioca ast diff-lcs erubi netrc parser prettier_print racc rbi spoom syntax_tree thor unparser sorbet yard parallel yard-sorbet
@@ -34,7 +34,7 @@ module Mocktail
34
34
  approved_call_sites = [
35
35
  /fulfills_stubbing.rb:(16|20)/,
36
36
  /validates_arguments.rb:(18|23)/,
37
- /validates_arguments.rb:(21|26)/
37
+ /validates_arguments.rb:(23|28)/
38
38
  ]
39
39
  if internal_call_sites.any? && approved_call_sites.none? { |approved_call_site|
40
40
  internal_call_sites.first&.match?(approved_call_site)
@@ -22,10 +22,13 @@ module Mocktail
22
22
  def self.optional(disable, &blk)
23
23
  return blk.call unless disable
24
24
 
25
+ previous = disabled?
25
26
  disable!
26
- ret = blk.call
27
- enable!
28
- ret
27
+ begin
28
+ blk.call
29
+ ensure
30
+ Thread.current[:mocktail_arity_validation_disabled] = previous
31
+ end
29
32
  end
30
33
 
31
34
  sig { void }
@@ -1,5 +1,7 @@
1
1
  # typed: strict
2
2
 
3
+ require_relative "share/folds_keywords_into_options_hash"
4
+
3
5
  module Mocktail
4
6
  class HandlesDryNewCall
5
7
  extend T::Sig
@@ -10,10 +12,13 @@ module Mocktail
10
12
  @logs_call = T.let(LogsCall.new, LogsCall)
11
13
  @fulfills_stubbing = T.let(FulfillsStubbing.new, FulfillsStubbing)
12
14
  @imitates_type = T.let(ImitatesType.new, ImitatesType)
15
+ @folds_keywords_into_options_hash = T.let(FoldsKeywordsIntoOptionsHash.new, FoldsKeywordsIntoOptionsHash)
13
16
  end
14
17
 
15
18
  sig { params(type: T::Class[T.all(T, Object)], args: T::Array[T.anything], kwargs: T::Hash[Symbol, T.anything], block: T.nilable(Proc)).returns(T.anything) }
16
19
  def handle(type, args, kwargs, block)
20
+ args, kwargs = @folds_keywords_into_options_hash.fold(type.instance_method(:initialize), args, kwargs)
21
+
17
22
  @validates_arguments.validate(Call.new(
18
23
  original_method: type.instance_method(:initialize),
19
24
  args: args,
@@ -1,5 +1,7 @@
1
1
  # typed: strict
2
2
 
3
+ require_relative "../share/folds_keywords_into_options_hash"
4
+
3
5
  module Mocktail
4
6
  class RedefinesSingletonMethods
5
7
  extend T::Sig
@@ -7,6 +9,7 @@ module Mocktail
7
9
  sig { void }
8
10
  def initialize
9
11
  @handles_dry_call = T.let(HandlesDryCall.new, HandlesDryCall)
12
+ @folds_keywords_into_options_hash = T.let(FoldsKeywordsIntoOptionsHash.new, FoldsKeywordsIntoOptionsHash)
10
13
  end
11
14
 
12
15
  sig { params(type: T.any(T::Class[T.anything], Module)).void }
@@ -20,10 +23,12 @@ module Mocktail
20
23
 
21
24
  declare_singleton_method_missing_errors!(type)
22
25
  handles_dry_call = @handles_dry_call
26
+ folds_keywords_into_options_hash = @folds_keywords_into_options_hash
23
27
  type_replacement.replacement_methods = type_replacement.original_methods&.map { |original_method|
24
28
  type.singleton_class.send(:undef_method, original_method.name)
25
29
  type.define_singleton_method original_method.name, ->(*args, **kwargs, &block) {
26
30
  if TopShelf.instance.singleton_methods_replaced?(type)
31
+ args, kwargs = folds_keywords_into_options_hash.fold(original_method, args, kwargs)
27
32
  handles_dry_call.handle(Call.new(
28
33
  singleton: true,
29
34
  double: type,
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+
3
+ module Mocktail
4
+ class FoldsKeywordsIntoOptionsHash
5
+ extend T::Sig
6
+
7
+ KEYWORD_PARAM_TYPES = T.let([:key, :keyreq, :keyrest, :nokey].freeze, T::Array[Symbol])
8
+
9
+ sig { void }
10
+ def initialize
11
+ @grabs_original_method_parameters = T.let(GrabsOriginalMethodParameters.new, GrabsOriginalMethodParameters)
12
+ end
13
+
14
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
15
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
16
+ # them out, so fold them back in to match what the real method would see
17
+ sig { params(original_method: T.nilable(T.any(UnboundMethod, Method)), args: T::Array[T.anything], kwargs: T::Hash[Symbol, T.anything]).returns([T::Array[T.anything], T::Hash[Symbol, T.anything]]) }
18
+ def fold(original_method, args, kwargs)
19
+ return [args, kwargs] if kwargs.empty? || original_method.nil?
20
+ return [args, kwargs] if @grabs_original_method_parameters.grab(original_method).any? { |type, _| KEYWORD_PARAM_TYPES.include?(type) }
21
+
22
+ [[*args, kwargs], {}]
23
+ end
24
+ end
25
+ end
@@ -8,5 +8,5 @@ module Mocktail
8
8
  Mocktail.send(:remove_const, :VERSION)
9
9
  end
10
10
 
11
- VERSION = "3.0.0"
11
+ VERSION = "3.0.1"
12
12
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- mocktail (3.0.0)
4
+ mocktail (3.0.1)
5
5
  sorbet-eraser (~> 0.3.1)
6
6
  sorbet-runtime (~> 0.5.9204)
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- mocktail (3.0.0)
4
+ mocktail (3.0.1)
5
5
  sorbet-eraser (~> 0.3.1)
6
6
  sorbet-runtime (~> 0.5.9204)
7
7
 
@@ -221,7 +221,6 @@ class Mocktail::Call < ::T::Struct
221
221
 
222
222
  class << self
223
223
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
224
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
225
224
  def inherited(s); end
226
225
  end
227
226
  end
@@ -392,7 +391,6 @@ class Mocktail::DemoConfig < ::T::Struct
392
391
 
393
392
  class << self
394
393
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
395
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
396
394
  def inherited(s); end
397
395
  end
398
396
  end
@@ -466,7 +464,6 @@ class Mocktail::Double < ::T::Struct
466
464
 
467
465
  class << self
468
466
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
469
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
470
467
  def inherited(s); end
471
468
  end
472
469
  end
@@ -482,7 +479,6 @@ class Mocktail::DoubleData < ::T::Struct
482
479
 
483
480
  class << self
484
481
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
485
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
486
482
  def inherited(s); end
487
483
  end
488
484
  end
@@ -615,7 +611,6 @@ class Mocktail::FakeMethodData < ::T::Struct
615
611
 
616
612
  class << self
617
613
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
618
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
619
614
  def inherited(s); end
620
615
  end
621
616
  end
@@ -653,6 +648,32 @@ class Mocktail::FindsVerifiableCalls
653
648
  def find(recording, demo_config); end
654
649
  end
655
650
 
651
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#4
652
+ class Mocktail::FoldsKeywordsIntoOptionsHash
653
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#10
654
+ sig { void }
655
+ def initialize; end
656
+
657
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
658
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
659
+ # them out, so fold them back in to match what the real method would see
660
+ #
661
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#18
662
+ # Ruby 3 passes keywords to a method with no keyword params as a trailing
663
+ # positional hash, but our generic (*args, **kwargs) lambdas always split
664
+ sig do
665
+ params(
666
+ original_method: T.nilable(T.any(::Method, ::UnboundMethod)),
667
+ args: T::Array[T.anything],
668
+ kwargs: T::Hash[::Symbol, T.anything]
669
+ ).returns([T::Array[T.anything], T::Hash[::Symbol, T.anything]])
670
+ end
671
+ def fold(original_method, args, kwargs); end
672
+ end
673
+
674
+ # source://mocktail//lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb#7
675
+ Mocktail::FoldsKeywordsIntoOptionsHash::KEYWORD_PARAM_TYPES = T.let(T.unsafe(nil), Array)
676
+
656
677
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/fulfills_stubbing.rb#7
657
678
  class Mocktail::FulfillsStubbing
658
679
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/fulfills_stubbing.rb#11
@@ -731,13 +752,13 @@ class Mocktail::HandlesDryCall
731
752
  def handle(dry_call); end
732
753
  end
733
754
 
734
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#4
755
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#6
735
756
  class Mocktail::HandlesDryNewCall
736
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#8
757
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#10
737
758
  sig { void }
738
759
  def initialize; end
739
760
 
740
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#16
761
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb#19
741
762
  sig do
742
763
  params(
743
764
  type: T::Class[T.all(::Object, ::T)],
@@ -1170,7 +1191,6 @@ class Mocktail::NoExplanationData < ::T::Struct
1170
1191
 
1171
1192
  class << self
1172
1193
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1173
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1174
1194
  def inherited(s); end
1175
1195
  end
1176
1196
  end
@@ -1192,7 +1212,6 @@ class Mocktail::Params < ::T::Struct
1192
1212
 
1193
1213
  class << self
1194
1214
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1195
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1196
1215
  def inherited(s); end
1197
1216
  end
1198
1217
  end
@@ -1370,23 +1389,23 @@ class Mocktail::RedefinesNew
1370
1389
  def redefine(type); end
1371
1390
  end
1372
1391
 
1373
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#4
1392
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#6
1374
1393
  class Mocktail::RedefinesSingletonMethods
1375
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#8
1394
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#10
1376
1395
  sig { void }
1377
1396
  def initialize; end
1378
1397
 
1379
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#47
1398
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#52
1380
1399
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
1381
1400
  def declare_singleton_method_missing_errors!(type); end
1382
1401
 
1383
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#13
1402
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#16
1384
1403
  sig { params(type: T.any(::Module, T::Class[T.anything])).void }
1385
1404
  def redefine(type); end
1386
1405
 
1387
1406
  private
1388
1407
 
1389
- # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#72
1408
+ # source://mocktail//lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb#77
1390
1409
  sig { params(method: ::Method).returns(T::Boolean) }
1391
1410
  def sorbet_method_hook?(method); end
1392
1411
  end
@@ -1545,7 +1564,6 @@ class Mocktail::Signature < ::T::Struct
1545
1564
 
1546
1565
  class << self
1547
1566
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1548
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1549
1567
  def inherited(s); end
1550
1568
  end
1551
1569
  end
@@ -1591,37 +1609,30 @@ class Mocktail::StringifiesCall
1591
1609
  private
1592
1610
 
1593
1611
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#46
1594
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#47
1595
1612
  sig { params(args: T::Array[::Object]).returns(T.nilable(::String)) }
1596
1613
  def argify(args); end
1597
1614
 
1598
1615
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#29
1599
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#30
1600
1616
  sig { params(call: ::Mocktail::Call, parens: T::Boolean).returns(T.nilable(::String)) }
1601
1617
  def args_to_s(call, parens: T.unsafe(nil)); end
1602
1618
 
1603
1619
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#64
1604
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#65
1605
1620
  sig { params(block: T.nilable(::Proc), anonymous: T::Boolean).returns(T.nilable(::String)) }
1606
1621
  def blockify(block, anonymous:); end
1607
1622
 
1608
1623
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#52
1609
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#53
1610
1624
  sig { params(kwargs: T::Hash[::Symbol, ::Object]).returns(T.nilable(::String)) }
1611
1625
  def kwargify(kwargs); end
1612
1626
 
1613
1627
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#58
1614
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#59
1615
1628
  sig { params(block: T.nilable(::Proc)).returns(T.nilable(::String)) }
1616
1629
  def lambdafy(block); end
1617
1630
 
1618
1631
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#75
1619
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#76
1620
1632
  sig { params(block: ::Proc).returns(::String) }
1621
1633
  def source_locationify(block); end
1622
1634
 
1623
1635
  # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#80
1624
- # source://mocktail//lib/mocktail/sorbet/mocktail/share/stringifies_call.rb#81
1625
1636
  sig { params(path: ::String).returns(::String) }
1626
1637
  def strip_pwd(path); end
1627
1638
  end
@@ -1676,7 +1687,6 @@ class Mocktail::Stubbing < ::T::Struct
1676
1687
 
1677
1688
  class << self
1678
1689
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1679
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1680
1690
  def inherited(s); end
1681
1691
  end
1682
1692
  end
@@ -1778,7 +1788,6 @@ class Mocktail::TypeReplacement < ::T::Struct
1778
1788
 
1779
1789
  class << self
1780
1790
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1781
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1782
1791
  def inherited(s); end
1783
1792
  end
1784
1793
  end
@@ -1798,7 +1807,6 @@ class Mocktail::TypeReplacementData < ::T::Struct
1798
1807
 
1799
1808
  class << self
1800
1809
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1801
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1802
1810
  def inherited(s); end
1803
1811
  end
1804
1812
  end
@@ -1814,7 +1822,6 @@ class Mocktail::UnsatisfyingCall < ::T::Struct
1814
1822
 
1815
1823
  class << self
1816
1824
  # source://sorbet-runtime/0.5.11971/lib/types/struct.rb#13
1817
- # source://sorbet-runtime/0.5.10983/lib/types/struct.rb#13
1818
1825
  def inherited(s); end
1819
1826
  end
1820
1827
  end
@@ -1846,11 +1853,11 @@ Mocktail::VERSION = T.let(T.unsafe(nil), String)
1846
1853
 
1847
1854
  # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#4
1848
1855
  class Mocktail::ValidatesArguments
1849
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#32
1856
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#35
1850
1857
  sig { void }
1851
1858
  def initialize; end
1852
1859
 
1853
- # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#37
1860
+ # source://mocktail//lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb#40
1854
1861
  sig { params(dry_call: ::Mocktail::Call).returns(::NilClass) }
1855
1862
  def validate(dry_call); end
1856
1863
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- mocktail (3.0.0)
4
+ mocktail (3.0.1)
5
5
  sorbet-eraser (~> 0.3.1)
6
6
  sorbet-runtime (~> 0.5.9204)
7
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mocktail
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
@@ -137,6 +137,7 @@ files:
137
137
  - lib/mocktail/share/cleans_backtrace.rb
138
138
  - lib/mocktail/share/creates_identifier.rb
139
139
  - lib/mocktail/share/determines_matching_calls.rb
140
+ - lib/mocktail/share/folds_keywords_into_options_hash.rb
140
141
  - lib/mocktail/share/stringifies_call.rb
141
142
  - lib/mocktail/share/stringifies_method_name.rb
142
143
  - lib/mocktail/simulates_argument_error.rb
@@ -195,6 +196,7 @@ files:
195
196
  - lib/mocktail/sorbet/mocktail/share/cleans_backtrace.rb
196
197
  - lib/mocktail/sorbet/mocktail/share/creates_identifier.rb
197
198
  - lib/mocktail/sorbet/mocktail/share/determines_matching_calls.rb
199
+ - lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb
198
200
  - lib/mocktail/sorbet/mocktail/share/stringifies_call.rb
199
201
  - lib/mocktail/sorbet/mocktail/share/stringifies_method_name.rb
200
202
  - lib/mocktail/sorbet/mocktail/simulates_argument_error.rb
@@ -397,6 +399,7 @@ files:
397
399
  - src/mocktail/share/cleans_backtrace.rb
398
400
  - src/mocktail/share/creates_identifier.rb
399
401
  - src/mocktail/share/determines_matching_calls.rb
402
+ - src/mocktail/share/folds_keywords_into_options_hash.rb
400
403
  - src/mocktail/share/stringifies_call.rb
401
404
  - src/mocktail/share/stringifies_method_name.rb
402
405
  - src/mocktail/simulates_argument_error.rb
@@ -450,7 +453,7 @@ files:
450
453
  - sub_projects/sorbet_user/sorbet/rbi/gems/m@1.6.2.rbi
451
454
  - sub_projects/sorbet_user/sorbet/rbi/gems/method_source@1.1.0.rbi
452
455
  - sub_projects/sorbet_user/sorbet/rbi/gems/minitest@5.27.0.rbi
453
- - sub_projects/sorbet_user/sorbet/rbi/gems/mocktail@3.0.0.rbi
456
+ - sub_projects/sorbet_user/sorbet/rbi/gems/mocktail@3.0.1.rbi
454
457
  - sub_projects/sorbet_user/sorbet/rbi/gems/netrc@0.11.0.rbi
455
458
  - sub_projects/sorbet_user/sorbet/rbi/gems/parallel@1.26.3.rbi
456
459
  - sub_projects/sorbet_user/sorbet/rbi/gems/parser@3.3.7.4.rbi