class Cucumber::CucumberExpressions::CucumberExpression
def assert_no_optionals(node, &raise_error)
def assert_no_optionals(node, &raise_error) nodes = node.nodes.select { |ast_node| NodeType::OPTIONAL == ast_node.type } raise_error.call(nodes[0]) if nodes.length > 0 end
def assert_no_parameters(node, &raise_error)
def assert_no_parameters(node, &raise_error) nodes = node.nodes.select { |ast_node| NodeType::PARAMETER == ast_node.type } raise_error.call(nodes[0]) if nodes.length > 0 end
def assert_not_empty(node, &raise_error)
def assert_not_empty(node, &raise_error) text_nodes = node.nodes.select { |ast_node| NodeType::TEXT == ast_node.type } raise_error.call(node) if text_nodes.length == 0 end
def escape_regex(expression)
def escape_regex(expression) expression.gsub(ESCAPE_PATTERN, '\\\\\1') end
def initialize(expression, parameter_type_registry)
def initialize(expression, parameter_type_registry) @expression = expression @parameter_type_registry = parameter_type_registry @parameter_types = [] parser = CucumberExpressionParser.new ast = parser.parse(expression) pattern = rewrite_to_regex(ast) @tree_regexp = TreeRegexp.new(pattern) end
def match(text)
def match(text) Argument.build(@tree_regexp, text, @parameter_types) end
def regexp
def regexp @tree_regexp.regexp end
def rewrite_alternation(node)
def rewrite_alternation(node) # Make sure the alternative parts aren't empty and don't contain parameter types node.nodes.each { |alternative| raise AlternativeMayNotBeEmpty.new(alternative, @expression) if alternative.nodes.length == 0 assert_not_empty(alternative) { |ast_node| raise AlternativeMayNotExclusivelyContainOptionals.new(ast_node, @expression) } } regex = node.nodes.map { |n| rewrite_to_regex(n) }.join('|') "(?:#{regex})" end
def rewrite_alternative(node)
def rewrite_alternative(node) node.nodes.map { |last_node| rewrite_to_regex(last_node) }.join('') end
def rewrite_expression(node)
def rewrite_expression(node) regex = node.nodes.map { |n| rewrite_to_regex(n) }.join('') "^#{regex}$" end
def rewrite_optional(node)
def rewrite_optional(node) assert_no_parameters(node) { |ast_node| raise ParameterIsNotAllowedInOptional.new(ast_node, @expression) } assert_no_optionals(node) { |ast_node| raise OptionalIsNotAllowedInOptional.new(ast_node, @expression) } assert_not_empty(node) { |ast_node| raise OptionalMayNotBeEmpty.new(ast_node, @expression) } regex = node.nodes.map { |n| rewrite_to_regex(n) }.join('') "(?:#{regex})?" end
def rewrite_parameter(node)
def rewrite_parameter(node) name = node.text parameter_type = @parameter_type_registry.lookup_by_type_name(name) raise UndefinedParameterTypeError.new(node, @expression, name) if parameter_type.nil? @parameter_types.push(parameter_type) regexps = parameter_type.regexps return "(#{regexps[0]})" if regexps.length == 1 "((?:#{regexps.join(')|(?:')}))" end
def rewrite_to_regex(node)
def rewrite_to_regex(node) case node.type when NodeType::TEXT return escape_regex(node.text) when NodeType::OPTIONAL return rewrite_optional(node) when NodeType::ALTERNATION return rewrite_alternation(node) when NodeType::ALTERNATIVE return rewrite_alternative(node) when NodeType::PARAMETER return rewrite_parameter(node) when NodeType::EXPRESSION return rewrite_expression(node) else # Can't happen as long as the switch case is exhaustive raise "#{node.type}" end end
def source
def source @expression end
def to_s
def to_s source.inspect end