Configuration Files

A while back someone submitted some code to this list for evaluating
Configuration files in the style of:

% cat test.config
editor.spacespertab = 4
toolbar.visible = true
statusbar.visible = false
. . .

One of the great things about their code was that it enabled you to use ruby
code within your configuration file so you could do things like this:

%cat test2.config
timer.alarm = 30 * 60 # set the timer to go off in 30 min

Their implementation was pretty simple. Mainly they created a hash,
splitting each line on /=/, and evaled the right side and stored the result
in the hash with a key of the left side.

I like this concept, but I wanted a better implementation. So I set to work
and created the attached files. The attached now enables you to do this:

%cat myprog.rb
require ‘config’

$conf = Config.new

set up the default values and configuration structure:

$conf.define %{
editor.spacespertab = 8
toolbar.visible = false
toolbar.caption = “Tools”
statusbar.visible = true
copyright = “Copyright © 2003, John W. Long”
}

$conf.read File.new(‘test.config’, ‘r’).read

you can even read multi line ruby snippets:

$conf.read %{
copyright = “Copyright © 2003, John W. Long
All Rights Reserved”
alarm = 30 * 60 #seconds
}

now for getting the values, note the object hierarchy

toolbar.caption = $conf.toolbar.caption.value
toolbar.show if $conf.toolbar.visible.value
aboutbox.copyright = $conf.copyright.value
. . .

You get the idea.

A couple of advantages that this has over the previous concept:
– You define the default values and create the config structure at the same
time
– Because you define a config structure if someone makes a typo in the
config file misspelling “toolbar” as “tolbar” an error will be thrown
(eventually it will even tell you what line the error was on)
– You access the values from the config file in almost the same way that
they are written into the config file on your Config object

I didn’t attach the unit tests of this version because the code still
relatively crude. Once I get things worked out a bit I may post it on
RubyForge.

Feedback is appreciated.

cleanobject.rb (315 Bytes)

config.rb (1.47 KB)

···

John Long
www.wiseheartdesign.com

John,

What type of environment would you think something like this would apply to?

I dont’ know what the “previous concept” was and it is hard for me to get a
good grasp in your post. Please help me understand. =) Thanks,

Zach

···

-----Original Message-----
From: John W. Long [mailto:ws@johnwlong.com]
Sent: Wednesday, December 17, 2003 11:01 PM
To: ruby-talk ML
Subject: Configuration Files

A while back someone submitted some code to this list for evaluating
Configuration files in the style of:

% cat test.config
editor.spacespertab = 4
toolbar.visible = true
statusbar.visible = false
… . .

One of the great things about their code was that it enabled you to use ruby
code within your configuration file so you could do things like this:

%cat test2.config
timer.alarm = 30 * 60 # set the timer to go off in 30 min

Their implementation was pretty simple. Mainly they created a hash,
splitting each line on /=/, and evaled the right side and stored the result
in the hash with a key of the left side.

I like this concept, but I wanted a better implementation. So I set to work
and created the attached files. The attached now enables you to do this:

%cat myprog.rb
require ‘config’

$conf = Config.new

set up the default values and configuration structure:

$conf.define %{
editor.spacespertab = 8
toolbar.visible = false
toolbar.caption = "Tools"
statusbar.visible = true
copyright = “Copyright © 2003, John W. Long”
}

$conf.read File.new(‘test.config’, ‘r’).read

you can even read multi line ruby snippets:

$conf.read %{
copyright = "Copyright © 2003, John W. Long
All Rights Reserved"
alarm = 30 * 60 #seconds
}

now for getting the values, note the object hierarchy

toolbar.caption = $conf.toolbar.caption.value
toolbar.show if $conf.toolbar.visible.value
aboutbox.copyright = $conf.copyright.value
… . .

You get the idea.

A couple of advantages that this has over the previous concept:
– You define the default values and create the config structure at the same
time
– Because you define a config structure if someone makes a typo in the
config file misspelling “toolbar” as “tolbar” an error will be thrown
(eventually it will even tell you what line the error was on)
– You access the values from the config file in almost the same way that
they are written into the config file on your Config object

I didn’t attach the unit tests of this version because the code still
relatively crude. Once I get things worked out a bit I may post it on
RubyForge.

Feedback is appreciated.


John Long
www.wiseheartdesign.com

