{"id":34634886,"url":"https://github.com/flori/complex_config","last_synced_at":"2025-12-24T17:00:53.964Z","repository":{"id":24511979,"uuid":"27917754","full_name":"flori/complex_config","owner":"flori","description":"Advanced YAML-based configuration management for Ruby apps, simple configs were yesterday","archived":false,"fork":false,"pushed_at":"2025-12-19T19:19:36.000Z","size":221,"stargazers_count":1,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-22T08:32:01.260Z","etag":null,"topics":["configuration","library","rails","ruby","yaml"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flori.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2014-12-12T11:28:13.000Z","updated_at":"2025-12-19T19:19:38.000Z","dependencies_parsed_at":"2024-03-15T09:26:59.178Z","dependency_job_id":"fd344e58-95d0-4d43-bb74-7d66091c2dca","html_url":"https://github.com/flori/complex_config","commit_stats":{"total_commits":109,"total_committers":4,"mean_commits":27.25,"dds":0.04587155963302747,"last_synced_commit":"6f11024faee76888f542d88fd5b75fe3e0e94a1b"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"purl":"pkg:github/flori/complex_config","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flori%2Fcomplex_config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flori%2Fcomplex_config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flori%2Fcomplex_config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flori%2Fcomplex_config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flori","download_url":"https://codeload.github.com/flori/complex_config/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flori%2Fcomplex_config/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28005407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","library","rails","ruby","yaml"],"created_at":"2025-12-24T17:00:17.400Z","updated_at":"2025-12-24T17:00:53.956Z","avatar_url":"https://github.com/flori.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ComplexConfig 🧠\n\n## Description 📝\n\nThis library makes your YAML configuration files available via a nice API. It\nalso supports different configurations for each `RAILS_ENV` environment and\nusing plugins to return more complex settings values. 🚀\n\n## Architecture Overview 🏗️\n\nComplexConfig follows a well-defined architectural pattern with clear\nseparation of concerns between several key components:\n\n### Core Components 🧩\n\n**Provider** (`ComplexConfig::Provider`)\n- The central hub managing configuration loading, caching, and access 🔄\n- Handles environment-specific configuration selection 🌍\n- Manages plugin registration and execution 🔌\n- Provides memoization for performance optimization ⚡\n\n**Settings** (`ComplexConfig::Settings`)\n- Represents structured configuration data with nested access 📊\n- Implements dynamic attribute access through `method_missing` 🧠\n- Supports conversion between different representations (hash, YAML, JSON) 🔄\n- Provides deep freezing for immutability 🔒\n\n**Proxy** (`ComplexConfig::Proxy`)\n- Enables lazy evaluation of configuration access ⏳\n- Defers loading until first method call 🚦\n- Supports environment-specific lookups 🌐\n- Handles safe existence checking ❓\n\n### Component Interactions 🔄\n\n```mermaid\ngraph LR\n    A[Provider] --\u003e B[Settings]\n    A --\u003e C[Proxy]\n    B --\u003e D[Configuration Files]\n    C --\u003e B\n    A --\u003e E[Plugins]\n    E --\u003e B\n```\n\nThe Provider acts as the main coordinator, loading configuration files and\ncreating Settings objects. The Proxy enables lazy loading, while Plugins can\naugment or transform attribute values at runtime.\n\n### Loading Mechanism 📥\n\nComplexConfig supports two primary access patterns if required via `require\n\"complex_config/rude\"`:\n\n1. **Environment-aware access** via `cc.config_name` (uses `RAILS_ENV` by\n   default): 🌐\n\n   ```ruby\n   # Loads config/products.yml and applies environment-specific settings\n   cc.products\n   ```\n\n2. **Explicit environment access** via `complex_config.config_name` (skips\n   automatic environment namespace): 🧪\n\n   ```ruby\n   # Loads config/products.yml without environment prefix\n   complex_config.products\n   ```\n\nThe proxy system automatically resolves configuration file paths based on\nmethod names, mapping `cc.products` to `config/products.yml`.\n\n### Environment Prefix Behavior 🌍\n\nWhen using the default `cc` accessor, ComplexConfig automatically applies\nenvironment-specific configurations. For example, with a YAML file like:\n\n```yaml\ndevelopment:\n  database:\n    host: localhost\n    port: 5432\nproduction:\n  database:\n    host: db.production.example.com\n    port: 5432\n```\n\nAccessing `cc.database.host` will return `\"localhost\"` in development and\n`\"db.production.example.com\"` in production, automatically selecting the\nappropriate environment section.\n\n### Rails Integration 🚀\n\nComplexConfig integrates seamlessly with Rails application lifecycle. During\ndevelopment, when Rails reloads classes (or the user types `reload!` into the\nconsole), ComplexConfig automatically flushes its internal cache to ensure that\nconfiguration changes are picked up correctly. This behavior is handled through\nthe Railtie integration which hooks into Rails' `to_prepare` callback.\n\n### Caching Strategy 📦\n\nComplexConfig employs memoization through the `mize` gem to cache expensive\noperations like file loading and parsing. In production environments, this\ncaching provides performance benefits, while in development, Rails' reloading\nmechanism ensures configuration changes are respected.\n\n### Design Patterns 🎯\n\n- **Delegation**: Provider delegates to Settings for attribute access 🔄\n- **Strategy Pattern**: Plugins provide different strategies for attribute\n  resolution 🧠\n- **Lazy Loading**: Proxy defers configuration loading until needed ⏳\n- **Singleton**: Provider follows singleton pattern for consistent\n  configuration access 🔁\n\nThis architecture enables flexible, performant configuration management while\nmaintaining clean separation between concerns.\n\n## Installation 📦\n\nYou can use rubygems to fetch the gem and install it for you:\n\n```bash\ngem install complex_config\n```\n\nYou can also put this line into your Gemfile\n\n```ruby\ngem 'complex_config', require: 'complex_config/rude'\n```\n\nand bundle. This command will enable all the default plugins and make the `cc`\nand `complex_config` shortcuts available. The configurations are expected to be\nin the `config` subdirectory according to the rails convention.\n\n## Usage 🛠️\n\nGiven a config file like this and named `config/products.yml`\n\n```yaml\ndevelopment:\n  flux_capacitor:\n    version_20:\n      name: Flux Capacitor Version 2.0\n      price_in_cents: 12_000_00\n      manual_pdf_url: \"http://brown-inc.com/manuals/fc_20.pdf\"\n      components:\n        - Miniature Chrono-Levitation Chamber (mCLC)\n        - Single Gravitational Displacement Coil (SGDC)\n        - Simple Quantum Flux Transducer (SQFT)\n        - Basic Time-Space Navigation System (BTN)\n    pro_version:\n      name: Flux Capacitor Professional\n      price_in_cents: 23_000_00\n      manual_pdf_url: \"http://brown-inc.com/manuals/fc_pro.pdf\"\n      components:\n        - Advanced Chrono-Levitation Chamber (ACL)\n        - Dual Gravitational Displacement Coils (DGDCs)\n        - Advanced Quantum Flux Transducer (AQFT)\n        - Professional Time-Space Navigation System (PTNS)\n    enterprise_version:\n      name: Flux Capacitor Enterpise\n      price_in_cents: 1_600_000_00\n      manual_pdf_url: \"http://brown-inc.com/manuals/fc_enterprise.pdf\"\n      components:\n        - Super-Advanced Chrono-Levitation Chamber (SACL)\n        - Quadruple Gravitational Displacement Coils (QGDCs)\n        - Ultra-Advanced Quantum Flux Transducer (UAQFT)\n        - Enterprise Time-Space Navigation System (ETNS)\ntest:\n  flux_capacitor:\n    test_version:\n      name: Yadayada\n      price_in_cents: 6_66\n      manual_pdf_url: \"http://staging.brown-inc.com/manuals/fc_10.pdf\"\n      components:\n        - Experimental Chrono-Levitation Chamber (ECLC)\n        - Modular Gravitational Displacement Coils (MGDCs)\n        - Variable Quantum Flux Transducer (VQFT)\n        - Development Time-Space Navigation System (DTNS)\n```\n\nand using `require \"complex_config/rude\"` in the `\"development\"` environment\nyou can now access the configuration.\n\n### Accessing configuration settings 📦\n\nFetching the name of a product:\n\n```ruby\ncc.products.flux_capacitor.enterprise_version.name # =\u003e \"Flux Capacitor Enterpise\"\n```\n\nIf the name of configuration file isn't valid ruby method name syntax you can\nalso use `cc(:products).flux_capacitor…` to avoid this problem.\n\nFetching the price of a product in cents:\n\n```ruby\ncc.products.flux_capacitor.enterprise_version.price_in_cents # =\u003e 160000000\n```\n\nFetching the price of a product and using the ComplexConfig::Plugins::MONEY\nplugin to format it:\n\n```ruby\ncc.products.flux_capacitor.enterprise_version.price.format # =\u003e \"€1,600,000.00\"\n```\n\nFetching the URL of a product manual as a string:\n\n```ruby\ncc.products.flux_capacitor.enterprise_version.manual_pdf_url\n  # =\u003e \"http://brown-inc.com/manuals/fc_enterprise.pdf\"\n```\n\nFetching the URL of a product manual and using the ComplexConfig::Plugins::URI\nplugin return an URI instance:\n\n```ruby\ncc.products.flux_capacitor.enterprise_version.manual_pdf_uri\n  # =\u003e #\u003cURI::HTTP:0x007ff626d2a2e8 URL:http://brown-inc.com/manuals/fc_enterprise.pdf\u003e\n```\n\nYou can also fetch config settings from a different environment:\n\n```ruby\npp cc.products(:test); nil\n```\n\nand output them.\n\n```\nproducts\n└─ flux_capacitor\n   └─ test_version\n      ├─ name = \"Yadayada\"\n      ├─ price_in_cents = 666\n      ├─ manual_pdf_url = \"http://staging.brown-inc.com/manuals/fc_10.pdf\"\n      └─ components\n         ├─ \"Experimental Chrono-Levitation Chamber (ECLC)\"\n         ├─ \"Modular Gravitational Displacement Coils (MGDCs)\"\n         ├─ \"Variable Quantum Flux Transducer (VQFT)\"\n         └─ \"Development Time-Space Navigation System (DTNS)\"\n```\n\nCalling `complex_config.products.` instead of `cc(…)` would skip the implicit\nnamespacing via the `RAILS_ENV` environment, so\n`complex_config(:products).test.flux_capacitor` returns the same settings\nobject.\n\n## Encryption Support in ComplexConfig 🛡️\n\nComplexConfig provides robust encryption capabilities for securing sensitive\nconfiguration data, with built-in compatibility with Rails' secret encryption\nsystem.\n\n### Secure Configuration Files 🔐\n\nThe library supports encrypting YAML configuration files using AES-128-GCM\nencryption. This allows you to store sensitive information like API keys,\npasswords, and other secrets in your version control without exposing them in\nplain text.\n\n#### Basic Usage 🛠️\n\n```ruby\n# Write encrypted configuration\nComplexConfig::Provider.write_config('database', \n  value: { password: 'secret_password' }, \n  encrypt: :random\n)\n# =\u003e Returns the random 128-bit master key as hexadecimal string.\n```\n\nThis creates `config/database.yml.enc` which contains the encrypted data and\nreturns the master key, which you can provide via an environment variable for\nlater read access.\n\n#### Key Management 🔑\n\nComplexConfig supports multiple key sources in priority order:\n\n1. **Explicit key setting**: Direct assignment via `config.key = 'your-key'`\n2. **Environment variables**: `COMPLEX_CONFIG_KEY` or `RAILS_MASTER_KEY`\n3. **Key files**: Files with `.key` extension alongside encrypted files\n4. **Master key files**: `config/master.key` (Rails-compatible)\n\n#### Rails Integration 🚀\n\nComplexConfig is fully compatible with Rails' secret encryption system:\n\n```ruby\n# Works seamlessly with Rails master.key\nENV['RAILS_MASTER_KEY'] = '0123456789abcdef0123456789abcdef' # Do not use this key.\n# Encrypted files created by Rails can be read by ComplexConfig\n```\n\n#### Encryption Process 🔐\n\nThe system uses OpenSSL's AES-128-GCM cipher mode which provides both\nconfidentiality and authenticity. The encryption process:\n\n1. **Marshals** the configuration object into binary format\n2. **Encrypts** using AES-128-GCM with a randomly generated IV\n3. **Authenticates** with an authentication tag to ensure integrity\n4. **Encodes** all components in base64 and combines them with `--` separators\n\n#### Security Features 🛡️\n\n- **Authenticated Encryption**: Ensures data hasn't been tampered with\n- **Secure Key Handling**: Validates key length requirements (16 bytes for\n  AES-128)\n- **Multiple Sources**: Flexible key management for different deployment\n  scenarios\n- **Atomic Writes**: Uses secure file writing to prevent corruption during\n  encryption operations\n\nThis approach allows you to maintain sensitive configuration data securely\nwhile keeping the same familiar YAML-based workflow that developers expect.\n\n### Command-Line Interface and Encryption Management 🛡️\n\nThe `complex_config` executable provides a convenient command-line interface\nfor managing encrypted configuration files. This tool is particularly useful\nwhen you need to securely store sensitive configuration data while maintaining\neasy access during development and deployment.\n\n#### Features ⚙️\n\n- **Secure File Operations**: Encrypts/decrypts configuration files with\n  automatic backup handling\n- **Edit Support**: Opens encrypted files in your preferred editor (`EDITOR`\n  environment variable or `vi` by default) \n- **Key Management**: Generates new encryption keys and supports key rotation\n- **Atomic Writes**: Uses secure file writing to prevent data corruption\n\n#### Usage Examples 📋\n\n```bash\n# Encrypt a configuration file\ncomplex_config encrypt config/database.yml\n\n# Decrypt a configuration file  \ncomplex_config decrypt config/database.yml.enc\n\n# Edit an encrypted configuration file\ncomplex_config edit config/database.yml.enc\n\n# Display decrypted content without writing to disk\ncomplex_config display config/database.yml.enc\n\n# Generate a new encryption key\ncomplex_config new_key\n\n# Recrypt a file with a different key\ncomplex_config recrypt -o OLD_KEY -n NEW_KEY config/database.yml.enc\n```\n\n#### Security Considerations ⚠️\n\nThe script uses symmetric encryption for configuration files. When using\nencrypted configurations:\n\n1. **Key Management**: Store your encryption keys securely (never in version\n   control)\n2. **File Permissions**: Ensure encrypted `.enc` files have appropriate\n   permissions\n3. **Backup Strategy**: The `recrypt` command automatically creates backup\n   files\n\n#### Integration with ComplexConfig 🔗\n\nWhen you use the `complex_config` executable, it works with the same encryption\nmechanism that ComplexConfig uses internally for its encrypted configuration\nfiles. This ensures consistency between your application's configuration\nloading and your manual encryption/decryption workflows.\n\nThe tool is particularly valuable in development environments where you want to\nmaintain sensitive configurations without committing them to version control\nwhile still being able to easily edit and manage them during development.\n\n#### Environment Variables 📝\n\n- `EDITOR`: Sets the preferred text editor for editing encrypted files\n  (defaults to `vi`)\n- `COMPLEX_CONFIG_KEY`: Can be set to provide a default encryption key\n\nThis command-line tool provides a bridge between secure configuration\nmanagement and practical workflow needs, making it easier to maintain encrypted\nconfigurations without sacrificing usability.\n\n## Debugging and Troubleshooting 🔍\n\nComplexConfig provides several built-in methods for inspecting and debugging\nconfiguration data:\n\n### Inspecting Configuration Structure 🧮\n\nTo see all available attributes and their values in a structured format:\n```ruby\nputs cc.products.flux_capacitor.enterprise_version.attributes_list\n```\n\nThis outputs a representation showing all configuration paths and values listed\nlike this:\n\n```\nname = \"Flux Capacitor Enterpise\"\nprice_in_cents = 160000000\nmanual_pdf_url = \"http://brown-inc.com/manuals/fc_enterprise.pdf\"\ncomponents[0] = \"Super-Advanced Chrono-Levitation Chamber (SACL)\"\ncomponents[1] = \"Quadruple Gravitational Displacement Coils (QGDCs)\"\ncomponents[2] = \"Ultra-Advanced Quantum Flux Transducer (UAQFT)\"\ncomponents[3] = \"Enterprise Time-Space Navigation System (ETNS)\"\n```\n\n### Visual Tree Representation 🌲\n\nFor a more visual representation of the configuration hierarchy:\n\n```ruby\nputs cc.products.flux_capacitor.enterprise_version\n```\n\nThis displays the configuration in a tree format:\n```\nproducts.flux_capacitor.enterprise_version\n├─ name = \"Flux Capacitor Enterpise\"\n├─ price_in_cents = 160000000\n├─ manual_pdf_url = \"http://brown-inc.com/manuals/fc_enterprise.pdf\"\n└─ components\n   ├─ \"Super-Advanced Chrono-Levitation Chamber (SACL)\"\n   ├─ \"Quadruple Gravitational Displacement Coils (QGDCs)\"\n   ├─ \"Ultra-Advanced Quantum Flux Transducer (UAQFT)\"\n   └─ \"Enterprise Time-Space Navigation System (ETNS)\"\n```\n\nThese debugging methods are particularly useful during development when you\nneed to verify that your configuration files are loaded correctly and contain\nthe expected values.\n\n## Error Handling ⚠️\n\nComplexConfig provides a comprehensive error handling system with specific\nexceptions for different failure scenarios, following Ruby conventions for\npredictable behavior.\n\n### Exception Hierarchy 📚\n\nThe library defines a clear exception hierarchy that inherits from\n`ComplexConfig::ComplexConfigError`:\n\n```mermaid\nclassDiagram\n    class ComplexConfigError {\n        \u003c\u003cabstract\u003e\u003e\n        +message\n    }\n\n    class AttributeMissing\n    class ConfigurationFileMissing\n    class ConfigurationSyntaxError\n    class EncryptionError {\n        \u003c\u003cabstract\u003e\u003e\n    }\n    class EncryptionKeyInvalid\n    class EncryptionKeyMissing\n    class DecryptionFailed\n\n    ComplexConfigError \u003c|-- AttributeMissing\n    ComplexConfigError \u003c|-- ConfigurationFileMissing\n    ComplexConfigError \u003c|-- ConfigurationSyntaxError\n    ComplexConfigError \u003c|-- EncryptionError\n    EncryptionError \u003c|-- EncryptionKeyInvalid\n    EncryptionError \u003c|-- EncryptionKeyMissing\n    EncryptionError \u003c|-- DecryptionFailed\n```\n\n### Error Scenarios 🚨\n\n#### Configuration File Access 📁\n\nWhen a configuration file is missing, `ConfigurationFileMissing` is raised.\nThis includes both regular `.yml` files and encrypted `.yml.enc` files:\n\n```ruby\n# Raises ComplexConfig::ConfigurationFileMissing if config/products.yml doesn't exist\ncc.products.flux_capacitor.enterprise_version.name\n```\n\n#### YAML Syntax Errors 🧾\n\nInvalid YAML syntax in configuration files raises `ConfigurationSyntaxError`,\nwhich wraps the underlying Psych::SyntaxError to provide context:\n\n```ruby\n# Raises ComplexConfig::ConfigurationSyntaxError for malformed YAML\ncc.products # ... with invalid YAML content\n```\n\n#### Attribute Access Errors ❌\n\nAccessing non-existent attributes raises `AttributeMissing`:\n\n```ruby\n# Raises ComplexConfig::AttributeMissing if 'nonexistent_attribute' doesn't exist\ncc.products.nonexistent_attribute\n```\n\n#### Encryption Errors 🔐\n\nWhen using encrypted configuration files without proper encryption keys,\n`EncryptionKeyMissing` is raised:\n\n```ruby\n# Raises ComplexConfig::EncryptionKeyMissing when no key is available for .enc files\ncc.products # ... with encrypted config but missing key\n```\n\n### Safe Access Patterns 🛡️\n\nComplexConfig supports safe access patterns to avoid exceptions in conditional\ncontexts:\n\n```ruby\n# Using method names ending with '?' returns nil instead of raising exceptions\ncc.products?(:test)        # Returns nil if 'test' environment doesn't exist\ncc.products.flux_capacitor.enterprise_version.name?  # Returns nil if name attribute missing\n\n# Safe access to configuration that may not exist\nif cc.products?(:test)\n  # Safe to access test config here\nend\n```\n\n### Error Recovery 🛠️\n\nFor robust applications, consider wrapping critical configuration access in\nexception handlers:\n\n```ruby\nbegin\n  price = cc.products.flux_capacitor.enterprise_version.price_in_cents\nrescue ComplexConfig::ConfigurationFileMissing =\u003e e\n  Rails.logger.warn \"Configuration file missing: #{e.message}\"\n  # Provide default value or fallback behavior\nrescue ComplexConfig::ConfigurationSyntaxError =\u003e e\n  Rails.logger.error \"Invalid YAML in configuration: #{e.message}\"\n  # Handle invalid syntax appropriately\nend\n```\n\nThe error handling system ensures that configuration loading and access\nfailures are predictable and can be handled gracefully by application code.\n\n## Configuration ⚙️\n\nYou can `complex_config` by passing a block to its configure method, which you\ncan for example do in a rails config/initializers file:\n\n```ruby\nComplexConfig.configure do |config|\n  # Allow modification during tests b/c of stubs etc.\n  config.deep_freeze = !Rails.env.test?\n\n  # config.env = 'some_environment'\n\n  # config.config_dir = Rails.root + 'config'\n\n  config.add_plugin -\u003e id do\n    if base64_string = ask_and_send(\"#{id}_base64\")\n      Base64.decode64 base64_string\n    else\n      skip\n    end\n  end\nend\n```\n\n- **`#env`**: Explicitly sets the environment instead of auto-detecting from\n  `RAILS_ENV`\n\n- **`#config_dir`**: Changes the directory where configuration files are loaded\n  from instead of using the default `config` folder\n\n- **`add_plugin`** registers custom lambdas that can transform configuration\n  values at runtime, allowing for intelligent data processing like base64\n  decoding or automatic type conversion when accessing config attributes. See\n  [Adding plugins](#adding-plugins-) below.\n\n📝 **Note** the `deep_freeze` setting, that is just enabled during testing and\nis explained in the [next section](#frozen-configuration-safety-and-optimization-).\n\n### Frozen Configuration: Safety and Optimization 🔒\n\nThe `deep_freeze` setting controls whether configuration objects are deeply\nfrozen after initialization. When enabled (default), this provides several\nimportant benefits:\n\n#### Safety Benefits 🛡️\n\n- **Immutability**: Configuration values cannot be modified after loading,\n  preventing accidental runtime changes 🚫\n- **Thread Safety**: Frozen configurations can be safely shared across threads\n  without synchronization 🔄\n- **Security**: Protects against runtime tampering of critical configuration\n  data 🔒\n\n#### Performance Benefits ⚡\n\n- **Memory Efficiency**: Ruby's garbage collector can optimize frozen objects\n  more effectively 🧠\n- **Cache Efficiency**: Immutable objects can be cached more aggressively 💾\n- **CPU Optimization**: Ruby's internal optimizations for frozen objects can\n  provide performance improvements, if configuration settings are accessed\n  often. ⚙️\n- **Predictable Behavior**: Eliminates potential race conditions and state\n  corruption 🧭\n\n#### Development Considerations 🧪\n\nIn test environments, you might disable deep freezing to allow for easier\ntesting and modification:\n\n```ruby\nComplexConfig.configure do |config|\n  config.deep_freeze = false\nend\n```\n\nThis setting is particularly important in production environments where\nconfiguration stability and performance are paramount.\n\n### Adding plugins 🔌\n\nYou can add your own plugins by calling\n\n```ruby\nComplexConfig::Provider.add_plugin SomeNamespace::PLUGIN\n```\n\nor in the configuration block by calling\n\n```ruby\nComplexConfig.configure do |config|\n  config.add_plugin SomeNamespace::PLUGIN\nend\n```\n\n#### Implementing your own plugins 🛠️\n\nA plugin is just a lambda expression with a single argument `id` which\nidentifies the attribute that is being accessed. If it calls `skip` it won't\napply and the following plugins are tried until one doesn't call `skip` and\nreturns a value instead.\n\nHere is the `ComplexConfig::Plugins::MONEY` plugin for example:\n\n```ruby\nrequire 'monetize'\n\nmodule ComplexConfig::Plugins\n  MONEY = -\u003e id do\n    if cents = ask_and_send(\"#{id}_in_cents\")\n      Money.new(cents)\n    else\n      skip\n    end\n  end\nend\n```\n\n### MONEY Plugin Configuration\n\nThe `MONEY` plugin supports configurable default currencies through the\n`COMPLEX_CONFIG_MONEY_DEFAULT_CURRENCY` environment variable:\n\n```ruby\n# Default behavior - uses EUR if no environment variable is set\nMONEY = -\u003e id, currency = ENV.fetch('COMPLEX_CONFIG_MONEY_DEFAULT_CURRENCY', 'EUR') do\n  if cents = ask_and_send(\"#{id}_in_cents\")\n    Money.from_cents(cents, currency.upcase)\n  else\n    skip\n  end\nend\n```\n\n**Important Note**: Modern versions of the `money` gem require explicit\ncurrency specification. The plugin now uses `Money.from_cents(cents, currency)`\ninstead of `Money.new(cents)` to ensure proper currency handling.\n\n## Download 📥\n\nThe homepage of this library is located at\n\n* https://github.com/flori/complex_config\n\n## Author 👨‍💻\n\n[Florian Frank](mailto:flori@ping.de)\n\n## License 📄\n\nThis software is licensed under the [Apache 2.0 license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflori%2Fcomplex_config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflori%2Fcomplex_config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflori%2Fcomplex_config/lists"}