On Mon, 2007-01-29 at 14:41 +0900, Nasir Khan wrote:
> Please look at this snippet -
> 
> --------------------------------
> class Test
> 
>   def initialize
>     @hash = {}
>   end
> 
>   def method_missing(m,*a)
>     if m.to_s =~ /=$/
>       Test.class_eval do
>         define_method($`.to_sym) do  #accessor
>           @hash[$`.to_sym]
>         end
>         define_method(m) do |arg| #mutator
>           @hash[$`.to_sym] = arg.split(",")
>         end
>       end
>       send m, *a
>     else
>       raise NoMethodError, "#{m}"
>     end
>   end
> end
> 
> t = Test.new
> t.a = "hello"
> puts t.a
> 
[snip]
> First of all can anyone please explain why it runs with debugger while fails
> with normal interpreter?
> 
> Second what is wrong with the snippet?

Perhaps you already know this, but using a local variable in place of $`
fixes your code:

class Test

  def initialize
    @hash = {}
  end

  def method_missing(m,*a)
    if m.to_s =~ /=$/
      key = $` #added here
      Test.class_eval do
        define_method(key.to_sym) do  #accessor
          @hash[key.to_sym]
        end
        define_method(m) do |arg| #mutator
          @hash[key.to_sym] = arg.split(",")
        end
      end
      send m, *a
    else
      raise NoMethodError, "#{m}"
    end
  end
end

t = Test.new
t.a = "hello,world"
puts t.a

$` is getting clobbered when you go into Test.class_eval so it gets set
to nil. Why this is different to a local variable I'm not sure to be
honest (ditto for why debug mode should be different).

As a related, follow up question, can someone explain the difference
between the two class_evals in the following snippet (one works, the
other doesn't):

"foo".match(/oo/)

class Test
end

Test.class_eval do
  define_method($`.to_sym) do
    puts $` + "oobared"
  end
end
Test.new.f

class Test
  class_eval do
    define_method($`.to_sym) do
      puts $` + "oobared"
    end
  end
end

-- 
Alex Gutteridge
Kyoto University