# Ruby equivalent to source command

**URL:** <https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909>\
**Category:** Ruby\
**Created:** [February 12, 2008, 4:26pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909 "2008-02-12T16:26:37Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 4:26pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/1 "2008-02-12T16:26:37Z")

</div>

Hello all,

I am trying to make a “source” command for Ruby (a la sh or tcl), but I  
think lexical scoping is tripping me up. I’ve done a lot of reading  
about bindings, and it seems I just can’t do what I’m trying to do.

def source(filename, bind = TOPLEVEL\_BINDING)  
code = nil  
File.open(filename) { |f| code = f.read }  
eval(code, bind)  
end

This works as I would like, with the exception of local variables  
present in the sourced file. For example, if I had something like this  
in the sourced file:

x = “value set in sourced file”

then I get an error : undefined local variable or method ‘x’

unless I extend the scope of x by setting it before sourcing the file.

Is there any way to accomplish what I want? I could work around this by  
sticking to instance variables or _gulp_ global variables for this  
application, but before I throw in the towel I wanted to throw this out  
to people here.

Thanks,

Brett W.

P.S.: Things have changed since I was a pretty regular poster back in  
2002-2003… 😉

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 5:12pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/2 "2008-02-12T17:12:26Z")

</div>

2008/2/12, Brett W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> This works as I would like, with the exception of local variables  
> present in the sourced file. For example, if I had something like this  
> in the sourced file:
> 
> x = “value set in sourced file”
> 
> then I get an error : undefined local variable or method ‘x’

Can you show more code? For me it works:

17:05:12 ~  
$ echo “x=123; puts x” | ruby -e ‘eval(ARGF.read, TOPLEVEL\_BINDING)’  
123  
17:05:18 ~  
$ echo “x=123; puts x” | ruby -e ‘eval(ARGF.read, binding)’  
123  
17:05:25 ~  
$

Or are you seeing this:

17:05:25 ~  
$ echo “x=123” | ruby -e ‘eval(ARGF.read, binding); puts x’  
-e:1: undefined local variable or method `x’ for main:Object (NameError)  
17:06:31 ~  
$

> unless I extend the scope of x by setting it before sourcing the file.

Like

17:06:31 ~  
$ echo “x=123” | ruby -e ‘x=1; eval(ARGF.read, binding); puts x’  
123  
17:07:32 ~  
$

This is because local variables are detected at compile time. That’s  
why Ruby thinks “x” in my bit above is a method because there is no  
assignment.

> Is there any way to accomplish what I want? I could work around this by  
> sticking to instance variables or _gulp_ global variables for this  
> application, but before I throw in the towel I wanted to throw this out  
> to people here.

A global is probably much more appropriate here. If the code you  
source somehow generates configuration settings then maybe you can set  
a global Hash that will receive values. It depends on the larger  
context of what you want to achieve.

> P.S.: Things have changed since I was a pretty regular poster back in  
> 2002-2003… 😉

Does this have to do with your email address? 😉 If yes, congrats  
and greetings to Becky!

Cheers

robert

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 5:27pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/3 "2008-02-12T17:27:38Z")

</div>

Robert K. wrote:

> 2008/2/12, Brett W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > This works as I would like, with the exception of local variables  
> > present in the sourced file. For example, if I had something like this  
> > in the sourced file:
> > 
> > x = “value set in sourced file”
> > 
> > then I get an error : undefined local variable or method ‘x’

[snip]

> Or are you seeing this:
> 
> 17:05:25 ~  
> $ echo “x=123” | ruby -e ‘eval(ARGF.read, binding); puts x’  
> -e:1: undefined local variable or method `x’ for main:Object (NameError)  
> 17:06:31 ~  
> $
> 
> > unless I extend the scope of x by setting it before sourcing the file.
> 
> Like
> 
> 17:06:31 ~  
> $ echo “x=123” | ruby -e ‘x=1; eval(ARGF.read, binding); puts x’  
> 123  
> 17:07:32 ~  
> $

Precisely.

> This is because local variables are detected at compile time. That’s  
> why Ruby thinks “x” in my bit above is a method because there is no  
> assignment.

Aye, that’s the problem.

> > Is there any way to accomplish what I want? I could work around this by  
> > sticking to instance variables or _gulp_ global variables for this  
> > application, but before I throw in the towel I wanted to throw this out  
> > to people here.
> 
> A global is probably much more appropriate here. If the code you  
> source somehow generates configuration settings then maybe you can set  
> a global Hash that will receive values. It depends on the larger  
> context of what you want to achieve.

I figured this was the case. I’ll go with globals for my context.

> > P.S.: Things have changed since I was a pretty regular poster back in  
> > 2002-2003… 😉
> 
> Does this have to do with your email address? 😉 If yes, congrats  
> and greetings to Becky!

Indeed no. Becky predates even my Ruby (which I started using as my  
primary language in 2001). I’m just very happy to see this list  
mirrored on ruby-forum which makes it much more convenient for me  
personally. The email address is one not used for much – it functions  
mainly as a spam magnet =)

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 7:50pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/4 "2008-02-12T19:50:02Z")

