Cascading configuration variables

Hi,

a little follow-up on loading config data as Ruby source files. I want my
project to load some full system defaults from a file, and then some
user-specified overrides from another file, and finally some special
overrides that are set on the commandline or from the calling environment.

I would like the variables with their values to be accessible as constants,
because I think that is faster than hash lookups, and it looks elegant,
because they will get referenced often from other script snippets that get
loaded after the config is read.

I figure that I can use modules to carry constants. Eg.

module Conf
include load (“userdefaults.conf”, true)
include load (“systemdefaults.conf”, true)
end

(This is done once, when starting the program.)

Now the Conf module contains all constants from systemdefaults,

but overridden by userdefaults (they are not overwritten by the system

defaults, because constants are not changed by include when they are set.

nou create a new class to hold new specified settings

(This can occur often during a session)

confc = Class.new ( OurBaseClass ) # OurBaseClass contains methods etc.
confc.const_set “CFLAGS”, “our value” # specific setting
confc.const_set “VAR2”, 1234
confc.class_eval “include Conf”

object = confc.new

our object now has all constants defined as needed, and all the methods from

OurBaseClass.

The constants will be referenced to like in my previous thread, by little

snippets of Ruby code loaded on demand.

My question: is this the most elegant (and fastest) way to do this? Or should
I use hashes where usersettings can simply overwrite system settings. The
code snippets then can’t just to:
ALSA && depend "audio/alsa-driver"
but must look like:
uses[“ALSA”] && depend "audio/alsa-driver"
or, using a method,
use “ALSA” && depend “audio/alsa-driver”

The 1st one really looks best to me.

Esp. wat is bothering me a little is that I need to create a new class for
every new object that I want to spawn that needs possibly different settings
for a few constants (user- and sys-defaults remain the same)

So what could be the most efficient way to set up cascading config options
like this?

thanks for all your help and thoughts!
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

Hi,

I would like the variables with their values to be accessible as constants,
because I think that is faster than hash lookups, and it looks elegant,
because they will get referenced often from other script snippets that get
loaded after the config is read.

Retrieving a constant needs to traverse the ancestors of that
module, it isn’t always faster than hash access. I agree it
looks simple/elegant.

I figure that I can use modules to carry constants. Eg.

module Conf
include load (“userdefaults.conf”, true)
include load (“systemdefaults.conf”, true)
end

I’m sorry to confuse you, Kernel#load never return created
wrapper modules. I wrote `If it were return’, it was just a
suggestion to modify. Use module_eval as you wrote, or
module_load I wrote, instead.

···

At Mon, 27 Jan 2003 00:15:38 +0900, Wilbert Berendsen wrote:


Nobu Nakada

a little follow-up on loading config data as Ruby source files. I
want my project to load some full system defaults from a file, and
then some user-specified overrides from another file, and finally
some special overrides that are set on the commandline or from the
calling environment.

I think there’s an RAA package called PseudoHash or something that
allows chaining hashes to retrieve different values (system, user,
default, etc.).

I would like the variables with their values to be accessible as
constants, because I think that is faster than hash lookups, and it
looks elegant, because they will get referenced often from other
script snippets that get loaded after the config is read.

I would go with hashes. Ruby hashes are very elegant, and I can’t
imagine there being any speed issue. Even if it wasn’t super fast, I
doubt it would be the bottleneck of your program.

If you really want to make them look like constants or whatever, the
package might define method_missing appropriately, but I think that’s
rather inelegant.

Gavin

···

On Monday, January 27, 2003, 2:15:38 AM, Wilbert wrote:

Hi,

I would like the variables with their values to be accessible as
constants, because I think that is faster than hash lookups, and it looks
elegant, because they will get referenced often from other script
snippets that get loaded after the config is read.

Retrieving a constant needs to traverse the ancestors of that
module, it isn’t always faster than hash access. I agree it
looks simple/elegant.

A question about that traversal to the ancestors of a module:
is it possible to exclude (‘mixout’) a module again?
e.g.:
include Modulename
# now stuff like constants is available
exclude Modulename
# now not anymore.

Also: when do like this:
module Bla
m=Module.new
m.const_set “ALSA”, true
include m
end

Bla.module_eval “ALSA”

true

Bla.module_eval “m=nil; GC.start”
Bla.module_eval “ALSA”

true

so it seems the ALSA constant is still there; you can’t remove modules it
seems.

(… re include load)
Yes, I read it. It would be nice and in the spirit of Ruby if it did!

So after all I think constants look nice, but hashes may be the best way to
go.

bye,
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

···

On Sunday 26 January 2003 16:44, nobu.nokada@softhome.net wrote:

At Mon, 27 Jan 2003 00:15:38 +0900, > > Wilbert Berendsen wrote:

the

load ‘path’, ModuleName

modification you suggested would be a really good one IMHO. since all
legacy code would only call

load ‘path’

or

load ‘path’, true

it seems like this could be implemented without breaking any existing code.

-a

···

On Mon, 27 Jan 2003 nobu.nokada@softhome.net wrote:

I’m sorry to confuse you, Kernel#load never return created wrapper modules.
I wrote `If it were return’, it was just a suggestion to modify. Use
module_eval as you wrote, or module_load I wrote, instead.

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

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

Gavin Sinclair wrote:

a little follow-up on loading config data as Ruby source files. I
want my project to load some full system defaults from a file, and
then some user-specified overrides from another file, and finally
some special overrides that are set on the commandline or from the
calling environment.

I think there’s an RAA package called PseudoHash or something that
allows chaining hashes to retrieve different values (system, user,
default, etc.).

PseudoHash appears to be an ordered hash.

SuperHash allows chains of hashes which inherit key-value pairs. This
might be useful if you need to reuse, say, the system defaults several
times during the program (maybe for different users). But Hash#update
might serve just as well. The main difference is that SuperHash is
dynamic (changing system options would affect all users, existing and
future) whereas Hash#update is static (changing system options would
only affect users generated after the change).

