Class: Settingslogic
- Inherits:
-
Hash
- Object
- Hash
- Settingslogic
- Defined in:
- lib/settingslogic.rb,
lib/settingslogic/version.rb
Overview
A simple settings solution using a YAML file. See README for more information.
Defined Under Namespace
Classes: MissingSetting
Constant Summary collapse
- VERSION =
'3.0.3'
Class Attribute Summary collapse
-
.yaml_permitted_classes ⇒ Object
Configure additional permitted classes for YAML deserialization Default: [Symbol, Date, Time, DateTime, BigDecimal] Example: Settingslogic.yaml_permitted_classes += [MyCustomClass].
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
- .use_yaml_unsafe_load ⇒ Object
-
.use_yaml_unsafe_load=(value) ⇒ Object
DEPRECATED: Temporarily allow unsafe YAML loading for backwards compatibility This option will be removed in v4.0.0 WARNING: This enables arbitrary code execution vulnerabilities!.
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.
-
#deep_merge(other_hash) ⇒ Object
Deep merge settings (useful for overrides).
-
#deep_merge!(other_hash) ⇒ Object
Deep merge in place.
-
#initialize(hash_or_file = self.class.source, section = nil) ⇒ Settingslogic
constructor
Initializes a new settings object.
-
#method_missing(name, *_args) ⇒ Object
Called for dynamically-defined keys, and also the first key deferenced at the top-level, if load! is not used.
-
#stringify_keys ⇒ Object
Convert all keys to strings recursively (Rails compatibility).
-
#symbolize_keys ⇒ Object
Convert all keys to symbols recursively.
-
#to_ary ⇒ Object
Prevents Array#flatten from trying to expand Settings objects This fixes RSpec issues when Settings objects are included in arrays.
-
#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.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/settingslogic.rb', line 123 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 replace hash_or_file else file_contents = read_file(hash_or_file) hash = file_contents.empty? ? {} : parse_yaml_content(file_contents) if self.class.namespace hash = hash[self.class.namespace] or return missing_key("Missing setting '#{self.class.namespace}' in #{hash_or_file}") end 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) ⇒ 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.
146 147 148 149 150 151 152 153 |
# File 'lib/settingslogic.rb', line 146 def method_missing(name, *_args) key = name.to_s return missing_key("Missing setting '#{key}' in #{@section}") unless key? key value = fetch(key) create_accessor_for(key) value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{@section}") : value end |
Class Attribute Details
.yaml_permitted_classes ⇒ Object
Configure additional permitted classes for YAML deserialization Default: [Symbol, Date, Time, DateTime, BigDecimal] Example: Settingslogic.yaml_permitted_classes += [MyCustomClass]
20 21 22 |
# File 'lib/settingslogic.rb', line 20 def yaml_permitted_classes @yaml_permitted_classes ||= [Symbol, Date, Time, DateTime, BigDecimal] end |
Class Method Details
.[](key) ⇒ Object
63 64 65 |
# File 'lib/settingslogic.rb', line 63 def [](key) instance.fetch(key.to_s, nil) end |
.[]=(key, val) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/settingslogic.rb', line 67 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
42 43 44 45 46 47 48 49 |
# File 'lib/settingslogic.rb', line 42 def get(key) parts = key.split('.') curs = self while (p = parts.shift) curs = curs.send(p) end curs end |
.load! ⇒ Object
74 75 76 77 |
# File 'lib/settingslogic.rb', line 74 def load! instance true end |
.name ⇒ Object
:nodoc:
13 14 15 |
# File 'lib/settingslogic.rb', line 13 def name # :nodoc: superclass != Hash && instance.key?('name') ? instance.name : super end |
.namespace(value = nil) ⇒ Object
55 56 57 |
# File 'lib/settingslogic.rb', line 55 def namespace(value = nil) @namespace ||= value end |
.reload! ⇒ Object
79 80 81 82 |
# File 'lib/settingslogic.rb', line 79 def reload! @instance = nil load! end |
.source(value = nil) ⇒ Object
51 52 53 |
# File 'lib/settingslogic.rb', line 51 def source(value = nil) @source ||= value end |
.suppress_errors(value = nil) ⇒ Object
59 60 61 |
# File 'lib/settingslogic.rb', line 59 def suppress_errors(value = nil) @suppress_errors ||= value end |
.use_yaml_unsafe_load ⇒ Object
37 38 39 |
# File 'lib/settingslogic.rb', line 37 def use_yaml_unsafe_load @use_yaml_unsafe_load ||= false end |
.use_yaml_unsafe_load=(value) ⇒ Object
DEPRECATED: Temporarily allow unsafe YAML loading for backwards compatibility This option will be removed in v4.0.0 WARNING: This enables arbitrary code execution vulnerabilities!
29 30 31 32 33 34 35 |
# File 'lib/settingslogic.rb', line 29 def use_yaml_unsafe_load=(value) if value warn '[DEPRECATION] Settingslogic.use_yaml_unsafe_load is deprecated and will be removed in v4.0.0. ' \ 'Please migrate to using Settingslogic.yaml_permitted_classes instead.' end @use_yaml_unsafe_load = value end |
Instance Method Details
#[](key) ⇒ Object
155 156 157 |
# File 'lib/settingslogic.rb', line 155 def [](key) fetch(key.to_s, nil) end |
#[]=(key, val) ⇒ Object
159 160 161 162 163 164 |
# File 'lib/settingslogic.rb', line 159 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/
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/settingslogic.rb', line 190 def create_accessor_for(key, val = nil) return unless /^\w+$/.match?(key.to_s) # could have "some-setting:" which blows up eval instance_variable_set("@#{key}", val) self.class.class_eval " def \#{key}\n return @\#{key} if @\#{key}\n return missing_key(\"Missing setting '\#{key}' in \#{@section}\") unless key? '\#{key}'\n value = fetch('\#{key}')\n @\#{key} = if value.is_a?(Hash)\n self.class.new(value, \"'\#{key}' section in \#{@section}\")\n elsif value.is_a?(Array) && value.all?{|v| v.is_a? Hash}\n value.map{|v| self.class.new(v)}\n else\n value\n end\n end\n ENDEVAL\nend\n", __FILE__, __LINE__ + 1 |
#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.
181 182 183 184 185 |
# File 'lib/settingslogic.rb', line 181 def create_accessors! each do |key, _val| create_accessor_for(key) end end |
#deep_merge(other_hash) ⇒ Object
Deep merge settings (useful for overrides)
245 246 247 |
# File 'lib/settingslogic.rb', line 245 def deep_merge(other_hash) self.class.new(deep_merge_hash(to_hash, other_hash)) end |
#deep_merge!(other_hash) ⇒ Object
Deep merge in place
250 251 252 |
# File 'lib/settingslogic.rb', line 250 def deep_merge!(other_hash) replace(deep_merge_hash(to_hash, other_hash)) end |
#stringify_keys ⇒ Object
Convert all keys to strings recursively (Rails compatibility)
232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/settingslogic.rb', line 232 def stringify_keys each_with_object({}) do |(key, value), memo| k = key.to_s v = begin send(key) rescue StandardError value end memo[k] = v.respond_to?(:stringify_keys) ? v.stringify_keys : v end end |
#symbolize_keys ⇒ Object
Convert all keys to symbols recursively
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/settingslogic.rb', line 211 def symbolize_keys each_with_object({}) do |(key, value), memo| k = begin key.to_sym rescue StandardError key end # Access the value properly through the accessor method v = respond_to?(key) ? send(key) : value # Recursively symbolize nested hashes memo[k] = if v.is_a?(self.class) v.symbolize_keys elsif v.respond_to?(:symbolize_keys) v.symbolize_keys else v end end end |
#to_ary ⇒ Object
Prevents Array#flatten from trying to expand Settings objects This fixes RSpec issues when Settings objects are included in arrays
173 174 175 |
# File 'lib/settingslogic.rb', line 173 def to_ary nil end |
#to_hash ⇒ Object
Returns an instance of a Hash object
167 168 169 |
# File 'lib/settingslogic.rb', line 167 def to_hash to_h end |