moduleRSpecmoduleCoreclassMetadata<Hash# Used to extend metadata Hashes to support lazy evaluation of locations# and descriptions.moduleMetadataHashdef[](key)returnsuperifhas_key?(key)casekeywhen:locationstore(:location,location)when:file_path,:line_numberfile_path,line_number=file_and_line_numberstore(:file_path,file_path)store(:line_number,line_number)superwhen:execution_resultstore(:execution_result,{})when:describesstore(:describes,described_class_for(self))when:full_descriptionstore(:full_description,full_description_for(self))when:descriptionstore(:description,build_description_from(*self[:description_args]))elsesuperendendprivatedeflocation"#{self[:file_path]}:#{self[:line_number]}"enddeffile_and_line_numberfirst_caller_from_outside_rspec=~/(.+?):(\d+)(|:\d+)/return[$1,$2.to_i]enddeffirst_caller_from_outside_rspecself[:caller].detect{|l|l!~/\/lib\/rspec\/core/}enddefdescribed_class_for(m)m[:example_group][:describes]enddeffull_description_for(m)build_description_from(m[:example_group][:full_description],*m[:description_args])enddefbuild_description_from(*parts)parts.map{|p|p.to_s}.reducedo|desc,p|p=~/^(#|::|\.)/?"#{desc}#{p}":"#{desc}#{p}"end||""endendmoduleGroupMetadataHashincludeMetadataHashdefdescribed_class_for(*)ancestors.eachdo|g|returng[:describes]ifg.has_key?(:describes)endancestors.reverse.eachdo|g|candidate=g[:description_args].firstreturncandidateunlessString===candidate||Symbol===candidateendnilenddeffull_description_for(*)build_description_from(*ancestors.reverse.mapdo|a|a.has_key?(:full_description)?a[:full_description]:a[:description_args]end.flatten)endprivatedefancestors@ancestors||=begingroups=[group=self]whilegroup.has_key?(:example_group)groups<<group[:example_group]group=group[:example_group]endgroupsendendenddefinitialize(parent_group_metadata=nil)ifparent_group_metadataupdate(parent_group_metadata)store(:example_group,{:example_group=>parent_group_metadata[:example_group]}.extend(GroupMetadataHash))elsestore(:example_group,{}.extend(GroupMetadataHash))endyieldselfifblock_given?enddefprocess(*args)user_metadata=args.last.is_a?(Hash)?args.pop:{}ensure_valid_keys(user_metadata)self[:example_group].store(:description_args,args)self[:example_group].store(:caller,user_metadata.delete(:caller)||caller)update(user_metadata)enddeffor_example(description,user_metadata)dup.extend(MetadataHash).configure_for_example(description,user_metadata)enddefany_apply?(filters)filters.any?{|k,v|filter_applies?(k,v)}enddefall_apply?(filters)filters.all?{|k,v|filter_applies?(k,v)}enddeffilter_applies?(key,value,metadata=self)casevaluewhenHashifkey==:locationsfile_path=(self[:example_group]||{})[:file_path]expanded_path=file_path&&File.expand_path(file_path)ifexpanded_path&&line_numbers=value[expanded_path]filter_applies?(:line_numbers,line_numbers)elsetrueendelsevalue.all?{|k,v|filter_applies?(k,v,metadata[key])}endwhenRegexpmetadata[key]=~valuewhenProcifvalue.arity==2# Pass the metadata hash to allow the proc to check if it even has the key.# This is necessary for the implicit :if exclusion filter:# { } # => run the example# { :if => nil } # => exclude the example# The value of metadata[:if] is the same in these two cases but# they need to be treated differently.value.call(metadata[key],metadata)rescuefalseelsevalue.call(metadata[key])rescuefalseendwhenStringmetadata[key].to_s==value.to_swhenEnumerableifkey==:line_numberspreceding_declaration_lines=value.map{|v|world.preceding_declaration_line(v)}!(relevant_line_numbers(metadata)&preceding_declaration_lines).empty?elsemetadata[key]==valueendelsemetadata[key].to_s==value.to_sendendprotecteddefconfigure_for_example(description,user_metadata)store(:description_args,[description])store(:caller,user_metadata.delete(:caller)||caller)update(user_metadata)endprivateRESERVED_KEYS=[:description,:example_group,:execution_result,:file_path,:full_description,:line_number,:location]defensure_valid_keys(user_metadata)RESERVED_KEYS.eachdo|key|ifuser_metadata.keys.include?(key)raise<<-EOM#{"*"*50}
:#{key} is not allowed
RSpec reserves some hash keys for its own internal use,
including :#{key}, which is used on:
#{caller(0)[4]}.
Here are all of RSpec's reserved hash keys:
#{RESERVED_KEYS.join("\n ")}#{"*"*50}EOMraise":#{key} is not allowed"endendenddefworldRSpec.worldenddefrelevant_line_numbers(metadata)line_numbers=[metadata[:line_number]]ifmetadata[:example_group]line_numbers+relevant_line_numbers(metadata[:example_group])elseline_numbersendendendendend