rspec-core 2.0.0.a1

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.
Files changed (143) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/.treasure_map.rb +23 -0
  4. data/License.txt +22 -0
  5. data/README.markdown +9 -0
  6. data/Rakefile +76 -0
  7. data/TODO.markdown +16 -0
  8. data/VERSION +1 -0
  9. data/VERSION.yml +5 -0
  10. data/bin/rspec +12 -0
  11. data/cucumber.yml +2 -0
  12. data/example_specs/failing/README.txt +7 -0
  13. data/example_specs/failing/diffing_spec.rb +36 -0
  14. data/example_specs/failing/failing_implicit_docstrings_example.rb +19 -0
  15. data/example_specs/failing/failure_in_after.rb +10 -0
  16. data/example_specs/failing/failure_in_before.rb +10 -0
  17. data/example_specs/failing/mocking_example.rb +40 -0
  18. data/example_specs/failing/mocking_with_flexmock.rb +26 -0
  19. data/example_specs/failing/mocking_with_mocha.rb +25 -0
  20. data/example_specs/failing/mocking_with_rr.rb +27 -0
  21. data/example_specs/failing/partial_mock_example.rb +20 -0
  22. data/example_specs/failing/pending_example.rb +9 -0
  23. data/example_specs/failing/predicate_example.rb +34 -0
  24. data/example_specs/failing/raising_example.rb +47 -0
  25. data/example_specs/failing/spec_helper.rb +3 -0
  26. data/example_specs/failing/syntax_error_example.rb +7 -0
  27. data/example_specs/failing/team_spec.rb +44 -0
  28. data/example_specs/failing/timeout_behaviour.rb +7 -0
  29. data/example_specs/passing/custom_formatter.rb +12 -0
  30. data/example_specs/passing/custom_matchers.rb +54 -0
  31. data/example_specs/passing/dynamic_spec.rb +9 -0
  32. data/example_specs/passing/file_accessor.rb +19 -0
  33. data/example_specs/passing/file_accessor_spec.rb +38 -0
  34. data/example_specs/passing/filtered_formatter.rb +18 -0
  35. data/example_specs/passing/filtered_formatter_example.rb +31 -0
  36. data/example_specs/passing/greeter_spec.rb +31 -0
  37. data/example_specs/passing/helper_method_example.rb +14 -0
  38. data/example_specs/passing/implicit_docstrings_example.rb +18 -0
  39. data/example_specs/passing/io_processor.rb +8 -0
  40. data/example_specs/passing/io_processor_spec.rb +21 -0
  41. data/example_specs/passing/mocking_example.rb +27 -0
  42. data/example_specs/passing/multi_threaded_example_group_runner.rb +26 -0
  43. data/example_specs/passing/nested_classes_example.rb +36 -0
  44. data/example_specs/passing/options_example.rb +31 -0
  45. data/example_specs/passing/options_formatter.rb +20 -0
  46. data/example_specs/passing/partial_mock_example.rb +29 -0
  47. data/example_specs/passing/pending_example.rb +20 -0
  48. data/example_specs/passing/predicate_example.rb +27 -0
  49. data/example_specs/passing/shared_example_group_example.rb +81 -0
  50. data/example_specs/passing/shared_stack_examples.rb +36 -0
  51. data/example_specs/passing/simple_matcher_example.rb +31 -0
  52. data/example_specs/passing/spec_helper.rb +14 -0
  53. data/example_specs/passing/stack.rb +36 -0
  54. data/example_specs/passing/stack_spec.rb +64 -0
  55. data/example_specs/passing/stack_spec_with_nested_example_groups.rb +67 -0
  56. data/example_specs/passing/stubbing_example.rb +69 -0
  57. data/example_specs/passing/yielding_example.rb +33 -0
  58. data/example_specs/ruby1.9.compatibility/access_to_constants_spec.rb +85 -0
  59. data/features-pending/command_line/line_number_option.feature +56 -0
  60. data/features-pending/command_line/line_number_option_with_example_with_no_name.feature +22 -0
  61. data/features-pending/example_groups/example_group_with_should_methods.feature +29 -0
  62. data/features-pending/example_groups/implicit_docstrings.feature +59 -0
  63. data/features-pending/example_groups/nested_groups.feature +32 -0
  64. data/features-pending/expectations/expect_change.feature +65 -0
  65. data/features-pending/expectations/expect_error.feature +44 -0
  66. data/features-pending/extensions/custom_example_group.feature +19 -0
  67. data/features-pending/formatters/custom_formatter.feature +30 -0
  68. data/features-pending/heckle/heckle.feature +56 -0
  69. data/features-pending/interop/examples_and_tests_together.feature +80 -0
  70. data/features-pending/interop/rspec_output.feature +25 -0
  71. data/features-pending/interop/test_but_not_test_unit.feature +26 -0
  72. data/features-pending/interop/test_case_with_should_methods.feature +46 -0
  73. data/features-pending/matchers/define_diffable_matcher.feature +26 -0
  74. data/features-pending/matchers/define_matcher.feature +179 -0
  75. data/features-pending/matchers/define_matcher_with_fluent_interface.feature +27 -0
  76. data/features-pending/mocks/mix_stubs_and_mocks.feature +22 -0
  77. data/features-pending/mocks/stub_implementation.feature +26 -0
  78. data/features-pending/pending/pending_examples.feature +81 -0
  79. data/features-pending/runner/specify_line_number.feature +32 -0
  80. data/features/before_and_after_blocks/before_and_after_blocks.feature +169 -0
  81. data/features/expectations/customized_message.feature +54 -0
  82. data/features/matchers/define_matcher_outside_rspec.feature +39 -0
  83. data/features/mock_framework_integration/use_flexmock.feature +23 -0
  84. data/features/mock_framework_integration/use_mocha.feature +23 -0
  85. data/features/mock_framework_integration/use_rr.feature +23 -0
  86. data/features/mock_framework_integration/use_rspec.feature +23 -0
  87. data/features/step_definitions/running_rspec_steps.rb +35 -0
  88. data/features/subject/explicit_subject.feature +31 -0
  89. data/features/subject/implicit_subject.feature +31 -0
  90. data/features/support/env.rb +82 -0
  91. data/features/support/matchers/smart_match.rb +14 -0
  92. data/lib/rspec/autorun.rb +2 -0
  93. data/lib/rspec/core.rb +38 -0
  94. data/lib/rspec/core/backward_compatibility.rb +9 -0
  95. data/lib/rspec/core/command_line_options.rb +60 -0
  96. data/lib/rspec/core/configuration.rb +222 -0
  97. data/lib/rspec/core/deprecation.rb +47 -0
  98. data/lib/rspec/core/example.rb +113 -0
  99. data/lib/rspec/core/example_group.rb +239 -0
  100. data/lib/rspec/core/example_group_subject.rb +77 -0
  101. data/lib/rspec/core/formatters.rb +16 -0
  102. data/lib/rspec/core/formatters/base_formatter.rb +123 -0
  103. data/lib/rspec/core/formatters/base_text_formatter.rb +139 -0
  104. data/lib/rspec/core/formatters/documentation_formatter.rb +84 -0
  105. data/lib/rspec/core/formatters/progress_formatter.rb +36 -0
  106. data/lib/rspec/core/kernel_extensions.rb +15 -0
  107. data/lib/rspec/core/mocking/with_absolutely_nothing.rb +13 -0
  108. data/lib/rspec/core/mocking/with_flexmock.rb +25 -0
  109. data/lib/rspec/core/mocking/with_mocha.rb +22 -0
  110. data/lib/rspec/core/mocking/with_rr.rb +26 -0
  111. data/lib/rspec/core/mocking/with_rspec.rb +21 -0
  112. data/lib/rspec/core/rake_task.rb +88 -0
  113. data/lib/rspec/core/runner.rb +66 -0
  114. data/lib/rspec/core/shared_behaviour.rb +41 -0
  115. data/lib/rspec/core/shared_behaviour_kernel_extensions.rb +31 -0
  116. data/lib/rspec/core/version.rb +16 -0
  117. data/lib/rspec/core/world.rb +105 -0
  118. data/rspec-core.gemspec +204 -0
  119. data/script/console +8 -0
  120. data/spec/resources/example_classes.rb +67 -0
  121. data/spec/rspec/core/command_line_options_spec.rb +63 -0
  122. data/spec/rspec/core/configuration_spec.rb +171 -0
  123. data/spec/rspec/core/example_group_spec.rb +351 -0
  124. data/spec/rspec/core/example_group_subject_spec.rb +67 -0
  125. data/spec/rspec/core/example_spec.rb +67 -0
  126. data/spec/rspec/core/formatters/base_formatter_spec.rb +105 -0
  127. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +5 -0
  128. data/spec/rspec/core/formatters/progress_formatter_spec.rb +29 -0
  129. data/spec/rspec/core/kernel_extensions_spec.rb +13 -0
  130. data/spec/rspec/core/mocha_spec.rb +29 -0
  131. data/spec/rspec/core/resources/a_bar.rb +0 -0
  132. data/spec/rspec/core/resources/a_foo.rb +0 -0
  133. data/spec/rspec/core/resources/a_spec.rb +1 -0
  134. data/spec/rspec/core/resources/custom_example_group_runner.rb +14 -0
  135. data/spec/rspec/core/resources/example_classes.rb +67 -0
  136. data/spec/rspec/core/resources/utf8_encoded.rb +8 -0
  137. data/spec/rspec/core/runner_spec.rb +34 -0
  138. data/spec/rspec/core/shared_behaviour_spec.rb +185 -0
  139. data/spec/rspec/core/world_spec.rb +167 -0
  140. data/spec/rspec/core_spec.rb +35 -0
  141. data/spec/ruby_forker.rb +13 -0
  142. data/spec/spec_helper.rb +72 -0
  143. metadata +219 -0
