gimme 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,16 @@
1
1
  require 'gimme/test_double'
2
- require 'gimme/method_resolver'
2
+ require 'gimme/resolves_methods'
3
3
  require 'gimme/errors'
4
+ require 'gimme/gives_class_methods'
4
5
  require 'gimme/gives'
5
6
  require 'gimme/verifies'
6
7
  require 'gimme/matchers'
7
8
  require 'gimme/captor'
9
+ require 'gimme/invokes_satisfied_stubbing'
10
+ require 'gimme/reset'
11
+ require 'gimme/dsl'
12
+
8
13
  require 'gimme/rspec_adapter'
9
14
 
10
- include Gimme
11
15
  include Gimme::Matchers
12
-
16
+ include Gimme::DSL
@@ -0,0 +1,50 @@
1
+ module Gimme
2
+ module DSL
3
+
4
+ # Instantiation
5
+
6
+ def gimme(cls=nil)
7
+ Gimme::TestDouble.new(cls)
8
+ end
9
+
10
+ def gimme_next(cls)
11
+ double = Gimme::TestDouble.new(cls)
12
+ meta_class = class << cls; self; end
13
+ real_new = cls.method(:new)
14
+ meta_class.send(:define_method,:new) do |*args|
15
+ double.send(:initialize,*args)
16
+ meta_class.send(:define_method,:new,real_new) #restore :new on the class
17
+ double
18
+ end
19
+ double
20
+ end
21
+
22
+
23
+ # Stubbing
24
+ def give(double)
25
+ if double.kind_of? Class
26
+ Gimme::GivesClassMethods.new(double)
27
+ else
28
+ Gimme::Gives.new(double)
29
+ end
30
+ end
31
+
32
+ def give!(double)
33
+ give = give(double)
34
+ give.raises_no_method_error = false
35
+ give
36
+ end
37
+
38
+ # Verification
39
+ def verify(double,times=1)
40
+ Gimme::Verifies.new(double,times)
41
+ end
42
+
43
+ def verify!(double,times=1)
44
+ verify = verify(double,times)
45
+ verify.raises_no_method_error = false
46
+ verify
47
+ end
48
+
49
+ end
50
+ end
@@ -8,20 +8,11 @@ module Gimme
8
8
  end
9
9
 
10
10
  def method_missing(sym, *args, &block)
11
- sym = MethodResolver.resolve_sent_method(@double,sym,args,@raises_no_method_error)
11
+ sym = ResolvesMethods.new(@double.cls,sym,args).resolve(@raises_no_method_error)
12
12
 
13
13
  @double.stubbings[sym] ||= {}
14
14
  @double.stubbings[sym][args] = block if block
15
15
  end
16
16
  end
17
17
 
18
- def give(double)
19
- Gimme::Gives.new(double)
20
- end
21
-
22
- def give!(double)
23
- give = give(double)
24
- give.raises_no_method_error = false
25
- give
26
- end
27
18
  end
