Skip to content

Instantly share code, notes, and snippets.

@artm
Created March 10, 2012 21:35
Show Gist options
  • Save artm/2013370 to your computer and use it in GitHub Desktop.
Save artm/2013370 to your computer and use it in GitHub Desktop.
Subpattern wrapper
class GroupWrap
def initialize(&block)
@wrap = block
@transformers = []
end
def handle(pattern, *tags)
@transformers << [pattern, *tags]
end
def range_tree(m, tags)
stack = []
tree = []
(1...m.length).each do |i|
r = { :begin => m.begin(i), :end => m.end(i), :tag => tags[i], :children => [] }
catch :inserted do
while !stack.empty?
if stack.last[:end] <= r[:begin] &&
stack.pop
else
# nest
stack.last[:children] << r
stack.push r
throw :inserted
end
end
stack.push r
tree << r
end
end
tree
end
def recursive_wrap(str, range, from=0, to=str.length)
if range == []
"#{str[from...to]}"
elsif Hash === range
@wrap.call(
recursive_wrap(str, range[:children], range[:begin], range[:end]),
range[:tag])
else
# handling a list of trees
cursor = from
accu = ""
range.each do |range|
replacement = recursive_wrap(str, range)
accu += str[cursor...range[:begin]] + replacement
cursor = range[:end]
end
accu += str[cursor...to]
end
end
def process(str)
@transformers.each do |tags|
pattern = tags[0]
pattern.match(str) do |m|
return recursive_wrap(str, range_tree(m, tags))
end
end
str
end
end
require 'rspec'
require './groupwrap'
describe GroupWrap do
gw = GroupWrap.new { |s, tag|
case tag
when :paren
"(#{s})"
when :bracket
"[#{s}]"
end
}
it "should wrap groups" do
gw.handle( /^E (\d+) (\w+)/, :paren, :bracket )
gw.handle( /^W (\d+) (\w+)/, :bracket, :paren )
gw.process("E 12 foo 1").should == "E (12) [foo] 1"
gw.process("W 12 foo 2").should == "W [12] (foo) 2"
end
it "should deal with nested groups properly" do
gw.handle( /^N (\w+?(\d+)\w+)/, :bracket, :paren )
gw.handle( /^NN (\w+?(\d+(\w+?)\d+)\w+)/, :bracket, :paren, :bracket )
gw.process("N foo12bar tail").should == "N [foo(12)bar] tail"
gw.process("NN foo12quux13bar tail").should == "NN [foo(12[quux]13)bar] tail"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment