Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 52bbe9fbfc
Fetching contributors…

Cannot retrieve contributors at this time

204 lines (175 sloc) 6.574 kb
module RSpec
module Core
# Manages the filtering of examples and groups by matching tags declared on
# the command line or options files, or filters declared via
# `RSpec.configure`, with hash key/values submitted within example group
# and/or example declarations. For example, given this declaration:
#
# describe Thing, :awesome => true do
# it "does something" do
# # ...
# end
# end
#
# That group (or any other with `:awesome => true`) would be filtered in
# with any of the following commands:
#
# rspec --tag awesome:true
# rspec --tag awesome
# rspec -t awesome:true
# rspec -t awesome
#
# Prefixing the tag names with `~` negates the tags, thus excluding this group with
# any of:
#
# rspec --tag ~awesome:true
# rspec --tag ~awesome
# rspec -t ~awesome:true
# rspec -t ~awesome
#
# ## Options files and command line overrides
#
# Tag declarations can be stored in `.rspec`, `~/.rspec`, or a custom
# options file. This is useful for storing defaults. For example, let's
# say you've got some slow specs that you want to suppress most of the
# time. You can tag them like this:
#
# describe Something, :slow => true do
#
# And then store this in `.rspec`:
#
# --tag ~slow:true
#
# Now when you run `rspec`, that group will be excluded.
#
# ## Overriding
#
# Of course, you probably want to run them sometimes, so you can override
# this tag on the command line like this:
#
# rspec --tag slow:true
#
# ## RSpec.configure
#
# You can also store default tags with `RSpec.configure`. We use `tag` on
# the command line (and in options files like `.rspec`), but for historical
# reasons we use the term `filter` in `RSpec.configure:
#
# RSpec.configure do |c|
# c.filter_run_including :foo => :bar
# c.filter_run_excluding :foo => :bar
# end
#
# These declarations can also be overridden from the command line.
#
# @see RSpec.configure
# @see Configuration#filter_run_including
# @see Configuration#filter_run_excluding
class FilterManager
DEFAULT_EXCLUSIONS = {
:if => lambda { |value| !value },
:unless => lambda { |value| value }
}
STANDALONE_FILTERS = [:locations, :line_numbers, :full_description]
module Describable
PROC_HEX_NUMBER = /0x[0-9a-f]+@/
PROJECT_DIR = File.expand_path('.')
def description
reject { |k, v| RSpec::Core::FilterManager::DEFAULT_EXCLUSIONS[k] == v }.inspect.gsub(PROC_HEX_NUMBER, '').gsub(PROJECT_DIR, '.').gsub(' (lambda)','')
end
def empty_without_conditional_filters?
reject { |k, v| RSpec::Core::FilterManager::DEFAULT_EXCLUSIONS[k] == v }.empty?
end
end
module BackwardCompatibility
def merge(orig, opposite, *updates)
_warn_deprecated_keys(updates.last)
super
end
def reverse_merge(orig, opposite, *updates)
_warn_deprecated_keys(updates.last)
super
end
# Supports a use case that probably doesn't exist: overriding the
# if/unless procs.
def _warn_deprecated_keys(updates)
_warn_deprecated_key(:unless, updates) if updates.has_key?(:unless)
_warn_deprecated_key(:if, updates) if updates.has_key?(:if)
end
# Emits a deprecation warning for keys that will not be supported in
# the future.
def _warn_deprecated_key(key, updates)
RSpec.warn_deprecation("\nDEPRECATION NOTICE: FilterManager#exclude(#{key.inspect} => #{updates[key].inspect}) is deprecated with no replacement, and will be removed from rspec-3.0.")
@exclusions[key] = updates.delete(key)
end
end
attr_reader :exclusions, :inclusions
def initialize
@exclusions = DEFAULT_EXCLUSIONS.dup.extend(Describable)
@inclusions = {}.extend(Describable)
extend(BackwardCompatibility)
end
def add_location(file_path, line_numbers)
# locations is a hash of expanded paths to arrays of line
# numbers to match against. e.g.
# { "path/to/file.rb" => [37, 42] }
locations = @inclusions.delete(:locations) || Hash.new {|h,k| h[k] = []}
locations[File.expand_path(file_path)].push(*line_numbers)
@inclusions.replace(:locations => locations)
@exclusions.clear
end
def empty?
inclusions.empty? && exclusions.empty_without_conditional_filters?
end
def prune(examples)
examples.select {|e| !exclude?(e) && include?(e)}
end
def exclude(*args)
merge(@exclusions, @inclusions, *args)
end
def exclude!(*args)
replace(@exclusions, @inclusions, *args)
end
def exclude_with_low_priority(*args)
reverse_merge(@exclusions, @inclusions, *args)
end
def exclude?(example)
@exclusions.empty? ? false : example.any_apply?(@exclusions)
end
def include(*args)
unless_standalone(*args) { merge(@inclusions, @exclusions, *args) }
end
def include!(*args)
unless_standalone(*args) { replace(@inclusions, @exclusions, *args) }
end
def include_with_low_priority(*args)
unless_standalone(*args) { reverse_merge(@inclusions, @exclusions, *args) }
end
def include?(example)
@inclusions.empty? ? true : example.any_apply?(@inclusions)
end
private
def unless_standalone(*args)
is_standalone_filter?(args.last) ? @inclusions.replace(args.last) : yield unless already_set_standalone_filter?
end
def merge(orig, opposite, *updates)
orig.merge!(updates.last).each_key {|k| opposite.delete(k)}
end
def replace(orig, opposite, *updates)
updates.last.each_key {|k| opposite.delete(k)}
orig.replace(updates.last)
end
def reverse_merge(orig, opposite, *updates)
updated = updates.last.merge(orig)
opposite.each_pair {|k,v| updated.delete(k) if updated[k] == v}
orig.replace(updated)
end
def already_set_standalone_filter?
is_standalone_filter?(inclusions)
end
def is_standalone_filter?(filter)
STANDALONE_FILTERS.any? {|key| filter.has_key?(key)}
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.