what's the diff between puts y and puts "#{y}" in class_eval

R

Raj Singh

Look at the code.

y = " another hi"

class Wes
end

Wes.class_eval <<-END
def hello
puts "#{y}"
puts y # I get wrong number of arguments error
end
END


While puts "#{y}" works puts y fails. And I am not sure what's the
explanation.

Any thoughts.
 
R

Raj Singh

Hi Matz,

Thanks for the answer but I couldn't quite follow it.

It seems that you are suggesting that the scope of "#{y}" is different
from the scope of plain vanilla 'y' in "puts y".

Could you please further elaborate on that. To me it seems like both of
them have the same scope because they are both being used in the same
method.
 
R

Ryan Ingram

Could you please further elaborate on that. To me it seems like both of
them have the same scope because they are both being used in the same
method.

Compare to this:

class T
def first
"hello"
end
def second
"chunky bacon"
end
end

y = "first"

T.class_eval <<-END
def hello
puts #{y}
end
END

T.new.hello # prints "hello"

The key is that the "<<-END" is creating an interpolated string in the
original context; the interpolation of #{y} isn't happening during the
call to "hello", but rather as part of the string passed to
class_eval.

You are probably confused by the fact that in the sample code, the
interpolation is happening inside of another string constant, which
makes it look like it's happening as part of "hello". It's not.

-- ryan
 
7

7stud --

Ryan said:
Compare to this:

class T
def first
"hello"
end
def second
"chunky bacon"
end
end

y = "first"

T.class_eval <<-END
def hello
puts #{y}
end
END

T.new.hello # prints "hello"

The key is that the "<<-END" is creating an interpolated string in the
original context; the interpolation of #{y} isn't happening during the
call to "hello", but rather as part of the string passed to
class_eval.

You are probably confused by the fact that in the sample code, the
interpolation is happening inside of another string constant, which
makes it look like it's happening as part of "hello". It's not.

-- ryan

Thanks for the explanation, I've been watching this thread and waiting
for an explanation that I could comprehend. If I understand your
explanation correctly, the steps are:

1) The substitution in the string:

str =<<STR
def hello
puts #{y}
end
STR

is performed. The scope is the global scope, so the string becomes:

str =<<STR
def hello
puts first
end
STR

2) The string is class_eval'ed in the scope of class T, producing:

class T
def first
"hello"
end

def second
"chunky bacon"
end

def hello
puts first
end
end

3) When the method hello is called, the line:

puts first

outputs the return value of the first method.


Applying those steps to the op's example:
y = " another hi"

class Wes
end

Wes.class_eval <<-END
def hello
puts "#{y}"
puts y # I get wrong number of arguments error
end
END

1) The string:
<<-END
def hello
puts "#{y}"
puts y # I get wrong number of arguments error
end
END

becomes:

<<-END
def hello
puts "another hi"
puts y # I get wrong number of arguments error
end
END

2) The class Wes is transformed into:

class Wes
def hello
puts "another hi"
puts y
end
end

3) Then a statement such as:

w = Wes.new
w.hello

produces an error because there is no variable or method named 'y'
inside class Wes:


rb:4:in `hello': undefined local variable or method `y' for
#<Wes:0x25328> (NameError)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top