There is no such thing as a method inside a method. When you wirte ‘def
hi’,
you actually define the method ‘hi’ at the same level than the method
‘go2’.
So, the later cannot acces the data of the former. However, as they are
defined at the same level, they can share data from the instance
variables of
the class they are defined in.
go2 ‘Larry’ ==>> NameError: undefined local variable or method `arg’ for
main:Object
In go2, is there a clean way for the hi method to have access to the
arg local?
Hi,
you may try something using 1. blocks, 2. passing actual binding, 3.
there was something called binding of caller, but I’m not sure whether
it still works, as it was based on a bug in ruby implementation.
Maybe if you post a bit higher perspective on your problem somebody
would come up with a solution…
Thank you for your help. To keep things dry, my main method uses one of
a number of methods, depending on the value of an argument. A hash is
used as a selector to choose the right child method.
The child methods need some data, I wanted to see how they could gain
access to the locals of the calling method, ie, the main method.
I appreciate the posts; I’ll continue to pass the arguments, which is
working fine.
Btw, I find it a bit lacking that the syntax checker allows me to
declare a method inside another method since such things don’t exist.
(Per Olivier’s helpful post.)
go2 ‘Larry’ ==>> NameError: undefined local variable or method `arg’ for
main:Object
In go2, is there a clean way for the hi method to have access to the
arg local?
def always starts a new local scope. If you want to define a method
but in the same scope, you need to use define_method, probably in
conjunction with class_eval or module_eval on the class or module you
want to put it in.
The child methods need some data, I wanted to see how they could gain
definition isn’t scoped to the outer definition. This is relatively
new (1.8.6, if I remember correctly), and made it easier to do
something that was always possible anyway with class_eval +
define_method.
ISTR def foo; def bar; end; end working in 1.8.4 and possibly even
1.8.2. (I didn’t hop aboard the ruby train before 1.8.2 though). I
know I’ve used def foo; def bar before 1.8.6.
Btw, I find it a bit lacking that the syntax checker allows me to
declare a method inside another method since such things don’t exist.
(Per Olivier’s helpful post.)
I wouldn’t say it doesn’t exist; it’s just that the lexically inner
definition isn’t scoped to the outer definition. This is relatively
new (1.8.6, if I remember correctly), and made it easier to do
something that was always possible anyway with class_eval +
define_method.
The general concept involved is that of a closure and it is certainly
possible to define closures in ruby and at some point or another someone
pointed out a way of turning closures into methods I don’t remember how
though.
Ok, just ignore all my previous posts. I should have done some more
research
before I started typing. This code will actually work.
def go2(arg)
(class << self; self; end).class_eval do
define_method(:hi) do puts “Hi #{arg}” end
end
end
Once you call go2 with some argument it will create the method hi that
will
have access to any argument passed to go2. I have to say though all the
redirection with the singleton class makes my head spin a little.
have access to any argument passed to go2. I have to say though all the
redirection with the singleton class makes my head spin a little.
This isn’t quite the same as doing an inner def, because you’re
defining #hi as a singleton method. If you want to define it as an
instance method of the enclosing class, you would want to do:
self.class.class_eval do …
As for the head spinning, hopefully someday we’ll have this method in
the core (and meanwhile you can write it yourself):
class Object
def singleton_class
class << self; self; end
end
end
Then you can do:
singleton_class.class_eval do …
which is a little less cluttered. Also, keep in mind that it’s not
really redirection; it’s just sending messages to objects The fact
that you can send messages to Class objects means that you can do what
feels like “meta” stuff in much the same way that you do other things.
Maybe you can answer another question. While trying to figure this out I
kept running into scoping issues. The first thing that popped into my
head
was
def go2(arg)
clos = proc {puts “Hi #{arg}”}
class << self
define_method(:hi,clos)
end
end
but this didn’t work because for some reason when I’m inside the scope
of
class << self … end define_method can’t find clos even though it is
inside
the enclosing scope. Is there a reason classes don’t close over their
enclosing scope because I was thinking just like we can have closures we
could also have closures for classes.
but this didn’t work because for some reason when I’m inside the scope of
class << self … end define_method can’t find clos even though it is inside
the enclosing scope. Is there a reason classes don’t close over their
enclosing scope because I was thinking just like we can have closures we
could also have closures for classes.
The class keyword always starts a new local scope, but class_eval
doesn’t:
x = 1
Object.class_eval { puts x } # 1
class/class_eval is analogous to def/define_method. class and def
start new local scopes; class_eval and define_method don’t.
I wouldn’t say it doesn’t exist; it’s just that the lexically inner
definition isn’t scoped to the outer definition. This is relatively
new (1.8.6, if I remember correctly), and made it easier to do
something that was always possible anyway with class_eval +
define_method.
ISTR def foo; def bar; end; end working in 1.8.4 and possibly even
1.8.2. (I didn’t hop aboard the ruby train before 1.8.2 though). I
know I’ve used def foo; def bar before 1.8.6.
I think I meant to type 1.8.4, though I’m semi-guessing anyway. I do
seem to remember that it was an intra-1.8 change, rather than as
between 1.6 and 1.8, but I’m not sure.
David
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.