Created
October 16, 2009 07:00
-
-
Save jedediah/211626 to your computer and use it in GitHub Desktop.
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
module RegexpBuilder | |
module RegexpExt | |
class Builder | |
class RegexpSource | |
def initialize x | |
@src = if x.is_a? self.class | |
x.to_s | |
else | |
x | |
end | |
end | |
def self.coerce x | |
if x.is_a? self | |
x | |
elsif x.respond_to? :source | |
new x.source | |
elsif x.respond_to? :to_str | |
new Regexp.quote x | |
else | |
new x | |
end | |
end | |
def to_s | |
@src | |
end | |
alias to_str to_s | |
def method_missing meth, *args, &block | |
self.class.new @src.send(meth,*args,&block) | |
end | |
end | |
def initialize | |
@preamble = '' | |
end | |
def build opts=0, &block | |
re = instance_exec &block | |
::Regexp.compile "#{@preamble}#{coerce re}", opts | |
end | |
def self.build opts=0, &block | |
new.build opts, &block | |
end | |
def regexp x | |
RegexpSource.new x | |
end | |
def coerce x | |
RegexpSource.coerce x | |
end | |
def concat *a | |
a.reduce(regexp ''){|acc,re| acc << coerce(re) } | |
end | |
alias cat concat | |
def alternate *a | |
regexp a.map{|re| "(?:#{coerce re})" }.join('|') | |
end | |
alias alt alternate | |
def zero_or_more re | |
regexp "(?:#{coerce re})*" | |
end | |
alias zom zero_or_more | |
def zero_or_one re | |
regexp "(?:#{coerce re})?" | |
end | |
alias zoo zero_or_one | |
alias optional zero_or_one | |
alias opt zero_or_one | |
def one_or_more re | |
regexp "(?:#{coerce re})+" | |
end | |
alias oom one_or_more | |
def repeat n, re | |
regexp "(?:#{coerce re}){#{if n.respond_to? :first | |
"#{n.first},#{n.last}" | |
else | |
n | |
end}}" | |
end | |
alias rep repeat | |
def capture re=nil | |
regexp "(#{coerce(if block_given? then yield else re end)})" | |
end | |
alias cap capture | |
def define id | |
if block_given? | |
@preamble << "(?<#{id}>#{coerce yield}){0}" | |
else | |
id.each do |k,v| | |
@preamble << "(?<#{k}>#{coerce v}){0}" | |
end | |
end | |
nil | |
end | |
def method_missing meth | |
regexp "\\g<#{meth}>" | |
end | |
end | |
end | |
module RegexpClassExt | |
def build opts=0, &block | |
RegexpExt::Builder.build opts, &block | |
end | |
end | |
end | |
class Regexp | |
include RegexpBuilder::RegexpExt | |
extend RegexpBuilder::RegexpClassExt | |
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
re = Regexp.build do | |
define :parens do | |
cat '(', expr, ')' | |
end | |
define :expr do | |
cat term, zero_or_more(cat /[+-]/, term) | |
end | |
define :term do | |
cat value, zero_or_more(cat /[*\/]/, value) | |
end | |
define :value do | |
alt integer, parens | |
end | |
define :integer => /\d+/ | |
expr | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment