Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Configuration Files

Reply
Thread Tools

Configuration Files

 
 
John W. Long
Guest
Posts: n/a
 
      12-18-2003
------=_NextPart_000_0020_01C3C4E8.FCD59B60
Content-Type: text/plain;
charset="Windows-1252"
Content-Transfer-Encoding: 7bit

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

------=_NextPart_000_0020_01C3C4E8.FCD59B60
Content-Type: application/octet-stream;
name="cleanobject.rb"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="cleanobject.rb"

class CleanObject=0A=
alias :__extend__ :extend=0A=
alias :__instance_eval__ :instance_eval=0A=
def initialize=0A=
methods.each { |s|=0A=
symbol =3D s.intern=0A=
next if s =3D~ /^__.*__$/=0A=
next if [:instance_eval].include?(symbol)=0A=
instance_eval %{ undef :#{symbol.to_s} }=0A=
}=0A=
instance_eval %{ undef :instance_eval }=0A=
end=0A=
end=0A=

------=_NextPart_000_0020_01C3C4E8.FCD59B60
Content-Type: application/octet-stream;
name="config.rb"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="config.rb"

require "cleanobject"=0A=
=0A=
class Config=0A=
module Node=0A=
attr_accessor :__defining__, :__children__, :value=0A=
def __defining__=3D(value)=0A=
@__children__ ||=3D Hash.new=0A=
@__children__.each{ |s, v|=0A=
v.__defining__ =3D value=0A=
}=0A=
@__defining__ =3D value=0A=
end=0A=
def method_missing(symbol, *args)=0A=
@__children__ ||=3D Hash.new=0A=
if @__defining__ =0A=
s =3D symbol.to_s=0A=
s =3D $1 if s =3D~ /(.*)=3D$/=0A=
__instance_eval__ <<-CODE=0A=
def #{s}=3D(value)=0A=
unless @__children__.has_key?(:#{s})=0A=
n =3D CleanObject.new=0A=
n.__extend__(Node)=0A=
n.__defining__ =3D true=0A=
@__children__[:#{s}] =3D n=0A=
end=0A=
@__children__[:#{s}].value =3D value=0A=
end=0A=
def #{s}=0A=
unless @__children__.has_key?(:#{s})=0A=
n =3D CleanObject.new=0A=
n.__extend__(Node)=0A=
n.__defining__ =3D true=0A=
@__children__[:#{s}] =3D n=0A=
end=0A=
@__children__[:#{s}]=0A=
end=0A=
CODE=0A=
__send__ symbol, *args=0A=
else=0A=
raise NoMethodError, "undefined method `#{symbol}'"=0A=
end=0A=
end=0A=
end=0A=
=0A=
def initialize=0A=
@root =3D CleanObject.new=0A=
@root.__extend__(Node)=0A=
end=0A=
=0A=
def define(object)=0A=
@root.__defining__ =3D true=0A=
@root.__instance_eval__(prep(object.to_s))=0A=
@root.__defining__ =3D false=0A=
end=0A=
=0A=
def read(object)=0A=
@root.__instance_eval__(prep(object.to_s))=0A=
end=0A=
=0A=
def prep(string)=0A=
code =3D ""=0A=
string.each { |line|=0A=
c =3D line.strip=0A=
c =3D "self.#{c}" unless c =3D~ /^self\./ or c !~ /=3D/=0A=
code << "#{c}\n"=0A=
}=0A=
code=0A=
end=0A=
=0A=
def method_missing(symbol, *args)=0A=
@root.__send__ symbol, *args=0A=
end=0A=
end=0A=

------=_NextPart_000_0020_01C3C4E8.FCD59B60--

 
Reply With Quote
 
 
 
 
Hal Fulton
Guest
Posts: n/a
 
      12-18-2003
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


Why, you lucky stiff...

Hal



 
Reply With Quote
 
 
 
 
NAKAMURA, Hiroshi
Guest
Posts: n/a
 
      12-18-2003
Hi,

> From: "John W. Long" <(E-Mail Removed)>
> 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/cvs...ap/property.rb
http://www.ruby-lang.org/cgi-bin/cvs...st_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:roperty.new
prop.add_hook("protocol.http.proxy") do |name, value|
# check value here...
puts "(proxy) #{name}: #{value}"
end

sitebag = prop["protocol.http.sites"] = SOAP:roperty.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


 
Reply With Quote
 
Ara.T.Howard
Guest
Posts: n/a
 
      12-18-2003
On Thu, 18 Dec 2003, Gavin Sinclair wrote:

> Date: Thu, 18 Dec 2003 13:51:45 +0900
> From: Gavin Sinclair <(E-Mail Removed)>
> 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.
> >
> > 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


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
--

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 :: http://www.ngdc.noaa.gov/stp/
| 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'
================================================== =============================

 
Reply With Quote
 
why the lucky stiff
Guest
Posts: n/a
 
      12-18-2003
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


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


 
Reply With Quote
 
Gennady
Guest
Posts: n/a
 
      12-18-2003

why the lucky stiff wrote:
> 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

>
>
> 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 ?), 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.

>
> 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
>
>




 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Caught Exception: System.Configuration.ConfigurationErrorsException: An error occurred loading a configuration file: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicK Mike ASP .Net 5 08-15-2007 08:57 AM
Enterprise Library exception: The configuration section securityCryptographyConfiguration is not defined in the current configuration for the AppDomain. Jess Chadwick ASP .Net 1 09-21-2006 09:18 AM
Configuration reverted to previous configuration after power loss ward@sciinc.com Cisco 0 03-03-2006 04:14 PM
Microsoft Configuration Block and Enterprise library configuration tool Mark ASP .Net 0 02-15-2006 11:27 PM
PEAP Configuration Woes - PEAP configuration help jester Cisco 1 12-20-2005 02:04 PM



Advertisments