Skip to content

Instantly share code, notes, and snippets.

@jedediah
Created October 16, 2009 07:00
Show Gist options
  • Save jedediah/211626 to your computer and use it in GitHub Desktop.
Save jedediah/211626 to your computer and use it in GitHub Desktop.
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
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