free_mutant/lib/mutant/matcher/object_space.rb
2012-09-15 23:23:53 +02:00

130 lines
2.7 KiB
Ruby

module Mutant
class Matcher
# Matcher against object space
class ObjectSpace < self
include Equalizer.new(:scope_name_pattern)
PATTERN = %r(\A::(.+)\z)
# Parse matcher
#
# @param [String] input
#
# @return [Matcher::ObjectSpace]
# returns object space matcher if successful
#
# @return [nil]
# returns nil otherwise
#
# @api private
#
def self.parse(input)
match = PATTERN.match(input)
return unless match
new(%r(\A#{Regexp.escape(match[1])}(\z|::)))
end
# Enumerate subjects
#
# @return [Enumerator<Subject>]
# returns subject enumerator when no block given
#
# @return [self]
# returns self otherwise
#
# @api private
#
def each(&block)
return to_enum unless block_given?
matchers.each do |matcher|
matcher.each(&block)
end
self
end
# Return scope name pattern
#
# @return [Regexp]
#
# @api private
#
def scope_name_pattern; @scope_name_pattern; end
private
# Initialize object space matcher
#
# @param [Regexp] scope_name_pattern
# @param [Enumerable<#each(scope)>] matchers
#
# @return [undefined]
#
# @api private
#
def initialize(scope_name_pattern)
@scope_name_pattern, @matchers = scope_name_pattern, [Method::Singleton, Method::Instance]
end
# Return matcher enumerator
#
# @return [Enumerable<Matcher>]
#
# @api private
#
def matchers(&block)
return to_enum(__method__) unless block_given?
scopes.each do |scope|
emit_scope_matches(scope, &block)
end
self
end
# Yield matchers for scope
#
# @param [::Class,::Module] scope
#
# @return [undefined]
#
# @api private
#
def emit_scope_matches(scope, &block)
@matchers.each do |matcher|
matcher.each(scope, &block)
end
end
# Return scope enumerator
#
# @return [Enumerable<Object>]
#
# @api private
#
def scopes(&block)
return to_enum(__method__) unless block_given?
::ObjectSpace.each_object(Module) do |scope|
emit_scope(scope, &block)
end
end
# Yield scope if name matches pattern
#
# @param [::Module,::Class]
#
# @return [undefined]
#
# @api private
#
def emit_scope(scope)
if [::Module, ::Class].include?(scope.class) and @scope_name_pattern =~ scope.name
yield scope
end
end
end
end
end