From 6b6140a3940e733b03a0b0b6cdf1b501765c6aac Mon Sep 17 00:00:00 2001 From: Seiichi KONDO Date: Sun, 18 Dec 2016 22:21:30 +0900 Subject: [PATCH] Fix that #to_hash replaces nested config objects with Hash `Config::Options#to_hash` mistakenly replaces nested `Config::Options` objects in arrays with `Hash` objects. Consider the following code: ```ruby > config = Config.load_files("spec/fixtures/development.yml"); > config.section.servers[0].class Config::Options > config.to_hash {:size=>2, :section=>{:size=>3, :servers=>[{:name=>"yahoo.com"}, {:name=>"amazon.com"}]}} > config.section.servers[0].class Hash ``` Therefore, after evaluating `config.to_hash`, `config.sections.servers[0].name` raises an exception. This is because `Config::Options#descend_array` overwrites array elements. This commit fixes the above problem by modifying the `Config::Options#descend_array`. --- lib/config/options.rb | 10 +++++----- spec/config_spec.rb | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/config/options.rb b/lib/config/options.rb index cf2f1cb5..f5713667 100644 --- a/lib/config/options.rb +++ b/lib/config/options.rb @@ -148,15 +148,15 @@ def []=(param, value) protected def descend_array(array) - array.length.times do |i| - value = array[i] + array.map do |value| if value.instance_of? Config::Options - array[i] = value.to_hash + value.to_hash elsif value.instance_of? Array - array[i] = descend_array(value) + descend_array(value) + else + value end end - array end # Recursively converts Hashes to Options (including Hashes inside Arrays) diff --git a/spec/config_spec.rb b/spec/config_spec.rb index 13286429..736bcd5f 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -60,6 +60,15 @@ expect(servers).to eq([{ name: "yahoo.com" }, { name: "amazon.com" }]) end + it "should convert to a hash without modifying nested settings" do + config = Config.load_files("#{fixture_path}/development.yml") + config.to_hash + expect(config).to be_kind_of(Config::Options) + expect(config[:section]).to be_kind_of(Config::Options) + expect(config[:section][:servers][0]).to be_kind_of(Config::Options) + expect(config[:section][:servers][1]).to be_kind_of(Config::Options) + end + it "should convert to a json" do config = Config.load_files("#{fixture_path}/development.yml").to_json expect(JSON.parse(config)["section"]["servers"]).to be_kind_of(Array)