Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sourcing files

0 views
Skip to first unread message

Björn Lindström

unread,
Feb 19, 2003, 12:20:08 AM2/19/03
to
I like using source files as configuration files for my hacks.

In shell I can easily do that by putting:

source ~/.configfile

or something like that at the top of the script.

Then I can put whatever settings I like in ~/.configfile

There seems to be no straightforward way to do that in Ruby,
neither with eval or with require/include.

How do you suggest I go about this?

--
Björn Lindström <bk...@privat.utfors.se> hem.fyristorg.com/bkhl/
Addr: Ramsta Svista, SE-755 91 Uppsala Ph: 018-398248/073-6171268
Listening to Massive Attack: Teardrop (Mezzanine)

Jim Weirich

unread,
Feb 19, 2003, 12:58:19 AM2/19/03
to
On Wed, 2003-02-19 at 00:20, Björn Lindström wrote:
> I like using source files as configuration files for my hacks.
>
> In shell I can easily do that by putting:
>
> source ~/.configfile
>
> or something like that at the top of the script.
>
> Then I can put whatever settings I like in ~/.configfile
>
> There seems to be no straightforward way to do that in Ruby,
> neither with eval or with require/include.

I do this too. In fact, I tend to use the same file for both Ruby and
shell. Suppose the config file has format

KEYWORD=VALUE
ANOTHERKEYWORD=Still another value
etc.

That file can be sourced directly into a shell script, and read into a
Ruby program with the following code ...

def read_config(config_file)
result = {}
open(config_file) do |file|
while line = file.gets
key, value = line.chomp.split("=")
result[key] = value
end
end
result
end

read_config returns a hash table containing the keys and the values. A
little extra code can handle comments and blank lines and you have a
quick and dirty config reader.

True, it isn't quite what you asked for, but I've found it to be quite
useful. And I really like that one config file works for both Ruby and
shell.

Of course, if your config data is more than just simple keyword/values,
I would suggest taking a look at YAML (or <shudder> XML).

--
-- Jim Weirich jwei...@one.net http://w3.one.net/~jweirich
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Gavin Sinclair

unread,
Feb 19, 2003, 1:10:00 AM2/19/03
to
On Wednesday, February 19, 2003, 4:58:19 PM, Jim wrote:


> Of course, if your config data is more than just simple keyword/values,
> I would suggest taking a look at YAML (or <shudder> XML).


That should be "<shudder> XML </shudder>".

# Sorry.

Gavin


Björn Lindström

unread,
Feb 19, 2003, 1:27:10 AM2/19/03
to
Jim Weirich <jwei...@one.net> [20030219 06:58]:

> I do this too. In fact, I tend to use the same file for both
> Ruby and shell. Suppose the config file has format

Well, this is not what I am looking for. The point of the whole
thing is that I want to be able to put loops and stuff into the
configuration file. Is there really no way to just include/source
a file in Ruby?

--
Björn Lindström <bk...@privat.utfors.se> hem.fyristorg.com/bkhl/
Addr: Ramsta Svista, SE-755 91 Uppsala Ph: 018-398248/073-6171268

Listening to Howard Shore

Jos Backus

unread,
Feb 19, 2003, 1:32:30 AM2/19/03
to
On Wed, Feb 19, 2003 at 03:27:10PM +0900, Bjrn Lindstrm wrote:
> Well, this is not what I am looking for. The point of the whole
> thing is that I want to be able to put loops and stuff into the
> configuration file. Is there really no way to just include/source
> a file in Ruby?

load "file"

?

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'

Björn Lindström

unread,
Feb 19, 2003, 1:56:05 AM2/19/03
to
Jos Backus <j...@catnook.com> [20030219 07:32]:
> load "file"
>
> ?

OK, say that config.rb is a file containing the line:
x = 23

and in my script I do:

load './config.rb'
puts x

this is what I get:

