From: "John W. Long" Date: 2003-12-18T13:01:10+09:00 Subject: Configuration Files ------=_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--