Skip to content

Commit

Permalink
More refactoring of Metadata#filter_applies? and its helpers.
Browse files Browse the repository at this point in the history
- related to #528.
  • Loading branch information
dchelimsky committed Dec 7, 2011
1 parent 42f2e1c commit 742a658
Showing 1 changed file with 57 additions and 58 deletions.
115 changes: 57 additions & 58 deletions lib/rspec/core/metadata.rb
Expand Up @@ -54,14 +54,6 @@ def first_caller_from_outside_rspec
self[:caller].detect {|l| l !~ /\/lib\/rspec\/core/} self[:caller].detect {|l| l !~ /\/lib\/rspec\/core/}
end end


def described_class
self[:example_group][:described_class]
end

def full_description
build_description_from(self[:example_group][:full_description], *self[:description_args])
end

def build_description_from(*parts) def build_description_from(*parts)
parts.map {|p| p.to_s}.inject do |desc, p| parts.map {|p| p.to_s}.inject do |desc, p|
p =~ /^(#|::|\.)/ ? "#{desc}#{p}" : "#{desc} #{p}" p =~ /^(#|::|\.)/ ? "#{desc}#{p}" : "#{desc} #{p}"
Expand All @@ -73,23 +65,28 @@ def build_description_from(*parts)
# lazy evaluation of some values. # lazy evaluation of some values.
module ExampleMetadataHash module ExampleMetadataHash
include MetadataHash include MetadataHash

def described_class
self[:example_group].described_class
end

def full_description
build_description_from(self[:example_group][:full_description], *self[:description_args])
end
end end


# Mixed in to Metadata for an ExampleGroup (extends MetadataHash) to # Mixed in to Metadata for an ExampleGroup (extends MetadataHash) to
# support lazy evaluation of some values. # support lazy evaluation of some values.
module GroupMetadataHash module GroupMetadataHash
include MetadataHash include MetadataHash


private

def described_class def described_class
ancestors.each do |g| container_stack.each do |g|
# TODO remove describes return g[:describes] if g.has_key?(:describes)
return g[:describes] if g.has_key?(:describes)
return g[:described_class] if g.has_key?(:described_class) return g[:described_class] if g.has_key?(:described_class)
end end


ancestors.reverse.each do |g| container_stack.reverse.each do |g|
candidate = g[:description_args].first candidate = g[:description_args].first
return candidate unless String === candidate || Symbol === candidate return candidate unless String === candidate || Symbol === candidate
end end
Expand All @@ -98,11 +95,11 @@ def described_class
end end


def full_description def full_description
build_description_from(*ancestors.reverse.map {|a| a[:description_args]}.flatten) build_description_from(*container_stack.reverse.map {|a| a[:description_args]}.flatten)
end end


def ancestors def container_stack
@ancestors ||= begin @container_stack ||= begin
groups = [group = self] groups = [group = self]
while group.has_key?(:example_group) while group.has_key?(:example_group)
groups << group[:example_group] groups << group[:example_group]
Expand All @@ -116,7 +113,7 @@ def ancestors
def initialize(parent_group_metadata=nil) def initialize(parent_group_metadata=nil)
if parent_group_metadata if parent_group_metadata
update(parent_group_metadata) update(parent_group_metadata)
store(:example_group, {:example_group => parent_group_metadata[:example_group]}.extend(GroupMetadataHash)) store(:example_group, {:example_group => parent_group_metadata[:example_group].extend(GroupMetadataHash)}.extend(GroupMetadataHash))
else else
store(:example_group, {}.extend(GroupMetadataHash)) store(:example_group, {}.extend(GroupMetadataHash))
end end
Expand Down Expand Up @@ -152,36 +149,48 @@ def all_apply?(filters)


# @private # @private
def filter_applies?(key, value, metadata=self) def filter_applies?(key, value, metadata=self)
case value case key
when Hash when :line_numbers
if key == :locations metadata.line_number_filter_applies?(value)
filter_for_locations?(value, metadata) when :locations

This comment has been minimized.

Copy link
@AlexKVal

AlexKVal Dec 7, 2011

Contributor

I was wanted to do like this, but was afraid of a nested case. But in the end the method looks more clean. IMHO.

else metadata.location_filter_applies?(value)
else
case value
when Hash
value.all? { |k, v| filter_applies?(k, v, metadata[key]) } value.all? { |k, v| filter_applies?(k, v, metadata[key]) }
end when Enumerable
when Regexp metadata[key] == value
metadata[key] =~ value when Regexp
when Proc metadata[key] =~ value
if value.arity == 2 when Proc
# Pass the metadata hash to allow the proc to check if it even has the key. if value.arity == 2
# This is necessary for the implicit :if exclusion filter: # Pass the metadata hash to allow the proc to check if it even has the key.
# { } # => run the example # This is necessary for the implicit :if exclusion filter:
# { :if => nil } # => exclude the example # { } # => run the example
# The value of metadata[:if] is the same in these two cases but # { :if => nil } # => exclude the example
# they need to be treated differently. # The value of metadata[:if] is the same in these two cases but
value.call(metadata[key], metadata) rescue false # they need to be treated differently.
value.call(metadata[key], metadata) rescue false
else
value.call(metadata[key]) rescue false
end
else else
value.call(metadata[key]) rescue false metadata[key].to_s == value.to_s
end end
when String
metadata[key].to_s == value

This comment has been minimized.

Copy link
@AlexKVal

AlexKVal Dec 7, 2011

Contributor

Also was wanted to remove and let the default case do this job, but some tests were failing and I had deffered it to later. (my lack of expirience)

when Enumerable
key == :line_numbers ? within_examples_lines?(value, metadata) : metadata[key] == value
else
metadata[key].to_s == value.to_s
end end
end end


def location_filter_applies?(locations)
# it ignores location filters for other files
line_number = example_group_declaration_line(locations)
line_number ? line_number_filter_applies?(line_number) : true
end

def line_number_filter_applies?(line_numbers)
preceding_declaration_lines = line_numbers.map {|n| RSpec.world.preceding_declaration_line(n)}
!(relevant_line_numbers & preceding_declaration_lines).empty?
end

protected protected


def configure_for_example(description, user_metadata) def configure_for_example(description, user_metadata)
Expand Down Expand Up @@ -223,24 +232,14 @@ def ensure_valid_keys(user_metadata)
end end
end end


def relevant_line_numbers(meta) def example_group_declaration_line(locations)
[meta[:line_number]] + (meta[:example_group] ? relevant_line_numbers(meta[:example_group]) : []) locations[File.expand_path(self[:example_group][:file_path])] if self[:example_group]
end

def within_examples_lines?(line_numbers, metadata)
preceding_declaration_lines = line_numbers.map{|n| RSpec.world.preceding_declaration_line(n)}
!(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
end end


def example_group_line_number(locations, metadata) # TODO - make this a method on metadata - the problem is
# An ExampleGroup always got one line number # metadata[:example_group] is not always a kind of GroupMetadataHash.

This comment has been minimized.

Copy link
@AlexKVal

AlexKVal Dec 7, 2011

Contributor

it's exactly what i mean. i'll try to investigate all places where metadata comes from.

locations[File.expand_path( metadata[:example_group][:file_path] )] if metadata[:example_group] def relevant_line_numbers(metadata=self)
end [metadata[:line_number]] + (metadata[:example_group] ? relevant_line_numbers(metadata[:example_group]) : [])

def filter_for_locations?(locations, metadata)
# it ignores location filters for other files
line_number = example_group_line_number(locations, metadata)
line_number ? within_examples_lines?(line_number, metadata) : true
end end


end end
Expand Down

2 comments on commit 742a658

@AlexKVal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I've learned much from this refactoring. It's all very new for me.

@AlexKVal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

location_filter_applies? and line_number_filter_applies? aren't they private ? (or at least with a @Private tag)

Please sign in to comment.