That sounds like a great config file system. I rolled my own basic one
not too long ago, but having seen this, I’m thinking I’d replace it. :slight_smile:

One thing I did in mine which I kind of like, but has drawbacks, is a sort
of grouping, where:
[plugin.player]
class=CommandPlayer
command=mpg123

is the same as:
plugin.player.class=CommandPlayer
plugin.player.command=mpg123

I didn’t have any equivalent of [/plugin.player] though, so once you’re
in a group, you couldn’t define top-level elements any more, and there’s
no way to nest the groups.

Even despite that, I really like being able to group someone to avoid
having to duplicate the “plugin.player”, because sometimes there’s 15 or
so config elements in a group.

···

On Thu, 18 Dec 2003, John W. Long wrote:

A while back someone submitted some code to this list for evaluating
Configuration files in the style of:

% cat test.config
editor.spacespertab = 4
toolbar.visible = true
statusbar.visible = false
. . .

One of the great things about their code was that it enabled you to use ruby
code within your configuration file so you could do things like this:

%cat test2.config
timer.alarm = 30 * 60 # set the timer to go off in 30 min

Their implementation was pretty simple. Mainly they created a hash,
splitting each line on /=/, and evaled the right side and stored the result
in the hash with a key of the left side.

I like this concept, but I wanted a better implementation. So I set to work
and created the attached files. The attached now enables you to do this:

%cat myprog.rb
require ‘config’

$conf = Config.new

set up the default values and configuration structure:

$conf.define %{
editor.spacespertab = 8
toolbar.visible = false
toolbar.caption = “Tools”
statusbar.visible = true
copyright = “Copyright © 2003, John W. Long”
}

$conf.read File.new(‘test.config’, ‘r’).read

you can even read multi line ruby snippets:

$conf.read %{
copyright = “Copyright © 2003, John W. Long
All Rights Reserved”
alarm = 30 * 60 #seconds
}

now for getting the values, note the object hierarchy

toolbar.caption = $conf.toolbar.caption.value
toolbar.show if $conf.toolbar.visible.value
aboutbox.copyright = $conf.copyright.value
. . .

You get the idea.

A couple of advantages that this has over the previous concept:
– You define the default values and create the config structure at the same
time
– Because you define a config structure if someone makes a typo in the
config file misspelling “toolbar” as “tolbar” an error will be thrown
(eventually it will even tell you what line the error was on)
– You access the values from the config file in almost the same way that
they are written into the config file on your Config object

I didn’t attach the unit tests of this version because the code still
relatively crude. Once I get things worked out a bit I may post it on
RubyForge.

Feedback is appreciated.


John Long
www.wiseheartdesign.com

Derek Lewis

===================================================================
Java Web-Application Developer

  Email    : email@lewisd.com
  Cellular : 604.312.2846
  Website  : http://www.lewisd.com

“If you’ve got a 5000-line JSP page that has “all in one” support
for three input forms and four follow-up screens, all controlled
by “if” statements in scriptlets, well … please don’t show it
to me :-). Its almost dinner time, and I don’t want to lose my
appetite :-).”
- Craig R. McClanahan

Hi,

From: “John W. Long” ws@johnwlong.com
Sent: Thursday, December 18, 2003 1:01 PM

I like this concept, but I wanted a better implementation. So I set to work
and created the attached files. The attached now enables you to do this:

Interesting.

You get the idea.

A couple of advantages that this has over the previous concept:
– You define the default values and create the config structure at the same
time
– Because you define a config structure if someone makes a typo in the
config file misspelling “toolbar” as “tolbar” an error will be thrown
(eventually it will even tell you what line the error was on)
– You access the values from the config file in almost the same way that
they are written into the config file on your Config object

Sorry for not related to your great work, but let me introduce mine.
From the similar point of view, I wrote my own version for soap4r, too.

http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/lib/soap4r/lib/soap/property.rb
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/lib/soap4r/test/soap/test_property.rb

My concept is; define property tree and lock to avoid typo.
And I want to “hook” property changes to reconfigure something
and value-space checking.

require ‘soap/property’

···

property definition

prop = SOAP::Property.new
prop.add_hook(“protocol.http.proxy”) do |name, value|

check value here…

puts “(proxy) #{name}: #{value}”
end

sitebag = prop[“protocol.http.sites”] = SOAP::Property.new

prop.lock(true) # true: locks properties cascading.
sitebag.unlock # unlock sitebag property node.

