tags:

views:

42

answers:

1

I have a configuration class in Ruby that used to have keys like "core.username" and "core.servers", which was stored in a YAML file just like that.

Now I'm trying to change it to be nested, but without having to change all the places that refer to keys in the old way. I've managed it with the reader-method:

def [](key)
  namespace, *rest = key.split(".")

  target = @config[namespace]
  rest.each do |k|
    return nil unless target[k]
    target = target[k]
  end

  target
end

But when I tried the same with the writer-class, that works, but isn't set in the @config-hash. @config is set with just a call to YAML.load_file

I managed to get it working with eval, but that is not something I would like to keep for long.

def []=(key, value)
  namespace, *rest = key.split(".")

  target = "@config[\"#{namespace}\"]"
  rest.each do |key|
    target += "[\"#{key}\"]"
  end

  eval "#{target} = value"
  self[key]
end

Is there any decent way to achieve this, preferably without changing plugins and code throughout?

A: 
def []=(key, value)
  subkeys = key.split(".")
  lastkey = subkeys.pop
  subhash = subkeys.inject(@config) do |hash, k|
    hash[k]
  end
  subhash[lastkey] = value
end

Edit: Fixed the split. PS: You can also replace the inject with an each-loop like in the [] method if you prefer. The important thing is that you do not call [] with the last key, but instead []= to set the value.

sepp2k
You forgot to split on "." instead of spaces, but other than that, it works like a charm. Thanks!