ExampleGroup and {Example} are the main structural elements of rspec-core. Consider this example:
describe Thing do it "does something" do end end
The object returned by `describe Thing` is a subclass of ExampleGroup. The object returned by `it “does something”` is an instance of Example, which serves as a wrapper for an instance of the ExampleGroup in which it is declared.
Example group bodies (e.g. `describe` or `context` blocks) are evaluated in the context of a new subclass of ExampleGroup. Individual examples are evalutaed in the context of an instance of the specific ExampleGroup subclass to which they belong.
Besides the class methods defined here, there are other interesting macros defined in {Hooks}, {MemoizedHelpers::ClassMethods} and {SharedExampleGroup}. There are additional instance methods available to your examples defined in {MemoizedHelpers} and {Pending}.
@private
# File lib/rspec/core/example_group.rb, line 523 def self.all_apply?(filters) MetadataFilter.all_apply?(filters, metadata) end
@private
# File lib/rspec/core/example_group.rb, line 518 def self.any_apply?(filters) MetadataFilter.any_apply?(filters, metadata) end
@private
# File lib/rspec/core/example_group.rb, line 410 def self.before_context_ivars @before_context_ivars ||= {} end
@private
# File lib/rspec/core/example_group.rb, line 381 def self.children @children ||= [] end
@private
# File lib/rspec/core/example_group.rb, line 528 def self.declaration_line_numbers @declaration_line_numbers ||= [metadata[:line_number]] + examples.collect {|e| e.metadata[:line_number]} + children.inject([]) {|l,c| l + c.declaration_line_numbers} end
@private @macro [attach] alias_example_group_to
@!scope class @param name [String] The example group doc string @param metadata [Hash] Additional metadata to attach to the example group @yield The example group definition Generates a subclass of this example group which inherits everything except the examples themselves. @example RSpec.describe "something" do # << This describe method is defined in # << RSpec::Core::DSL, included in the # << global namespace (optional) before do do_something_before end let(:thing) { Thing.new } $1 "attribute (of something)" do # examples in the group get the before hook # declared above, and can access `thing` end end
@see DSL#describe
# File lib/rspec/core/example_group.rb, line 205 def self.define_example_group_method(name, metadata={}) define_singleton_method(name) do |*args, &example_group_block| thread_data = RSpec.thread_local_metadata top_level = self == ExampleGroup if top_level if thread_data[:in_example_group] raise "Creating an isolated context from within a context is " + "not allowed. Change `RSpec.#{name}` to `#{name}` or " + "move this to a top-level scope." end thread_data[:in_example_group] = true end begin description = args.shift combined_metadata = metadata.dup combined_metadata.merge!(args.pop) if args.last.is_a? Hash args << combined_metadata subclass(self, description, args, &example_group_block).tap do |child| children << child end ensure thread_data.delete(:in_example_group) if top_level end end RSpec::Core::DSL.expose_example_group_alias(name) end
@private @macro [attach] define_example_method
@!scope class @param name [String] @param extra_options [Hash] @param implementation [Block] @yield [Example] the example object @example $1 do end $1 "does something" do end $1 "does something", :with => 'additional metadata' do end $1 "does something" do |ex| # ex is the Example object that contains metadata about the example end
# File lib/rspec/core/example_group.rb, line 107 def self.define_example_method(name, extra_options={}) define_singleton_method(name) do |*all_args, &block| desc, *args = *all_args options = Metadata.build_hash_from(args) options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block options.update(extra_options) # Metadata inheritance normally happens in `Example#initialize`, # but for `:pending` specifically we need it earlier. pending_metadata = options[:pending] || metadata[:pending] if pending_metadata options, block = ExampleGroup.pending_metadata_and_block_for( options.merge(:pending => pending_metadata), block ) end examples << RSpec::Core::Example.new(self, desc, options, block) examples.last end end
@private
# File lib/rspec/core/example_group.rb, line 35 def self.define_singleton_method(*a, &b) (class << self; self; end).__send__(:define_method, *a, &b) end
@private
# File lib/rspec/core/example_group.rb, line 55 def self.delegate_to_metadata(*names) names.each do |name| define_singleton_method(name) { metadata.fetch(name) } end end
@private
# File lib/rspec/core/example_group.rb, line 376 def self.descendant_filtered_examples @descendant_filtered_examples ||= filtered_examples + children.inject([]){|l,c| l + c.descendant_filtered_examples} end
@private
# File lib/rspec/core/example_group.rb, line 386 def self.descendants @_descendants ||= [self] + children.inject([]) {|list, c| list + c.descendants} end
@return [String] the current example group description
# File lib/rspec/core/example_group.rb, line 64 def self.description description = metadata[:description] RSpec.configuration.format_docstrings_block.call(description) end
@private
# File lib/rspec/core/example_group.rb, line 401 def self.ensure_example_groups_are_configured unless defined?(@@example_groups_configured) RSpec.configuration.configure_mock_framework RSpec.configuration.configure_expectation_framework @@example_groups_configured = true end end
@private
# File lib/rspec/core/example_group.rb, line 366 def self.examples @examples ||= [] end
@private
# File lib/rspec/core/example_group.rb, line 513 def self.fail_fast? RSpec.configuration.fail_fast? end
@private
# File lib/rspec/core/example_group.rb, line 371 def self.filtered_examples RSpec.world.filtered_examples[self] end
@private
# File lib/rspec/core/example_group.rb, line 501 def self.for_filtered_examples(reporter, &block) filtered_examples.each(&block) children.each do |child| reporter.example_group_started(child) child.for_filtered_examples(reporter, &block) reporter.example_group_finished(child) end false end
Includes shared content mapped to `name` directly in the group in which it is declared, as opposed to `it_behaves_like`, which creates a nested group. If given a block, that block is also eval’d in the current context.
@see SharedExampleGroup
# File lib/rspec/core/example_group.rb, line 301 def self.include_context(name, *args, &block) find_and_eval_shared("context", name, *args, &block) end
Includes shared content mapped to `name` directly in the group in which it is declared, as opposed to `it_behaves_like`, which creates a nested group. If given a block, that block is also eval’d in the current context.
@see SharedExampleGroup
# File lib/rspec/core/example_group.rb, line 310 def self.include_examples(name, *args, &block) find_and_eval_shared("examples", name, *args, &block) end
@private
# File lib/rspec/core/example_group.rb, line 473 def self.ordering_strategy order = metadata.fetch(:order, :global) registry = RSpec.configuration.ordering_registry registry.fetch(order) do warn |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata. | Falling back to configured global ordering. | Unrecognized ordering specified at: #{location}.gsub(/^ +\|/, '') registry.fetch(:global) end end
@private
# File lib/rspec/core/example_group.rb, line 391 def self.parent_groups @parent_groups ||= ancestors.select {|a| a < RSpec::Core::ExampleGroup} end
@private
# File lib/rspec/core/example_group.rb, line 545 def self.pending_metadata_and_block_for(options, block) if String === options[:pending] reason = options[:pending] else options[:pending] = true reason = RSpec::Core::Pending::NO_REASON_GIVEN end # Assign :caller so that the callback's source_location isn't used # as the example location. options[:caller] ||= Metadata.backtrace_from(block) # This will fail if no block is provided, which is effectively the # same as failing the example so it will be marked correctly as # pending. callback = Proc.new { pending(reason); instance_exec(&block) } return options, callback end
Runs all the examples in this group
# File lib/rspec/core/example_group.rb, line 448 def self.run(reporter) if RSpec.world.wants_to_quit RSpec.world.clear_remaining_example_groups if top_level? return end reporter.example_group_started(self) begin run_before_context_hooks(new) result_for_this_group = run_examples(reporter) results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all? result_for_this_group && results_for_descendants rescue Pending::SkipDeclaredInExample => ex for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) } rescue Exception => ex RSpec.world.wants_to_quit = true if fail_fast? for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) } ensure run_after_context_hooks(new) before_context_ivars.clear reporter.example_group_finished(self) end end
@private
# File lib/rspec/core/example_group.rb, line 438 def self.run_after_context_hooks(example_group_instance) return if descendant_filtered_examples.empty? set_ivars(example_group_instance, before_context_ivars) ContextHookMemoizedHash::After.isolate_for_context_hook(example_group_instance) do hooks.run(:after, :context, example_group_instance) end end
@private
# File lib/rspec/core/example_group.rb, line 424 def self.run_before_context_hooks(example_group_instance) return if descendant_filtered_examples.empty? begin set_ivars(example_group_instance, superclass.before_context_ivars) ContextHookMemoizedHash::Before.isolate_for_context_hook(example_group_instance) do hooks.run(:before, :context, example_group_instance) end ensure store_before_context_ivars(example_group_instance) end end
@private
# File lib/rspec/core/example_group.rb, line 489 def self.run_examples(reporter) ordering_strategy.order(filtered_examples).map do |example| next if RSpec.world.wants_to_quit instance = new set_ivars(instance, before_context_ivars) succeeded = example.run(instance, reporter) RSpec.world.wants_to_quit = true if fail_fast? && !succeeded succeeded end.all? end
@private
# File lib/rspec/core/example_group.rb, line 343 def self.set_it_up(*args, &example_group_block) # Ruby 1.9 has a bug that can lead to infinite recursion and a # SystemStackError if you include a module in a superclass after # including it in a subclass: https://gist.github.com/845896 # To prevent this, we must include any modules in RSpec::Core::ExampleGroup # before users create example groups and have a chance to include # the same module in a subclass of RSpec::Core::ExampleGroup. # So we need to configure example groups here. ensure_example_groups_are_configured description = args.shift user_metadata = Metadata.build_hash_from(args) args.unshift(description) @metadata = Metadata::ExampleGroupHash.create( superclass_metadata, user_metadata, *args, &example_group_block ) hooks.register_globals(self, RSpec.configuration.hooks) RSpec.world.configure_group(self) end
@private
# File lib/rspec/core/example_group.rb, line 540 def self.set_ivars(instance, ivars) ivars.each {|name, value| instance.instance_variable_set(name, value)} end
@private
# File lib/rspec/core/example_group.rb, line 415 def self.store_before_context_ivars(example_group_instance) return if example_group_instance.instance_variables.empty? example_group_instance.instance_variables.each { |ivar| before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar) } end
@private
# File lib/rspec/core/example_group.rb, line 327 def self.subclass(parent, description, args, &example_group_block) subclass = Class.new(parent) subclass.set_it_up(description, *args, &example_group_block) ExampleGroups.assign_const(subclass) subclass.module_exec(&example_group_block) if example_group_block # The LetDefinitions module must be included _after_ other modules # to ensure that it takes precedence when there are name collisions. # Thus, we delay including it until after the example group block # has been eval'd. MemoizedHelpers.define_helpers_on(subclass) subclass end
@private @return [Metadata] belonging to the parent of a nested {ExampleGroup}
# File lib/rspec/core/example_group.rb, line 50 def self.superclass_metadata @superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil end
Returns the class or module passed to the `describe` method (or alias). Returns nil if the subject is not a class or module. @example
describe Thing do it "does something" do described_class == Thing end end
# File lib/rspec/core/example_group.rb, line 79 def described_class self.class.described_class end
Generated with the Darkfish Rdoc Generator 2.