assigning values

prop[“protocol.http.proxy”] = “myproxy:8080”
prop[“protocol.http.sites”] << “foo”
prop[“protocol.http.sites”] << “bar”

p prop[“protocol.http.sites.0”] # => “foo”
p prop[“protocol.http.sites.1”] # => “bar”
p prop[“protocol.http.sites”].values # => [“foo”, “bar”]

typo

prop[“protocooool.http.proxy”] = “foo” #=> error
prop[“protocol.htttttp.proxy”] = “foo” #=> error
prop[“protocol.http.proxxxxy”] = “foo” #=> error

But mine cannot read property file after property definition for now
though it may be able to do easily.

How do you think hooking feature of configuration files?

Regards,
// NaHi

----- “Derek Lewis” wrote: -----

That sounds like a great config file system. I rolled my own basic one
not too long ago, but having seen this, I’m thinking I’d replace it. :slight_smile:

One thing I did in mine which I kind of like, but has drawbacks, is a sort
of grouping, where:
[plugin.player]
class=CommandPlayer
command=mpg123

is the same as:
plugin.player.class=CommandPlayer
plugin.player.command=mpg123

I wonder about using ruby’s natural bracket syntax:

plugin.player {
class=CommandPlayer
comand=mpg123
}

If you look at the internal workings of my class you will see that I do a
bit of prep work on the code, but then I just instance_eval it. If I used
the bracket syntax I would have to change my objects so that they would know
how to handle it, but I have the advantage of allowing ruby evaluate my code
once I’ve done the prep work.

I’ll consider it.

···

John Long
www.wiseheartdesign.com

That sounds like a great config file system. I rolled my own basic one
not too long ago, but having seen this, I’m thinking I’d replace it. :slight_smile:

One thing I did in mine which I kind of like, but has drawbacks, is a
sort of grouping, where:
[plugin.player]
class=CommandPlayer
command=mpg123

is the same as:
plugin.player.class=CommandPlayer
plugin.player.command=mpg123

I have a really cool way of specifying config files. It goes like this:

plugin:
player:
class: CommandPlayer
command: mpg123

However, the code for parsing this is a secret :slight_smile:

Gavin

----- “Zach Dennis” wrote: -----

What type of environment would you think something like this would apply
to?

I dont’ know what the “previous concept” was and it is hard for me to get
a
good grasp in your post. Please help me understand. =) Thanks,

If you have ever found yourself storing configuration information in a ruby
file setting a bunch of global constants:

$TOOLBAR_VISIBLE = true
$TOOLBAR_CAPTION = “My Toolbar”
. . .

and then requiring your ‘configuration.rb’ into your main program you might
consider replacing your current constant based configuration with a file
like this:

toolbar.visible = true
toolbar.caption = “My Toolbar”

You can then read it into your program like this:

require ‘config.rb’

$conf = Config.new

define the structure of your configuration object

and the default values for your configuration.

$conf.define %{
menu.visible = true
toolbar.visible = false
toolbar.caption = “Tools”
statusbar.visible = true
}

we have defined the initial values of our Config object

so we can now use them:

puts $conf.toolbar.visible.value #output: false
puts $conf.toolbar.caption.value #outputs: “Tools”

most people will want to override the default values

with something of their own, so we will read in the

default values from our configuration file:

text = ‘’
File.open(‘myprogram.conf’, ‘r’) { |file| text = file.read }
$conf.read text

we just read in the values from our configuration file

so we can now use them:

puts $conf.toolbar.visible.value #outputs: true
puts $conf.toolbar.caption.value #outputs: “My Toolbar”

the rest of our program follows

. . .

I hope this is easier to understand than the last example. Let me know if
something is still not clear.

···

John Long
www.wiseheartdesign.com

Gavin Sinclair wrote:

I have a really cool way of specifying config files. It goes like this:

plugin:
player:
class: CommandPlayer
command: mpg123

However, the code for parsing this is a secret :slight_smile:

Why, you lucky stiff…

Hal

Thanks John for your reply. That was the clarification I needed. I am going
to pull down your attachments in your last post and play with them, now that
I understand what’s happening. Thanks again!

Zach

i’m with you (and use it myself), but the above is problematic if you actually
want non-programmers to be able to configure a system. for example, how long
do you think it would take a non-programmer to debug this?

file config.rb:

···

On Thu, 18 Dec 2003, Gavin Sinclair wrote:

