# Help with the DSL (ish) config class

**URL:** <https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505>\
**Category:** Ruby\
**Created:** [February 28, 2008, 8:52pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505 "2008-02-28T20:52:05Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 28, 2008, 8:52pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/1 "2008-02-28T20:52:05Z")

</div>

Hi,

I experimenting with this config class. I’m hoping to get something  
really easy to write and I’m on to something here, well at least I  
thought I was. This class allows me to build a nested Has like:

Config.new do  
simple\_setting ‘the value’  
nested {  
nested\_key ‘nested\_value’  
deep\_nesting {  
deep\_nested\_key ‘deep nested value’  
}  
}  
end

The problem is that if I have a key that matches the name of the Hash  
class method set, problems arise. Currently, the only way that the  
settings can be made is if the method doesn’t exist (using  
method\_missing). Obviously, this is a problem. Would someone mind  
kicking in here and giving me a clue as to how I could solve this  
problem? Is it possible to do what I want, with out having to use  
method\_missing?

Thanks - matt

class Config \< Hash  
def initialize(init\_data=nil, &block)  
update init\_data if init\_data.respond\_to?(:each\_pair)  
configure(&block)  
end

def configure(&block)  
instance\_eval(&block) if block\_given?  
end

def method\_missing(method, data=nil, &block)  
self[method] = data  
if data.nil?  
# if data.nil?, create a skelton using the method as key (method  
chaining)  
return self[method] = self.class.new(data, &block)  
end  
self  
end  
end

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 28, 2008, 9:50pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/2 "2008-02-28T21:50:32Z")

</div>

