verbal_expressions icon indicating copy to clipboard operation
verbal_expressions copied to clipboard

"Alternatively" gives unexpected behaviour

Open tom-lord opened this issue 10 years ago • 0 comments

def alternatively(value = nil)
  @prefixes += "(?:" unless @prefixes.include?("(")
  @suffixes = ")" + @suffixes unless @suffixes.include?(")")
  add(")|(?:")
  find(value) if value
end

I don't like this abuse of the @prefixes and @suffixes. Especially given that we also have the methods:

def start_of_line(enable = true)
  @prefixes = '^' if enable
end

def end_of_line(enable=true)
  @suffixes = '$' if enable
end

For example, the following code creates an invalid RegEx:

VerEx.new do
  find 'a'
  alternatively
  find 'b'
  end_of_line
end

(The @suffixes gets overwritten by end_of_line, so we are left with a trailing bracket.)

There were two possible solutions to this: Fix the end_of_line method by using += rather than just =, or (what I chose to do instead):

def start_of_line
  add('^')
end

def end_of_line
  add('$')
end

This gives the important added benefit that we can now match start/end of lines in the middle of strings!


However, with the new code I wrote, we can still end up with slightly unexpected behaviour such as:

VerEx.new do
  start_of_line
  find 'a'
  alternatively
  find 'b'
end
#=> /(?:^a)|(?:b)

Rather than ^(?:a)|(?:b)/, as one might expect. In order to achieve this, our VerEx would have needed to be:

VerEx.new do
  start_of_line
  find 'a'
  alternatively
  start_of_line
  find 'b'
end
#=> /(?:^a)|(?^:b)

This is a slight change in behaviour. Basically, to cut a long story short, this alternatively method may be simple and powerful, but must be used with caution. A little usage example, such as the one I gave above, would be a good idea for the README.

tom-lord avatar Jun 07 '14 20:06 tom-lord