Date: Thu, 18 Dec 2003 13:51:45 +0900
From: Gavin Sinclair gsinclair@soyabean.com.au
Newsgroups: comp.lang.ruby
Subject: Re: Configuration Files

That sounds like a great config file system. I rolled my own basic one
not too long ago, but having seen this, I’m thinking I’d replace it. :slight_smile:

One thing I did in mine which I kind of like, but has drawbacks, is a
sort of grouping, where:
[plugin.player]
class=CommandPlayer
command=mpg123

is the same as:
plugin.player.class=CommandPlayer
plugin.player.command=mpg123

I have a really cool way of specifying config files. It goes like this:

plugin:
player:
class: CommandPlayer
command: mpg123

However, the code for parsing this is a secret :slight_smile:

========
require ‘yaml’
config = <<-txt
plugin:
player:
class: CommandPlayer
command: mpg123
txt
YAML::load(config)

~/eg/ruby > ruby config.rb
/data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in load': parse error on line 3, col 12: command: mpg123’ (ArgumentError)
from /data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in `load’
from config.rb:8

-a

ATTN: please update your address books with address below!

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
STP :: Solar-Terrestrial Physics Data | NCEI
NGDC :: http://www.ngdc.noaa.gov/
NESDIS :: http://www.nesdis.noaa.gov/
NOAA :: http://www.noaa.gov/
US DOC :: http://www.commerce.gov/

The difference between art and science is that science is what we
understand well enough to explain to a computer.
Art is everything else.
– Donald Knuth, “Discover”

/bin/sh -c ‘for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done’
===============================================================================

The above throws an error for you? Man, a lot has been fixed since 1.8.0.

Anyhow, I’m with ya. So, let’s solve the problem. Would it help if you could
hook the parse error handler to generate your own nice errors? We can also
start to provide more specific parse error messages, though this can be
needly on some edges.

~/eg/ruby > ruby config.rb
Error in configuration file. See line 4.

        2  player:
        3    class: CommandPlayer

Here!! → 4 command: mpg123

Yeah, the indentation on that line needs to be trimmed
a bit. Just line it up cozy with the line above it.

_why

···

On Thursday 18 December 2003 10:11 am, Ara.T.Howard wrote:

i’m with you (and use it myself), but the above is problematic if you
actually want non-programmers to be able to configure a system. for
example, how long do you think it would take a non-programmer to debug
this?

file config.rb:

require ‘yaml’
config = <<-txt
plugin:
player:
class: CommandPlayer
command: mpg123
txt
YAML::load(config)

~/eg/ruby > ruby config.rb
/data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in load': parse error on line 3, col 12: command: mpg123’ (ArgumentError) from
/data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in `load’
from config.rb:8

-a

why the lucky stiff wrote:

i’m with you (and use it myself), but the above is problematic if you
actually want non-programmers to be able to configure a system. for
example, how long do you think it would take a non-programmer to debug
this?

file config.rb:

require ‘yaml’
config = <<-txt
plugin:
player:
class: CommandPlayer
command: mpg123
txt
YAML::load(config)

~/eg/ruby > ruby config.rb
/data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in load': parse error on line 3, col 12: command: mpg123’ (ArgumentError) from
/data/ruby-1.8.0//lib/ruby/1.8/yaml.rb:39:in `load’
from config.rb:8

-a

The above throws an error for you? Man, a lot has been fixed since 1.8.0.

I use YAML form the latest ruby-1.8.1preview3, and when I
copy-and-pasted the code from Ara’s post, I got the same error. The
problem was that there was a TAB character after “player:” (was it
deliberately implanted to prove the point :wink: ?), and it caused the
problem. If you remove TAB or convert it to spaces, everything starts
working fine.

_why, could you just ignore trailing spaces and tabs?

Gennady.

···

On Thursday 18 December 2003 10:11 am, Ara.T.Howard wrote:

Anyhow, I’m with ya. So, let’s solve the problem. Would it help if you could
hook the parse error handler to generate your own nice errors? We can also
start to provide more specific parse error messages, though this can be
needly on some edges.

~/eg/ruby > ruby config.rb
Error in configuration file. See line 4.

        2  player:
        3    class: CommandPlayer

Here!! → 4 command: mpg123

Yeah, the indentation on that line needs to be trimmed
a bit. Just line it up cozy with the line above it.

_why