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 +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +1 -1
- data/lib/mocktail/debug.rb +1 -1
- data/lib/mocktail/handles_dry_call/validates_arguments.rb +6 -3
- data/lib/mocktail/handles_dry_new_call.rb +5 -0
- data/lib/mocktail/replaces_type/redefines_singleton_methods.rb +5 -0
- data/lib/mocktail/share/folds_keywords_into_options_hash.rb +22 -0
- data/lib/mocktail/sorbet/mocktail/debug.rb +1 -1
- data/lib/mocktail/sorbet/mocktail/handles_dry_call/validates_arguments.rb +6 -3
- data/lib/mocktail/sorbet/mocktail/handles_dry_new_call.rb +5 -0
- data/lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb +5 -0
- data/lib/mocktail/sorbet/mocktail/share/folds_keywords_into_options_hash.rb +25 -0
- data/lib/mocktail/sorbet/mocktail/version.rb +1 -1
- data/lib/mocktail/version.rb +1 -1
- data/rbi/mocktail-pregenerated.rbi +34 -83
- data/script/build +1 -1
- data/src/mocktail/debug.rb +1 -1
- data/src/mocktail/handles_dry_call/validates_arguments.rb +6 -3
- data/src/mocktail/handles_dry_new_call.rb +5 -0
- data/src/mocktail/replaces_type/redefines_singleton_methods.rb +5 -0
- data/src/mocktail/share/folds_keywords_into_options_hash.rb +25 -0
- data/src/mocktail/version.rb +1 -1
- data/sub_projects/rbi_generator/Gemfile.lock +1 -1
- data/sub_projects/sorbet_user/Gemfile.lock +1 -1
- data/sub_projects/sorbet_user/sorbet/rbi/gems/{mocktail@3.0.0.rbi → mocktail@3.0.1.rbi} +36 -29
- data/sub_projects/untyped_user/Gemfile.lock +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f97cc51c4c07f73a4d9b5adeeba1d9f6d36c70fa29d6061bb28df91948019c3
|
|
4
|
+
data.tar.gz: a9471b225f4d03664485993c6976e3368c49f7771ac4db11b59c4080153fe8ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
data/lib/mocktail/debug.rb
CHANGED
|
@@ -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:(
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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:(
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
data/lib/mocktail/version.rb
CHANGED
|
@@ -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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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
|
data/src/mocktail/debug.rb
CHANGED
|
@@ -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:(
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
data/src/mocktail/version.rb
CHANGED
|
@@ -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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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#
|
|
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
|
|
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.
|
|
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.
|
|
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
|