README.md in qonfig-0.13.0 vs README.md in qonfig-0.14.0

- old
+ new

@@ -34,28 +34,41 @@ - [Config reloading](#config-reloading) (reload config definitions and option values) - [Clear options](#clear-options) (set to nil) - [State freeze](#state-freeze) - [Settings as Predicates](#settings-as-predicates) - [Validation](#validation) + - [Introduction](#introdaction) - [Key search pattern](#key-search-pattern) - [Proc-based validation](#proc-based-validation) - [Method-based validation](#method-based-validation) - [Predefined validations](#predefined-validations) - [Work with files](#work-with-files) - [Load from YAML file](#load-from-yaml-file) - [Expose YAML](#expose-yaml) (`Rails`-like environment-based YAML configs) - [Load from JSON file](#load-from-json-file) + - [Expose JSON](#expose-json) (`Rails`-like environment-based JSON configs) - [Load from ENV](#load-from-env) - [Load from \_\_END\_\_](#load-from-__end__) (aka `load_from_self`) + - [Expose \_\_END\_\_](#expose-__end__) (aka `expose_self`) - [Save to JSON file](#save-to-json-file) (`save_to_json`) - [Save to YAML file](#save-to-yaml-file) (`save_to_yaml`) - [Plugins](#plugins) - [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`) +- [Roadmap](#roadmap) --- ## Definition +- [Definition and Settings Access](#definition-and-access) +- [Configuration](#configuration) +- [Inheritance](#inheritance) +- [Composition](#composition) +- [Hash representation](#hash-representation) +- [Smart Mixin](#smart-mixin) (`Qonfig::Configurable`) + +--- + ### Definition and Access ```ruby # --- definition --- class Config < Qonfig::DataSet @@ -394,23 +407,29 @@ # and etc... (all Qonfig-related features) ``` --- - ## Interaction +- [Iteration over setting keys](#iteration-over-setting-keys) (`#each_setting`, `#deep_each_setting`) +- [Config reloading](#config-reloading) (reload config definitions and option values) +- [Clear options](#clear-options) (set to nil) +- [State freeze](#state-freeze) +- [Settings as Predicates](#settings-as-predicates) + --- ### Iteration over setting keys - `#each_setting { |key, value| }` - iterates over the root setting keys; - `#deep_each_setting { |key, value| }` - iterates over all setting keys (deep inside); - - key object is represented as a string of `.`-joined keys; + - key object is represented as a string of `.`-joined setting key names; + ```ruby class Config < Qonfig::DataSet setting :db do setting :creds do setting :user, 'D@iVeR' @@ -422,20 +441,28 @@ setting :telegraf_url, 'udp://localhost:8094' setting :telegraf_prefix, 'test' end config = Config.new +``` -# 1. #each_setting +#### .each_setting + +```ruby config.each_setting { |key, value| { key => value } } + # result of each step: { 'db' => <Qonfig::Settings:0x00007ff8> } { 'telegraf_url' => 'udp://localhost:8094' } { 'telegraf_prefix' => 'test' } +``` -# 2. #deep_each_setting +#### .deep_each_setting + +```ruby config.deep_each_setting { |key, value| { key => value } } + # result of each step: { 'db.creds.user' => 'D@iveR' } { 'db.creds.password' => 'test123' } { 'db.creds.data' => { test: false } } { 'telegraf_url' => 'udp://localhost:8094' } @@ -593,29 +620,36 @@ --- ## Validation +- [Introduction](#introduction) +- [Key Search Pattern](#key-search-pattern) +- [Proc-based validation](#proc-based-validation) +- [Method-based validation](#method-based-validation) +- [Predefined validations](#predefined-validations) + +--- + +### Introduction + Qonfig provides a lightweight DSL for defining validations and works in all cases when setting values are initialized or mutated. -Settings are validated as keys (matched with a [specific string pattern](#key-search-patern)). +Settings are validated as keys (matched with a [specific string pattern](#key-search-pattern)). You can validate both a set of keys and each key separately. If you want to check the config object completely you can define a custom validation. **Features**: - -- is invoked on any mutation of any setting key +- validation is invoked on any mutation of any setting: - during dataset instantiation; - when assigning new values; - when calling `#reload!`; - when calling `#clear!`; - - provides special [key search pattern](#key-search-pattern) for matching setting key names; - uses the [key search pattern](#key-search-pattern) for definging what the setting key should be validated; - you can define your own custom validation logic and validate dataset instance completely; - validation logic should return **truthy** or **falsy** value; - -- supprots two validation techniques (**proc-based** and **dataset-method-based**) +- supprots two validation techniques (**proc-based** ([doc](#proc-based-validation)) and **dataset-method-based** ([doc](#method-based-validation))): - **proc-based** (`setting validation`) ```ruby validate 'db.user' do |value| value.is_a?(String) end @@ -640,27 +674,28 @@ def check_config settings.user == User[1] end ``` +- provides a **set of standard validations** ([doc](#predefined-validations)): + - DSL: `validate 'key.pattern', :predefned_validator`; + - validators: + - `integer` + - `float` + - `numeric` + - `big_decimal` + - `boolean` + - `string` + - `symbol` + - `text` (string or symbol) + - `array` + - `hash` + - `proc` + - `class` + - `module` + - `not_nil` -- provides a set of standard validations: - - `integer` - - `float` - - `numeric` - - `big_decimal` - - `boolean` - - `string` - - `symbol` - - `text` (string or symbol) - - `array` - - `hash` - - `proc` - - `class` - - `module` - - `not_nil` - --- ### Key search pattern **Key search pattern** works according to the following rules: @@ -816,16 +851,16 @@ - `:module` - `:proc` ```ruby class Config < Qonfig::DataSet - setting :user - setting :password + setting :user, 'empty' + setting :password, 'empty' setting :service do - setting :provider - setting :protocol + setting :provider, :empty + setting :protocol, :empty setting :on_fail, -> { puts 'atata!' } end setting :ignorance, false @@ -849,10 +884,22 @@ --- ## Work with files +- [Load from YAML file](#load-from-yaml-file) +- [Expose YAML](#expose-yaml) (`Rails`-like environment-based YAML configs) +- [Load from JSON file](#load-from-json-file) +- [Expose JSON](#expose-json) (`Rails`-like environment-based JSON configs) +- [Load from ENV](#load-from-env) +- [Load from \_\_END\_\_](#load-from-__end__) (aka `load_from_self`) +- [Expose \_\_END\_\_](#expose-__end__) (aka `expose_self`) +- [Save to JSON file](#save-to-json-file) (`save_to_json`) +- [Save to YAML file](#save-to-yaml-file) (`save_to_yaml`) + +--- + ### Load from YAML file - supports `ERB`; - `:strict` mode (fail behaviour when the required yaml file doesnt exist): - `true` (by default) - causes `Qonfig::FileNotFoundError`; @@ -1095,10 +1142,124 @@ Config.new.to_h # => { "nonexistent_json" => {}, "another_key" => nil } ``` --- +### Expose JSON + +- load configurations from JSON file in Rails-like manner (with environments); +- works in `load_from_jsom`/`expose_yaml` manner; +- `via:` - how an environment will be determined: + - `:file_name` + - load configuration from JSON file that have an `:env` part in it's name; + - `:env_key` + - load configuration from JSON file; + - concrete configuration should be defined in the root key with `:env` name; +- `env:` - your environment name (must be a type of `String`, `Symbol` or `Numeric`); +- `strict:` - requires the existence of the file and/or key with the name of the used environment: + - `true`: + - file should exist; + - root key with `:env` name should exist (if `via: :env_key` is used); + - raises `Qonfig::ExposeError` if file does not contain the required env key (if `via: :env` key is used); + - raises `Qonfig::FileNotFoundError` if the required file does not exist; + - `false`: + - file is not required; + - root key with `:env` name is not required (if `via: :env_key` is used); + +#### Environment is defined as a root key of JSON file + +```json +// config/project.json + +{ + "development": { + "api_mode_enabled": true, + "logging": false, + "db_driver": "sequel", + "throttle_requests": false, + "credentials": {} + }, + "test": { + "api_mode_enabled": true, + "logging": false, + "db_driver": "in_memory", + "throttle_requests": false, + "credentials": {} + }, + "staging": { + "api_mode_enabled": true, + "logging": true, + "db_driver": "active_record", + "throttle_requests": true, + "credentials": {} + }, + "production": { + "api_mode_enabled": true, + "logging": true, + "db_driver": "rom", + "throttle_requests": true, + "credentials": {} + } +} +``` + +```ruby +class Config < Qonfig::DataSet + expose_json 'config/project.json', via: :env_key, env: :production # load from production env + + # NOTE: in rails-like application you can use this: + expose_json 'config/project.json', via: :env_key, env: Rails.env +end + +config = Config.new + +config.settings.api_mode_enabled # => true (from :production subset of keys) +config.settings.logging # => true (from :production subset of keys) +config.settings.db_driver # => "rom" (from :production subset of keys) +config.settings.throttle_requests # => true (from :production subset of keys) +config.settings.credentials # => {} (from :production subset of keys) +``` + +#### Environment is defined as a part of JSON file name + +```json +// config/sidekiq.staging.json +{ + "web": { + "username": "staging_admin", + "password": "staging_password" + } +} +``` + +```json +// config/sidekiq.production.json +{ + "web": { + "username": "urj1o2", + "password": "u192jd0ixz0" + } +} +``` + +```ruby +class SidekiqConfig < Qonfig::DataSet + # NOTE: file name should be described WITHOUT environment part (in file name attribute) + expose_json 'config/sidekiq.json', via: :file_name, env: :staging # load from staging env + + # NOTE: in rails-like application you can use this: + expose_json 'config/sidekiq.json', via: :file_name, env: Rails.env +end + +config = SidekiqConfig.new + +config.settings.web.username # => "staging_admin" (from sidekiq.staging.json) +config.settings.web.password # => "staging_password" (from sidekiq.staging.json) +``` + +--- + ### Load from ENV - `:convert_values` (`false` by default): - `'t'`, `'T'`, `'true'`, `'TRUE'` - covnerts to `true`; - `'f'`, `'F'`, `'false'`, `'FALSE'` - covnerts to `false`; @@ -1166,10 +1327,11 @@ --- ### Load from \_\_END\_\_ - aka `load_from_self` +- works with `YAML` format; ```ruby class Config < Qonfig::DataSet load_from_self # on the root @@ -1204,10 +1366,61 @@ enabled: false ``` --- +### Expose \_\_END\_\_ + +- aka `expose_self`; +- works in `expose_json` and `expose_yaml` manner, but with `__END__` instruction of the current file; +- `env:` - your environment name (must be a type of `String`, `Symbol` or `Numeric`); +- works with `YAML` format; + +```ruby +class Config < Qonfig::DataSet + expose_self env: :production + + # NOTE: for Rails-like applications you can use this: + expose_self env: Rails.env +end + +config = Config.new + +config.settings.log # => true (from :production environment) +config.settings.api_enabled # => true (from :production environment) +config.settings.creds.user # => "D@iVeR" (from :production environment) +config.settings.creds.password # => "test123" (from :production environment) + +__END__ +default: &default + log: false + api_enabled: true + creds: + user: admin + password: 1234 + +development: + <<: *default + log: true + +test: + <<: *default + log: false + +staging: + <<: *default + +production: + <<: *default + log: true + creds: + user: D@iVeR + password: test123 +``` + +--- + ### Save to JSON file - `#save_to_json` - represents config object as a json structure and saves it to a file: - uses native `::JSON.generate` under the hood; - writes new file (or rewrites existing file); @@ -1357,9 +1570,13 @@ Qonfig.plugins # => array of strings # --- load specific plugin --- Qonfig.plugin(:plugin_name) # or Qonfig.plugin('plugin_name') ``` + +Provided plugins: + +- [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`) --- ### Plugins: toml