Eric C. wrote in post #983739:
On Thu, Feb 24, 2011 at 2:59 PM, 7stud – [email protected]
comp1 = Computer.new(1, DataSource.new)
+': can't convert nil into String (TypeError) from t.rb:32:inmouse’
I’m not sure of the specifics, but $1 doesn’t persist outside of the
block created in the grep statement. When you call comp1.mouse, that’s
no longer within that block – the method was defined in it, but once
it was made a method it took on an existence of its own.
$1 is a global variable, so saying it doesn’t persist outside of a
block doesn’t make any sense.
I think what is happening is that the body of the define_method() call
forms a closure around the variable $1. Unfortunately, the problem with
global variables is that other parts of the code can change their value.
In this instance, I think what is happening is that a subsequent
unsuccessful pattern match assigns nil to $1. Here is an example of
arr = [“hello”]
arr.each do |x|
x =~ /h(.)ll/
puts $1 #=>e
puts $1 #=>e
“hello” =~ /xxx/
puts $1 #=>nil
There are a lot of other methods in the DataSource class, which are
inherited by all classes, and the last method in the list of methods
traversed by grep() must not be one of the methods I defined, so the
pattern match fails against the last method name, and $1 gets set to
nil. Subsequently, when I call the mouse() method, it reads the current
value of $1, which is nil.
On the other hand, when I assign $1 to a local variable, like ‘name’,
‘name’ does not become a reference to $1–instead ‘name’ gets assigned a
copy of $1’s value at the instant the method is created. Furthermore,
because ‘name’ is a local variable, each method created by
define_method() gets its own ‘name’ variable in the method body.