rspec_candy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/.gitignore +8 -0
  2. data/README.md +7 -0
  3. data/Rakefile +18 -0
  4. data/lib/rspec_candy/helpers/disposable_copy.rb +16 -0
  5. data/lib/rspec_candy/helpers/it_should_act_like.rb +39 -0
  6. data/lib/rspec_candy/helpers/new_with_stubs.rb +16 -0
  7. data/lib/rspec_candy/helpers/rails/create_without_callbacks.rb +25 -0
  8. data/lib/rspec_candy/helpers/rails/it_should_run_callbacks.rb +111 -0
  9. data/lib/rspec_candy/helpers/rails/prevent_storage.rb +20 -0
  10. data/lib/rspec_candy/helpers/should_receive_and_execute.rb +38 -0
  11. data/lib/rspec_candy/helpers/should_receive_and_return.rb +17 -0
  12. data/lib/rspec_candy/helpers/should_receive_chain.rb +43 -0
  13. data/lib/rspec_candy/helpers/stub_any_instance.rb +25 -0
  14. data/lib/rspec_candy/helpers/stub_existing.rb +20 -0
  15. data/lib/rspec_candy/switcher.rb +44 -0
  16. data/lib/rspec_candy/version.rb +3 -0
  17. data/lib/rspec_candy.rb +16 -0
  18. data/rspec_candy.gemspec +19 -0
  19. data/spec/rspec1/Gemfile +13 -0
  20. data/spec/rspec1/Rakefile +11 -0
  21. data/spec/rspec1/app_root/config/boot.rb +114 -0
  22. data/spec/rspec1/app_root/config/database.yml +21 -0
  23. data/spec/rspec1/app_root/config/environment.rb +14 -0
  24. data/spec/rspec1/app_root/config/environments/in_memory.rb +0 -0
  25. data/spec/rspec1/app_root/config/environments/mysql.rb +0 -0
  26. data/spec/rspec1/app_root/config/environments/postgresql.rb +0 -0
  27. data/spec/rspec1/app_root/config/environments/sqlite.rb +0 -0
  28. data/spec/rspec1/app_root/config/environments/sqlite3.rb +0 -0
  29. data/spec/rspec1/app_root/config/initializers/state_machine.rb +1 -0
  30. data/spec/rspec1/app_root/config/routes.rb +4 -0
  31. data/spec/rspec1/app_root/log/.gitignore +1 -0
  32. data/spec/rspec1/rcov.opts +2 -0
  33. data/spec/rspec1/spec.opts +4 -0
  34. data/spec/rspec1/spec_helper.rb +24 -0
  35. data/spec/rspec2/.rspec +2 -0
  36. data/spec/rspec2/Gemfile +13 -0
  37. data/spec/rspec2/Rakefile +11 -0
  38. data/spec/rspec2/app_root/.gitignore +4 -0
  39. data/spec/rspec2/app_root/config/application.rb +32 -0
  40. data/spec/rspec2/app_root/config/boot.rb +13 -0
  41. data/spec/rspec2/app_root/config/database.yml +21 -0
  42. data/spec/rspec2/app_root/config/environment.rb +5 -0
  43. data/spec/rspec2/app_root/config/environments/in_memory.rb +0 -0
  44. data/spec/rspec2/app_root/config/environments/mysql.rb +0 -0
  45. data/spec/rspec2/app_root/config/environments/postgresql.rb +0 -0
  46. data/spec/rspec2/app_root/config/environments/sqlite.rb +0 -0
  47. data/spec/rspec2/app_root/config/environments/sqlite3.rb +0 -0
  48. data/spec/rspec2/app_root/config/environments/test.rb +35 -0
  49. data/spec/rspec2/app_root/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/rspec2/app_root/config/initializers/inflections.rb +10 -0
  51. data/spec/rspec2/app_root/config/initializers/mime_types.rb +5 -0
  52. data/spec/rspec2/app_root/config/initializers/secret_token.rb +7 -0
  53. data/spec/rspec2/app_root/config/initializers/session_store.rb +8 -0
  54. data/spec/rspec2/app_root/config/initializers/state_machine.rb +1 -0
  55. data/spec/rspec2/app_root/config/locales/en.yml +5 -0
  56. data/spec/rspec2/app_root/config/routes.rb +58 -0
  57. data/spec/rspec2/app_root/log/.gitkeep +0 -0
  58. data/spec/rspec2/rcov.opts +2 -0
  59. data/spec/rspec2/spec_helper.rb +25 -0
  60. data/spec/shared/app_root/app/controllers/application_controller.rb +2 -0
  61. data/spec/shared/app_root/app/models/model.rb +19 -0
  62. data/spec/shared/app_root/app/models/state_machine_model.rb +30 -0
  63. data/spec/shared/app_root/config/initializers/state_machine.rb +1 -0
  64. data/spec/shared/app_root/db/migrate/001_create_model.rb +13 -0
  65. data/spec/shared/app_root/db/migrate/002_create_state_machine_model.rb +13 -0
  66. data/spec/shared/rspec_candy/helpers/disposable_copy_spec.rb +45 -0
  67. data/spec/shared/rspec_candy/helpers/it_should_act_like_spec.rb +139 -0
  68. data/spec/shared/rspec_candy/helpers/new_with_stubs_spec.rb +41 -0
  69. data/spec/shared/rspec_candy/helpers/rails/create_without_callbacks_spec.rb +41 -0
  70. data/spec/shared/rspec_candy/helpers/rails/it_should_run_callbacks_spec.rb +142 -0
  71. data/spec/shared/rspec_candy/helpers/rails/prevent_storage_spec.rb +85 -0
  72. data/spec/shared/rspec_candy/helpers/should_receive_and_execute_spec.rb +32 -0
  73. data/spec/shared/rspec_candy/helpers/should_receive_and_return_spec.rb +30 -0
  74. data/spec/shared/rspec_candy/helpers/should_receive_chain_spec.rb +99 -0
  75. data/spec/shared/rspec_candy/helpers/stub_any_instance_spec.rb +32 -0
  76. data/spec/shared/rspec_candy/helpers/stub_existing_spec.rb +27 -0
  77. data/spec/shared/support/matchers/pass_as_describe_block.rb +32 -0
  78. data/spec/shared/support/matchers/pass_as_example.rb +30 -0
  79. data/template/spec_candy.rails2.rb +171 -0
  80. data/template/spec_candy.rails3.rb +175 -0
  81. metadata +159 -0
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ doc
2
+ pkg
3
+ *.gem
4
+ .idea
5
+ spec/**/app_root/log/*
6
+ Gemfile.lock
7
+
8
+
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ Changes from previous versions:
2
+
3
+ - `new_and_store` has been renamed `create_without_callbacks`
4
+ - `keep_invalid!` has been renamed to `prevent_storage`
5
+ - `Object#should_not_receive_and_execute` has been removed (same as `Object#should_not_receive`)
6
+ - `should_receive_all_with` (over-generic method name for a helper that is rarely useful)
7
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ require "bundler/gem_tasks"
5
+
6
+
7
+ desc 'Default: Run all specs.'
8
+ task :default => :all_specs
9
+
10
+ desc "Run all specs"
11
+ task :all_specs do
12
+ Dir['spec/**/Rakefile'].sort.each do |rakefile|
13
+ directory = File.dirname(rakefile)
14
+ puts '', "\033[44m#{directory}\033[0m", ''
15
+ env = "SPEC=../../#{ENV['SPEC']} " if ENV['SPEC']
16
+ system("cd #{directory} && #{env} bundle exec rake")
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module DisposableCopy
4
+
5
+ def disposable_copy(&body)
6
+ this = self
7
+ copy = Class.new(self, &body)
8
+ copy.singleton_class.send(:define_method, :name) { this.name }
9
+ copy
10
+ end
11
+
12
+ Class.send(:include, self)
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module ItShouldActLike
4
+
5
+ def self.included(by)
6
+ by.class_eval do
7
+
8
+ # Improves it_should_behave_like in some ways:
9
+ # - It scopes the reused examples so #let und #subject does not bleed into the reusing example groups
10
+ # - It allows to parametrize the reused example group by appending a hash argument.
11
+ # Every key/value pair in the hash will become a #let variable for the reused example group
12
+ # - You can call it with a block. It will be available to the reused example group as let(:block)
13
+ def it_should_act_like(shared_example_group, environment = {}, &block)
14
+ if Switcher.rspec_version == :rspec2
15
+ warn('"it_should_act_like" is deprecated. Consider using "it_should_behave_like".')
16
+ end
17
+
18
+ description = "as #{shared_example_group}"
19
+ description << " (#{environment.inspect})" if environment.present?
20
+ describe description do
21
+ environment.each do |name, value|
22
+ let(name) { value }
23
+ end
24
+ let(:block) { block } if block
25
+ it_should_behave_like(shared_example_group)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ case Switcher.rspec_version
32
+ when :rspec1
33
+ Spec::Example::ExampleGroupMethods.send(:include, self)
34
+ when :rspec2
35
+ RSpec::Core::ExampleGroup.singleton_class.send(:include, self)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module NewWithStubs
4
+
5
+ def new_with_stubs(stubs)
6
+ obj = new
7
+ obj.stub_existing stubs
8
+ obj
9
+ end
10
+
11
+ Class.send(:include, self)
12
+
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,25 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module Rails
4
+ module CreateWithoutCallbacks
5
+
6
+ def create_without_callbacks(*args)
7
+ table_name = self.table_name
8
+ plain_model = Class.new(ActiveRecord::Base) do
9
+ self.table_name = table_name
10
+ end
11
+ plain_record = plain_model.create!(*args)
12
+ find plain_record.id
13
+ end
14
+
15
+ def new_and_store(*args)
16
+ warn 'new_and_store is deprecated. Use create_without_callbacks instead.'
17
+ create_without_callbacks(*args)
18
+ end
19
+
20
+ ActiveRecord::Base.send(:extend, self)
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,111 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module Rails
4
+ module ItShouldRunCallbacks
5
+
6
+ module ExampleGroupMethods
7
+ def self.included(by)
8
+ by.class_eval do
9
+
10
+ def it_should_run_callbacks_in_order(*callbacks)
11
+ callbacks.push(:ordered => true)
12
+ it_should_run_callbacks(*callbacks)
13
+ end
14
+
15
+ def it_should_run_callbacks(*callbacks)
16
+ options = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
17
+ reason = callbacks.pop if callbacks.last.is_a?(String)
18
+ should = ['should run callbacks', callbacks.inspect, ('in order' if options[:ordered]), reason].compact.join ' '
19
+
20
+ prose = case Switcher.rspec_version
21
+ when :rspec1
22
+ description_parts.last
23
+ when :rspec2
24
+ description.split(/(?=#)/).last
25
+ end
26
+
27
+ send(:it, should) do
28
+ extend ExampleMethods
29
+ if subject.class.respond_to?(:state_machine) and defined?(StateMachine)
30
+ extend StateMachineExampleMethods
31
+ end
32
+ callbacks.each do |callback|
33
+ expectation = subject.should_receive(callback).once
34
+ expectation.ordered if options[:ordered]
35
+ end
36
+ run_all_callbacks(prose)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ module ExampleMethods
44
+ private
45
+
46
+ def run_all_callbacks(prose)
47
+ run_active_record_callbacks_from_prose(prose)
48
+ end
49
+
50
+ case Switcher.rspec_version
51
+ when :rspec1
52
+
53
+ def run_active_record_callbacks_from_prose(prose)
54
+ subject.run_callbacks(prose.sub(/^#/, ''))
55
+ end
56
+
57
+ when :rspec2
58
+
59
+ def run_active_record_callbacks_from_prose(prose)
60
+ hook = prose.split.last.sub(/^#/, '')
61
+ if hook.sub!(/_on_(create|update)$/, '')
62
+ condition = "validation_context == :#{$1}"
63
+ else
64
+ condition = nil
65
+ end
66
+ if hook == 'validate'
67
+ kind = 'before'
68
+ action = 'validate'
69
+ else
70
+ hook =~ /^(before|after|around)_(.*)$/
71
+ kind = $1
72
+ action = $2
73
+ end
74
+ # Run all matching callbacks
75
+ subject.send("_#{action}_callbacks").send(kind == 'after' ? :reverse_each : :each) do |callback|
76
+ if callback.kind.to_s == kind && (condition.nil? || callback.options[:if].include?(condition))
77
+ subject.send(callback.filter.to_s.gsub(/[\(,\)]/, '').to_sym) {}
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+
85
+ module StateMachineExampleMethods
86
+ def run_all_callbacks(prose)
87
+ run_state_machine_callbacks_from_prose(prose) or super
88
+ end
89
+
90
+ def run_state_machine_callbacks_from_prose(prose)
91
+ if parts = prose.match(/^(#\w+) from ([\:\w]+) to ([\:\w]+)$/)
92
+ name = parts[1].sub(/^#/, '').to_sym
93
+ from = parts[2].sub(/^:/, '').to_sym
94
+ to = parts[3].sub(/^:/, '').to_sym
95
+ transition = StateMachine::Transition.new(subject, subject.class.state_machine, name, from, to)
96
+ transition.run_callbacks
97
+ end
98
+ end
99
+ end
100
+
101
+ case Switcher.rspec_version
102
+ when :rspec1
103
+ Spec::Example::ExampleGroupMethods.send(:include, self::ExampleGroupMethods)
104
+ when :rspec2
105
+ RSpec::Core::ExampleGroup.singleton_class.send(:include, self::ExampleGroupMethods)
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,20 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module Rails
4
+ module PreventStorage
5
+
6
+ def prevent_storage
7
+ errors.stub :empty? => false
8
+ end
9
+
10
+ def keep_invalid!
11
+ warn 'keep_invalid! is deprecated. Use prevent_storage instead.'
12
+ prevent_storage
13
+ end
14
+
15
+ ActiveRecord::Base.send(:include, self)
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module ShouldReceiveAndExecute
4
+
5
+ def should_receive_and_execute(method)
6
+ method_base = method.to_s.gsub(/([\?\!\=\[\]]+)$/, '')
7
+ method_suffix = $1
8
+
9
+ method_called = "_#{method_base}_called#{method_suffix}"
10
+ method_with_spy = "#{method_base}_with_spy#{method_suffix}"
11
+ method_without_spy = "#{method_base}_without_spy#{method_suffix}"
12
+
13
+ prototype = respond_to?(:singleton_class) ? singleton_class : metaclass
14
+ prototype.class_eval do
15
+
16
+ unless method_defined?(method_with_spy)
17
+
18
+ define_method method_called do
19
+ end
20
+
21
+ define_method method_with_spy do |*args, &block|
22
+ send(method_called, *args)
23
+ send(method_without_spy, *args, &block)
24
+ end
25
+ alias_method_chain method, :spy
26
+ end
27
+
28
+ end
29
+
30
+ should_receive(method_called)
31
+ end
32
+
33
+ Object.send(:include, self)
34
+
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,17 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module ShouldReceiveAndReturn
4
+
5
+ def should_receive_and_return(methods_and_values)
6
+ methods_and_values.each do |method, value|
7
+ should_receive(method).and_return(value)
8
+ end
9
+ self
10
+ end
11
+
12
+ Object.send(:include, self)
13
+
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,43 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module ShouldReceiveChain
4
+
5
+ def should_receive_chain(*parts)
6
+ setup_expectation_chain(parts)
7
+ end
8
+
9
+ def should_not_receive_chain(*parts)
10
+ setup_expectation_chain(parts, :negate => true)
11
+ end
12
+
13
+ private
14
+
15
+ def setup_expectation_chain(parts, options = {})
16
+ obj = self
17
+ for part in parts
18
+ if part == parts.last
19
+ expectation = options[:negate] ? :should_not_receive : :should_receive
20
+ obj = add_expectation_chain_link(obj, expectation, part)
21
+ else
22
+ next_obj = Switcher.new_mock('chain link')
23
+ add_expectation_chain_link(obj, :stub, part).and_return(next_obj)
24
+ obj = next_obj
25
+ end
26
+ end
27
+ obj
28
+ end
29
+
30
+ def add_expectation_chain_link(obj, expectation, part)
31
+ if part.is_a?(Array)
32
+ obj.send(expectation, part.first).with(*part[1..-1])
33
+ else
34
+ obj.send(expectation, part)
35
+ end
36
+ end
37
+
38
+ Object.send(:include, self)
39
+
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,25 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module StubAnyInstance
4
+
5
+ def stub_any_instance(stubs)
6
+ case Switcher.rspec_version
7
+ when :rspec1
8
+ unstubbed_new = method(:new)
9
+ stub(:new).and_return do |*args|
10
+ unstubbed_new.call(*args).tap do |obj|
11
+ obj.stub stubs
12
+ end
13
+ end
14
+ stubs
15
+ when :rspec2
16
+ any_instance.stub(stubs)
17
+ end
18
+ end
19
+
20
+ Class.send(:include, self)
21
+
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,20 @@
1
+ module RSpecCandy
2
+ module Helpers
3
+ module StubExisting
4
+
5
+ def stub_existing(attrs)
6
+ attrs.each do |method, value|
7
+ if respond_to?(method, true)
8
+ stub(method => value)
9
+ else
10
+ raise "Attempted to stub non-existing method ##{method} on #{inspect}"
11
+ end
12
+ end
13
+ end
14
+
15
+ Object.send(:include, self)
16
+
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,44 @@
1
+ module RSpecCandy
2
+ module Switcher
3
+ extend self
4
+
5
+ def rspec_version
6
+ if defined?(RSpec)
7
+ :rspec2
8
+ elsif defined?(Spec)
9
+ :rspec1
10
+ else
11
+ raise 'Cannot determine RSpec version'
12
+ end
13
+ end
14
+
15
+ def rails_version
16
+ if Rails.version.to_i < 3
17
+ :rails2
18
+ else
19
+ :rails3
20
+ end
21
+ end
22
+
23
+ def rails_loaded?
24
+ defined?(Rails)
25
+ end
26
+
27
+ def new_mock(*args)
28
+ rspec_root.const_get(:Mocks).const_get(:Mock).new(*args)
29
+ end
30
+
31
+ def rspec_root
32
+ (defined?(RSpec) ? RSpec : Spec)
33
+ end
34
+
35
+ def rspec_matcher_registry
36
+ rspec_root.const_get(:Matchers)
37
+ end
38
+
39
+ def define_matcher(*args, &block)
40
+ rspec_matcher_registry.define(*args, &block)
41
+ end
42
+
43
+ end
44
+ end