public
Last active

big_pattern_matcher

  • Download Gist
big_pattern_matcher.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
# -*- coding: utf-8 -*-
 
# Given multiple regular expressions and a string to match them
# against, call a method on a receiver that corresponds to the matched
# expression.
#
# see example.rb
 
class BigPatternMatcher
 
def initialize(patterns_and_functions, no_match_function)
@regex = make_big_regex(patterns_and_functions)
@no_match_function = no_match_function
end
def match(s, context)
match = @regex.match(s)
context.send(function_name(match), match)
end
 
private
 
FUNC_GROUP_PREFIX = "func_"
FUNC_GROUP_REGEX = /^#{FUNC_GROUP_PREFIX}(.*)$/
 
def function_name(match)
if match
match.names.grep(FUNC_GROUP_REGEX).find do |name|
match[name]
end[FUNC_GROUP_REGEX, 1]
else
@no_match_function
end
end
 
def make_big_regex(patterns_and_functions)
patterns = patterns_and_functions.map do |pattern, function|
/(?<#{FUNC_GROUP_PREFIX}#{function}>#{pattern.source})/
end
Regexp.union(patterns)
end
 
end
big_pattern_matcher_spec.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
# -*- coding: utf-8 -*-
 
require_relative 'big_pattern_matcher'
 
describe BigPatternMatcher do
let(:receiver) do
Class.new do
 
attr_reader :method
 
def method_missing(method, *args)
if @match_group
@match_group[method]
else
@method = method
@match_group = args.first
end
end
 
end.new
end
 
let(:matcher) {BigPatternMatcher.new(patterns, :no_match)}
 
before(:each) do
matcher.match(string, receiver)
end
 
subject {receiver}
 
context "when no patterns" do
 
let(:patterns) do
[]
end
 
let(:string) {''}
its(:method) {should == :no_match}
 
end
 
context "when two simple patterns with no match groups" do
 
let(:patterns) do
[
[/foo/, :foo],
[/bar/, :bar],
]
end
 
context 'when matching the first pattern' do
let(:string) {'abc foo xyz'}
its(:method) {should == :foo}
end
 
context 'when matching the second pattern' do
let(:string) {'abc bar xyz'}
its(:method) {should == :bar}
end
 
context 'when both patterns present' do
let(:string) {'foobar'}
its(:method) {should == :foo}
end
 
end
 
context "when patterns with match groups" do
 
let(:patterns) do
[
[/foo(?<number>\d+)/, :foo],
[/bar(?<number>\d+)/, :bar],
]
end
 
context 'when matching the first pattern' do
let(:string) {'foo123'}
its(:method) {should == :foo}
its(:number) {should == '123'}
end
 
context 'when matching the second pattern' do
let(:string) {'bar456'}
its(:method) {should == :bar}
its(:number) {should == '456'}
end
 
end
 
end
example.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
 
require_relative 'big_pattern_matcher'
 
PATTERNS_AND_FUNCTIONS = [
[/ABC(?<value>\d+)/, :foo],
[/DEF(?<value>\d+)/, :bar],
]
 
def foo(match)
p ["foo", match[:value]]
end
 
def bar(match)
p ["bar", match[:value]]
end
 
def no_match(match)
p "no match"
end
 
matcher = BigPatternMatcher.new(PATTERNS_AND_FUNCTIONS, :no_match)
matcher.match('blah ABC1 blah', self) # => ["foo", "1"
matcher.match('blah DEF2 blah', self) # => ["bar", "2"]
matcher.match('blah blah', self) # => "no_match"

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.