# Scope when reopening method

**URL:** https://rubytalk.org/t/scope-when-reopening-method/60550
**Category:** ruby-talk
**Created:** [21 October 2010 07:23 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550 "2010-10-21T07:23:52Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![R\_Kumar](https://avatars.discourse-cdn.com/v4/letter/r/c0e974/32.png) [@R\_Kumar](https://rubytalk.org/u/R_Kumar)
#### Post date: [21 October 2010 07:23 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/1 "2010-10-21T07:23:52Z")

</div>

Here is a dummy class with a method "meth".

&nbsp;&nbsp;&nbsp;class My

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# str contains some value generated by My  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def meth str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def call\_meth  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;meth "abc"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;# ------ my application starts here

&nbsp;&nbsp;&nbsp;arr = []

&nbsp;&nbsp;&nbsp;m = My.new  
&nbsp;&nbsp;&nbsp;def m.meth(str)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# access some other object in application scope  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do\_something str # call some method in my app  
&nbsp;&nbsp;&nbsp;end

I have the method "meth" above which is of interest to user apps.  
The app overrides the method and would like to access methods or  
variables  
in my application scope.

Is there anyway this is possible (other than using global variables) ?  
To me it appears that meth() can only access what is in that objects  
scope plus globals. thx.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

### Author: ![Jesus\_Gabriel\_y\_Gala](https://avatars.discourse-cdn.com/v4/letter/j/96bed5/32.png) [@Jesus\_Gabriel\_y\_Gala](https://rubytalk.org/u/Jesus_Gabriel_y_Gala)
#### Post date: [21 October 2010 08:06 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/2 "2010-10-21T08:06:08Z")

</div>

If I understand correctly, you want the meth method defined for object  
a to be able to access methods and instance variables defined in the  
My class. Nothing special needs to be done:

irb(main):001:0\> class My  
irb(main):002:1\> def initialize  
irb(main):003:2\> @value = 3  
irb(main):004:2\> end  
irb(main):005:1\> def do\_something  
irb(main):006:2\> puts "my value is #{@value}"  
irb(main):007:2\> end  
irb(main):008:1\> def call\_meth  
irb(main):009:2\> meth "abc"  
irb(main):010:2\> end  
irb(main):011:1\> def meth str  
irb(main):012:2\> str \* 2  
irb(main):013:2\> end  
irb(main):014:1\> end  
=\> nil  
irb(main):015:0\> My.new.call\_meth  
=\> "abcabc"  
irb(main):016:0\> a = My.new  
irb(main):025:0\> def a.meth str  
irb(main):026:1\> do\_something  
irb(main):027:1\> str + @value.to\_s  
irb(main):028:1\> end  
=\> nil  
irb(main):029:0\> a.call\_meth  
my value is 3  
=\> "abc3"

Maybe I misunderstood the question.

Jesus.

> **···**
>
> On Thu, Oct 21, 2010 at 9:23 AM, Rahul Kumar \<sentinel1879@gmail.com\> wrote:
> 
> > Here is a dummy class with a method "meth".
> > 
> > class My
> > 
> > ```
> > \# str contains some value generated by My
> > def meth str
> > end
> > 
> > def call\_meth
> > meth &quot;abc&quot;
> > end
> > 
> > ```
> > 
> > end
> > 
> > # ------ my application starts here
> > 
> > arr =
> > 
> > m = My.new  
> > def m.meth(str)  
> > # access some other object in application scope  
> > arr \<\< str  
> > do\_something str # call some method in my app  
> > end
> > 
> > I have the method "meth" above which is of interest to user apps.  
> > The app overrides the method and would like to access methods or  
> > variables  
> > in my application scope.
> > 
> > Is there anyway this is possible (other than using global variables) ?  
> > To me it appears that meth() can only access what is in that objects  
> > scope plus globals. thx.

---

<div class="post-metadata">

### Author: ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)
#### Post date: [21 October 2010 08:32 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/3 "2010-10-21T08:32:27Z")

</div>

Rahul Kumar wrote in post #956000:

> &nbsp;&nbsp;&nbsp;class My
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# str contains some value generated by My  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def meth str  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def call\_meth  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;meth "abc"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;end
> 
> &nbsp;&nbsp;&nbsp;# ------ my application starts here
> 
> &nbsp;&nbsp;&nbsp;arr =
> 
> &nbsp;&nbsp;&nbsp;m = My.new  
> &nbsp;&nbsp;&nbsp;def m.meth(str)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# access some other object in application scope  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do\_something str # call some method in my app  
> &nbsp;&nbsp;&nbsp;end
> 
> I have the method "meth" above which is of interest to user apps.  
> The app overrides the method and would like to access methods or  
> variables  
> in my application scope.

By "My application scope", you mean the top-level scope? For example,  
you want methods inside instances of My to be able to access local  
variables like 'arr' ?

The simple answer(\*) is that you can't - each 'def' method and 'class'  
definition starts its own local variable scope. That's why they're  
called "local" variables 🙂

You should pass references to those objects explicitly when needed. For  
example:

class My  
&nbsp;&nbsp;def initialize(arr)  
&nbsp;&nbsp;&nbsp;&nbsp;@arr = arr  
&nbsp;&nbsp;end

&nbsp;&nbsp;def meth(str)  
&nbsp;&nbsp;&nbsp;&nbsp;@arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;do\_something str  
&nbsp;&nbsp;end  
end

Because everything in Ruby is an object reference, you are only copying  
the reference, not copying the entire object. So @arr \<\< str modifies  
the same array that arr \<\< str did before.

Or you could just pass the object reference only when needed:

&nbsp;&nbsp;def meth(str, arr)  
&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;do\_something str  
&nbsp;&nbsp;end

It depends on the cleanest way to encapsulate the logic you're  
implementing.

> Is there anyway this is possible (other than using global variables) ?  
> To me it appears that meth() can only access what is in that objects  
> scope plus globals. thx.

Not exactly: meth() can only access local variables in that \*method's\*  
scope, plus instance variables of the object (@foo), plus global  
variables ($bar)

Generally you want to avoid global variables at all costs. At worst, you  
can use an instance variable of the class object (since the class itself  
is an object)

class Foo  
&nbsp;&nbsp;def self.bar=(x)  
&nbsp;&nbsp;&nbsp;&nbsp;@bar=x  
&nbsp;&nbsp;end  
&nbsp;&nbsp;def self.bar  
&nbsp;&nbsp;&nbsp;&nbsp;@bar  
&nbsp;&nbsp;end  
end

Foo.bar = 123  
puts Foo.bar

This is like a global variable, but at least it's qualified by class  
'Foo' so you know you're not stamping on any other global variable.

Regards,

Brian.

(\*) The long answer is you can break this rule using eval and binding,  
e.g. TOPLEVEL\_BINDING, but you really don't want to do that.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

### Author: ![R\_Kumar](https://avatars.discourse-cdn.com/v4/letter/r/c0e974/32.png) [@R\_Kumar](https://rubytalk.org/u/R_Kumar)
#### Post date: [21 October 2010 08:36 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/4 "2010-10-21T08:36:14Z")

</div>

Yes, you have misunderstood. "meth" already has access to its own  
variables.  
There is an application that creates an instance of My.  
It also contains an array "arr". I'd like to refer to that array within  
the reopened "meth".  
I would also like to call some methods that are in my app from the  
reopened method.

&nbsp;&nbsp;&nbsp;# i create an array that is not inside My class. Its in my  
application.  
&nbsp;&nbsp;&nbsp;arr = []

&nbsp;&nbsp;&nbsp;# this method belongs to my app, not to My class  
&nbsp;&nbsp;&nbsp;def do\_something str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts str  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;m = My.new  
&nbsp;&nbsp;&nbsp;def m.meth(str)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# access some other object in application scope  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# arr can be instance variable or local variable in application  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do\_something str # call some method in my app  
&nbsp;&nbsp;&nbsp;end

Hope i am clear. thx.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

### Author: ![R\_Kumar](https://avatars.discourse-cdn.com/v4/letter/r/c0e974/32.png) [@R\_Kumar](https://rubytalk.org/u/R_Kumar)
#### Post date: [21 October 2010 08:43 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/5 "2010-10-21T08:43:32Z")

</div>

Brian Candler wrote in post #956015:

> The simple answer(\*) is that you can't - each 'def' method and 'class'  
> definition starts its own local variable scope. That's why they're  
> called "local" variables 🙂
> 
> Or you could just pass the object reference only when needed:
> 
> &nbsp;&nbsp;def meth(str, arr)  
> &nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
> &nbsp;&nbsp;&nbsp;&nbsp;do\_something str  
> &nbsp;&nbsp;end
> 
> It depends on the cleanest way to encapsulate the logic you're  
> implementing.

Thanks. I understand that one way is to pass a reference to an object to  
My.

The second option of when needed wont work since My will call meth() at  
some point that i don't know. I would have liked to leave meth() blank  
so that callers can do what they want there.

Another approach I had is to pass a block in advance which is stored,  
meth calls that block.

However, i had sort of hoped somehow the reopened method could access  
scope of the class that was reopening it. You have clearly explained  
that it is operating in the space of the class itself. So no magic can  
happen here ☹

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

### Author: ![Jesus\_Gabriel\_y\_Gala](https://avatars.discourse-cdn.com/v4/letter/j/96bed5/32.png) [@Jesus\_Gabriel\_y\_Gala](https://rubytalk.org/u/Jesus_Gabriel_y_Gala)
#### Post date: [21 October 2010 08:46 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/6 "2010-10-21T08:46:21Z")

</div>

> Yes, you have misunderstood. "meth" already has access to its own  
> variables.  
> There is an application that creates an instance of My.  
> It also contains an array "arr". I'd like to refer to that array within  
> the reopened "meth".  
> I would also like to call some methods that are in my app from the  
> reopened method.

OK. Clear.

> # i create an array that is not inside My class. Its in my  
> application.  
> arr =
> 
> # this method belongs to my app, not to My class  
> def do\_something str  
> puts str  
> end
> 
> m = My.new  
> def m.meth(str)  
> # access some other object in application scope  
> # arr can be instance variable or local variable in application  
> arr \<\< str  
> do\_something str # call some method in my app  
> end

You could create a closure around your global scope. For that, you  
need to avoid keywords such as class and def, because those do not  
create closures, but create a new scope. You can try something like  
this:

irb(main):001:0\> arr = [1,2,3]  
=\> [1, 2, 3]  
irb(main):002:0\> a = Object.new  
=\> #\<Object:0xb7505264\>  
irb(main):003:0\> class Object  
irb(main):004:1\> def metaclass; class \<\< self; self; end  
irb(main):005:2\> end  
irb(main):006:1\> end  
=\> nil  
irb(main):008:0\> a.metaclass.instance\_eval { define\_method(:something)  
{ "the array #{arr.inspect}"}}  
=\> #\<Proc:0xb74d783c@(irb):8\>  
irb(main):009:0\> a.something  
=\> "the array [1, 2, 3]"

Jesus.

> **···**
>
> On Thu, Oct 21, 2010 at 10:36 AM, Rahul Kumar \<sentinel1879@gmail.com\> wrote:

---

<div class="post-metadata">

### Author: ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)
#### Post date: [21 October 2010 08:58 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/7 "2010-10-21T08:58:47Z")

</div>

Rahul Kumar wrote in post #956019:

> The second option of "when needed" wont work since My will call meth()  
> at  
> some point that i don't know. I would have liked to leave meth() blank  
> so that callers can do what they want there.

Yes, so my suggested solution would be to pass arr at the time the  
object is instantiated:

&nbsp;&nbsp;&nbsp;arr =

&nbsp;&nbsp;&nbsp;m = My.new(arr) # \<\<\< NOTE  
&nbsp;&nbsp;&nbsp;def m.meth(str)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# access some other object in application scope  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do\_something str # call some method in my app  
&nbsp;&nbsp;&nbsp;end

i.e. you squirrel it away in an instance variable for later use.

> However, i had sort of hoped somehow the reopened method could access  
> scope of the class that was reopening it. You have clearly explained  
> that it is operating in the space of the class itself. So no magic can  
> happen here ☹

Well, the particular example you showed \*can\* be made to work, using  
define\_method() instead of def. That doesn't open a new scope, and so  
you have a closure, i.e. access to all the local variables in the  
enclosing scope.

&nbsp;&nbsp;&nbsp;arr =

&nbsp;&nbsp;&nbsp;m = My.new  
&nbsp;&nbsp;&nbsp;class \<\<m;self;end.class\_eval do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;define\_method(:meth) do |str|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# access some other object in application scope  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts str # call some method in my app  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;m.meth "hello"  
&nbsp;&nbsp;&nbsp;puts arr.inspect

However I would consider this to be "advanced" ruby, and would advise  
against it unless it's really needed. There may be a simpler solution to  
the way you've designed your application.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

### Author: ![John\_Mair](https://avatars.discourse-cdn.com/v4/letter/j/ac91a4/32.png) [@John\_Mair](https://rubytalk.org/u/John_Mair)
#### Post date: [23 October 2010 05:49 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/8 "2010-10-23T05:49:38Z")

</div>

arr = []  
&nbsp;&nbsp;&nbsp;&nbsp;m = My.new

&nbsp;&nbsp;&nbsp;&nbsp;m.define\_singleton\_method(:meth) do |str|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
&nbsp;&nbsp;&nbsp;&nbsp;end

John

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

### Author: ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)
#### Post date: [23 October 2010 12:26 UTC](https://rubytalk.org/t/scope-when-reopening-method/60550/9 "2010-10-23T12:26:54Z")

</div>

John Mair wrote in post #956482:

> arr =   
> &nbsp;&nbsp;&nbsp;&nbsp;m = My.new
> 
> &nbsp;&nbsp;&nbsp;&nbsp;m.define\_singleton\_method(:meth) do |str|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr \<\< str  
> &nbsp;&nbsp;&nbsp;&nbsp;end

Not in 1.8.7 though.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
