From f7172034fae634fe1eaeb75ece4e02848d8a18b3 Mon Sep 17 00:00:00 2001 From: Ricardo Valeriano Date: Wed, 16 Apr 2014 18:20:33 -0300 Subject: [PATCH 1/4] generalizes `#get`, now it can be used to retrieve nested values from any hash. you can pass a block to say what need to be done when a key isn't in the hash. --- lib/settingslogic.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/settingslogic.rb b/lib/settingslogic.rb index a99acaf..1e75596 100644 --- a/lib/settingslogic.rb +++ b/lib/settingslogic.rb @@ -12,11 +12,11 @@ def name # :nodoc: end # Enables Settings.get('nested.key.name') for dynamic access - def get(key) + def get(key, hash = nil) parts = key.split('.') - curs = self + curs = hash || self while p = parts.shift - curs = curs.send(p) + curs = curs[p] or (yield p if block_given?) end curs end From 423c7a4b41fa3da6204e2cc52603c24399404dec Mon Sep 17 00:00:00 2001 From: Ricardo Valeriano Date: Wed, 16 Apr 2014 18:21:27 -0300 Subject: [PATCH 2/4] accepts a nested namespace: # /some/file/here.yml professional: preferences: order: desc client: prefs: order: asc class ProfessionalPreferences < Settingslogic source "/some/file/here.yml" namespace "professional.preferences" end >> ProfessionalPreferences.order => "desc" --- lib/settingslogic.rb | 19 ++++++++++++++++--- spec/settings.rb | 12 +++++++++++- spec/settingslogic_spec.rb | 13 +++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/settingslogic.rb b/lib/settingslogic.rb index 1e75596..77d79e8 100644 --- a/lib/settingslogic.rb +++ b/lib/settingslogic.rb @@ -101,15 +101,28 @@ def initialize(hash_or_file = self.class.source, section = nil) else file_contents = open(hash_or_file).read hash = file_contents.empty? ? {} : YAML.load(ERB.new(file_contents).result).to_hash - if self.class.namespace - hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}") - end + hash = namespaced_hash(hash, hash_or_file) if self.class.namespace self.replace hash end @section = section || self.class.source # so end of error says "in application.yml" create_accessors! end + def namespaced_hash(hash, hash_or_file) + if self.class.namespace.include? "." + nested_namespaced_hash hash, hash_or_file + else + hash[namespace] or return missing_key("Missing setting '#{namespace}' in #{hash_or_file}") + end + end + + def nested_namespaced_hash(hash, hash_or_file) + self.class.get self.class.namespace, hash do |setting| + missing_key "Missing setting '#{setting}' for '#{self.class.namespace}' in #{hash_or_file}" + end + end + private :namespaced_hash, :nested_namespaced_hash + # Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used. # Otherwise, create_accessors! (called by new) will have created actual methods for each key. def method_missing(name, *args, &block) diff --git a/spec/settings.rb b/spec/settings.rb index 8c5be68..e80d41c 100644 --- a/spec/settings.rb +++ b/spec/settings.rb @@ -3,4 +3,14 @@ class Settings < Settingslogic end class SettingsInst < Settingslogic -end \ No newline at end of file +end + +class SettingsNestedNamespace < Settingslogic + source "#{File.dirname(__FILE__)}/settings.yml" + namespace "language.smalltalk" +end + +class SettingsInvalidNestedNamespace < Settingslogic + source "#{File.dirname(__FILE__)}/settings.yml" + namespace "inexistent.namespace.omg" +end diff --git a/spec/settingslogic_spec.rb b/spec/settingslogic_spec.rb index 34e4798..6f3ff1c 100644 --- a/spec/settingslogic_spec.rb +++ b/spec/settingslogic_spec.rb @@ -190,6 +190,19 @@ class NoSource < Settingslogic; end SettingsEmpty.keys.should eql([]) end + context "using a nested namespace (`language.smalltalk`)" do + it "returns the right internal nested value" do + expect(SettingsNestedNamespace.paradigm).to eq "object oriented" + end + + context "when namespace doesn't exists" do + it "raises the missing key error" do + expect { SettingsInvalidNestedNamespace.paradigm }.to \ + raise_error Settingslogic::MissingSetting + end + end + end + # Put this test last or else call to .instance will load @instance, # masking bugs. it "should be a hash" do From 17314f0ef51f549b782bcffb6456aa39893974a4 Mon Sep 17 00:00:00 2001 From: Ricardo Valeriano Date: Wed, 16 Apr 2014 18:21:35 -0300 Subject: [PATCH 3/4] documents the nested namespace feature --- README.rdoc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.rdoc b/README.rdoc index 7bcd4ae..2914cd0 100644 --- a/README.rdoc +++ b/README.rdoc @@ -61,6 +61,28 @@ If your default settings seem to be overwriting your environment-specific settin require 'yaml' YAML::ENGINE.yamler= 'syck' +==== Namespaced settings + +Maybe you need to use another semantics for your namespace besides the current +environment. You can put a nested namespace in your settings and you are good +to go. + + # /some/file/here.yml + professional: + preferences: + order: desc + client: + prefs: + order: asc + + class ProfessionalPreferences < Settingslogic + source "/some/file/here.yml" + namespace "professional.preferences" + end + + >> ProfessionalPreferences.order + => "desc" + === 3. Access your settings >> Rails.env From 96ceb1a55260c8aef63dbb0c033d8e8c90454b9d Mon Sep 17 00:00:00 2001 From: Ricardo Valeriano Date: Thu, 17 Apr 2014 01:56:42 -0300 Subject: [PATCH 4/4] just drying things a bit --- lib/settingslogic.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/settingslogic.rb b/lib/settingslogic.rb index 77d79e8..3bdf80e 100644 --- a/lib/settingslogic.rb +++ b/lib/settingslogic.rb @@ -108,20 +108,20 @@ def initialize(hash_or_file = self.class.source, section = nil) create_accessors! end - def namespaced_hash(hash, hash_or_file) - if self.class.namespace.include? "." - nested_namespaced_hash hash, hash_or_file + def missing_setting_action(namespace) + if namespace.include? "." + proc { missing_key "Missing setting '#{setting}' for '#{namespace}' in #{hash_or_file}" } else - hash[namespace] or return missing_key("Missing setting '#{namespace}' in #{hash_or_file}") + proc { missing_key "Missing setting '#{namespace}' in #{hash_or_file}" } end end - def nested_namespaced_hash(hash, hash_or_file) - self.class.get self.class.namespace, hash do |setting| - missing_key "Missing setting '#{setting}' for '#{self.class.namespace}' in #{hash_or_file}" - end + def namespaced_hash(hash, hash_or_file) + namespace = self.class.namespace + self.class.get namespace, hash, &missing_setting_action(namespace) end - private :namespaced_hash, :nested_namespaced_hash + + private :missing_setting_action, :namespaced_hash # Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used. # Otherwise, create_accessors! (called by new) will have created actual methods for each key.