On 01/08/05, Garance A Drosehn <drosihn / gmail.com> wrote:
> On 8/1/05, Garance A Drosehn <drosihn / gmail.com> wrote:
> >
> > The downside to this is that the regular-expression is now
> > defined somewhere "far away" from the when-clause that
> > uses it.  After some testing I may need to make changes to
> > the regexp, such as:
> >
> >     re_simple = Regexp.new('(check|test) (\d+)')
> >
> > The thing is, by changing 'check' to '(check|test)', I have to
> > remember that the when clause also needs to change from
> > referencing $1 to referencing $2.  [...]
> >
> > I was kinda wondering if it would make sense for ruby to
> > support something like:
> >
> >     re_simple = Regexp.new('check (\d+)') { cnum = $1 }
> >
> > so I could then have the when clause say:
> >
> >             when re_simple
> >                 check_number = cnum
> >
> > I realize this is a trivial example, but as the expressions get
> > more involved, and the case-statement has many when's, it
> > would be nice if I could have the compiled regular-expression
> > set values on variable names that *I* pick, in addition to the
> > standard values in a MatchData object.
> 
> I thought about this some more after going home and getting
> some sleep...  One obvious question is what would be the
> scope of the commands inside the { ...code-fragment...}.  It
> also occurred to me that I sometimes I make a match, and
> then I pass around the resulting MatchData object to other
> methods, and *they* do things based on info in MatchData.
> 
> So, I came up with this idea:
> 
> Allow MatchData to include some user-settable value,
> which would initially be set to 'nil' at the time of the match.
> And then support:
> 
>     re_simple = Regexp.new('check (\d+)') { |mdata|
>         mdata.userdata = mdata[1]
>     }
> 
> or:
> 
>     re_simple = Regexp.new('check (\d+)') { |mdata|
>         mdata.userdata = Hash.new
>         mdata.userdata["cnum"] = mdata[1]
>         mdata.userdata["otherval"] = mdata[7]
>     }
> 
> That way, all the variables that the user is setting will
> be tied to the appropriate MatchData object.
> 
> I almost think I could implement this by creating my own
> subclasses for Regexp and MatchData...
> 

You could define it like this:

bschroed@black:~/svn/projekte/ruby-things$ cat regexp_data.rb 
class DataRegexp < Regexp
  def initialize(regexp, &block)
    @block = block
    @userdata = {}
    super(regexp)
  end
  
  def match(str)
    result = super(str)
    class <<result
      def userdata
        @userdata ||= {}
      end
    end
    @block[result] if @block
    result
  end
end

re_simple = DataRegexp.new('check (\d+)') { | mdata |
  mdata.userdata[:check_number] = mdata[1].to_i if mdata
}

if match = re_simple.match("Something")
  puts "Something matched"
end

if match = re_simple.match("check 12")
  puts "Checking #{match.userdata[:check_number]}"
end
bschroed@black:~/svn/projekte/ruby-things$ ruby regexp_data.rb 
Checking 12

regards,

Brian

-- 
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/