# Object#instance\_eval but better

**URL:** <https://rubytalk.org/t/object-instance-eval-but-better/49818>\
**Category:** ruby-talk\
**Created:** [24 October 2008 17:55 UTC](https://rubytalk.org/t/object-instance-eval-but-better/49818 "2008-10-24T17:55:13Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Richard\_Crowley](https://avatars.discourse-cdn.com/v4/letter/r/ecd19e/32.png) [@Richard\_Crowley](https://rubytalk.org/u/Richard_Crowley)\
**Post date:** [24 October 2008 17:55 UTC](https://rubytalk.org/t/object-instance-eval-but-better/49818/1 "2008-10-24T17:55:13Z")

</div>

I have a bit of code here that I'd love to make better:

class Foo  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(path)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.instance\_eval(File.read(path))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
end

I don't want to continue down the path of reading an entire file into a string and then eval'ing that string just to get the contents of the file executed as if it were the body of a method in a class. The file passed to the constructor above might contain something like:

@foo = 'This will become an instance variable when you do Foo.new(path)'

I've tried all manner of hacks to make Kernel#load and friends execute code as if it were in the calling scope. In every case I've seen the loaded file leave no lasting effect on the instance variables of the calling method. My goal is to be able to do exactly this:

class Foo  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(path)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;load\_in\_scope path  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
end  
f = Foo.new('load\_me.rb')  
f.instance\_variables # =\> ['@foo']

My assumption here is that reading a file into a string and eval'ing it is very slow and is bad form. Am I right?

Is this possible without reading the file into a string? Is this possible without hacking the C code? Should I go bother ruby-core?

Thanks,

Richard

---

<div class="post-metadata">

**Author:** ![7rans](https://avatars.discourse-cdn.com/v4/letter/7/a8b319/32.png) [@7rans](https://rubytalk.org/u/7rans)\
**Post date:** [24 October 2008 18:08 UTC](https://rubytalk.org/t/object-instance-eval-but-better/49818/2 "2008-10-24T18:08:45Z")

</div>

Ultimately, it's the same thing, whether you do it in Ruby or C. I  
doubt it would be that much faster in C than it is in pure Ruby b/c it  
is dynamic --the path can change. However, you may actually intend:

&nbsp;&nbsp;class Foo  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(path)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eval(File.read(path), \_\_FILE\_\_, \_\_LINE\_\_)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

T.

> **···**
>
> On Oct 24, 1:55 pm, Richard Crowley \<r...@rcrowley.org\> wrote:
> 
> > I have a bit of code here that I'd love to make better:
> > 
> > class Foo  
> > def initialize(path)  
> > self.instance\_eval(File.read(path))  
> > end  
> > end
> > 
> > I don't want to continue down the path of reading an entire file into a  
> > string and then eval'ing that string just to get the contents of the  
> > file executed as if it were the body of a method in a class. The file  
> > passed to the constructor above might contain something like:
> > 
> > @foo = 'This will become an instance variable when you do Foo.new(path)'
> > 
> > I've tried all manner of hacks to make Kernel#load and friends execute  
> > code as if it were in the calling scope. In every case I've seen the  
> > loaded file leave no lasting effect on the instance variables of the  
> > calling method. My goal is to be able to do exactly this:
> > 
> > class Foo  
> > def initialize(path)  
> > load\_in\_scope path  
> > end  
> > end  
> > f = Foo.new('load\_me.rb')  
> > f.instance\_variables # =\> ['@foo']
> > 
> > My assumption here is that reading a file into a string and eval'ing it  
> > is very slow and is bad form. Am I right?
> > 
> > Is this possible without reading the file into a string? Is this  
> > possible without hacking the C code? Should I go bother ruby-core?

---

<div class="post-metadata">

**Author:** ![a11](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/a11/32/8169_2.png) [@a11](https://rubytalk.org/u/a11)\
**Post date:** [26 October 2008 04:41 UTC](https://rubytalk.org/t/object-instance-eval-but-better/49818/3 "2008-10-26T04:41:52Z")

</div>

reverse your logic: don't force the code to eval inside a context - provide the context.

cfp:~ \> cat a.rb  
class Foo  
&nbsp;&nbsp;&nbsp;class \<\< self  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attr\_accessor :current

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initializing &block  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;caller = eval 'self', block

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if caller.is\_a?(Foo)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;previous = current  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Foo.current = caller  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;block.call  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ensure  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Foo.current = previous  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current.instance\_eval &block  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def initialize path  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Foo.initializing{ load path }  
&nbsp;&nbsp;&nbsp;end  
end

foo = Foo.new('b.rb')  
p foo.instance\_variables

cfp:~ \> cat b.rb  
Foo.initializing do  
&nbsp;&nbsp;&nbsp;@foo = 42  
end

cfp:~ \> ruby a.rb  
["@foo"]

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

> **···**
>
> On Oct 24, 2008, at 11:55 AM, Richard Crowley wrote:
> 
> > have a bit of code here that I'd love to make better:
> > 
> > class Foo  
> > &nbsp;&nbsp;&nbsp;def initialize(path)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.instance\_eval(File.read(path))  
> > &nbsp;&nbsp;&nbsp;end  
> > end
> > 
> > I don't want to continue down the path of reading an entire file into a string and then eval'ing that string just to get the contents of the file executed as if it were the body of a method in a class. The file passed to the constructor above might contain something like:
> > 
> > @foo = 'This will become an instance variable when you do Foo.new(path)'
> > 
> > I've tried all manner of hacks to make Kernel#load and friends execute code as if it were in the calling scope. In every case I've seen the loaded file leave no lasting effect on the instance variables of the calling method. My goal is to be able to do exactly this:
> 
> --  
> we can deny everything, except that we have the possibility of being better. simply reflect on that.  
> h.h. the 14th dalai lama

---

<div class="post-metadata">

**Author:** ![Ken\_Bloom](https://avatars.discourse-cdn.com/v4/letter/k/f08c70/32.png) [@Ken\_Bloom](https://rubytalk.org/u/Ken_Bloom)\
**Post date:** [26 October 2008 02:09 UTC](https://rubytalk.org/t/object-instance-eval-but-better/49818/4 "2008-10-26T02:09:48Z")

</div>

> > I have a bit of code here that I'd love to make better:
> > 
> > class Foo  
> > def initialize(path)  
> > self.instance\_eval(File.read(path))  
> > end  
> > end
> > 
> > I don't want to continue down the path of reading an entire file into a  
> > string and then eval'ing that string just to get the contents of the  
> > file executed as if it were the body of a method in a class. The file  
> > passed to the constructor above might contain something like:
> > 
> > @foo = 'This will become an instance variable when you do  
> > Foo.new(path)'
> > 
> > I've tried all manner of hacks to make Kernel#load and friends execute  
> > code as if it were in the calling scope. In every case I've seen the  
> > loaded file leave no lasting effect on the instance variables of the  
> > calling method. My goal is to be able to do exactly this:
> > 
> > class Foo  
> > def initialize(path)  
> > load\_in\_scope path  
> > end  
> > end  
> > f = Foo.new('load\_me.rb')  
> > f.instance\_variables # =\> ['@foo']
> > 
> > My assumption here is that reading a file into a string and eval'ing it  
> > is very slow and is bad form. Am I right?

I can't imagine that it would be slower than simply loading the ruby  
file. If there's a hint of bad form in it (and I'm not personally going  
to say whether there is or isn't), it would have to relate to security  
implications. And the only way to comment on that is to ask what exactly  
you're trying to do with this construction.

> > Is this possible without reading the file into a string? Is this  
> > possible without hacking the C code? Should I go bother ruby-core?
> 
> Ultimately, it's the same thing, whether you do it in Ruby or C. I doubt  
> it would be that much faster in C than it is in pure Ruby b/c it is  
> dynamic --the path can change. However, you may actually intend:
> 
> &nbsp;&nbsp;class Foo  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(path)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eval(File.read(path), \_\_FILE\_\_, \_\_LINE\_\_)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end
> 
> T.

He almost certainly doesn't intend \_\_FILE\_\_, \_\_LINE\_\_ because that is the  
default behavior of eval. (and besides it won't work since the second  
parameter has to be a binding)

irb(main):014:0\> eval "puts \_\_FILE\_\_\nfail", \_\_FILE\_\_  
TypeError: wrong argument type String (expected Proc/Binding)  
&nbsp;&nbsp;from (irb):14:in `eval'  
&nbsp;&nbsp;from (irb):14

> **···**
>
> On Fri, 24 Oct 2008 13:08:45 -0500, Trans wrote:
> 
> > On Oct 24, 1:55 pm, Richard Crowley \<r...@rcrowley.org\> wrote:
> 
> &nbsp;&nbsp;from :0
> 
> Propably he wants  
> eval(File.read(path),binding,path)
> 
> (the filename and line number passed indicate the location used for  
> \_\_FILE\_\_, \_\_LINE\_\_ and exception stack traces that occur in the eval'ed  
> code
> 
> irb(main):013:0\> eval "puts \_\_FILE\_\_\nfail", binding, 'foo'  
> foo  
> RuntimeError:  
> &nbsp;&nbsp;from foo:2  
> &nbsp;&nbsp;from (irb):13  
> &nbsp;&nbsp;from :0
> 
> --  
> Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.  
> Department of Computer Science. Illinois Institute of Technology.  
> [http://www.iit.edu/~kbloom1/](http://www.iit.edu/~kbloom1/)