./script.rb:3: undefined local variable or method `x' for #<Object:0x401d1ce0> (NameError)

--
Björn Lindström <bk...@privat.utfors.se> hem.fyristorg.com/bkhl/
Addr: Ramsta Svista, SE-755 91 Uppsala Ph: 018-398248/073-6171268

Listening to: Tristania: Beyond the Veil (Beyond the Veil)

Robert

unread,
Feb 19, 2003, 2:57:51 AM2/19/03
to

Your config file should've read

$x=23

Since x should be a global variable. You can use @@x alternatively but I
don't recommend this in your case.

robert

"Björn Lindström" <bk...@privat.utfors.se> schrieb im Newsbeitrag
news:20030219065...@lucien.dreaming...


> Jos Backus <j...@catnook.com> [20030219 07:32]:
> > load "file"
> >
> > ?
>
> OK, say that config.rb is a file containing the line:
> x = 23
>
> and in my script I do:
>
> load './config.rb'
> puts x
>
> this is what I get:
>

Robert Feldt

unread,
Feb 19, 2003, 9:44:36 AM2/19/03
to
On Wed, 19 Feb 2003, Björn Lindström wrote:

> Jos Backus <j...@catnook.com> [20030219 07:32]:
> > load "file"
> >
> > ?
>
> OK, say that config.rb is a file containing the line:
> x = 23
>
> and in my script I do:
>
> load './config.rb'
> puts x
>
> this is what I get:
>
> ./script.rb:3: undefined local variable or method `x' for #<Object:0x401d1ce0> (NameError)
>

Well, what about:

File.open("./config.rb") {|f| eval f.read}
puts x

?

/Robert Feldt


dbl...@candle.superlink.net

unread,
Feb 19, 2003, 10:37:11 AM2/19/03
to
Hi --

The local variable x will only exist in the scope of the eval, so
you'll get the same error.


David

--
David Alan Black
home: dbl...@candle.superlink.net
work: blac...@shu.edu
Web: http://pirate.shu.edu/~blackdav


Brian Candler

unread,
Feb 19, 2003, 10:41:03 AM2/19/03
to
On Wed, Feb 19, 2003 at 03:56:05PM +0900, Björn Lindström wrote:
> OK, say that config.rb is a file containing the line:
> x = 23
>
> and in my script I do:
>
> load './config.rb'
> puts x
>
> this is what I get:
>
> ./script.rb:3: undefined local variable or method `x' for #<Object:0x401d1ce0> (NameError)

I'd expect that. When Ruby is parsing the main program, it has not seen any
assignment to 'x' by the time it gets to line 2. It therefore assumes that x
is a method call, so compiles it the same as
puts self.x

Then it starts running; the load command is executed, and 'x=23' creates a
local variable. But it's too late, line 2 was already parsed, and 'x' is not
treated as a local variable.

You'd think it might work this way, but it doesn't:

x=nil
load './config.rb'
puts x #>> prints nil

Now 'puts x' refers to a local variable, but config.rb isn't setting it. It
must have its own scope for local variables (which I suppose it would, being
a method call)

Now, you could change the main program to:

class <<self
attr_accessor :x
end
load './config.rb'
puts x

and config.rb to:

self.x = 23

and then it works. But that's not pretty.

You'd think there would be a more Rubyesque way of doing this. I thought
about an object which represents your configuration information:

# main.rb
class Config
attr_accessor :x,:y,:z
end
conf = Config.new
conf.instance_eval { load 'config.rb' } # no
puts conf.x

# config.rb
self.x = 23

But 'load' doesn't work in that way inside instance_eval, since it seems to
reset the context to the object 'main'

So I think you're left with reading the file as a string and then eval'ing
it:
x=nil
eval File.open('config.rb').read
puts x

Note the assignment to 'x' is still needed, as explained above. See also
http://www.rubygarden.org/ruby?LocalVariablesAndBlocks/CurrentBehaviour

Regards,

Brian.

Robert Feldt

unread,
Feb 19, 2003, 11:29:07 AM2/19/03
to
On Thu, 20 Feb 2003 dbl...@candle.superlink.net wrote:

> > > OK, say that config.rb is a file containing the line:
> > > x = 23
> > >
> > > and in my script I do:
> > >
> > > load './config.rb'
> > > puts x
> > >
> > > this is what I get:
> > >
> > > ./script.rb:3: undefined local variable or method `x' for #<Object:0x401d1ce0> (NameError)
> > >
> > Well, what about:
> >
> > File.open("./config.rb") {|f| eval f.read}
> > puts x
>
> The local variable x will only exist in the scope of the eval, so
> you'll get the same error.
>

