Created
March 10, 2012 21:35
-
-
Save artm/2013370 to your computer and use it in GitHub Desktop.
Subpattern wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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