From 567d4f1c2d152cd3424861df053ed2f2dec9eb7e Mon Sep 17 00:00:00 2001 From: Wes Boynton Date: Sat, 6 Mar 2021 17:13:49 -0500 Subject: [PATCH 1/3] Add namespaces to YAML sources per #288 --- lib/config/sources/yaml_source.rb | 17 +++++++++++--- spec/sources/yaml_source_spec.rb | 37 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/config/sources/yaml_source.rb b/lib/config/sources/yaml_source.rb index b14eb676..c007cea5 100644 --- a/lib/config/sources/yaml_source.rb +++ b/lib/config/sources/yaml_source.rb @@ -6,15 +6,26 @@ module Sources class YAMLSource attr_accessor :path - def initialize(path) + def initialize(path, namespace = nil) @path = path.to_s + + # Make sure @namespace is an array if it exists at all + if namespace + @namespace = namespace + @namespace = [@namespace] unless @namespace.is_a?(Array) + end end # returns a config hash from the YML file def load result = YAML.load(ERB.new(IO.read(@path)).result) if @path and File.exist?(@path) - - result || {} + return {} unless result + return result unless @namespace + + # Resolves namespacing multiple layers deep + # i.e. ['layer1', 'layer2'] comes out to {'layer1' => {'layer2' => content}} + return result = @namespace.reverse.inject(result) { |a, n| { n => a } } + rescue Psych::SyntaxError => e raise "YAML syntax error occurred while parsing #{@path}. " \ diff --git a/spec/sources/yaml_source_spec.rb b/spec/sources/yaml_source_spec.rb index ee93410f..c70a2d98 100644 --- a/spec/sources/yaml_source_spec.rb +++ b/spec/sources/yaml_source_spec.rb @@ -25,6 +25,43 @@ module Config::Sources end end + context "basic yml file with single namespace" do + let(:source) do + YAMLSource.new "#{fixture_path}/development.yml", 'test_namespace' + end + + it "should properly read the settings" do + results = source.load + expect(results['test_namespace']["size"]).to eq(2) + end + + it "should properly read nested settings" do + results = source.load + pp results + expect(results['test_namespace']["section"]["size"]).to eq(3) + expect(results['test_namespace']["section"]["servers"]).to be_instance_of(Array) + expect(results['test_namespace']["section"]["servers"].size).to eq(2) + end + end + + context "basic yml file with nested namespace" do + let(:source) do + YAMLSource.new "#{fixture_path}/development.yml", ['test_namespace', 'test_layer_2'] + end + + it "should properly read the settings" do + results = source.load + expect(results['test_namespace']['test_layer_2']["size"]).to eq(2) + end + + it "should properly read nested settings" do + results = source.load + expect(results['test_namespace']['test_layer_2']["section"]["size"]).to eq(3) + expect(results['test_namespace']['test_layer_2']["section"]["servers"]).to be_instance_of(Array) + expect(results['test_namespace']['test_layer_2']["section"]["servers"].size).to eq(2) + end + end + context "yml file with erb tags" do let(:source) do YAMLSource.new "#{fixture_path}/with_erb.yml" From 244c5758edf34e232810a1619f93e8becc3a407c Mon Sep 17 00:00:00 2001 From: Wes Boynton Date: Sat, 6 Mar 2021 21:58:43 -0500 Subject: [PATCH 2/3] Removed leftover test code from yaml_source_spec --- spec/sources/yaml_source_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/sources/yaml_source_spec.rb b/spec/sources/yaml_source_spec.rb index c70a2d98..e61fc1e8 100644 --- a/spec/sources/yaml_source_spec.rb +++ b/spec/sources/yaml_source_spec.rb @@ -37,7 +37,6 @@ module Config::Sources it "should properly read nested settings" do results = source.load - pp results expect(results['test_namespace']["section"]["size"]).to eq(3) expect(results['test_namespace']["section"]["servers"]).to be_instance_of(Array) expect(results['test_namespace']["section"]["servers"].size).to eq(2) From 5b76cd9f6eda1301093729ce3ac88e81131c9d97 Mon Sep 17 00:00:00 2001 From: Wes Boynton Date: Sat, 6 Mar 2021 23:34:54 -0500 Subject: [PATCH 3/3] Adding the namespace-type functionality for hashes as well. --- lib/config/options.rb | 12 +++---- lib/config/sources/hash_source.rb | 12 +++++-- lib/config/sources/yaml_source.rb | 2 +- spec/sources/hash_source_spec.rb | 56 +++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/lib/config/options.rb b/lib/config/options.rb index 40e49f6a..fa89432c 100644 --- a/lib/config/options.rb +++ b/lib/config/options.rb @@ -14,18 +14,18 @@ def empty? marshal_dump.empty? end - def add_source!(source) + def add_source!(source, namespace = nil) # handle yaml file paths - source = (Sources::YAMLSource.new(source)) if source.is_a?(String) - source = (Sources::HashSource.new(source)) if source.is_a?(Hash) + source = (Sources::YAMLSource.new(source, namespace)) if source.is_a?(String) + source = (Sources::HashSource.new(source, namespace)) if source.is_a?(Hash) @config_sources ||= [] @config_sources << source end - def prepend_source!(source) - source = (Sources::YAMLSource.new(source)) if source.is_a?(String) - source = (Sources::HashSource.new(source)) if source.is_a?(Hash) + def prepend_source!(source, namespace = nil) + source = (Sources::YAMLSource.new(source, namespace)) if source.is_a?(String) + source = (Sources::HashSource.new(source, namespace)) if source.is_a?(Hash) @config_sources ||= [] @config_sources.unshift(source) diff --git a/lib/config/sources/hash_source.rb b/lib/config/sources/hash_source.rb index f32dda2a..2e0c6ad5 100644 --- a/lib/config/sources/hash_source.rb +++ b/lib/config/sources/hash_source.rb @@ -3,13 +3,21 @@ module Sources class HashSource attr_accessor :hash - def initialize(hash) + def initialize(hash, namespace = nil) @hash = hash + + # Make sure @namespace is an array if it exists at all + if namespace + @namespace = namespace + @namespace = [@namespace] unless @namespace.is_a?(Array) + end end # returns hash that was passed in to initialize def load - hash.is_a?(Hash) ? hash : {} + return {} unless hash.is_a?(Hash) + return hash unless @namespace + return @namespace.reverse.inject(hash) { |a, n| { n => a } } end end end diff --git a/lib/config/sources/yaml_source.rb b/lib/config/sources/yaml_source.rb index c007cea5..3d17db6e 100644 --- a/lib/config/sources/yaml_source.rb +++ b/lib/config/sources/yaml_source.rb @@ -24,7 +24,7 @@ def load # Resolves namespacing multiple layers deep # i.e. ['layer1', 'layer2'] comes out to {'layer1' => {'layer2' => content}} - return result = @namespace.reverse.inject(result) { |a, n| { n => a } } + return @namespace.reverse.inject(result) { |a, n| { n => a } } rescue Psych::SyntaxError => e diff --git a/spec/sources/hash_source_spec.rb b/spec/sources/hash_source_spec.rb index c6d22958..ddfe3869 100644 --- a/spec/sources/hash_source_spec.rb +++ b/spec/sources/hash_source_spec.rb @@ -9,7 +9,7 @@ module Config::Sources context "basic hash" do let(:source) do - HashSource.new( + example_hash = { "size" => 2, "section" => { @@ -17,7 +17,7 @@ module Config::Sources "servers" => [ {"name" => "yahoo.com"}, {"name" => "amazon.com"} ] } } - ) + HashSource.new(example_hash) end it "should properly read the settings" do @@ -33,6 +33,58 @@ module Config::Sources end end + context "basic hash with single namespace" do + let(:source) do + example_hash = + { + "size" => 2, + "section" => { + "size" => 3, + "servers" => [ {"name" => "yahoo.com"}, {"name" => "amazon.com"} ] + } + } + HashSource.new(example_hash, 'test_namespace') + end + + it "should properly read the settings" do + results = source.load + expect(results['test_namespace']["size"]).to eq(2) + end + + it "should properly read nested settings" do + results = source.load + expect(results['test_namespace']["section"]["size"]).to eq(3) + expect(results['test_namespace']["section"]["servers"]).to be_instance_of(Array) + expect(results['test_namespace']["section"]["servers"].size).to eq(2) + end + end + + context "basic hash with nested namespace" do + let(:source) do + example_hash = + { + "size" => 2, + "section" => { + "size" => 3, + "servers" => [ {"name" => "yahoo.com"}, {"name" => "amazon.com"} ] + } + } + HashSource.new(example_hash, ['test_namespace', 'test_layer_2']) + end + + it "should properly read the settings" do + results = source.load + expect(results['test_namespace']['test_layer_2']["size"]).to eq(2) + end + + it "should properly read nested settings" do + results = source.load + expect(results['test_namespace']['test_layer_2']["section"]["size"]).to eq(3) + expect(results['test_namespace']['test_layer_2']["section"]["servers"]).to be_instance_of(Array) + expect(results['test_namespace']['test_layer_2']["section"]["servers"].size).to eq(2) + end + end + context "parameter is not a hash" do let(:source) do HashSource.new "hello world"