class RSpec::Core::Metadata

Each ExampleGroup class and Example instance owns an instance of Metadata, which is Hash extended to support lazy evaluation of values associated with keys that may or may not be used by any example or group.

In addition to metadata that is used internally, this also stores user-supplied metadata, e.g.

describe Something, :type => :ui do
  it "does something", :slow => true do
    # ...
  end
end

`:type => :ui` is stored in the Metadata owned by the example group, and `:slow => true` is stored in the Metadata owned by the example. These can then be used to select which examples are run using the `–tag` option on the command line, or several methods on `Configuration` used to filter a run (e.g. `filter_run_including`, `filter_run_excluding`, etc).

@see RSpec::Core::Example#metadata @see RSpec::Core::ExampleGroup.metadata @see FilterManager @see RSpec::Core::Configuration#filter_run_including @see RSpec::Core::Configuration#filter_run_excluding

Constants

RESERVED_KEYS

Public Class Methods

new(parent_group_metadata=nil) { |self| ... } click to toggle source
# File lib/rspec/core/metadata.rb, line 163
def initialize(parent_group_metadata=nil)
  if parent_group_metadata
    update(parent_group_metadata)
    store(:example_group, {:example_group => parent_group_metadata[:example_group].extend(GroupMetadataHash)}.extend(GroupMetadataHash))
  else
    store(:example_group, {}.extend(GroupMetadataHash))
  end

  yield self if block_given?
end
relative_path(line) click to toggle source
# File lib/rspec/core/metadata.rb, line 29
def self.relative_path(line)
  line = line.sub(File.expand_path("."), ".")
  line = line.sub(/\A([^:]+:\d+)$/, '\\1')
  return nil if line == '-e:1'
  line
rescue SecurityError
  nil
end

Public Instance Methods

all_apply?(filters) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 196
def all_apply?(filters)
  filters.all? {|k,v| filter_applies?(k,v)}
end
any_apply?(filters) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 191
def any_apply?(filters)
  filters.any? {|k,v| filter_applies?(k,v)}
end
filter_applies?(key, value, metadata=self) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 201
def filter_applies?(key, value, metadata=self)
  return metadata.filter_applies_to_any_value?(key, value) if Array === metadata[key] && !(Proc === value)
  return metadata.line_number_filter_applies?(value)       if key == :line_numbers
  return metadata.location_filter_applies?(value)          if key == :locations
  return metadata.filters_apply?(key, value)               if Hash === value

  return false unless metadata.has_key?(key)

  case value
  when Regexp
    metadata[key] =~ value
  when Proc
    case value.arity
    when 0 then value.call
    when 2 then value.call(metadata[key], metadata)
    else value.call(metadata[key])
    end
  else
    metadata[key].to_s == value.to_s
  end
end
filter_applies_to_any_value?(key, value) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 229
def filter_applies_to_any_value?(key, value)
  self[key].any? {|v| filter_applies?(key, v, {key => value})}
end
filters_apply?(key, value) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 224
def filters_apply?(key, value)
  value.all? {|k, v| filter_applies?(k, v, self[key])}
end
for_example(description, user_metadata) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 186
def for_example(description, user_metadata)
  dup.extend(ExampleMetadataHash).configure_for_example(description, user_metadata)
end
line_number_filter_applies?(line_numbers) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 241
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
location_filter_applies?(locations) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 234
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
process(*args) click to toggle source

@private

# File lib/rspec/core/metadata.rb, line 175
def process(*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)
end

Protected Instance Methods

configure_for_example(description, user_metadata) click to toggle source
# File lib/rspec/core/metadata.rb, line 248
def configure_for_example(description, user_metadata)
  store(:description_args, [description]) if description
  store(:caller, user_metadata.delete(:caller) || caller)
  update(user_metadata)
end

Private Instance Methods

ensure_valid_keys(user_metadata) click to toggle source
# File lib/rspec/core/metadata.rb, line 266
      def ensure_valid_keys(user_metadata)
        RESERVED_KEYS.each do |key|
          if user_metadata.has_key?(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}
            EOM
          end
        end
      end
example_group_declaration_line(locations) click to toggle source
# File lib/rspec/core/metadata.rb, line 287
def example_group_declaration_line(locations)
  locations[File.expand_path(self[:example_group][:file_path])] if self[:example_group]
end
relevant_line_numbers(metadata=self) click to toggle source

TODO - make this a method on metadata - the problem is metadata is not always a kind of GroupMetadataHash.

# File lib/rspec/core/metadata.rb, line 293
def relevant_line_numbers(metadata=self)
  [metadata[:line_number]] + (metadata[:example_group] ? relevant_line_numbers(metadata[:example_group]) : [])
end