From d941ba79cc16db2c94ec198140677ed26e32bc01 Mon Sep 17 00:00:00 2001 From: David Chelimsky Date: Sun, 26 Aug 2012 21:19:33 -0400 Subject: [PATCH 1/2] yield current running example to it/example and before/after hooks --- lib/rspec/core/example.rb | 4 +- lib/rspec/core/example_group.rb | 32 +++++++++------ lib/rspec/core/hooks.rb | 2 +- lib/rspec/core/pending.rb | 13 +++--- spec/rspec/core/example_group_spec.rb | 58 +++++++++------------------ spec/rspec/core/example_spec.rb | 21 ++++++---- 6 files changed, 63 insertions(+), 67 deletions(-) diff --git a/lib/rspec/core/example.rb b/lib/rspec/core/example.rb index 415dfe54fe..e444d40114 100644 --- a/lib/rspec/core/example.rb +++ b/lib/rspec/core/example.rb @@ -111,7 +111,7 @@ def run(example_group_instance, reporter) with_around_each_hooks do begin run_before_each - @example_group_instance.instance_eval(&@example_block) + @example_group_instance.instance_exec(self, &@example_block) rescue Pending::PendingDeclaredInExample => e @pending_declared_in_example = e.message rescue Exception => e @@ -239,7 +239,7 @@ def instance_eval(*args, &block) # @private def instance_eval_with_rescue(context = nil, &block) - @example_group_instance.instance_eval_with_rescue(context, &block) + @example_group_instance.instance_eval_with_rescue(self, context, &block) end # @private diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index 163680a049..367ded1917 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -439,16 +439,24 @@ def self.set_ivars(instance, ivars) ivars.each {|name, value| instance.instance_variable_set(name, value)} end - # @attr_reader - # Returns the {Example} object that wraps this instance of - # `ExampleGroup` - attr_accessor :example + def initialize + @_current_rspec_example = nil + end + + def example=(current_example) + @_current_rspec_example = current_example + end + + # @deprecated use a block argument + def example + RSpec.deprecate("example", :replacement => "a block argument") + @_current_rspec_example + end - # @deprecated use {ExampleGroup#example} + # @deprecated use a block argument def running_example - RSpec.deprecate("running_example", - :replacement => "example") - example + RSpec.deprecate("running_example", :replacement => "a block argument") + @_current_rspec_example end # Returns the class or module passed to the `describe` method (or alias). @@ -468,12 +476,12 @@ def described_class # @private # instance_evals the block, capturing and reporting an exception if # raised - def instance_eval_with_rescue(context = nil, &hook) + def instance_eval_with_rescue(example, context = nil, &hook) begin - instance_eval(&hook) + instance_exec(example, &hook) rescue Exception => e - raise unless example - example.set_exception(e, context) + raise unless @_current_rspec_example + @_current_rspec_example.set_exception(e, context) end end end diff --git a/lib/rspec/core/hooks.rb b/lib/rspec/core/hooks.rb index f6b2fe5b87..f3338c0468 100644 --- a/lib/rspec/core/hooks.rb +++ b/lib/rspec/core/hooks.rb @@ -18,7 +18,7 @@ def options_apply?(example_or_group) class BeforeHook < Hook def run(example) - example.instance_eval(&block) + example.instance_exec(example, &block) end def display_name diff --git a/lib/rspec/core/pending.rb b/lib/rspec/core/pending.rb index 301379c110..c0d624d3e9 100644 --- a/lib/rspec/core/pending.rb +++ b/lib/rspec/core/pending.rb @@ -76,7 +76,7 @@ def pending_fixed?; true; end # # ... # end def pending(*args) - return self.class.before(:each) { pending(*args) } unless example + return self.class.before(:each) { pending(*args) } unless @_current_rspec_example options = args.last.is_a?(Hash) ? args.pop : {} message = args.first || NO_REASON_GIVEN @@ -85,18 +85,17 @@ def pending(*args) return block_given? ? yield : nil end - example.metadata[:pending] = true - example.metadata[:execution_result][:pending_message] = message + @_current_rspec_example.metadata[:pending] = true + @_current_rspec_example.metadata[:execution_result][:pending_message] = message if block_given? begin result = begin yield - example.example_group_instance.instance_eval { verify_mocks_for_rspec } - true + @_current_rspec_example.example_group_instance.instance_eval { verify_mocks_for_rspec } end - example.metadata[:pending] = false + @_current_rspec_example.metadata[:pending] = false rescue Exception => e - example.execution_result[:exception] = e + @_current_rspec_example.execution_result[:exception] = e ensure teardown_mocks_for_rspec end diff --git a/spec/rspec/core/example_group_spec.rb b/spec/rspec/core/example_group_spec.rb index 0a6ea7d58d..538f1dfdd5 100644 --- a/spec/rspec/core/example_group_spec.rb +++ b/spec/rspec/core/example_group_spec.rb @@ -65,8 +65,8 @@ def metadata_hash(*args) examples_run = [] group = ExampleGroup.describe("parent") do describe("child") do - it "does something" do - examples_run << example + it "does something" do |ex| + examples_run << ex end end end @@ -79,13 +79,13 @@ def metadata_hash(*args) it "runs its children " do examples_run = [] group = ExampleGroup.describe("parent") do - it "fails" do - examples_run << example + it "fails" do |ex| + examples_run << ex raise "fail" end describe("child") do - it "does something" do - examples_run << example + it "does something" do |ex| + examples_run << ex end end end @@ -663,19 +663,10 @@ def define_and_run_group(define_outer_example = false) end end - it "has no 'running example' within before(:all)" do - group = ExampleGroup.describe - running_example = :none - group.before(:all) { running_example = example } - group.example("no-op") { } - group.run - expect(running_example).to be(nil) - end - it "has access to example options within before(:each)" do group = ExampleGroup.describe option = nil - group.before(:each) { option = example.options[:data] } + group.before(:each) {|ex| option = ex.options[:data] } group.example("no-op", :data => :sample) { } group.run expect(option).to eq(:sample) @@ -684,20 +675,11 @@ def define_and_run_group(define_outer_example = false) it "has access to example options within after(:each)" do group = ExampleGroup.describe option = nil - group.after(:each) { option = example.options[:data] } + group.after(:each) {|ex| option = ex.options[:data] } group.example("no-op", :data => :sample) { } group.run expect(option).to eq(:sample) end - - it "has no 'running example' within after(:all)" do - group = ExampleGroup.describe - running_example = :none - group.after(:all) { running_example = example } - group.example("no-op") { } - group.run - expect(running_example).to be(nil) - end end %w[pending xit xspecify xexample].each do |method_name| @@ -755,20 +737,20 @@ def define_and_run_group(define_outer_example = false) describe Object, "describing nested example_groups", :little_less_nested => 'yep' do describe "A sample nested group", :nested_describe => "yep" do - it "sets the described class to the described class of the outer most group" do - expect(example.example_group.described_class).to eq(ExampleGroup) + it "sets the described class to the described class of the outer most group" do |ex| + expect(ex.example_group.described_class).to eq(ExampleGroup) end - it "sets the description to 'A sample nested describe'" do - expect(example.example_group.description).to eq('A sample nested group') + it "sets the description to 'A sample nested describe'" do |ex| + expect(ex.example_group.description).to eq('A sample nested group') end - it "has top level metadata from the example_group and its parent groups" do - expect(example.example_group.metadata).to include(:little_less_nested => 'yep', :nested_describe => 'yep') + it "has top level metadata from the example_group and its parent groups" do |ex| + expect(ex.example_group.metadata).to include(:little_less_nested => 'yep', :nested_describe => 'yep') end - it "exposes the parent metadata to the contained examples" do - expect(example.metadata).to include(:little_less_nested => 'yep', :nested_describe => 'yep') + it "exposes the parent metadata to the contained examples" do |ex| + expect(ex.metadata).to include(:little_less_nested => 'yep', :nested_describe => 'yep') end end @@ -826,12 +808,12 @@ def define_and_run_group(define_outer_example = false) expect(@before_all_top_level).to eq('before_all_top_level') end - it "can access the before all ivars in the before_all_ivars hash", :ruby => 1.8 do - expect(example.example_group.before_all_ivars).to include('@before_all_top_level' => 'before_all_top_level') + it "can access the before all ivars in the before_all_ivars hash", :ruby => 1.8 do |ex| + expect(ex.example_group.before_all_ivars).to include('@before_all_top_level' => 'before_all_top_level') end - it "can access the before all ivars in the before_all_ivars hash", :ruby => 1.9 do - expect(example.example_group.before_all_ivars).to include(:@before_all_top_level => 'before_all_top_level') + it "can access the before all ivars in the before_all_ivars hash", :ruby => 1.9 do |ex| + expect(ex.example_group.before_all_ivars).to include(:@before_all_top_level => 'before_all_top_level') end describe "but now I am nested" do diff --git a/spec/rspec/core/example_spec.rb b/spec/rspec/core/example_spec.rb index abce779c43..d138e0c7ea 100644 --- a/spec/rspec/core/example_spec.rb +++ b/spec/rspec/core/example_spec.rb @@ -171,19 +171,19 @@ def assert(val) end describe "accessing metadata within a running example" do - it "has a reference to itself when running" do - expect(example.description).to eq("has a reference to itself when running") + it "has a reference to itself when running" do |ex| + expect(ex.description).to eq("has a reference to itself when running") end - it "can access the example group's top level metadata as if it were its own" do - expect(example.example_group.metadata).to include(:parent_metadata => 'sample') - expect(example.metadata).to include(:parent_metadata => 'sample') + it "can access the example group's top level metadata as if it were its own" do |ex| + expect(ex.example_group.metadata).to include(:parent_metadata => 'sample') + expect(ex.metadata).to include(:parent_metadata => 'sample') end end describe "accessing options within a running example" do - it "can look up option values by key", :demo => :data do - expect(example.metadata[:demo]).to eq(:data) + it "can look up option values by key", :demo => :data do |ex| + expect(ex.metadata[:demo]).to eq(:data) end end @@ -436,4 +436,11 @@ def run_and_capture_reported_message(group) expect(values.uniq).to have(2).values end + + describe "optional block argument" do + it "contains the example" do |ex| + expect(ex).to be_an(RSpec::Core::Example) + expect(ex.description).to match(/contains the example/) + end + end end From 45d0e2b59941b274b37ba92f5e3066e34d48049a Mon Sep 17 00:00:00 2001 From: David Chelimsky Date: Sun, 26 Aug 2012 23:29:51 -0400 Subject: [PATCH 2/2] rdoc tweaks for deprecated example method and block argument --- lib/rspec/core/example_group.rb | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index 367ded1917..470c54b728 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -55,6 +55,7 @@ def description # @param [String] name # @param [Hash] extra_options # @param [Block] implementation + # @yield [Example] the example object def self.define_example_method(name, extra_options={}) define_method(name) do |*all_args, &block| desc, *args = *all_args @@ -67,10 +68,22 @@ def self.define_example_method(name, extra_options={}) end # Defines an example within a group. + # @example + # example do + # end + # + # example "does something" do + # end + # + # example "does something", :with => 'addtional metadata' do + # end + # + # example "does something" do |ex| + # # ex is a wrapper for the current running example + # end define_example_method :example # Defines an example within a group. - # - # @see example + # @example define_example_method :it # Defines an example within a group. # This is here primarily for backward compatibility with early versions @@ -79,17 +92,23 @@ def self.define_example_method(name, extra_options={}) define_example_method :specify # Shortcut to define an example with `:focus` => true + # @see example define_example_method :focus, :focused => true, :focus => true # Shortcut to define an example with `:focus` => true + # @see example define_example_method :focused, :focused => true, :focus => true # Shortcut to define an example with :pending => true + # @see example define_example_method :pending, :pending => true # Shortcut to define an example with :pending => 'Temporarily disabled with xexample' + # @see example define_example_method :xexample, :pending => 'Temporarily disabled with xexample' # Shortcut to define an example with :pending => 'Temporarily disabled with xit' + # @see example define_example_method :xit, :pending => 'Temporarily disabled with xit' # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify' + # @see example define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify' # Works like `alias_method :name, :example` with the added benefit of