Hi David,

Thats right. I was too quick on the trigger there.

It would work for constants though

$ ruby -v -e 'eval "X = 1"; p X'
ruby 1.8.0 (2003-02-13) [i386-mingw32]
1

Regards,

Robert Feldt

Mauricio Fernández

unread,
Feb 19, 2003, 11:59:02 AM2/19/03
to
On Thu, Feb 20, 2003 at 12:41:03AM +0900, Brian Candler wrote:
> You'd think there would be a more Rubyesque way of doing this. I thought
> about an object which represents your configuration information:
>
> # main.rb
> class Config
> attr_accessor :x,:y,:z
> end
> conf = Config.new
> conf.instance_eval { load 'config.rb' } # no
> puts conf.x
>
> # config.rb
> self.x = 23
>
> But 'load' doesn't work in that way inside instance_eval, since it seems to
> reset the context to the object 'main'
>

Using instance_eval is a good idea IMHO:

batsman@tux-chan:/tmp$ expand -t 2 h.rb


class Config
attr_accessor :x, :y, :z
end

USEFILE = false

conf = Config.new
conftext = case USEFILE
when true
File.open("./config.rb") { |f| f.read }
when false
'self.x = 1; self.y = 2; self.z = "test" '
end
conf.instance_eval conftext
conf.instance_variables.each do |f|
puts "#{f} => #{conf.instance_eval(f).inspect} "
end
batsman@tux-chan:/tmp$ ruby h.rb
@z => "test"
@y => 2
@x => 1

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Debian is like Suse with yast turned off, just better. :)
-- Goswin Brederlow

Brian Candler

unread,
Feb 19, 2003, 4:19:29 PM2/19/03
to
On Thu, Feb 20, 2003 at 01:59:02AM +0900, Mauricio Fern?ndez wrote:
> Using instance_eval is a good idea IMHO:
>
> batsman@tux-chan:/tmp$ expand -t 2 h.rb
> class Config
> attr_accessor :x, :y, :z
> end
>
> USEFILE = false
>
> conf = Config.new
> conftext = case USEFILE
> when true
> File.open("./config.rb") { |f| f.read }
> when false
> 'self.x = 1; self.y = 2; self.z = "test" '
> end
> conf.instance_eval conftext
> conf.instance_variables.each do |f|
> puts "#{f} => #{conf.instance_eval(f).inspect} "
> end
> batsman@tux-chan:/tmp$ ruby h.rb
> @z => "test"
> @y => 2
> @x => 1

That's tidier. The config file can say '@x=1' instead of 'self.x=1' which is
cleaner too.

I guess it's an example of an application which would be cleaner without the
local variable / method dichotomy; ATM there's no way to invoke an attribute
writer without prefixing it with the object reference.

B.

Robert Feldt

unread,
Feb 21, 2003, 1:35:13 AM2/21/03
to
Hi,

It struck me that you can actually accomplish what the orig poster wants
using eval and DATA. Unconventional, has drawbacks and not what you'd
typically do in his situation but anyway:

$ cat config
x = 1

$ cat c.rb
eval(File.open("config") {|f| f.read} + DATA.read)
__END__

p x

$ ruby -v c.rb

0 new messages