gimme 0.1.8 → 0.2.0

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.
@@ -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