</div>

Brett W. wrote:

> I figured this was the case. I’ll go with globals for my context.

The horror, the horror.

Here’s an alternative: [http://redshift.sourceforge.net/script](http://redshift.sourceforge.net/script).

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 6:30pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/5 "2008-02-12T18:30:44Z")

</div>

On Feb 12, 10:11 am, Robert K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> A global is probably much more appropriate here. If the code you  
> source somehow generates configuration settings then maybe you can set  
> a global Hash that will receive values. It depends on the larger  
> context of what you want to achieve.

In cases like this, I’ve found it helpful to define a method that  
returns the configuration hash:

$ echo “def config; {:a =\> 2}; end” | ruby -e ‘eval(ARGF.read,  
binding); puts config[:a]’

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 9:15pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/6 "2008-02-12T21:15:21Z")

</div>

On Feb 12, 2008 7:47 PM, Joel VanderWerf [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Brett W. wrote:
> 
> > I figured this was the case. I’ll go with globals for my context.
> 
> The horror, the horror.  
> I agree, i agree 😉
> 
> Here’s an alternative: [http://redshift.sourceforge.net/script](http://redshift.sourceforge.net/script).  
> It does not seem to handle OP’s problem though, which are locals or am I  
> wrong?  
> My idea would be to use Smalltalk constants, does anybody save Rick  
> know what that is? 😉  
> But of course constants are not enough so I will define setters too 🙂

But I am not sure if that works let me see:  
Yup seems to work

file: test1.rb  
a=“sourced a”  
b=“sourced b”

file: main.rb  
a = “Main a”  
eval File.open(“test1.rb”){|f| f.read } \<\< %{  
local\_variables.each do |lvar|  
this = class \<\< self; self end  
this.send :define\_method, lvar do eval lvar end  
this.send :define\_method, lvar + “=” do |new\_val| lvar = new\_val  
end  
end  
}  
p [:now\_a, a]  
p [:now\_b, b]  
b = “changed”  
p [:changed\_b, b]

* * *

Now it depends very much on the use case if you can live with this.  
Any pitfalls I have overseen?

HTH  
Robert

> –  
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

–  
[http://ruby-smalltalk.blogspot.com/](http://ruby-smalltalk.blogspot.com/)

* * *

Whereof one cannot speak, thereof one must be silent.  
Ludwig Wittgenstein

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 10:30pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/7 "2008-02-12T22:30:52Z")

</div>

Robert D. wrote:

> On Feb 12, 2008 7:47 PM, Joel VanderWerf [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > Brett W. wrote:
> > 
> > > I figured this was the case. I’ll go with globals for my context.  
> > > The horror, the horror.  
> > > I agree, i agree 😉  
> > > Here’s an alternative: [http://redshift.sourceforge.net/script](http://redshift.sourceforge.net/script).  
> > > It does not seem to handle OP’s problem though, which are locals or am I wrong?

Sorry, I should have made that clear. It uses module\_eval, so you don’t  
get locals, but using module constants and/or methods is better than  
globals 🙂

I like your hack. One possible pitfall is if the file has **END**.  
Another is that local vars can become methods that globally shadow  
Kernel/Object methods. For example, add this line to test1.rb:

open = false

Still, I might add this to the script lib as an option to capture locals  
in the module.

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 11:07pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/8 "2008-02-12T23:07:21Z")

</div>

On Feb 12, 2008, at 8:26 AM, Brett W. wrote:

> Is there any way to accomplish what I want? I could work around  
> this by  
> sticking to instance variables or _gulp_ global variables for this  
> application, but before I throw in the towel I wanted to throw this  
> out  
> to people here.

slightly different, but check this out

[http://codeforpeople.com/lib/ruby/configuration/configuration-0.0.3/README](http://codeforpeople.com/lib/ruby/configuration/configuration-0.0.3/README)

gem install configuration

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

---

<div class="post-metadata">

**Author:** ![vor\_lord](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/3ec8ea/32.png) [@vor\_lord](https://www.ruby-forum.com/u/vor_lord)\
**Post date:** [February 12, 2008, 11:37pm UTC](https://www.ruby-forum.com/t/ruby-equivalent-to-source-command/128909/9 "2008-02-12T23:37:57Z")

</div>

On Feb 12, 2008 10:28 PM, Joel VanderWerf [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> get locals, but using module constants and/or methods is better than  
> globals 🙂
> 
> I like your hack. One possible pitfall is if the file has **END**.  
> Another is that local vars can become methods that globally shadow  
> Kernel/Object methods. For example, add this line to test1.rb:
> 
> open = false  
> very good OP watch out
> 
> Still, I might add this to the script lib as an option to capture locals  
> in the module.  
> If you do so just substract the Kernel methods (and potentially  
> Objects instance methods) from the locals array to avoid shadowing.

I knew I had forgotten something important, thx Joel.  
R.
