stubborn 0.2.0 → 0.3.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.
@@ -63,13 +63,16 @@ You can control which methods to check with the options :except and :only. Both
63
63
  Stubborn.should_be_stubbed(Api.new, :except => :safe_method)
64
64
  Stubborn.should_be_stubbed(Api.new, :only => [:slow_method, :external_service])
65
65
 
66
+ You can also filter on instance methods. All you need to do is using the :instance_methods key to scope your :only or :except methods like this:
67
+
68
+ Stubborn.should_be_stubbed(User, :instance_methods => {:only => :save})
69
+
66
70
  == Installation
67
71
 
68
- sudo gem install stubborn -s http://gemcutter.org
72
+ sudo gem install stubborn
69
73
 
70
74
  == To Do
71
75
 
72
- * Filters so that you can choose which methods to include or exclude
73
76
  * Give stub suggestions for more test frameworks. It currently shows only rspec syntax
74
77
 
75
78
  == Collaborate
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -1,70 +1,21 @@
1
- require 'suggesters/rspec_suggester'
2
- require 'missed_stub_exception'
1
+ require 'stubborn/suggesters/rspec_suggester'
2
+ require 'stubborn/proxy_for_instance'
3
+ require 'stubborn/proxy_for_module'
3
4
 
4
5
  module Stubborn
5
6
  def self.should_be_stubbed(object, options = {})
6
- if object.is_a?(Class)
7
- ProxyForClass.new(object, options)
7
+ if object.is_a?(Module)
8
+ ProxyForModule.new(object, options)
8
9
  else
9
10
  ProxyForInstance.new(object, options)
10
11
  end
11
12
  end
12
13
 
13
- class ProxyForInstance
14
- instance_methods.each do |sym|
15
- undef_method(sym) unless sym.to_s =~ /__/ || sym.to_s == "send"
16
- end
17
-
18
- def initialize(proxy_target, options = {})
19
- @proxy_target = proxy_target
20
-
21
- options[:except] = [options[:except]].flatten.compact.map{|m| m.to_s}
22
- options[:only] = [options[:only]].flatten.compact.map{|m| m.to_s}
23
- options = {:class => proxy_target.class}.merge(options)
24
- @label = options[:label]
25
- @class = options[:class]
26
- @methods_to_skip = ["respond_to?", "is_a?", "kind_of?", "equal?", "eql?", "==", "==="] + options[:except]
27
- @only_methods = options[:only]
28
- end
29
-
30
- def class
31
- @class
32
- end
33
-
34
- def method_missing(method_name, *args, &block)
35
- were_we_already_processing_a_missed_stub = Thread.current["inside_missed_stub"]
36
- Thread.current["inside_missed_stub"] = true
37
- result = @proxy_target.send(method_name, *args, &block)
38
- return result if !@only_methods.include?(method_name.to_s) && !@only_methods.empty? || @methods_to_skip.include?(method_name.to_s) || were_we_already_processing_a_missed_stub
39
- raise MissedStubException.new(@label || @proxy_target, method_name, args, result, Suggesters::RSpecSuggester)
40
- ensure
41
- Thread.current["inside_missed_stub"] = false unless were_we_already_processing_a_missed_stub
42
- end
14
+ def self.suggester=(suggester)
15
+ @suggester = suggester
43
16
  end
44
17
 
45
- class ProxyForClass < ProxyForInstance
46
- def initialize(proxy_target, options = {})
47
- super
48
- redefine_const(proxy_target, self) unless proxy_target.name.strip.empty?
49
- end
50
-
51
- def name
52
- @proxy_target.name
53
- end
54
-
55
- def new(*args, &block)
56
- new_instance = @proxy_target.new(*args, &block)
57
- ProxyForInstance.new(new_instance, :class => self)
58
- end
59
-
60
- private
61
- def redefine_const(const, value)
62
- const_parts = const.name.split('::')
63
- const_name = const_parts.pop
64
- parent_const = const_parts.inject(Object){|a, c| a.const_get(c) }
65
-
66
- parent_const.__send__(:remove_const, const_name) if parent_const.const_defined?(const_name)
67
- parent_const.const_set(const_name, value)
68
- end
18
+ def self.suggester
19
+ @suggester ||= Suggesters::RSpecSuggester
69
20
  end
