Class: ComplexConfig::Provider
- Includes:
- Shortcuts, Tins::SexySingleton
- Defined in:
- lib/complex_config/provider.rb,
lib/complex_config/provider/shortcuts.rb
Overview
A provider class that manages configuration loading, caching, and access
The Provider class serves as the central hub for accessing and managing configuration data within the ComplexConfig system. It handles loading configuration files from disk, applying environment-specific settings, processing plugins for dynamic attribute resolution, and providing memoized access to configuration data through caching mechanisms.
Defined Under Namespace
Modules: Shortcuts
Instance Attribute Summary collapse
-
#env ⇒ String
The env method retrieves the current environment name for configuration lookups.
-
#key(pathname = nil) ⇒ String?
The key method retrieves an encryption key from configured sources.
-
#master_key_pathname ⇒ String, Pathname
The master_key_pathname method retrieves the configured master key file path.
-
#plugins ⇒ Set<Proc>
readonly
The plugins attribute reader provides access to the set of plugins registered with this provider.
Instance Method Summary collapse
-
#[](name) ⇒ ComplexConfig::Settings
The [] method provides access to configuration data by name.
-
#add_plugin(plugin) ⇒ self
The add_plugin method adds a new plugin to the provider’s collection of plugins.
-
#apply_plugins(setting, id) ⇒ Object?
The apply_plugins method executes registered plugins for a given setting and ID.
-
#config(pathname, name = nil) ⇒ ComplexConfig::Settings
The config method reads and processes configuration data from a file.
-
#config_dir ⇒ Pathname
The config_dir method retrieves the configuration directory path.
-
#config_dir=(dir) ⇒ Object
The config_dir= method sets the configuration directory path for the provider.
-
#configure_with(config) ⇒ self
The configure_with method applies the given configuration to this provider instance.
-
#decrypt_config(pathname) ⇒ String?
The decrypt_config method retrieves decrypted configuration data from an encrypted file.
-
#deep_freeze=(flag) ⇒ Object
The deep_freeze= method sets the deep freezing behavior for configuration objects.
-
#deep_freeze? ⇒ TrueClass, FalseClass
The deep_freeze? method checks whether deep freezing is enabled for configuration objects.
-
#encrypt_config(pathname, config) ⇒ String
The encrypt_config method encrypts configuration data using a key source.
-
#evaluate(pathname, data) ⇒ String
The evaluate method processes ERB template data and returns the result.
-
#exist?(name) ⇒ TrueClass, FalseClass
The exist? method checks whether a configuration file exists and is accessible.
-
#flush_cache ⇒ ComplexConfig::Provider
The flush_cache method clears the configuration cache and returns the receiver.
-
#initialize ⇒ Provider
constructor
Initializes a new provider instance with default settings.
-
#key_source(pathname = nil) ⇒ ComplexConfig::KeySource?
The key_source method retrieves an encryption key from configured sources.
-
#new_key ⇒ String
The new_key method generates a random encryption key.
-
#pathname(name) ⇒ Pathname
The pathname method constructs a file path for a configuration file.
-
#prepare_output(value) ⇒ String
The prepare_output method converts a value into YAML format.
-
#proxy(env = nil) ⇒ ComplexConfig::Proxy
The proxy method creates and returns a new proxy object for dynamic configuration access.
-
#valid_key?(key) ⇒ ComplexConfig::KeySource, FalseClass
The valid_key? method checks whether a given key is valid for encryption purposes.
-
#write_config(name, value: nil, encrypt: false, store_key: false) ⇒ String, Boolean
The write_config method writes configuration data to a file.
Methods included from Shortcuts
#complex_config, #complex_config_with_env
Constructor Details
#initialize ⇒ Provider
Initializes a new provider instance with default settings
Sets up the provider with an empty plugins collection and enables deep freezing by default to ensure configuration immutability.
30 31 32 33 |
# File 'lib/complex_config/provider.rb', line 30 def initialize @plugins = Set.new @deep_freeze = true end |
Instance Attribute Details
#env ⇒ String
The env method retrieves the current environment name for configuration lookups
This method determines the appropriate environment to use for configuration access by checking various possible sources in order: an explicitly set instance variable, Rails environment if available, the RAILS_ENV environment variable, or falling back to ‘development’ as the default
434 435 436 437 438 |
# File 'lib/complex_config/provider.rb', line 434 def env @env || defined?(Rails) && Rails.respond_to?(:env) && Rails.env || ENV['RAILS_ENV'] || 'development' end |
#key(pathname = nil) ⇒ String?
The key method retrieves an encryption key from configured sources
This method obtains an encryption key by delegating to the key_source method with the provided pathname, then extracts the actual key value from the returned KeySource object
481 482 483 |
# File 'lib/complex_config/provider.rb', line 481 def key(pathname = nil) key_source(pathname).ask_and_send(:key) end |
#master_key_pathname ⇒ String, Pathname
The master_key_pathname method retrieves the configured master key file path
This method returns the explicitly set master key pathname if one has been configured, otherwise it defaults to a ‘master.key’ file within the configuration directory
54 55 56 57 58 59 60 |
# File 'lib/complex_config/provider.rb', line 54 def master_key_pathname if @master_key_pathname @master_key_pathname else config_dir + 'master.key' end end |
#plugins ⇒ Set<Proc> (readonly)
The plugins attribute reader provides access to the set of plugins registered with this provider
81 82 83 |
# File 'lib/complex_config/provider.rb', line 81 def plugins @plugins end |
Instance Method Details
#[](name) ⇒ ComplexConfig::Settings
The [] method provides access to configuration data by name
This method serves as a shortcut for retrieving configuration settings by their name, delegating to the config method with the appropriate pathname and name parameters
288 289 290 |
# File 'lib/complex_config/provider.rb', line 288 def [](name) config pathname(name), name end |
#add_plugin(plugin) ⇒ self
The add_plugin method adds a new plugin to the provider’s collection of plugins
This method registers a plugin proc with the provider, allowing it to be executed when configuration attributes are accessed and no direct value is found
92 93 94 95 |
# File 'lib/complex_config/provider.rb', line 92 def add_plugin(plugin) plugins.add plugin self end |
#apply_plugins(setting, id) ⇒ Object?
The apply_plugins method executes registered plugins for a given setting and ID
This method iterates through all registered plugins and attempts to execute each one with the provided setting and ID. It uses catch/throw to handle plugin skipping behavior, returning the first non-skipped plugin result.
138 139 140 141 142 143 144 145 |
# File 'lib/complex_config/provider.rb', line 138 def apply_plugins(setting, id) plugins.find do |plugin| catch :skip do value = setting.instance_exec(id, &plugin) and return value end nil end end |
#config(pathname, name = nil) ⇒ ComplexConfig::Settings
The config method reads and processes configuration data from a file
This method loads configuration data from the specified file path, handling both plain YAML files and encrypted YAML files. It processes the configuration data through ERB evaluation, parses it into Ruby objects, and builds a Settings object with appropriate environment-specific values.
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/complex_config/provider.rb', line 237 def config(pathname, name = nil) datas = [] path_exist = File.exist?(pathname) if path_exist datas << IO.binread(pathname) end decrypted, reason, enc_pathname = decrypt_config_case(pathname) case reason when :ok datas << decrypted when :key_missing datas.empty? and raise ComplexConfig::EncryptionKeyMissing, "encryption key for #{enc_pathname.to_s.inspect} is missing" when :file_missing datas.empty? and raise ComplexConfig::ConfigurationFileMissing, "configuration file #{pathname.to_s.inspect} is missing" end results = datas.map { |d| evaluate(pathname, d) } hashes = if ::Psych::VERSION < "4" results.map { |r| ::YAML.load(r, pathname) } else results.map { |r| ::YAML.unsafe_load(r, filename: pathname) } end settings = ComplexConfig::Settings.build(name, hashes.shift) hashes.each { |h| settings.attributes_update(h) } if shared = settings.shared? shared = shared.to_h settings.each do |key, value| if value.is_a? ComplexConfig::Settings value.attributes_update_if_nil(shared) elsif value.nil? settings[key] = ComplexConfig::Settings.build(nil, shared.dup) end end end deep_freeze? and settings.deep_freeze settings rescue ::Psych::SyntaxError => e raise ComplexConfig::ComplexConfigError.wrap(:ConfigurationSyntaxError, e) end |
#config_dir ⇒ Pathname
The config_dir method retrieves the configuration directory path
This method returns the configured configuration directory path, falling back to a default location based on Rails root or the current working directory when no explicit path is set
171 172 173 |
# File 'lib/complex_config/provider.rb', line 171 def config_dir @config_dir || (defined?(Rails) && Rails.respond_to?(:root) && Rails.root || Pathname.pwd) + 'config' end |
#config_dir=(dir) ⇒ Object
The config_dir= method sets the configuration directory path for the provider
This setter method assigns a new configuration directory path to the provider instance, allowing it to locate configuration files at the specified location
156 157 158 159 160 161 162 |
# File 'lib/complex_config/provider.rb', line 156 def config_dir=(dir) if dir.nil? @config_dir = nil else @config_dir = Pathname.new(dir) end end |
#configure_with(config) ⇒ self
The configure_with method applies the given configuration to this provider instance
This method takes a configuration object and applies its settings to the current provider instance It then flushes the configuration cache to ensure the changes take effect immediately
72 73 74 75 |
# File 'lib/complex_config/provider.rb', line 72 def configure_with(config) config.configure(self) flush_cache end |
#decrypt_config(pathname) ⇒ String?
The decrypt_config method retrieves decrypted configuration data from an encrypted file
198 199 200 |
# File 'lib/complex_config/provider.rb', line 198 def decrypt_config(pathname) decrypt_config_case(pathname).first end |
#deep_freeze=(flag) ⇒ Object
The deep_freeze= method sets the deep freezing behavior for configuration objects
This method configures whether configuration settings should be deeply frozen to prevent modification after initialization. When disabling deep freezing, it clears the configuration cache to ensure changes take effect immediately.
106 107 108 109 110 111 |
# File 'lib/complex_config/provider.rb', line 106 def deep_freeze=(flag) if @deep_freeze && !flag mize_cache_clear end @deep_freeze = flag end |
#deep_freeze? ⇒ TrueClass, FalseClass
The deep_freeze? method checks whether deep freezing is enabled for configuration objects
This method returns a boolean value indicating whether the provider has been configured to deeply freeze configuration settings, preventing modification after initialization
122 123 124 |
# File 'lib/complex_config/provider.rb', line 122 def deep_freeze? !!@deep_freeze end |
#encrypt_config(pathname, config) ⇒ String
The encrypt_config method encrypts configuration data using a key source
210 211 212 213 |
# File 'lib/complex_config/provider.rb', line 210 def encrypt_config(pathname, config) ks = key_source(pathname) ComplexConfig::Encryption.new(ks.key_bytes).encrypt(config) end |
#evaluate(pathname, data) ⇒ String
The evaluate method processes ERB template data and returns the result
This method takes raw configuration data that may contain ERB templating syntax and evaluates it using Ruby’s built-in ERB processor. It sets up the ERB environment with appropriate trim mode and filename for proper error reporting before executing the template.
412 413 414 415 416 |
# File 'lib/complex_config/provider.rb', line 412 def evaluate(pathname, data) erb = ::ERB.new(data, trim_mode: '-') erb.filename = pathname.to_s erb.result end |
#exist?(name) ⇒ TrueClass, FalseClass
The exist? method checks whether a configuration file exists and is accessible
360 361 362 363 364 |
# File 'lib/complex_config/provider.rb', line 360 def exist?(name) !!config(pathname(name), name) rescue ComplexConfig::ConfigurationFileMissing, ComplexConfig::EncryptionKeyMissing false end |
#flush_cache ⇒ ComplexConfig::Provider
The flush_cache method clears the configuration cache and returns the receiver
This method invalidates the cached configuration data stored in the provider, ensuring that subsequent configuration accesses will reload the data from source. It is typically used during development when configuration files may have changed or when explicit cache invalidation is required.
393 394 395 396 |
# File 'lib/complex_config/provider.rb', line 393 def flush_cache mize_cache_clear self end |
#key_source(pathname = nil) ⇒ ComplexConfig::KeySource?
The key_source method retrieves an encryption key from configured sources
This method attempts to find a valid encryption key by checking multiple possible sources in a specific order until one provides a usable key. It prioritizes keys from instance variables, file paths, environment variables, and master key files.
461 462 463 464 465 466 467 468 469 |
# File 'lib/complex_config/provider.rb', line 461 def key_source(pathname = nil) [ ComplexConfig::KeySource.new(var: @key), ComplexConfig::KeySource.new(pathname: pathname), ComplexConfig::KeySource.new(env_var: 'COMPLEX_CONFIG_KEY'), ComplexConfig::KeySource.new(env_var: 'RAILS_MASTER_KEY'), ComplexConfig::KeySource.new(master_key_pathname: master_key_pathname), ].find(&:key) end |
#new_key ⇒ String
The new_key method generates a random encryption key
This method creates a secure random key suitable for encryption purposes by generating a hexadecimal string of 32 characters (16 bytes).
500 501 502 |
# File 'lib/complex_config/provider.rb', line 500 def new_key SecureRandom.hex(16) end |
#pathname(name) ⇒ Pathname
The pathname method constructs a file path for a configuration file
This method takes a configuration name and returns the full path to the corresponding YAML configuration file by combining the configuration directory with the name and file extension.
183 184 185 |
# File 'lib/complex_config/provider.rb', line 183 def pathname(name) config_dir + "#{name}.yml" end |
#prepare_output(value) ⇒ String
The prepare_output method converts a value into YAML format
This method takes a value and transforms it into a YAML string representation by first converting it to a hash with string keys and then serializing it as YAML
345 346 347 348 349 |
# File 'lib/complex_config/provider.rb', line 345 def prepare_output(value) value.each_with_object({}) do |(k, v), h| h[k.to_s] = v end.to_yaml end |
#proxy(env = nil) ⇒ ComplexConfig::Proxy
The proxy method creates and returns a new proxy object for dynamic configuration access
This method instantiates a ComplexConfig::Proxy object that defers configuration loading until a method is first called. The proxy supports environment-specific configuration lookups and can handle both direct configuration access and existence checks.
378 379 380 |
# File 'lib/complex_config/provider.rb', line 378 def proxy(env = nil) ComplexConfig::Proxy.new(env) end |
#valid_key?(key) ⇒ ComplexConfig::KeySource, FalseClass
The valid_key? method checks whether a given key is valid for encryption purposes
This method attempts to validate an encryption key by creating a KeySource object with the provided key and then trying to instantiate an Encryption object with it to verify the key’s format and validity
514 515 516 517 518 519 520 |
# File 'lib/complex_config/provider.rb', line 514 def valid_key?(key) ks = ComplexConfig::KeySource.new(var: key) ComplexConfig::Encryption.new(ks.key_bytes) ks rescue false end |
#write_config(name, value: nil, encrypt: false, store_key: false) ⇒ String, Boolean
The write_config method writes configuration data to a file
This method handles writing configuration data to either a plain YAML file or an encrypted file depending on the encryption settings. It supports storing encryption keys alongside the encrypted configuration file and provides options for specifying the encryption key source.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/complex_config/provider.rb', line 313 def write_config(name, value: nil, encrypt: false, store_key: false) name, value = interpret_name_value(name, value) config_pathname = pathname(name).to_s if encrypt ks = provide_key_source(config_pathname, encrypt) File.secure_write(config_pathname + '.enc') do |out| out.write ComplexConfig::Encryption.new(ks.key_bytes).encrypt(prepare_output(value)) end if store_key File.secure_write(config_pathname + '.key') do |out| out.write ks.key end end ks.key else File.secure_write(config_pathname) do |out| out.puts prepare_output(value) end true end ensure flush_cache end |