Class: Settingslogic
Overview
A simple settings solution using a YAML file. See README for more information.
Defined Under Namespace
Classes: InvalidSettingsFile, MissingSetting
Class Method Summary collapse
- .[](key) ⇒ Object
- .[]=(key, val) ⇒ Object
-
.get(key) ⇒ Object
Enables Settings.get(‘nested.key.name’) for dynamic access.
- .load! ⇒ Object
-
.name ⇒ Object
:nodoc:.
- .namespace(value = nil) ⇒ Object
- .reload! ⇒ Object
- .source(value = nil) ⇒ Object
- .suppress_errors(value = nil) ⇒ Object
Instance Method Summary collapse
- #[](key) ⇒ Object
- #[]=(key, val) ⇒ Object
-
#create_accessor_for(key, val = nil) ⇒ Object
Use instance_eval/class_eval because they’re actually more efficient than define_method{} stackoverflow.com/questions/185947/ruby-definemethod-vs-def bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/.
-
#create_accessors! ⇒ Object
This handles naming collisions with Sinatra/Vlad/Capistrano.
-
#initialize(hash_or_file_or_array = self.class.source, section = nil, options = {}) ⇒ Settingslogic
constructor
Initializes a new settings object.
- #load_source(hash_or_file_or_array, section = nil, options = {}) ⇒ Object
-
#merge_settings_from_files(array, options = {}) ⇒ Object
For each array element - if file exists, parse it to hash if namespace is present take only specified part.
-
#method_missing(name, *args, &block) ⇒ Object
Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
- #missing_key(msg) ⇒ Object
Methods inherited from Hash
#deep_delete_nil, #deep_merge!
Constructor Details
#initialize(hash_or_file_or_array = self.class.source, section = nil, options = {}) ⇒ Settingslogic
Initializes a new settings object. You can initialize an object in any of the following ways:
Settings.new(:application) # will look for config/application.yml
Settings.new("application.yaml") # will look for application.yaml
Settings.new("/var/configs/application.yml") # will look for /var/configs/application.yml
Settings.new(:config1 => 1, :config2 => 2)
Settings.new(["defaults.yml", "test.yml"]) # will look for defaults.yml and test.yml and merge them
Basically if you pass a symbol it will look for that file in the configs directory of your rails app, if you are using this in rails. If you pass a string it should be an absolute path to your settings file. If you pass an array, it should have strings that are absolute paths to your settings files. Then you can pass a hash, and it just allows you to access the hash via methods.
Options
-
deep_delete_nil: remove nil values from hash ex. :a=>{:b=>nil}.deep_delete_nil => {}
-
replace: if true, replace existing value, by new one, otherwise merge
128 129 130 |
# File 'lib/settingslogic.rb', line 128 def initialize(hash_or_file_or_array = self.class.source, section = nil, ={}) load_source(hash_or_file_or_array, section, {:replace => true}.merge()) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
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.
175 176 177 178 179 180 181 |
# File 'lib/settingslogic.rb', line 175 def method_missing(name, *args, &block) key = name.to_s return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? key value = fetch(key) create_accessor_for(key) value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value end |
Class Method Details
.[](key) ⇒ Object
64 65 66 |
# File 'lib/settingslogic.rb', line 64 def [](key) instance.fetch(key.to_s, nil) end |
.[]=(key, val) ⇒ Object
68 69 70 71 72 73 |
# File 'lib/settingslogic.rb', line 68 def []=(key, val) # Setting[:key][:key2] = 'value' for dynamic settings val = new(val, source) if val.is_a? Hash instance.store(key.to_s, val) instance.create_accessor_for(key, val) end |
.get(key) ⇒ Object
Enables Settings.get(‘nested.key.name’) for dynamic access
30 31 32 33 34 35 36 37 |
# File 'lib/settingslogic.rb', line 30 def get(key) parts = key.split('.') curs = self while p = parts.shift curs = curs.send(p) end curs end |
.load! ⇒ Object
75 76 77 78 |
# File 'lib/settingslogic.rb', line 75 def load! instance true end |
.name ⇒ Object
:nodoc:
25 26 27 |
# File 'lib/settingslogic.rb', line 25 def name # :nodoc: self.superclass != Hash && instance.key?("name") ? instance.name : super end |
.namespace(value = nil) ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/settingslogic.rb', line 48 def namespace(value = nil) if value.nil? @namespace else @namespace = value end end |
.reload! ⇒ Object
80 81 82 83 |
# File 'lib/settingslogic.rb', line 80 def reload! @instance = nil load! end |
.source(value = nil) ⇒ Object
39 40 41 42 43 44 45 46 |
# File 'lib/settingslogic.rb', line 39 def source(value = nil) #puts "source! #{value.inspect}" if value.nil? || value.empty? @source else @source = value end end |
.suppress_errors(value = nil) ⇒ Object
56 57 58 59 60 61 62 |
# File 'lib/settingslogic.rb', line 56 def suppress_errors(value = nil) if value.nil? @suppress_errors else @suppress_errors = value end end |
Instance Method Details
#[](key) ⇒ Object
183 184 185 |
# File 'lib/settingslogic.rb', line 183 def [](key) fetch(key.to_s, nil) end |
#[]=(key, val) ⇒ Object
187 188 189 190 191 192 |
# File 'lib/settingslogic.rb', line 187 def []=(key,val) # Setting[:key][:key2] = 'value' for dynamic settings val = self.class.new(val, @section) if val.is_a? Hash store(key.to_s, val) create_accessor_for(key, val) end |
#create_accessor_for(key, val = nil) ⇒ Object
Use instance_eval/class_eval because they’re actually more efficient than define_method{} stackoverflow.com/questions/185947/ruby-definemethod-vs-def bmorearty.wordpress.com/2009/01/09/fun-with-rubys-instance_eval-and-class_eval/
207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/settingslogic.rb', line 207 def create_accessor_for(key, val=nil) return unless key.to_s =~ /^\w+$/ # could have "some-setting:" which blows up eval instance_variable_set("@#{key}", val) if val self.class.class_eval <<-EndEval def #{key} return @#{key} if @#{key} return missing_key("Missing setting '#{key}' in " + @section.to_s) unless has_key? '#{key}' value = fetch('#{key}') @#{key} = value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in "+ @section.to_s) : value end EndEval end |
#create_accessors! ⇒ Object
This handles naming collisions with Sinatra/Vlad/Capistrano. Since these use a set() helper that defines methods in Object, ANY method_missing ANYWHERE picks up the Vlad/Sinatra settings! So settings.deploy_to title actually calls Object.deploy_to (from set :deploy_to, “host”), rather than the app_yml hash. Jeezus.
198 199 200 201 202 |
# File 'lib/settingslogic.rb', line 198 def create_accessors! self.each do |key,val| create_accessor_for(key) end end |
#load_source(hash_or_file_or_array, section = nil, options = {}) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/settingslogic.rb', line 132 def load_source(hash_or_file_or_array, section = nil, ={}) hash = case hash_or_file_or_array when nil raise Errno::ENOENT, "No file specified as Settingslogic source" when Hash hash_or_file_or_array when Array merge_settings_from_files(hash_or_file_or_array, ) else merge_settings_from_files([hash_or_file_or_array], ) end hash.deep_delete_nil if [:deep_delete_nil] [:replace] ? self.replace(hash) : self.deep_merge!(hash) @section = section || self.class.source # so end of error says "in application.yml" create_accessors! end |
#merge_settings_from_files(array, options = {}) ⇒ Object
For each array element - if file exists, parse it to hash if namespace is present take only specified part
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/settingslogic.rb', line 151 def merge_settings_from_files(array, ={}) hash = array.inject({}) do |sum, file| if File.exists?(file) begin tmp_hash = YAML.load(ERB.new(open(file).read).result).to_hash if self.class.namespace tmp_hash = tmp_hash[self.class.namespace] || {} end rescue tmp_hash = {} # https://github.com/tenderlove/psych/issues/23 (Psych::SyntaxError doesn't inherit from StandardError) rescue Psych::SyntaxError tmp_hash = {} end sum.deep_merge!(tmp_hash) end sum end raise InvalidSettingsFile, "No correct settings in any of files #{array.inspect}" if hash.empty? hash end |
#missing_key(msg) ⇒ Object
220 221 222 223 224 |
# File 'lib/settingslogic.rb', line 220 def missing_key(msg) return nil if self.class.suppress_errors raise MissingSetting, msg end |