70
21
  end
@@ -0,0 +1,11 @@
1
+ module Stubborn
2
+ class MissedStubException < RuntimeError
3
+ def initialize(object_or_label, method_name, args, result, suggester)
4
+ @suggestions = suggester.suggestions(object_or_label, method_name, args, result)
5
+ end
6
+
7
+ def message
8
+ "You've missed adding a stub. Consider this suggestion#{@suggestions.size > 1 ? "s" : ""}:\n#{@suggestions.join("\n")}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ require 'stubborn/missed_stub_exception'
2
+
3
+ module Stubborn
4
+ class ProxyForInstance
5
+ instance_methods.each do |sym|
6
+ undef_method(sym) unless sym.to_s =~ /__/ || sym.to_s == "send"
7
+ end
8
+
9
+ def initialize(proxy_target, options = {})
10
+ @proxy_target = proxy_target
11
+
12
+ options[:except] = [options[:except]].flatten.compact.map{|m| m.to_s}
13
+ options[:only] = [options[:only]].flatten.compact.map{|m| m.to_s}
14
+ options = {:class => proxy_target.class}.merge(options)
15
+ @label = options[:label]
16
+ @class = options[:class]
17
+ @methods_to_skip = ["respond_to?", "is_a?", "kind_of?", "equal?", "eql?", "==", "==="] + options[:except]
18
+ @only_methods = options[:only]
19
+ @instance_methods = options[:instance_methods]
20
+ end
21
+
22
+ def class
23
+ @class
24
+ end
25
+
26
+ def method_missing(method_name, *args, &block)
27
+ were_we_already_processing_a_missed_stub = Thread.current["inside_missed_stub"]
28
+ Thread.current["inside_missed_stub"] = true
29
+ result = begin
30
+ @proxy_target.send(method_name, *args, &block)
31
+ rescue => e
32
+ e
33
+ end
34
+
35
+ return result if !@only_methods.include?(method_name.to_s) && !@only_methods.empty? || @methods_to_skip.include?(method_name.to_s) || were_we_already_processing_a_missed_stub
36
+ raise_missed_stub_exception(method_name, args, result)
37
+ ensure
38
+ Thread.current["inside_missed_stub"] = false unless were_we_already_processing_a_missed_stub
39
+ end
40
+
41
+ private
42
+ def raise_missed_stub_exception(method_name, args, result)
43
+ raise MissedStubException.new(@label || @proxy_target, method_name, args, result, Stubborn.suggester)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module Stubborn
2
+ class ProxyForModule < ProxyForInstance
3
+ def initialize(proxy_target, options = {})
4
+ super
5
+ redefine_const(proxy_target, self) unless proxy_target.name.strip.empty?
6
+ end
7
+
8
+ def name
9
+ @proxy_target.name
10
+ end
11
+
12
+ def new(*args, &block)
13
+ new_instance = @proxy_target.new(*args, &block)
14
+ raise_missed_stub_exception("new", args, new_instance) if @only_methods.include?("new") && !@methods_to_skip.include?("new")
15
+ options = {:class => self}
16
+
17
+ if @instance_methods
18
+ options[:only] = @instance_methods[:only]
19
+ options[:except] = @instance_methods[:except]
20
+ end
21
+
22
+ ProxyForInstance.new(new_instance, options)
23
+ end
24
+
25
+ private
26
+ def redefine_const(const, value)
27
+ const_parts = const.name.split('::')
28
+ const_name = const_parts.pop
29
+ parent_const = const_parts.inject(Object){|a, c| a.const_get(c) }
30
+
31
+ parent_const.__send__(:remove_const, const_name) if parent_const.const_defined?(const_name)
32
+ parent_const.const_set(const_name, value)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ module Stubborn
2
+ module Suggesters
3
+ module RSpecSuggester
4
+ def self.suggestions(object_or_label, method_name, args, result_object)
5
+ object_label = object_or_label.respond_to?(:to_str) ? object_or_label : friendly_name(object_or_label)
6
+ args = args.map{|a| friendly_name(a)}.join(", ")
7
+ result = friendly_name(result_object)
8
+
9
+ with = args.strip.empty? ? nil : ".with(#{args})"
10
+
11
+ return_method = if result_object.is_a?(Exception)
12
+ ".and_raise(#{result_object.class})"
13
+ elsif result_object.nil?
14
+ nil
15
+ else
16
+ ".and_return(#{result})"
17
+ end
18
+
19
+ suggestions = []
20
+ suggestions << "#{object_label}.stub!(:#{method_name})#{with}#{return_method}"
21
+ suggestions << "#{object_label}.stub!(:#{method_name})#{return_method}"
22
+ suggestions.uniq
23
+ end
24
+
25
+ private
26
+ def self.friendly_name(object)
27
+ return "\"#{object}\"" if object.respond_to?(:to_str)
28
+ return object.inspect if object.respond_to?(:to_int) || object.is_a?(Hash) || object.nil? || object == true || object == false
29
+
30
+ if object.is_a?(Class)
31
+ object.name
32
+ else
33
+ "#{object.class.name.downcase.gsub(/\W+/, '_')}_instance"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,12 +1,15 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{stubborn}
5
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["Daniel Cadenas"]
9
- s.date = %q{2009-10-05}
12
+ s.date = %q{2010-02-17}
10
13
  s.email = %q{dcadenas@gmail.com}