@@ -0,0 +1,47 @@
1
+ module Rspec
2
+ module Core
3
+
4
+ class << self
5
+ def deprecate(method, alternate_method=nil)
6
+ message = <<-NOTICE
7
+
8
+ *****************************************************************
9
+ DEPRECATION WARNING: you are using deprecated behaviour that will
10
+ be removed from a future version of RSpec.
11
+
12
+ #{caller(0)[2]}
13
+
14
+ * #{method} is deprecated.
15
+ NOTICE
16
+ if alternate_method
17
+ message << <<-ADDITIONAL
18
+ * please use #{alternate_method} instead.
19
+ ADDITIONAL
20
+ end
21
+
22
+ message << "*****************************************************************"
23
+ warn(message)
24
+ end
25
+
26
+ def warn(message)
27
+ Kernel.warn(message)
28
+ end
29
+
30
+ end
31
+
32
+ class HashWithDeprecationNotice < Hash
33
+
34
+ def initialize(method, alternate_method=nil, &block)
35
+ @method, @alternate_method = method, alternate_method
36
+ end
37
+
38
+ def []=(k,v)
39
+ Rspec.deprecate(@method, @alternate_method)
40
+ super
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,113 @@
1
+ module Rspec
2
+ module Core
3
+ class Example
4
+
5
+ attr_reader :behaviour, :description, :metadata, :example_block
6
+
7
+ def initialize(behaviour, desc, options, example_block=nil)
8
+ @behaviour, @description, @options, @example_block = behaviour, desc, options, example_block
9
+ @metadata = @behaviour.metadata.dup
10
+ @metadata[:description] = description
11
+ @metadata[:execution_result] = {}
12
+ @metadata[:caller] = options.delete(:caller)
13
+ if @metadata[:caller]
14
+ @metadata[:file_path] = @metadata[:caller].split(":")[0].strip
15
+ @metadata[:line_number] = @metadata[:caller].split(":")[1].to_i
16
+ end
17
+ @metadata.update(options)
18
+ end
19
+
20
+ def record_results(results={})
21
+ @metadata[:execution_result].update(results)
22
+ end
23
+
24
+ def execution_result
25
+ @metadata[:execution_result]
26
+ end
27
+
28
+ def file_path
29
+ @metadata[:file_path] || behaviour.file_path
30
+ end
31
+
32
+ def run_started
33
+ record_results :started_at => Time.now
34
+ end
35
+
36
+ def run_passed
37
+ run_finished 'passed'
38
+ end
39
+
40
+ def run_pending(message='Not yet implemented')
41
+ run_finished 'pending', :pending_message => message
42
+ end
43
+
44
+ def run_failed(exception)
45
+ run_finished 'failed', :exception_encountered => exception
46
+ end
47
+
48
+ def run_finished(status, results={})
49
+ record_results results.update(:status => status)
50
+ finish_time = Time.now
51
+ record_results :finished_at => finish_time, :run_time => (finish_time - execution_result[:started_at])
52
+ Rspec::Core.configuration.formatter.example_finished(self)
53
+ end
54
+
55
+ def run_before_each
56
+ @behaviour_instance._setup_mocks if @behaviour_instance.respond_to?(:_setup_mocks)
57
+ @behaviour.eval_before_eachs(@behaviour_instance)
58
+ end
59
+
60
+ def run_after_each
61
+ @behaviour.eval_after_eachs(@behaviour_instance)
62
+ @behaviour_instance._verify_mocks if @behaviour_instance.respond_to?(:_verify_mocks)
63
+ ensure
64
+ @behaviour_instance._teardown_mocks if @behaviour_instance.respond_to?(:_teardown_mocks)
65
+ end
66
+
67
+ def run(behaviour_instance)
68
+ @behaviour_instance = behaviour_instance
69
+ @behaviour_instance.running_example = self
70
+
71
+ run_started
72
+
73
+ all_systems_nominal = true
74
+ exception_encountered = nil
75
+
76
+ begin
77
+ run_before_each
78
+ @behaviour_instance.instance_eval(&example_block) if example_block
79
+ rescue Exception => e
80
+ exception_encountered = e
81
+ all_systems_nominal = false
82
+ end
83
+
84
+ begin
85
+ run_after_each
86
+ rescue Exception => e
87
+ exception_encountered ||= e
88
+ all_systems_nominal = false
89
+ ensure
90
+ @behaviour_instance.running_example = nil
91
+ end
92
+
93
+ if exception_encountered
94
+ run_failed(exception_encountered)
95
+ else
96
+ example_block ? run_passed : run_pending
97
+ end
98
+
99
+ all_systems_nominal
100
+ end
101
+
102
+ def inspect
103
+ "#{@metadata[:behaviour][:name]} - #{@metadata[:description]}"
104
+ end
105
+
106
+ def to_s
107
+ inspect
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,239 @@
1
+ module Rspec
2
+ module Core
3
+ class ExampleGroup
4
+ include ExampleGroupSubject
5
+
6
+ attr_accessor :running_example, :reporter
7
+
8
+ def self.inherited(klass)
9
+ super
10
+ Rspec::Core.configuration.autorun!
11
+ Rspec::Core.world.behaviours << klass
12
+ end
13
+
14
+ def self.extended_modules #:nodoc:
15
+ ancestors = class << self; ancestors end
16
+ ancestors.select { |mod| mod.class == Module } - [ Object, Kernel ]
17
+ end
18
+
19
+ def self.befores
20
+ @_befores ||= { :all => [], :each => [] }
21
+ end
22
+
23
+ def self.before_eachs
24
+ befores[:each]
25
+ end
26
+
27
+ def self.before_alls
28
+ befores[:all]
29
+ end
30
+
31
+ def self.before(type=:each, &block)
32
+ befores[type] << block
33
+ end
34
+
35
+ def self.afters
36
+ @_afters ||= { :all => [], :each => [] }
37
+ end
38
+
39
+ def self.after_eachs
40
+ afters[:each]
41
+ end
42
+
43
+ def self.after_alls
44
+ afters[:all]
45
+ end
46
+
47
+ def self.after(type=:each, &block)
48
+ afters[type] << block
49
+ end
50
+
51
+ def self.example(desc=nil, options={}, &block)
52
+ examples << Rspec::Core::Example.new(self, desc, options.update(:caller => caller[0]), block)
53
+ end
54
+
55
+ def self.alias_example_to(new_alias, extra_options={})
56
+ new_alias = <<-END_RUBY
57
+ def self.#{new_alias}(desc=nil, options={}, &block)
58
+ updated_options = options.update(:caller => caller[0])
59
+ updated_options.update(#{extra_options.inspect})
60
+ block = nil if updated_options[:pending] == true || updated_options[:disabled] == true
61
+ examples << Rspec::Core::Example.new(self, desc, updated_options, block)
62
+ end
63
+ END_RUBY
64
+ module_eval(new_alias, __FILE__, __LINE__)
65
+ end
66
+
67
+ alias_example_to :it
68
+ alias_example_to :specify
69
+ alias_example_to :focused, :focused => true
70
+ alias_example_to :disabled, :disabled => true
71
+ alias_example_to :pending, :pending => true
72
+
73
+ def self.it_should_behave_like(*names)
74
+ Rspec::Core.world.shared_behaviours.each do |name, block|
75
+ module_eval(&block) if names.include?(name)
76
+ end
77
+ end
78
+
79
+ def self.examples
80
+ @_examples ||= []
81
+ end
82
+
83
+ def self.examples_to_run
84
+ @_examples_to_run ||= []
85
+ end
86
+
87
+ def self.generate_name(options, metadata)
88
+ if superclass.metadata[:behaviour][:name]
89
+ metadata[:behaviour][:name] = "#{self.superclass.metadata[:behaviour][:name]} #{description} "
90
+ else
91
+ metadata[:behaviour][:name] = "#{describes} #{description} "
92
+ end
93
+ metadata[:behaviour][:name].strip!
94
+ end
95
+
96
+ def self.set_it_up(*args)
97
+ @metadata = { }
98
+ extra_metadata = args.last.is_a?(Hash) ? args.pop : {}
99
+ extra_metadata.delete(:behaviour) # Remove it when present to prevent it clobbering the one we setup
100
+ @metadata.update(self.superclass.metadata)
101
+ @metadata[:behaviour] = {}
102
+ @metadata[:behaviour][:describes] = args.shift unless args.first.is_a?(String)
103
+ @metadata[:behaviour][:describes] ||= self.superclass.metadata && self.superclass.metadata[:behaviour][:describes]
104
+ @metadata[:behaviour][:description] = args.shift || ''
105
+ @metadata[:behaviour][:name] = generate_name(args, metadata)
106
+ @metadata[:behaviour][:block] = extra_metadata.delete(:behaviour_block)
107
+ @metadata[:behaviour][:caller] = extra_metadata.delete(:caller) || caller(1)
108
+ @metadata[:behaviour][:file_path] = extra_metadata.delete(:file_path) || @metadata[:behaviour][:caller][4].split(":")[0].strip
109
+ @metadata[:behaviour][:line_number] = extra_metadata.delete(:line_number) || @metadata[:behaviour][:caller][4].split(":")[1].to_i
110
+
111
+ @metadata.update(extra_metadata)
112
+
113
+ Rspec::Core.configuration.find_modules(self).each do |include_or_extend, mod, opts|
114
+ if include_or_extend == :extend
115
+ send(:extend, mod) unless extended_modules.include?(mod)
116
+ else
117
+ send(:include, mod) unless included_modules.include?(mod)
118
+ end
119
+ end
120
+ end
121
+
122
+ def self.metadata
123
+ @metadata ||= { :behaviour => {} }
124
+ end
125
+
126
+ def self.name(friendly=true)
127
+ friendly ? metadata[:behaviour][:name] : super
128
+ end
129
+
130
+ def self.describes
131
+ metadata[:behaviour][:describes]
132
+ end
133
+
134
+ def self.described_class
135
+ describes || description
136
+ end
137
+
138
+ def self.description
139
+ metadata[:behaviour][:description]
140
+ end
141
+
142
+ def self.file_path
143
+ metadata[:behaviour][:file_path]
144
+ end
145
+
146
+ def self.describe(*args, &behaviour_block)
147
+ raise(ArgumentError, "No arguments given. You must a least supply a type or description") if args.empty?
148
+ raise(ArgumentError, "You must supply a block when calling describe") if behaviour_block.nil?
149
+
150
+ # TODO: Pull out the below into a metadata object, that we can defer the subclassing if necessary
151
+ # describe 'foo', :shared => true will need this to be completed first
152
+ subclass('NestedLevel') do
153
+ args << {} unless args.last.is_a?(Hash)
154
+ args.last.update(:behaviour_block => behaviour_block)
155
+ set_it_up(*args)
156
+ module_eval(&behaviour_block)
157
+ end
158
+ end
159
+
160
+ def self.ancestors(superclass_last=false)
161
+ classes = []
162
+ current_class = self
163
+
164
+ while current_class < Rspec::Core::ExampleGroup
165
+ superclass_last ? classes << current_class : classes.unshift(current_class)
166
+ current_class = current_class.superclass
167
+ end
168
+
169
+ classes
170
+ end
171
+
172
+ def self.before_ancestors
173
+ @_before_ancestors ||= ancestors
174
+ end
175
+
176
+ def self.after_ancestors
177
+ @_after_ancestors ||= ancestors(true)
178
+ end
179
+
180
+ def self.before_all_ivars
181
+ @before_all_ivars ||= {}
182
+ end
183
+
184
+ def self.eval_before_alls(running_behaviour)
185
+ superclass.before_all_ivars.each { |ivar, val| running_behaviour.instance_variable_set(ivar, val) }
186
+ Rspec::Core.configuration.find_before_or_after(:before, :all, self).each { |blk| running_behaviour.instance_eval(&blk) }
187
+
188
+ before_alls.each { |blk| running_behaviour.instance_eval(&blk) }
189
+ running_behaviour.instance_variables.each { |ivar| before_all_ivars[ivar] = running_behaviour.instance_variable_get(ivar) }
190
+ end
191
+
192
+ def self.eval_before_eachs(running_behaviour)
193
+ Rspec::Core.configuration.find_before_or_after(:before, :each, self).each { |blk| running_behaviour.instance_eval(&blk) }
194
+ before_ancestors.each { |ancestor| ancestor.before_eachs.each { |blk| running_behaviour.instance_eval(&blk) } }
195
+ end
196
+
197
+ def self.eval_after_alls(running_behaviour)
198
+ after_alls.each { |blk| running_behaviour.instance_eval(&blk) }
199
+ Rspec::Core.configuration.find_before_or_after(:after, :all, self).each { |blk| running_behaviour.instance_eval(&blk) }
200
+ before_all_ivars.keys.each { |ivar| before_all_ivars[ivar] = running_behaviour.instance_variable_get(ivar) }
201
+ end
202
+
203
+ def self.eval_after_eachs(running_behaviour)
204
+ after_ancestors.each { |ancestor| ancestor.after_eachs.each { |blk| running_behaviour.instance_eval(&blk) } }
205
+ Rspec::Core.configuration.find_before_or_after(:after, :each, self).each { |blk| running_behaviour.instance_eval(&blk) }
206
+ end
207
+
208
+ def self.run(reporter)
209
+ behaviour_instance = new
210
+ reporter.add_behaviour(self)
211
+ eval_before_alls(behaviour_instance)
212
+ success = run_examples(behaviour_instance, reporter)
213
+ eval_after_alls(behaviour_instance)
214
+
215
+ success
216
+ end
217
+
218
+ # Runs all examples, returning true only if all of them pass
219
+ def self.run_examples(behaviour_instance, reporter)
220
+ examples_to_run.map { |ex| ex.run(behaviour_instance) }.all?
221
+ end
222
+
223
+ def self.subclass(base_name, &body) # :nodoc:
224
+ @_sub_class_count ||= 0
225
+ @_sub_class_count += 1
226
+ klass = Class.new(self)
227
+ class_name = "#{base_name}_#{@_sub_class_count}"
228
+ const_set(class_name, klass)
229
+ klass.instance_eval(&body)
230
+ klass
231
+ end
232
+
233
+ def self.to_s
234
+ self == Rspec::Core::ExampleGroup ? 'Rspec::Core::ExampleGroup' : name
235
+ end
236
+
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,77 @@
1
+ module Rspec
2
+ module Core
3
+ module ExampleGroupSubject
4
+
5
+ def self.included(kls)
6
+ kls.extend ClassMethods
7
+ kls.send :alias_method, :__should_for_example_group__, :should
8
+ kls.send :alias_method, :__should_not_for_example_group__, :should_not
9
+ end
10
+
11
+ def subject
12
+ @subject ||= self.class.subject.call
13
+ end
14
+
15
+ # When +should+ is called with no explicit receiver, the call is
16
+ # delegated to the object returned by +subject+. Combined with
17
+ # an implicit subject (see +subject+), this supports very concise
18
+ # expressions.
19
+ #
20
+ # == Examples
21
+ #
22
+ # describe Person do
23
+ # it { should be_eligible_to_vote }
24
+ # end
25
+ def should(matcher=nil, message=nil)
26
+ self == subject ? self.__should_for_example_group__(matcher) : subject.should(matcher,message)
27
+ end
28
+
29
+ # Just like +should+, +should_not+ delegates to the subject (implicit or
30
+ # explicit) of the example group.
31
+ #
32
+ # == Examples
33
+ #
34
+ # describe Person do
35
+ # it { should_not be_eligible_to_vote }
36
+ # end
37
+ def should_not(matcher=nil, message=nil)
38
+ self == subject ? self.__should_not_for_example_group__(matcher) : subject.should_not(matcher,message)
39
+ end
40
+
41
+ module ClassMethods
42
+ # Defines an explicit subject for an example group which can then be the
43
+ # implicit receiver (through delegation) of calls to +should+.
44
+ #
45
+ # == Examples
46
+ #
47
+ # describe CheckingAccount, "with $50" do
48
+ # subject { CheckingAccount.new(:amount => 50, :currency => :USD) }
49
+ # it { should have_a_balance_of(50, :USD) }
50
+ # it { should_not be_overdrawn }
51
+ # end
52
+ #
53
+ # See +ExampleMethods#should+ for more information about this approach.
54
+ def subject(&block)
55
+ block.nil? ?
56
+ explicit_subject || implicit_subject : @explicit_subject_block = block
57
+ end
58
+
59
+ attr_reader :explicit_subject_block # :nodoc:
60
+
61
+ private
62
+
63
+ def explicit_subject
64
+ group = self
65
+ while group.respond_to?(:explicit_subject_block)
66
+ return group.explicit_subject_block if group.explicit_subject_block
67
+ group = group.superclass
68
+ end
69
+ end
70
+
71
+ def implicit_subject
72
+ described_class.is_a?(Class) ? lambda { described_class.new } : lambda { described_class }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end