lib/mutant/expression.rb in mutant-0.8.0 vs lib/mutant/expression.rb in mutant-0.8.1
- old
+ new
@@ -1,95 +1,31 @@
module Mutant
# Abstract base class for match expression
class Expression
- include AbstractType, Adamantium::Flat, Concord::Public.new(:match)
+ include AbstractType, Adamantium::Flat
- include Equalizer.new(:syntax)
+ fragment = /[A-Za-z][A-Za-z\d_]*/.freeze
+ SCOPE_NAME_PATTERN = /(?<scope_name>#{fragment}(?:#{SCOPE_OPERATOR}#{fragment})*)/.freeze
+ SCOPE_SYMBOL_PATTERN = '(?<scope_symbol>[.#])'.freeze
- SCOPE_NAME_PATTERN = /[A-Za-z][A-Za-z\d_]*/.freeze
+ private_constant(*constants(false))
- METHOD_NAME_PATTERN = Regexp.union(
- /[A-Za-z_][A-Za-z\d_]*[!?=]?/,
- *AST::Types::OPERATOR_METHODS.map(&:to_s)
- ).freeze
-
- INSPECT_FORMAT = '<Mutant::Expression: %s>'.freeze
-
- SCOPE_PATTERN = /#{SCOPE_NAME_PATTERN}(?:#{SCOPE_OPERATOR}#{SCOPE_NAME_PATTERN})*/.freeze
-
- REGISTRY = {}
-
- # Error raised on invalid expressions
- class InvalidExpressionError < RuntimeError; end
-
- # Error raised on ambiguous expressions
- class AmbiguousExpressionError < RuntimeError; end
-
- # Initialize expression
+ # Syntax of expression
#
- # @param [MatchData] match
- #
- # @api private
- #
- def initialize(*)
- super
- @syntax = match.to_s
- @inspect = format(INSPECT_FORMAT, syntax)
- end
-
- # Return marshallable representation
- #
- # FIXME: Remove the need for this.
- #
- # Refactoring Expression objects not to reference a MatchData instance.
- # This will make this hack unneeded.
- #
# @return [String]
#
# @api private
- #
- def _dump(_level)
- syntax
- end
+ abstract_method :syntax
- # Load serializable representation
+ # Match length with other expression
#
- # @return [String]
- #
- # @return [Expression]
- #
- # @api private
- #
- def self._load(syntax)
- parse(syntax)
- end
-
- # Return inspection
- #
- # @return [String]
- #
- # @api private
- #
- attr_reader :inspect
-
- # Return syntax
- #
- # @return [String]
- #
- # @api private
- #
- attr_reader :syntax
-
- # Return match length for expression
- #
# @param [Expression] other
#
# @return [Fixnum]
#
# @api private
- #
def match_length(other)
if eql?(other)
syntax.length
else
0
@@ -101,83 +37,29 @@
# @param [Expression] other
#
# @return [Boolean]
#
# @api private
- #
def prefix?(other)
!match_length(other).zero?
end
- # Register expression
+ # Try to parse input into expression of receiver class
#
- # @return [undefined]
- #
- # @api private
- #
- def self.register(regexp)
- REGISTRY[regexp] = self
- end
- private_class_method :register
-
- # Parse input into expression or raise
- #
- # @param [String] syntax
- #
- # @return [Expression]
- # if expression is valid
- #
- # @raise [RuntimeError]
- # otherwise
- #
- # @api private
- #
- def self.parse(input)
- try_parse(input) or fail InvalidExpressionError, "Expression: #{input.inspect} is not valid"
- end
-
- # Parse input into expression
- #
# @param [String] input
#
# @return [Expression]
- # if expression is valid
+ # when successful
#
# @return [nil]
# otherwise
#
# @api private
- #
def self.try_parse(input)
- expressions = expressions(input)
- case expressions.length
- when 0
- when 1
- expressions.first
- else
- fail AmbiguousExpressionError, "Ambiguous expression: #{input.inspect}"
- end
+ match = self::REGEXP.match(input)
+ return unless match
+ names = anima.attribute_names
+ new(Hash[names.zip(names.map(&match.method(:[])))])
end
-
- # Return expressions for input
- #
- # @param [String] input
- #
- # @return [Classifier]
- # if classifier can be found
- #
- # @return [nil]
- # otherwise
- #
- # @api private
- #
- def self.expressions(input)
- REGISTRY.each_with_object([]) do |(regexp, klass), expressions|
- match = regexp.match(input)
- next unless match
- expressions << klass.new(match)
- end
- end
- private_class_method :expressions
end # Expression
end # Mutant