···

On Monday, January 27, 2003, 2:15:38 AM, Wilbert wrote:

  include Modulename
  # now stuff like constants is available
  exclude Modulename
  # now not anymore.

   module A
      A_nice_constant = 12
   end
   module B
      include A
   end
   module C
      include A
   end

   class D
      include C
      include B
      exclude B # what module do you remove ? only B, or B and A ?
   end

Guy Decoux

Hi,

···

At Mon, 27 Jan 2003 01:13:39 +0900, ahoward wrote:

I’m sorry to confuse you, Kernel#load never return created wrapper modules.
I wrote `If it were return’, it was just a suggestion to modify. Use
module_eval as you wrote, or module_load I wrote, instead.

the

load ‘path’, ModuleName

modification you suggested would be a really good one IMHO. since all

Though it may be good, I guess an instance method of Module is
better.


Nobu Nakada

include Modulename
# now stuff like constants is available
exclude Modulename
# now not anymore.

module A
A_nice_constant = 12
end
module B
include A
end
module C
include A
end

class D
include C
include B
exclude B # what module do you remove ? only B, or B and A ?
end

well, I would think B and all ancestors of B. But the stuff from A would still
be available, because it also got included in C.

This way one could also do:
module A
CONSTANT=“hi there”
end
module B
include A
end
class C
include B
end
C.class_eval “CONSTANT”

“hi there”
B.module_eval “exclude A”
C.class_eval “CONSTANT”
warning: Uninitialized constant

But the problem is in fact, that I try to build something that is partially
dynamic, but using constants. I now think I just should use hashes instead of
a carefully constructed cascade of constants.

all the best,
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

···

On Sunday 26 January 2003 17:32, ts wrote:

well, I would think B and all ancestors of B. But the stuff from A would still
be available, because it also got included in C.

Unfortunately no : ruby never include twice the same module. If you remove
A and B, the stuff from A will not be available for the class D

Guy Decoux

well, I would think B and all ancestors of B. But the stuff from A
would still be available, because it also got included in C.

Unfortunately no : ruby never include twice the same module. If you
remove A and B, the stuff from A will not be available for the class D

I understand. But if every module has a list of (pointers to) different
ancestors, then this would be easily done.

e.g.: (assume A,B,C,D exist)

module E
include A, B, C, D
end

now module E has A,B,C and D mixed in.

module F
include E
end

Now F has 1 ancestor. E has 4. When ruby starts to search for a constant
(or method or whatever) it first looks in F itself. Then in the ancestor
that first got added, etc.

When I would do “exclude E” from within F, it would simply delete the
internal pointer to the E module. Now E would not be accessible any more.

But this is all imaginary. In reality, is a mixed-in module really like a
superclass? because a module can mix-in (include) another module in at
any time of its life, but classes cannot inherit a superclass later on.

to illutrate all my musings:

module A
KDE=true
end

module B
KDE=false
include A
end

B.module_eval “KDE”

false

so at the moment A gets included in B, Ruby finds that there is already a
constant with the name “KDE” and does not update it. But is this constant
KDE now in B or in A?

Because:

module A
KDE=true
end
module B
include A
KDE=false
end

issues a warning. Apparently, the “include A” from within B really sets
the constant in B.

Let me make clear, I understand (I hope:) how Ruby does it, but I’m just
curious.

all the best,
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

···

On Sunday 26 January 2003 17:56, ts wrote:

Sorry, little error on my part: This does not issue a warning but it
silently sets KDE to false in B.

Groet,
Wilbert


Wilbert Berendsen (http://www.xs4all.nl/~wbsoft/)
To understand recursion, one must first understand recursion.

···

On Sunday 26 January 2003 18:34, Wilbert Berendsen wrote:

Because:

module A
KDE=true
end
module B
include A
KDE=false
end

issues a warning. Apparently, the “include A” from within B really sets
the constant in B.

But this is all imaginary. In reality, is a mixed-in module really like a
superclass? because a module can mix-in (include) another module in at
any time of its life, but classes cannot inherit a superclass later on.

Well, with my previous example

   module A
      A_nice_constant = 12
   end
   module B
      include A
   end
   module C
      include A
   end

   class D # D inherit from Object
                   # search path is : D ==> Object

      include C # ruby make the include : first C then A
                   # search path is : D ==> C ==> A ==> Object

      include B # ruby make the include : first B, then A
                   # search path is : D ==> B ==> C ==> A ==> Object
                   # A is not included twice
   end

At this step, ruby has lost the information that `A' was provided by `B'
and `C'

Guy Decoux