On Feb 28, 12:50 pm, goodieboy [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> deep_nesting {
> 
> ```
> 
> problem? Is it possible to do what I want, with out having to use  
> def configure(&block)  
> self  
> end  
> end

i’ve already done it for you:

[http://codeforpeople.com/lib/ruby/configuration/configuration-0.0.5/README](http://codeforpeople.com/lib/ruby/configuration/configuration-0.0.5/README)

gem install configuration

cheeers

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 28, 2008, 10:16pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/3 "2008-02-28T22:16:43Z")

</div>

Hi that’s great! I’m wondering though, is it possible to turn the  
whole thing into a Hash?

What I’d like to be able to do is:

1. create a default config with only the code to be evaluated
2. push that code into a file (no problem)
3. load it into a hash later

With #1, here is an example:  
Configuration.for(‘a’){  
a 40  
b 4  
c 2  
}

I’d like to have a file with only this in it:  
a 40  
b 4  
c 2

Is that possible? Without calling self?

Thanks again, I’m going to pick this apart and see if I can learn  
something from it! 🙂

Matt

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 29, 2008, 12:11am UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/4 "2008-02-29T00:11:23Z")

</div>

Drew O. wrote:

> M.W. Mitchell wrote:
> 
> > Hi,
> > 
> > I experimenting with this config class. I’m hoping to get something  
> > really easy to write and I’m on to something here, well at least I  
> > thought I was. This class allows me to build a nested Has like:
> 
> I threw this together in a few minutes, doesn’t support nested hashes  
> though ☹

I spoke too soon, it does now 🙂

require ‘yaml’

class Configuration  
def initialize(filename=nil)  
@filename = filename  
@hash = {}  
end

def method\_missing(name,\*args,&block)  
if block  
config = Configuration.new  
config.instance\_eval(&block)  
@hash[name] = config.hash\_value  
else  
@hash[name] = args.first  
end  
end

def store  
File.open(@filename,“w”) do |out|  
out \<\< YAML::dump(@hash)  
end  
end

def hash\_value  
@hash  
end  
end

def Configuration filename=nil,&block  
config = Configuration.new(filename)  
config.instance\_eval(&block)  
end

Configuration “my\_app.yaml” do  
a 10  
b 20  
c 30  
d do  
d1 10  
d2 20  
end

store  
end

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 29, 2008, 12:05am UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/5 "2008-02-29T00:05:52Z")

</div>

M.W. Mitchell wrote:

> Hi,
> 
> I experimenting with this config class. I’m hoping to get something  
> really easy to write and I’m on to something here, well at least I  
> thought I was. This class allows me to build a nested Has like:

I threw this together in a few minutes, doesn’t support nested hashes  
though ☹ It writes out your hash to a .yaml file that you can read in  
later.

- Drew

require ‘yaml’

class Configuration  
def initialize(filename)  
@filename = filename  
@hash = {}  
end

def method\_missing(name,\*args)  
@hash[name] = args.first  
end

def store  
File.open(@filename,“w”) do |out|  
out \<\< YAML::dump(@hash)  
end  
end  
end

def Configuration filename,&block  
config = Configuration.new(filename)  
config.instance\_eval(&block)  
end

Configuration “my\_app.yaml” do  
a 10  
b 20  
c 30

store  
end

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [March 2, 2008, 4:34pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/6 "2008-03-02T16:34:40Z")

</div>

Hi,

Thanks Drew. I had something like that working too. But the problem is  
method\_missing. What if I want to create a key that happens to have  
the same name as a method that actually exists? Also, how would you  
convert that to a hash?

Thanks again,  
Matt

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [March 2, 2008, 5:27pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/7 "2008-03-02T17:27:08Z")

</div>

M.W. Mitchell wrote:

> Hi,
> 
> Thanks Drew. I had something like that working too. But the problem is  
> method\_missing. What if I want to create a key that happens to have  
> the same name as a method that actually exists? Also, how would you  
> convert that to a hash?
> 
> Thanks again,  
> Matt

Matt -

That code actually produces a hash, we are just storing it in a file. If  
you wanted to grab the file and use the hash, you would do something  
along the lines of:

my\_hash = YAML::load(File.read(“my\_file.yaml”))

As far as the method\_missing issues, this is a typical example of where  
using something like BlankSlate would be helpful. You can read more  
about it here:  
[http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc](http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc)

- Drew

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [March 14, 2008, 6:10pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/8 "2008-03-14T18:10:36Z")

</div>

Cool that’s exactly what I was looking for! I came up with this simple  
little piece:

class Config

instance\_methods.each { |m| undef\_method m unless (m =~ /^\_\_/) or  
[‘class’, ‘instance\_eval’].include?(m) }

def initialize(init\_data=nil, &block)  
@d = init\_data || {}  
instance\_eval(&block) if block\_given?  
end

def to\_hash; @d; end

def method\_missing(method, data=nil, &block)  
@d[method] = data  
return @d[method] = self.class.new(data, &block).to\_hash if  
data.nil?  
@d  
end

end

c = Config.new do  
simple\_setting ‘the value’  
send ‘Testing send’  
nested {  
new ‘Testing new, make sure it gets passed to method\_missing’  
nested\_key ‘nested\_value’  
deep\_nesting {  
deep\_nested\_key ‘deep nested value’  
o ‘Test’  
instance\_variables ‘test’  
}  
}  
end

puts c.to\_hash.inspect

Thanks for all of your help and suggestions. I learned quite a bit  
from this 🙂

Matt

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [March 14, 2008, 6:23pm UTC](https://www.ruby-forum.com/t/help-with-the-dsl-ish-config-class/130505/9 "2008-03-14T18:23:01Z")

</div>

Thought I’d just update this as it’s exactly what I was trying to do -  
have the config settings in a file, but only the block contents. Now  
in your config file, you can do:

# my\_config.rb

rows 10  
query\_fields [:name,:address]  
facets {  
fields [:business,:product\_category]  
offset 0  
}

And to turn that into a Hash:  
Config.load\_from\_file(‘my\_config.rb’).to\_hash

Neat!

-matt

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

class Config

instance\_methods.each { |m| undef\_method m unless (m =~ /^\_\_/) or  
[‘class’, ‘instance\_eval’].include?(m) }

def initialize(init\_data=nil, &block)  
@d = init\_data || {}  
instance\_eval(&block) if block\_given?  
end

def to\_hash; @d; end

def self.load\_from\_file(file)  
self.new.instance\_eval File.read(file)  
end

protected

def method\_missing(method, data=nil, &block)  
@d[method] = data  
return @d[method] = self.class.new(data, &block).to\_hash if  
data.nil?  
@d  
end

end
