gimme 0.2.0 → 0.3.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.
- data/Gemfile +3 -2
- data/Guardfile +1 -2
- data/LICENSE.txt +1 -1
- data/README.markdown +1 -1
- data/VERSION +1 -1
- data/features/basics.feature +66 -0
- data/features/matchers.feature +126 -0
- data/features/{argument_captors.feature → old/argument_captors.feature} +0 -0
- data/features/{gimme_next.feature → old/gimme_next.feature} +0 -0
- data/features/{stub_basic.feature → old/stub_basic.feature} +0 -0
- data/features/{stub_class_methods.feature → old/stub_class_methods.feature} +0 -1
- data/features/{stub_matchers.feature → old/stub_matchers.feature} +0 -0
- data/features/{stub_sensible_defaults.feature → old/stub_sensible_defaults.feature} +0 -0
- data/features/{unknown_methods.feature → old/unknown_methods.feature} +0 -0
- data/features/{verify_matcher_anything.feature → old/verify_matcher_anything.feature} +0 -0
- data/features/old/verify_no_args.feature +23 -0
- data/features/{verify_with_args.feature → old/verify_with_args.feature} +0 -0
- data/features/readme.md +3 -0
- data/features/step_definitions/doc_steps.rb +12 -0
- data/features/step_definitions/gimme_steps.rb +17 -0
- data/features/support/animals.rb +9 -0
- data/gimme.gemspec +35 -18
- data/lib/gimme.rb +8 -1
- data/lib/gimme/dsl.rb +19 -5
- data/lib/gimme/ensures_class_method_restoration.rb +18 -0
- data/lib/gimme/gives.rb +1 -2
- data/lib/gimme/gives_class_methods.rb +5 -29
- data/lib/gimme/invocation_store.rb +14 -0
- data/lib/gimme/invokes_satisfied_stubbing.rb +18 -10
- data/lib/gimme/method_store.rb +21 -0
- data/lib/gimme/reset.rb +10 -3
- data/lib/gimme/resolves_methods.rb +1 -1
- data/lib/gimme/spies_on_class_methods.rb +28 -0
- data/lib/gimme/store.rb +38 -0
- data/lib/gimme/stubbing_store.rb +17 -0
- data/lib/gimme/test_double.rb +13 -10
- data/lib/gimme/verifies.rb +10 -6
- data/lib/gimme/verifies_class_methods.rb +8 -0
- data/spec/gimme/shared_examples/shared_gives_examples.rb +28 -26
- data/spec/gimme/shared_examples/shared_verifies_examples.rb +91 -0
- data/spec/gimme/spies_on_class_method_spec.rb +58 -0
- data/spec/gimme/verifies_class_methods_spec.rb +46 -0
- data/spec/gimme/verifies_spec.rb +7 -94
- metadata +59 -42
- data/features/verify_no_args.feature +0 -18
data/lib/gimme.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
require 'gimme/test_double'
|
2
2
|
require 'gimme/resolves_methods'
|
3
3
|
require 'gimme/errors'
|
4
|
-
require 'gimme/gives_class_methods'
|
5
4
|
require 'gimme/gives'
|
5
|
+
require 'gimme/gives_class_methods'
|
6
|
+
require 'gimme/ensures_class_method_restoration'
|
6
7
|
require 'gimme/verifies'
|
8
|
+
require 'gimme/spies_on_class_methods'
|
9
|
+
require 'gimme/verifies_class_methods'
|
7
10
|
require 'gimme/matchers'
|
8
11
|
require 'gimme/captor'
|
9
12
|
require 'gimme/invokes_satisfied_stubbing'
|
10
13
|
require 'gimme/reset'
|
11
14
|
require 'gimme/dsl'
|
15
|
+
require 'gimme/store'
|
16
|
+
require 'gimme/stubbing_store'
|
17
|
+
require 'gimme/invocation_store'
|
18
|
+
require 'gimme/method_store'
|
12
19
|
|
13
20
|
require 'gimme/rspec_adapter'
|
14
21
|
|
data/lib/gimme/dsl.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Gimme
|
2
2
|
module DSL
|
3
|
-
|
3
|
+
|
4
4
|
# Instantiation
|
5
|
-
|
5
|
+
|
6
6
|
def gimme(cls=nil)
|
7
7
|
Gimme::TestDouble.new(cls)
|
8
8
|
end
|
@@ -19,7 +19,7 @@ module Gimme
|
|
19
19
|
double
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
|
23
23
|
# Stubbing
|
24
24
|
def give(double)
|
25
25
|
if double.kind_of? Class
|
@@ -37,7 +37,11 @@ module Gimme
|
|
37
37
|
|
38
38
|
# Verification
|
39
39
|
def verify(double,times=1)
|
40
|
-
|
40
|
+
if double.kind_of? Class
|
41
|
+
Gimme::VerifiesClassMethods.new(double, times)
|
42
|
+
else
|
43
|
+
Gimme::Verifies.new(double,times)
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
47
|
def verify!(double,times=1)
|
@@ -45,6 +49,16 @@ module Gimme
|
|
45
49
|
verify.raises_no_method_error = false
|
46
50
|
verify
|
47
51
|
end
|
48
|
-
|
52
|
+
|
53
|
+
# Spying on class methods
|
54
|
+
def spy_on(cls, method)
|
55
|
+
SpiesOnClassMethod.new(cls).spy(method)
|
56
|
+
end
|
57
|
+
|
58
|
+
def spy_on!(cls, method)
|
59
|
+
spies_on = SpiesOnClassMethod.new(cls)
|
60
|
+
spies_on.raises_no_method_error = false
|
61
|
+
spies_on.spy(method)
|
62
|
+
end
|
49
63
|
end
|
50
64
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gimme
|
2
|
+
class EnsuresClassMethodRestoration
|
3
|
+
def initialize(cls)
|
4
|
+
@cls = cls
|
5
|
+
end
|
6
|
+
|
7
|
+
def ensure(method)
|
8
|
+
meta_class = (class << @cls; self; end)
|
9
|
+
Gimme.on_reset do
|
10
|
+
if real_method = Gimme.class_methods.get(@cls, method)
|
11
|
+
meta_class.instance_eval { define_method method, real_method }
|
12
|
+
else
|
13
|
+
meta_class.send(:remove_method, method)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/gimme/gives.rb
CHANGED
@@ -10,8 +10,7 @@ module Gimme
|
|
10
10
|
def method_missing(sym, *args, &block)
|
11
11
|
sym = ResolvesMethods.new(@double.cls,sym,args).resolve(@raises_no_method_error)
|
12
12
|
|
13
|
-
@double
|
14
|
-
@double.stubbings[sym][args] = block if block
|
13
|
+
Gimme.stubbings.set(@double, sym, args, block)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
@@ -5,50 +5,26 @@ module Gimme
|
|
5
5
|
def initialize(cls)
|
6
6
|
@cls = cls
|
7
7
|
@raises_no_method_error = true
|
8
|
-
@@stubbings ||= {}
|
9
8
|
end
|
10
9
|
|
11
10
|
def method_missing(method, *args, &block)
|
12
11
|
cls = @cls
|
13
|
-
meta_class =
|
12
|
+
meta_class = (class << cls; self; end)
|
14
13
|
method = ResolvesMethods.new(meta_class,method,args).resolve(@raises_no_method_error)
|
15
|
-
hidden_method_name = hidden_name_for(method)
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
@@stubbings[cls] ||= {}
|
22
|
-
@@stubbings[cls][method] ||= {}
|
23
|
-
@@stubbings[cls][method][args] = block if block
|
15
|
+
Gimme.class_methods.set(cls, method)
|
16
|
+
Gimme.stubbings.set(cls, method, args, block)
|
24
17
|
|
25
18
|
#TODO this will be redundantly overwritten
|
26
19
|
meta_class.instance_eval do
|
27
20
|
define_method method do |*actual_args|
|
28
|
-
InvokesSatisfiedStubbing.new(
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
Gimme.on_reset do
|
33
|
-
if cls.respond_to?(hidden_method_name)
|
34
|
-
meta_class.instance_eval { define_method method, cls.method(hidden_method_name) }
|
35
|
-
meta_class.send(:remove_method, hidden_method_name)
|
36
|
-
else
|
37
|
-
meta_class.send(:remove_method, method)
|
21
|
+
InvokesSatisfiedStubbing.new(Gimme.stubbings.get(cls)).invoke(method, actual_args)
|
38
22
|
end
|
39
|
-
@@stubbings.clear
|
40
23
|
end
|
41
|
-
end
|
42
24
|
|
43
|
-
|
44
|
-
|
45
|
-
def meta_for(cls)
|
46
|
-
(class << cls; self; end)
|
25
|
+
EnsuresClassMethodRestoration.new(@cls).ensure(method)
|
47
26
|
end
|
48
27
|
|
49
|
-
def hidden_name_for(method)
|
50
|
-
"__gimme_#{method}"
|
51
|
-
end
|
52
28
|
end
|
53
29
|
|
54
30
|
end
|
@@ -1,11 +1,24 @@
|
|
1
1
|
module Gimme
|
2
2
|
class InvokesSatisfiedStubbing
|
3
3
|
def initialize(stubbings)
|
4
|
-
@stubbings = stubbings
|
4
|
+
@stubbings = stubbings || {}
|
5
5
|
end
|
6
6
|
|
7
7
|
def invoke(method, args)
|
8
|
-
|
8
|
+
if @stubbings[method] && blk = find_matching_stubbing(method, args)
|
9
|
+
blk.call
|
10
|
+
elsif method.to_s[-1,1] == '?'
|
11
|
+
false
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def find_matching_stubbing(method, args)
|
20
|
+
match = nil
|
21
|
+
|
9
22
|
@stubbings[method].each do |stub_args,stub_block|
|
10
23
|
matching = args.size == stub_args.size
|
11
24
|
args.each_index do |i|
|
@@ -14,16 +27,11 @@ module Gimme
|
|
14
27
|
break
|
15
28
|
end
|
16
29
|
end
|
17
|
-
|
30
|
+
match = stub_block if matching
|
18
31
|
end
|
19
32
|
|
20
|
-
|
21
|
-
matching_stub_block.call
|
22
|
-
elsif method.to_s[-1,1] == '?'
|
23
|
-
false
|
24
|
-
else
|
25
|
-
nil
|
26
|
-
end
|
33
|
+
match
|
27
34
|
end
|
35
|
+
|
28
36
|
end
|
29
37
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Gimme
|
2
|
+
|
3
|
+
class ClassMethodStore < Store
|
4
|
+
|
5
|
+
def set(cls, method_name)
|
6
|
+
id = cls.__id__
|
7
|
+
meta = (class << cls; self; end)
|
8
|
+
@store[id] ||= {}
|
9
|
+
|
10
|
+
if meta.method_defined?(method_name) && !@store[id][method_name]
|
11
|
+
@store[id][method_name] = cls.method(method_name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.class_methods
|
18
|
+
@@class_methods ||= ClassMethodStore.new
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/gimme/reset.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
module Gimme
|
2
2
|
@@stuff_to_do_on_reset = []
|
3
|
+
@@stuff_to_do_on_every_reset = []
|
3
4
|
|
4
|
-
def self.on_reset (&blk)
|
5
|
-
|
5
|
+
def self.on_reset (situation = :once, &blk)
|
6
|
+
if situation == :once
|
7
|
+
@@stuff_to_do_on_reset << blk
|
8
|
+
else
|
9
|
+
@@stuff_to_do_on_every_reset << blk
|
10
|
+
end
|
6
11
|
end
|
7
12
|
|
8
13
|
def self.reset
|
9
14
|
@@stuff_to_do_on_reset.delete_if do |stuff|
|
10
15
|
stuff.call
|
11
|
-
|
16
|
+
end
|
17
|
+
@@stuff_to_do_on_every_reset.each do |stuff|
|
18
|
+
stuff.call
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gimme
|
2
|
+
class SpiesOnClassMethod
|
3
|
+
attr_accessor :raises_no_method_error
|
4
|
+
def initialize(cls)
|
5
|
+
@cls = cls
|
6
|
+
@raises_no_method_error = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def spy(method)
|
10
|
+
meta_class = (class << @cls; self; end)
|
11
|
+
method = ResolvesMethods.new(meta_class, method).resolve(@raises_no_method_error)
|
12
|
+
|
13
|
+
if meta_class.method_defined? method
|
14
|
+
Gimme.class_methods.set(@cls, method)
|
15
|
+
meta_class.send(:remove_method, method)
|
16
|
+
end
|
17
|
+
|
18
|
+
cls = @cls
|
19
|
+
meta_class.instance_eval do
|
20
|
+
define_method method do |*args|
|
21
|
+
Gimme.invocations.increment(cls, method, args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
EnsuresClassMethodRestoration.new(@cls).ensure(method)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/gimme/store.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gimme
|
2
|
+
class Store
|
3
|
+
@store = {}
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@store = {}
|
7
|
+
Gimme.on_reset(:each) do
|
8
|
+
@store.clear
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@store = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(double, method, args, content)
|
17
|
+
id = double.__id__
|
18
|
+
@store[id] ||= {}
|
19
|
+
@store[id][method] ||= {}
|
20
|
+
@store[id][method][args] = content
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(double, method=nil, args=nil)
|
24
|
+
id = double.__id__
|
25
|
+
if !method
|
26
|
+
@store[id]
|
27
|
+
elsif @store[id] && !args
|
28
|
+
@store[id][method]
|
29
|
+
elsif @store[id] && @store[id][method]
|
30
|
+
@store[id][method][args]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear
|
35
|
+
@store.clear
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/gimme/test_double.rb
CHANGED
@@ -8,24 +8,27 @@ module Gimme
|
|
8
8
|
|
9
9
|
class TestDouble < BlankSlate
|
10
10
|
attr_accessor :cls
|
11
|
-
attr_accessor :stubbings
|
12
|
-
attr_reader :invocations
|
13
11
|
|
14
12
|
def initialize(cls=nil)
|
15
13
|
@cls = cls
|
16
|
-
@stubbings = {}
|
17
|
-
@invocations = {}
|
18
14
|
end
|
19
15
|
|
20
|
-
def method_missing(
|
21
|
-
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
method = ResolvesMethods.new(self.cls, method, args).resolve(false)
|
18
|
+
Gimme.invocations.increment(self, method, args)
|
19
|
+
InvokesSatisfiedStubbing.new(Gimme.stubbings.get(self)).invoke(method, args)
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
def hash
|
23
|
+
__id__
|
24
|
+
end
|
25
25
|
|
26
|
-
|
26
|
+
def eql?(other)
|
27
|
+
__id__ == other.__id__
|
28
|
+
end
|
27
29
|
|
28
|
-
|
30
|
+
def ==(other)
|
31
|
+
eql?(other)
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
data/lib/gimme/verifies.rb
CHANGED
@@ -8,13 +8,17 @@ module Gimme
|
|
8
8
|
@raises_no_method_error = true
|
9
9
|
end
|
10
10
|
|
11
|
+
def __gimme__cls
|
12
|
+
@double.cls
|
13
|
+
end
|
14
|
+
|
11
15
|
def method_missing(sym, *args, &block)
|
12
|
-
sym = ResolvesMethods.new(
|
16
|
+
sym = ResolvesMethods.new(__gimme__cls,sym,args).resolve(@raises_no_method_error)
|
13
17
|
|
14
18
|
#gosh, this loop sure looks familiar. just like another ugly loop I know. TODO.
|
15
19
|
invoked = 0
|
16
|
-
if @double
|
17
|
-
@double
|
20
|
+
if Gimme.invocations.get(@double, sym)
|
21
|
+
Gimme.invocations.get(@double, sym).each do |invoke_args,count|
|
18
22
|
matching = args.size == invoke_args.size
|
19
23
|
invoke_args.each_index do |i|
|
20
24
|
unless invoke_args[i] == args[i] || (args[i].respond_to?(:matches?) && args[i].matches?(invoke_args[i]))
|
@@ -27,11 +31,11 @@ module Gimme
|
|
27
31
|
end
|
28
32
|
|
29
33
|
if invoked != @times
|
30
|
-
msg = "expected #{
|
31
|
-
if
|
34
|
+
msg = "expected #{__gimme__cls.to_s}##{sym} to have been called with arguments #{args}"
|
35
|
+
if !Gimme.invocations.get(@double, sym) || Gimme.invocations.get(@double, sym).empty?
|
32
36
|
msg << "\n but was never called"
|
33
37
|
else
|
34
|
-
msg = @double
|
38
|
+
msg = Gimme.invocations.get(@double, sym).inject msg do |memo, actual|
|
35
39
|
memo + "\n was actually called #{actual[1]} times with arguments #{actual[0]}"
|
36
40
|
end
|
37
41
|
end
|