Class: Settingslogic
- Inherits:
-
Hash
- Object
- Hash
- Settingslogic
- Defined in:
- lib/settingslogic.rb
Overview
A simple settings solution using a YAML file. See README for more information.
Defined Under Namespace
Classes: 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 = self.class.source, section = nil) ⇒ Settingslogic
constructor
Initializes a new settings object.
-
#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
- #symbolize_keys ⇒ Object
-
#to_hash ⇒ Object
Returns an instance of a Hash object.
Constructor Details
#initialize(hash_or_file = self.class.source, section = nil) ⇒ 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)
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. Then you can pass a hash, and it just allows you to access the hash via methods.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/settingslogic.rb', line 95 def initialize(hash_or_file = self.class.source, section = nil) #puts "new! #{hash_or_file}" case hash_or_file when nil raise Errno::ENOENT, "No file specified as Settingslogic source" when Hash self.replace hash_or_file else hash = {} files = hash_or_file.reject { |file| file.nil? } files.each do |file| next unless File.exist? file file_contents = open(file).read raw_result = YAML.load(ERB.new(file_contents).result) single_hash = raw_result ? raw_result : {} hash.merge! single_hash end if self.class.namespace hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{files.join(', ')}") end self.replace hash end @section = section || self.class.source.reject { |file| file.nil? }.join(', ') # so end of error says "in application.yml" create_accessors! 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.
124 125 126 127 128 129 130 |
# File 'lib/settingslogic.rb', line 124 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
37 38 39 |
# File 'lib/settingslogic.rb', line 37 def [](key) instance.fetch(key.to_s, nil) end |
.[]=(key, val) ⇒ Object
41 42 43 44 45 46 |
# File 'lib/settingslogic.rb', line 41 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
15 16 17 18 19 20 21 22 |
# File 'lib/settingslogic.rb', line 15 def get(key) parts = key.split('.') curs = self while p = parts.shift curs = curs.send(p) end curs end |
.load! ⇒ Object
48 49 50 51 |
# File 'lib/settingslogic.rb', line 48 def load! instance true end |
.name ⇒ Object
:nodoc:
10 11 12 |
# File 'lib/settingslogic.rb', line 10 def name # :nodoc: self.superclass != Hash && instance.key?("name") ? instance.name : super end |
.namespace(value = nil) ⇒ Object
29 30 31 |
# File 'lib/settingslogic.rb', line 29 def namespace(value = nil) @namespace ||= value end |
.reload! ⇒ Object
53 54 55 56 |
# File 'lib/settingslogic.rb', line 53 def reload! @instance = nil load! end |
.source(value = nil) ⇒ Object
24 25 26 27 |
# File 'lib/settingslogic.rb', line 24 def source(value = nil) @source ||= [] @source << value end |
.suppress_errors(value = nil) ⇒ Object
33 34 35 |
# File 'lib/settingslogic.rb', line 33 def suppress_errors(value = nil) @suppress_errors ||= value end |
Instance Method Details
#[](key) ⇒ Object
132 133 134 |
# File 'lib/settingslogic.rb', line 132 def [](key) fetch(key.to_s, nil) end |
#[]=(key, val) ⇒ Object
136 137 138 139 140 141 |
# File 'lib/settingslogic.rb', line 136 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/
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/settingslogic.rb', line 161 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) self.class.class_eval <<-EndEval def #{key} return @#{key} if @#{key} return missing_key("Missing setting '#{key}' in #{@section}") unless has_key? '#{key}' value = fetch('#{key}') @#{key} = if value.is_a?(Hash) self.class.new(value, "'#{key}' section in #{@section}") elsif value.is_a?(Array) && value.all?{|v| v.is_a? Hash} value.map{|v| self.class.new(v)} else value end 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.
152 153 154 155 156 |
# File 'lib/settingslogic.rb', line 152 def create_accessors! self.each do |key,val| create_accessor_for(key) end end |
#missing_key(msg) ⇒ Object
192 193 194 195 196 |
# File 'lib/settingslogic.rb', line 192 def missing_key(msg) return nil if self.class.suppress_errors raise MissingSetting, msg end |
#symbolize_keys ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/settingslogic.rb', line 180 def symbolize_keys inject({}) do |memo, tuple| k = (tuple.first.to_sym rescue tuple.first) || tuple.first v = k.is_a?(Symbol) ? send(k) : tuple.last # make sure the value is accessed the same way Settings.foo.bar works memo[k] = v && v.respond_to?(:symbolize_keys) ? v.symbolize_keys : v #recurse for nested hashes memo end end |
#to_hash ⇒ Object
Returns an instance of a Hash object
144 145 146 |
# File 'lib/settingslogic.rb', line 144 def to_hash Hash[self] end |