@@ -0,0 +1,54 @@
1
+ module Gimme
2
+
3
+ class GivesClassMethods < BlankSlate
4
+ attr_accessor :raises_no_method_error
5
+ def initialize(cls)
6
+ @cls = cls
7
+ @raises_no_method_error = true
8
+ @@stubbings ||= {}
9
+ end
10
+
11
+ def method_missing(method, *args, &block)
12
+ cls = @cls
13
+ meta_class = meta_for(@cls)
14
+ method = ResolvesMethods.new(meta_class,method,args).resolve(@raises_no_method_error)
15
+ hidden_method_name = hidden_name_for(method)
16
+
17
+ if @cls.respond_to?(method) && !@cls.respond_to?(hidden_method_name)
18
+ meta_class.send(:alias_method, hidden_method_name, method)
19
+ end
20
+
21
+ @@stubbings[cls] ||= {}
22
+ @@stubbings[cls][method] ||= {}
23
+ @@stubbings[cls][method][args] = block if block
24
+
25
+ #TODO this will be redundantly overwritten
26
+ meta_class.instance_eval do
27
+ define_method method do |*actual_args|
28
+ InvokesSatisfiedStubbing.new(@@stubbings[cls]).invoke(method, actual_args)
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)
38
+ end
39
+ @@stubbings.clear
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def meta_for(cls)
46
+ (class << cls; self; end)
47
+ end
48
+
49
+ def hidden_name_for(method)
50
+ "__gimme_#{method}"
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,29 @@
1
+ module Gimme
2
+ class InvokesSatisfiedStubbing
3
+ def initialize(stubbings)
4
+ @stubbings = stubbings
5
+ end
6
+
7
+ def invoke(method, args)
8
+ matching_stub_block = nil
9
+ @stubbings[method].each do |stub_args,stub_block|
10
+ matching = args.size == stub_args.size
11
+ args.each_index do |i|
12
+ unless args[i] == stub_args[i] || (stub_args[i].respond_to?(:matches?) && stub_args[i].matches?(args[i]))
13
+ matching = false
14
+ break
15
+ end
16
+ end
17
+ matching_stub_block = stub_block if matching
18
+ end
19
+
20
+ if matching_stub_block
21
+ matching_stub_block.call
22
+ elsif method.to_s[-1,1] == '?'
23
+ false
24
+ else
25
+ nil
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module Gimme
2
+ @@stuff_to_do_on_reset = []
3
+
4
+ def self.on_reset (&blk)
5
+ @@stuff_to_do_on_reset << blk
6
+ end
7
+
8
+ def self.reset
9
+ @@stuff_to_do_on_reset.delete_if do |stuff|
10
+ stuff.call
11
+ true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ module Gimme
2
+
3
+ class ResolvesMethods
4
+ def initialize(cls,sym,args)
5
+ @cls = cls
6
+ @sym = sym
7
+ @args = args
8
+ end
9
+
10
+ def resolve(raises_no_method_error=true)
11
+ @sym = @args.shift if @sym == :send
12
+ if @cls && raises_no_method_error
13
+ if @cls.private_method_defined?(named(@sym))
14
+ raise NoMethodError.new("#{@sym} is a private method of your #{@cls} test double, so stubbing/verifying it
15
+ might not be a great idea. If you want to try to stub or verify this method anyway, then you can
16
+ invoke give! or verify! to suppress this error.")
17
+ elsif !@cls.instance_methods.include?(named(@sym))
18
+ raise NoMethodError.new("Your test double of #{@cls} may not know how to respond to the '#{@sym}' method.
19
+ If you're confident that a real #{@cls} will know how to respond to '#{@sym}', then you can
20
+ invoke give! or verify! to suppress this error.")
21
+ end
22
+ end
23
+
24
+ @sym
25
+ end
26
+
27
+ private
28
+
29
+ if RUBY_VERSION >= "1.9.2"
30
+ def named(sym)
31
+ sym
32
+ end
33
+ else
34
+ def named(sym)
35
+ sym.to_s
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -7,6 +7,7 @@ module Gimme
7
7
  end
8
8
 
9
9
  def teardown_mocks_for_rspec
10
+ Gimme.reset
10
11
  end
11
12
  end
12
13
  end
@@ -18,49 +18,15 @@ module Gimme
18
18
  end
19
19
 
20
20
  def method_missing(sym, *args, &block)
21
- sym = MethodResolver.resolve_sent_method(self,sym,args,false)
21
+ sym = ResolvesMethods.new(self.cls,sym,args).resolve(false)
22
22
 
23
23
  @invocations[sym] ||= {}
24
24
  @stubbings[sym] ||= {}
25
25
 
26
26
  @invocations[sym][args] = 1 + (@invocations[sym][args]||0)
27
27
 
28
- matching_stub_block = nil
29
- @stubbings[sym].each do |stub_args,stub_block|
30
- matching = args.size == stub_args.size
31
- args.each_index do |i|
32
- unless args[i] == stub_args[i] || (stub_args[i].respond_to?(:matches?) && stub_args[i].matches?(args[i]))
33
- matching = false
34
- break
35
- end
36
- end
37
- matching_stub_block = stub_block if matching
38
- end
39
-
40
- if matching_stub_block
41
- matching_stub_block.call
42
- elsif sym.to_s[-1,1] == '?'
43
- false
44
- else
45
- nil
46
- end
47
- end
48
- end
49
-
50
- def gimme(cls=nil)
51
- Gimme::TestDouble.new(cls)
52
- end
53
-
54
- def gimme_next(cls)
55
- double = Gimme::TestDouble.new(cls)
56
- meta_class = class << cls; self; end
57
- real_new = cls.method(:new)
58
- meta_class.send(:define_method,:new) do |*args|
59
- double.send(:initialize,*args)
60
- meta_class.send(:define_method,:new,real_new) #restore :new on the class
61
- double
28
+ InvokesSatisfiedStubbing.new(@stubbings).invoke(sym, args)
62
29
  end
63
- double
64
30
  end
65
31
 
66
32
  end
@@ -9,7 +9,7 @@ module Gimme
9
9
  end
10
10
 
11
11
  def method_missing(sym, *args, &block)
12
- sym = MethodResolver.resolve_sent_method(@double,sym,args,@raises_no_method_error)
12
+ sym = ResolvesMethods.new(@double.cls,sym,args).resolve(@raises_no_method_error)
13
13
 
14
14
  #gosh, this loop sure looks familiar. just like another ugly loop I know. TODO.
15
15
  invoked = 0
@@ -41,13 +41,4 @@ module Gimme
41
41
  end
42
42
  end
43
43
 
44
- def verify(double,times=1)
45
- Gimme::Verifies.new(double,times)
46
- end
47
-
48
- def verify!(double,times=1)
49
- verify = verify(double,times)
50
- verify.raises_no_method_error = false
51
- verify
52
- end
53
44
  end
@@ -1,34 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
-
4
- describe Gimme::Captor do
5
- describe "#value" do
6
- Given(:captor) { Captor.new }
7
- When { captor.value = "panda" }
8
- Then { captor.value.should == "panda" }
3
+ module Gimme
4
+ describe Captor do
5
+ describe "#value" do
6
+ Given(:captor) { Captor.new }
7
+ When { captor.value = "panda" }
8
+ Then { captor.value.should == "panda" }
9
+ end
9
10
  end
10
- end
11
11
 
12
- describe Gimme::Matchers::Capture do
13
- Given(:captor) { Captor.new }
12
+ describe Matchers::Capture do
13
+ Given(:captor) { Captor.new }
14
14
 
15
- shared_examples_for "an argument captor" do
16
- describe "#matches?" do
17
- When(:result) { a_capture.matches?("anything at all") }
18
- Then { result.should == true }
19
- Then { captor.value.should == "anything at all" }
15
+ shared_examples_for "an argument captor" do
16
+ describe "#matches?" do
17
+ When(:result) { a_capture.matches?("anything at all") }
18
+ Then { result.should == true }
19
+ Then { captor.value.should == "anything at all" }
20
+ end
20
21
  end
21
- end
22
22
 
23
- context "using the class API" do
24
- it_behaves_like "an argument captor" do
25
- Given(:a_capture) { Capture.new(captor) }
23
+ context "using the class API" do
24
+ it_behaves_like "an argument captor" do
25
+ Given(:a_capture) { Capture.new(captor) }
26
+ end
26
27
  end
27
- end
28
28
 
29
- context "using gimme DSL" do
30
- it_behaves_like "an argument captor" do
31
- Given(:a_capture) { capture(captor) }
29
+ context "using gimme DSL" do
30
+ it_behaves_like "an argument captor" do
31
+ Given(:a_capture) { capture(captor) }
32
+ end
32
33
  end
33
34
  end
34
35
  end
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Gimme::Errors do
4
- specify { Gimme::Errors::VerificationFailedError.kind_of? StandardError }
3
+ module Gimme
4
+ describe Errors do
5
+ specify { Errors::VerificationFailedError.kind_of? StandardError }
6
+ end
5
7
  end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'gimme/shared_examples/shared_gives_examples'
3
+
4
+ module Gimme
5
+ describe GivesClassMethods do
6
+
7
+ class Bunny
8
+ def self.nibble
9
+ end
10
+
11
+ def self.eat(food)
12
+ end
13
+ end
14
+
15
+ class Rabbit
16
+ def self.eat(food)
17
+ end
18
+ end
19
+
20
+ describe "two classes with similar stubbings" do
21
+ Given { give(Rabbit).eat("carrot") { "yum" } }
22
+ Given { give(Bunny).eat("carrot") { "yay" } }
23
+ Then { Rabbit.eat("carrot").should == "yum" }
24
+ Then { Bunny.eat("carrot").should == "yay" }
25
+ end
26
+
27
+ context "using the class API" do
28
+ Given(:subject) { Bunny }
29
+
30
+ it_behaves_like "a normal stubbing" do
31
+ Given(:gives) { GivesClassMethods.new(subject) }
32
+ end
33
+
34
+ it_behaves_like "an overridden stubbing" do
35
+ Given(:gives) { GivesClassMethods.new(subject) }
36
+ end
37
+ end
38
+
39
+ context "using the gimme DSL" do
40
+ Given(:subject) { Bunny }
41
+
42
+ it_behaves_like "a normal stubbing" do
43
+ Given(:gives) { give(subject) }
44
+ end
45
+
46
+ it_behaves_like "an overridden stubbing" do
47
+ Given(:gives) { give!(subject) }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,52 +1,39 @@
1
1
  require 'spec_helper'
2
+ require 'gimme/shared_examples/shared_gives_examples'
2
3
 
3
- describe Gimme::Gives do
4
- class Bunny
5
- def nibble
6
- end
7
- end
4
+ module Gimme
5
+ describe Gives do
8
6
 
9
- shared_examples_for "a normal stubbing" do
10
- context "stubbing an existing method" do
11
- When { gives.nibble() { "nom" } }
12
- Then { subject.nibble.should == "nom" }
13
- end
14
-
15
- context "stubbing a non-existent method" do
16
- When(:stubbing) { lambda { gives.bark { "woof" } } }
17
- Then { stubbing.should raise_error NoMethodError }
18
- end
19
- end
7
+ class Bunny
8
+ def nibble
9
+ end
20
10
 
21
- shared_examples_for "an overridden stubbing" do
22
- context "configured to _not_ raise an error when stubbed method does not exist" do
23
- Given { gives.raises_no_method_error =false }
24
- When { gives.bark { "woof" } }
25
- Then { subject.bark.should == "woof" }
11
+ def eat(food)
12
+ end
26
13
  end
27
- end
28
14
 
29
- context "using the class API" do
30
- Given(:subject) { TestDouble.new(Bunny) }
15
+ context "using the class API" do
16
+ Given(:subject) { TestDouble.new(Bunny) }
31
17
 
32
- it_behaves_like "a normal stubbing" do
33
- Given(:gives) { Gives.new(subject) }
34
- end
18
+ it_behaves_like "a normal stubbing" do
19
+ Given(:gives) { Gives.new(subject) }
20
+ end
35
21
 
36
- it_behaves_like "an overridden stubbing" do
37
- Given(:gives) { Gives.new(subject) }
22
+ it_behaves_like "an overridden stubbing" do
23
+ Given(:gives) { Gives.new(subject) }
24
+ end
38
25
  end
39
- end
40
26
 
41
- context "using the gimme DSL" do
42
- Given(:subject) { gimme(Bunny) }
27
+ context "using the gimme DSL" do
28
+ Given(:subject) { gimme(Bunny) }
43
29
 
44
- it_behaves_like "a normal stubbing" do
45
- Given(:gives) { give(subject) }
46
- end
30
+ it_behaves_like "a normal stubbing" do
31
+ Given(:gives) { give(subject) }
32
+ end
47
33
 
48
- it_behaves_like "an overridden stubbing" do
49
- Given(:gives) { give!(subject) }
34
+ it_behaves_like "an overridden stubbing" do
35
+ Given(:gives) { give!(subject) }
36
+ end
50
37
  end
51
38
  end
52
- end
39
+ end