From: Jamis Buck Date: 2004-01-02T16:01:49+09:00 Subject: Re: nested methods and scope Joel VanderWerf wrote: > > I can't give much of an explanation of the rationale, but here's a way > to do what you were probably trying to do: > > def test_outer( a, b ) > self.class.instance_eval do > define_method :test_inner do > puts "#{a} and #{b}" > end > end > > test_inner( a+b ) > end > > test_outer( 1, 2 ) # ==> prints "1 and 2" > > The reason this works is that #define_method, unlike the def "special > form", takes a closure. You have to do the "self.class.instance_eval" > because #define_method is private. > That's clever -- thanks for the suggestion. :) In further research, I think I've discovered why the local environment of the declaring method aren't accessible. def outer def inner puts "hello" end end inner #-> displays "hello" The inner method is actually not declared within the scope of the (apparently) declaring method--it is promoted to exist at the same scope level of its declarer, and therefore is not really "inside" the method at all. I was hoping for a Pascal-like nesting of methods, which is not really what is happening here. I will frankly admit that there are no doubt lots of different ways to accomplish (more-or-less) what I was wanting to do, but the benefits of the way I original submitted (if it would work as I had hoped) are: 1) the inner method is inside the outer method's scope, and cannot be referenced from outside. I could make the 'inner' method private and declare it at the object scope, but then other methods of the object could invoke it... The way I'm proposing is actually even more restrictive than private access, and cannot be circumvented by using the 'instance_eval' trick. 2) the inner method could have complete access to the nesting methods local environment, including other nested methods (which, incidentally, works -- nested methods can call other nested methods in the same scope, they just can't access local variables declared at the same scope). This is really more of a theoretical question, though. I'm not actually attempting to do this for any practical reason, I'm just trying to "push the envelope" to see how much Ruby can do. :) -- Jamis Buck jgb3@email.byu.edu ruby -h | ruby -e 'a=[];readlines.join.scan(/-(.)\[e|Kk(\S*)|le.l(..)e|#!(\S*)/) {|r| a << r.compact.first };puts "\n>#{a.join(%q/ /)}<\n\n"'