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.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/settingslogic.rb', line 94 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 file_contents = open(hash_or_file).read hash = if file_contents.empty? {} else payload = ::ERB.new(file_contents).result (::YAML.respond_to?(:unsafe_load) ? ::YAML.unsafe_load(payload) : ::YAML.load(payload)).to_hash end if self.class.namespace hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}") end self.replace hash end @section = section || self.class.source # 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.
120 121 122 123 124 125 126 |
# File 'lib/settingslogic.rb', line 120 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
36 37 38 |
# File 'lib/settingslogic.rb', line 36 def [](key) instance.fetch(key.to_s, nil) end |
.[]=(key, val) ⇒ Object
40 41 42 43 44 45 |
# File 'lib/settingslogic.rb', line 40 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
47 48 49 50 |
# File 'lib/settingslogic.rb', line 47 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
28 29 30 |
# File 'lib/settingslogic.rb', line 28 def namespace(value = nil) @namespace ||= value end |
.reload! ⇒ Object
52 53 54 55 |
# File 'lib/settingslogic.rb', line 52 def reload! @instance = nil load! end |
.source(value = nil) ⇒ Object
24 25 26 |
# File 'lib/settingslogic.rb', line 24 def source(value = nil) @source ||= value end |
.suppress_errors(value = nil) ⇒ Object
32 33 34 |
# File 'lib/settingslogic.rb', line 32 def suppress_errors(value = nil) @suppress_errors ||= value end |
Instance Method Details
#[](key) ⇒ Object
128 129 130 |
# File 'lib/settingslogic.rb', line 128 def [](key) fetch(key.to_s, nil) end |
#[]=(key, val) ⇒ Object
132 133 134 135 136 137 |
# File 'lib/settingslogic.rb', line 132 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/
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/settingslogic.rb', line 157 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.
148 149 150 151 152 |
# File 'lib/settingslogic.rb', line 148 def create_accessors! self.each do |key,val| create_accessor_for(key) end end |
#missing_key(msg) ⇒ Object
191 192 193 194 195 |
# File 'lib/settingslogic.rb', line 191 def missing_key(msg) return nil if self.class.suppress_errors raise MissingSetting, msg end |
#symbolize_keys ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/settingslogic.rb', line 176 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
140 141 142 |
# File 'lib/settingslogic.rb', line 140 def to_hash Hash[self] end |