[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Ruby equivalent to source command

Brett Williams

2/12/2008 3:27:00 PM

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 Williams



P.S.: Things have changed since I was a pretty regular poster back in
2002-2003... ;)
--
Posted via http://www.ruby-....

8 Answers

Robert Klemme

2/12/2008 4:11:00 PM

0

2008/2/12, Brett Williams <brettandbecky@gmail.com>:
> 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'

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


--
use.inject do |as, often| as.you_can - without end

Brett Williams

2/12/2008 4:28:00 PM

0

Robert Klemme wrote:
> 2008/2/12, Brett Williams <brettandbecky@gmail.com>:
>> 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 =)
--
Posted via http://www.ruby-....

yermej

2/12/2008 5:28:00 PM

0

On Feb 12, 10:11 am, Robert Klemme <shortcut...@googlemail.com> 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]'

Joel VanderWerf

2/12/2008 6:48:00 PM

0

Brett Williams 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.....

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Robert Dober

2/12/2008 8:15:00 PM

0

On Feb 12, 2008 7:47 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> Brett Williams 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.....
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 <blush> 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.blo...

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

Joel VanderWerf

2/12/2008 9:29:00 PM

0

Robert Dober wrote:
> On Feb 12, 2008 7:47 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
>> Brett Williams 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.....
> 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.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

ara.t.howard

2/12/2008 10:05:00 PM

0


On Feb 12, 2008, at 8:26 AM, Brett Williams 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://codeforp...lib/ruby/configuration/configuration-0....

gem install configuration


a @ http://codeforp...
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama



Robert Dober

2/12/2008 10:37:00 PM

0

On Feb 12, 2008 10:28 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> Robert Dober wrote:
> > On Feb 12, 2008 7:47 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> >> Brett Williams 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.....
> > 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
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.