11
14
  s.extra_rdoc_files = [
12
15
  "LICENSE",
@@ -19,9 +22,11 @@ Gem::Specification.new do |s|
19
22
  "README.rdoc",
20
23
  "Rakefile",
21
24
  "VERSION",
22
- "lib/missed_stub_exception.rb",
23
25
  "lib/stubborn.rb",
24
- "lib/suggesters/rspec_suggester.rb",
26
+ "lib/stubborn/missed_stub_exception.rb",
27
+ "lib/stubborn/proxy_for_instance.rb",
28
+ "lib/stubborn/proxy_for_module.rb",
29
+ "lib/stubborn/suggesters/rspec_suggester.rb",
25
30
  "stubborn.gemspec",
26
31
  "test/stubborn_method_filtering_test.rb",
27
32
  "test/stubborn_test.rb",
@@ -32,7 +37,7 @@ Gem::Specification.new do |s|
32
37
  s.rdoc_options = ["--charset=UTF-8"]
33
38
  s.require_paths = ["lib"]
34
39
  s.rubyforge_project = %q{stubborn}
35
- s.rubygems_version = %q{1.3.3}
40
+ s.rubygems_version = %q{1.3.5}
36
41
  s.summary = %q{A gem to help you find your missing stubs}
37
42
  s.test_files = [
38
43
  "test/stubborn_method_filtering_test.rb",
@@ -51,3 +56,4 @@ Gem::Specification.new do |s|
51
56
  else
52
57
  end
53
58
  end
59
+
@@ -1,8 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
- module FilteringTest; end
3
+ module FilteringTest
4
+ class Error < StandardError; end
5
+ end
4
6
 
5
- def reset_FilteringTest_api_class
7
+ def reset_filtering_test_api_class
6
8
  name = "Api"
7
9
  FilteringTest.send(:remove_const, name) if FilteringTest.const_defined?(name)
8
10
  klass = Class.new do
@@ -14,6 +16,10 @@ def reset_FilteringTest_api_class
14
16
  "instance_method_2 called"
15
17
  end
16
18
 
19
+ def instance_method_3
20
+ raise FilteringTest::Error
21
+ end
22
+
17
23
  def self.class_method_1
18
24
  "class_method_1 called"
19
25
  end
@@ -27,51 +33,98 @@ end
27
33
 
28
34
  Expectations do
29
35
  expect "instance_method_1 called" do
30
- reset_FilteringTest_api_class
31
- api = FilteringTest::Api.new
36
+ reset_filtering_test_api_class
37
+ api = FilteringTest::Api.new
32
38
  api = Stubborn.should_be_stubbed(api, :except => [:instance_method_1, :instance_method_2])
33
39
  api.instance_method_1
34
40
  end
35
41
 
36
42
  expect "instance_method_2 called" do
37
- reset_FilteringTest_api_class
38
- api = FilteringTest::Api.new
43
+ reset_filtering_test_api_class
44
+ api = FilteringTest::Api.new
39
45
  api = Stubborn.should_be_stubbed(api, :except => [:instance_method_1, :instance_method_2])
40
46
  api.instance_method_2
41
47
  end
42
48
 
43
49
  expect Stubborn::MissedStubException do
44
- reset_FilteringTest_api_class
45
- api = FilteringTest::Api.new
50
+ reset_filtering_test_api_class
51
+ api = FilteringTest::Api.new
46
52
  api = Stubborn.should_be_stubbed(api, :except => :instance_method_1)
47
53
  api.instance_method_2
48
54
  end
49
55
 
50
56
  expect "instance_method_2 called" do
51
- reset_FilteringTest_api_class
52
- api = FilteringTest::Api.new
57
+ reset_filtering_test_api_class
58
+ api = FilteringTest::Api.new
53
59
  api = Stubborn.should_be_stubbed(api, :only => :instance_method_1)
54
60
  api.instance_method_2
55
61
  end
56
62
 
57
63
  expect Stubborn::MissedStubException do
58
- reset_FilteringTest_api_class
59
- api = FilteringTest::Api.new
64
+ reset_filtering_test_api_class
65
+ api = FilteringTest::Api.new
60
66
  api = Stubborn.should_be_stubbed(api, :only => :instance_method_1)
61
67
  api.instance_method_1
62
68
  end
63
69
 
64
70
  expect Stubborn::MissedStubException do
65
- reset_FilteringTest_api_class
66
- api = FilteringTest::Api.new
71
+ reset_filtering_test_api_class
72
+ api = FilteringTest::Api.new
67
73
  api = Stubborn.should_be_stubbed(api, :only => [:instance_method_1, :instance_method_2])
68
74
  api.instance_method_1
69
75
  end
70
76
 
71
77
  expect Stubborn::MissedStubException do
72
- reset_FilteringTest_api_class
73
- api = FilteringTest::Api.new
78
+ reset_filtering_test_api_class
79
+ api = FilteringTest::Api.new
74
80
  api = Stubborn.should_be_stubbed(api, :only => [:instance_method_1, :instance_method_2])
75
81
  api.instance_method_2
76
82
  end
83
+
84
+ expect Stubborn::MissedStubException do
85
+ reset_filtering_test_api_class
86
+ Stubborn.should_be_stubbed(FilteringTest::Api, :only => :new)
87
+ FilteringTest::Api.new
88
+ end
89
+
90
+ expect Stubborn::MissedStubException do
91
+ reset_filtering_test_api_class
92
+ Stubborn.should_be_stubbed(FilteringTest::Api, :instance_methods => {:only => :instance_method_1})
93
+ api = FilteringTest::Api.new
94
+ api.instance_method_1
95
+ end
96
+
97
+ expect "instance_method_2 called" do
98
+ reset_filtering_test_api_class
99
+ Stubborn.should_be_stubbed(FilteringTest::Api, :instance_methods => {:only => :instance_method_1})
100
+ api = FilteringTest::Api.new
101
+ api.instance_method_2
102
+ end
103
+
104
+ expect Stubborn::MissedStubException do
105
+ reset_filtering_test_api_class
106
+ Stubborn.should_be_stubbed(FilteringTest::Api, :instance_methods => {:except => :instance_method_1})
107
+ api = FilteringTest::Api.new
108
+ api.instance_method_2
109
+ end
110
+
111
+ expect "instance_method_1 called" do
112
+ reset_filtering_test_api_class
113
+ Stubborn.should_be_stubbed(FilteringTest::Api, :instance_methods => {:except => :instance_method_1})
114
+ api = FilteringTest::Api.new
115
+ api.instance_method_1
116
+ end
117
+
118
+ expect Stubborn::MissedStubException do
119
+ reset_filtering_test_api_class
120
+ Stubborn.should_be_stubbed(FilteringTest::Api)
121
+ api = FilteringTest::Api.new
122
+ api.instance_method_1
123
+ end
124
+
125
+ expect Stubborn::MissedStubException do
126
+ reset_filtering_test_api_class
127
+ api = Stubborn.should_be_stubbed(FilteringTest::Api.new)
128
+ api.instance_method_3
129
+ end
77
130
  end
@@ -4,7 +4,3 @@ require 'expectations'
4
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
6
  require 'stubborn'
7
-
8
- class Test::Unit::TestCase
9
- end
10
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stubborn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Cadenas
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-05 00:00:00 -02:00
12
+ date: 2010-02-17 00:00:00 -02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,9 +29,11 @@ files:
29
29
  - README.rdoc
30
30
  - Rakefile
31
31
  - VERSION
32
- - lib/missed_stub_exception.rb
33
32
  - lib/stubborn.rb
34
- - lib/suggesters/rspec_suggester.rb
33
+ - lib/stubborn/missed_stub_exception.rb
34
+ - lib/stubborn/proxy_for_instance.rb
35
+ - lib/stubborn/proxy_for_module.rb
36
+ - lib/stubborn/suggesters/rspec_suggester.rb
35
37
  - stubborn.gemspec
36
38
  - test/stubborn_method_filtering_test.rb
37
39
  - test/stubborn_test.rb
@@ -61,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
63
  requirements: []
62
64
 
63
65
  rubyforge_project: stubborn
64
- rubygems_version: 1.3.3
66
+ rubygems_version: 1.3.5
65
67
  signing_key:
66
68
  specification_version: 3
67
69
  summary: A gem to help you find your missing stubs
@@ -1,27 +0,0 @@
1
- module Stubborn
2
- class MissedStubException < RuntimeError
3
- def initialize(object_or_label, method_name, args, result, suggester)
4
- object_label = object_or_label.respond_to?(:to_str) ? object_or_label : friendly_name(object_or_label)
5
- args = args.map{|a| friendly_name(a)}.join(", ")
6
- result = friendly_name(result)
7
-
8
- @suggestions = suggester.suggestions(object_label, method_name, args, result)
9
- end
10
-
11
- def message
12
- "You've missed adding a stub. Consider this suggestion#{@suggestions.size > 1 ? "s" : ""}:\n#{@suggestions.join("\n")}"
13
- end
14
-
15
- private
16
- def friendly_name(object)
17
- return "\"#{object}\"" if object.respond_to?(:to_str)
18
- return object.inspect if object.respond_to?(:to_int) || object.is_a?(Hash) || object.nil? || object == true || object == false
19
-
20
- if object.is_a?(Class)
21
- object.name
22
- else
23
- "#{object.class.name.downcase.gsub(/\W+/, '_')}_instance"
24
- end
25
- end
26
- end
27
- end
@@ -1,14 +0,0 @@
1
- module Stubborn
2
- module Suggesters
3
- module RSpecSuggester
4
- def self.suggestions(object_label, method_name, args, result)
5
- with = args.strip.empty? ? nil : ".with(#{args})"
6
- and_return = result == "nil" ? nil : ".and_return(#{result})"
7
- suggestions = []
8
- suggestions << "#{object_label}.stub!(:#{method_name})#{with}#{and_return}"
9
- suggestions << "#{object_label}.stub!(:#{method_name})#{and_return}"
10
- suggestions.uniq
11
- end
12
- end
13
- end
14
- end