moduleRSpecmoduleCore# Represents some functionality that is shared with multiple example groups.# The functionality is defined by the provided block, which is lazily# eval'd when the `SharedExampleGroupModule` instance is included in an example# group.classSharedExampleGroupModule<Moduledefinitialize(description,definition)@description=description@definition=definitionend# Provides a human-readable representation of this module.definspect"#<#{self.class.name}#{@description.inspect}>"endaliasto_sinspect# Ruby callback for when a module is included in another module is class.# Our definition evaluates the shared group block in the context of the# including example group.defincluded(klass)inclusion_line=klass.metadata[:location]SharedExampleGroupInclusionStackFrame.with_frame(@description,inclusion_line)doklass.class_exec(&@definition)endendend# Shared example groups let you define common context and/or common# examples that you wish to use in multiple example groups.## When defined, the shared group block is stored for later evaluation.# It can later be included in an example group either explicitly# (using `include_examples`, `include_context` or `it_behaves_like`)# or implicitly (via matching metadata).## Named shared example groups are scoped based on where they are# defined. Shared groups defined in an example group are available# for inclusion in that example group or any child example groups,# but not in any parent or sibling example groups. Shared example# groups defined at the top level can be included from any example group.moduleSharedExampleGroup# @overload shared_examples(name, &block)# @param name [String, Symbol, Module] identifer to use when looking up# this shared group# @param block The block to be eval'd# @overload shared_examples(name, metadata, &block)# @param name [String, Symbol, Module] identifer to use when looking up# this shared group# @param metadata [Array<Symbol>, Hash] metadata to attach to this# group; any example group or example with matching metadata will# automatically include this shared example group.# @param block The block to be eval'd# @overload shared_examples(metadata, &block)# @param metadata [Array<Symbol>, Hash] metadata to attach to this# group; any example group or example with matching metadata will# automatically include this shared example group.# @param block The block to be eval'd## Stores the block for later use. The block will be evaluated# in the context of an example group via `include_examples`,# `include_context`, or `it_behaves_like`.## @example# shared_examples "auditable" do# it "stores an audit record on save!" do# expect { auditable.save! }.to change(Audit, :count).by(1)# end# end## describe Account do# it_behaves_like "auditable" do# let(:auditable) { Account.new }# end# end## @see ExampleGroup.it_behaves_like# @see ExampleGroup.include_examples# @see ExampleGroup.include_contextdefshared_examples(name,*args,&block)top_level=self==ExampleGroupiftop_level&&RSpec.thread_local_metadata[:in_example_group]raise"Creating isolated shared examples from within a context is "\"not allowed. Remove `RSpec.` prefix or move this to a "\"top-level scope."endRSpec.world.shared_example_group_registry.add(self,name,*args,&block)endaliasshared_contextshared_examplesaliasshared_examples_forshared_examples# @api private## Shared examples top level DSL.moduleTopLevelDSL# @privatedefself.definitionsprocdodefshared_examples(name,*args,&block)RSpec.world.shared_example_group_registry.add(:main,name,*args,&block)endaliasshared_contextshared_examplesaliasshared_examples_forshared_examplesendend# @privatedefself.exposed_globally?@exposed_globally||=falseend# @api private## Adds the top level DSL methods to Module and the top level binding.defself.expose_globally!returnifexposed_globally?Core::DSL.change_global_dsl(&definitions)@exposed_globally=trueend# @api private## Removes the top level DSL methods to Module and the top level binding.defself.remove_globally!returnunlessexposed_globally?Core::DSL.change_global_dsldoundefshared_examplesundefshared_contextundefshared_examples_forend@exposed_globally=falseendend# @privateclassRegistrydefadd(context,name,*metadata_args,&block)ensure_block_has_source_location(block){CallerFilter.first_non_rspec_line}ifvalid_name?(name)warn_if_key_takencontext,name,blockshared_example_groups[context][name]=blockelsemetadata_args.unshiftnameendreturnifmetadata_args.empty?RSpec.configuration.includeSharedExampleGroupModule.new(name,block),*metadata_argsenddeffind(lookup_contexts,name)lookup_contexts.eachdo|context|found=shared_example_groups[context][name]returnfoundiffoundendshared_example_groups[:main][name]endprivatedefshared_example_groups@shared_example_groups||=Hash.new{|hash,context|hash[context]={}}enddefvalid_name?(candidate)casecandidatewhenString,Symbol,Modulethentrueelsefalseendenddefwarn_if_key_taken(context,key,new_block)existing_block=shared_example_groups[context][key]returnunlessexisting_blockRSpec.warn_with<<-WARNING.gsub(/^ +\|/,''),:call_site=>nil
|WARNING: Shared example group '#{key}' has been previously defined at:
| #{formatted_locationexisting_block}
|...and you are now defining it at:
| #{formatted_locationnew_block}
|The new definition will overwrite the original one.
WARNINGenddefformatted_location(block)block.source_location.join":"endifProc.method_defined?(:source_location)defensure_block_has_source_location(_block);endelse# for 1.8.7defensure_block_has_source_location(block)source_location=yield.split(':')block.extendModule.new{define_method(:source_location){source_location}}endendendendendinstance_exec(&Core::SharedExampleGroup::TopLevelDSL.definitions)end