2.0.0 🐙
New major release including significant internals refactoring and multiple new features.
See the complete documentation in the repo Readme.
Highlights
Loaders API (📖 Docs)
Now it's possible to extend and modify data sources for configs.
By default, YAML files, ENV, secrets.yml
and credentials (NEW) for Rails are supported.
Local configuration files (📖 Docs)
Now users can store their personal configurations in local files:
config/<config_name>.local.yml
config/credentials/local.yml.enc
(for Rails 6).
Rails integration (📖 Docs)
Using Anyway Config to manage application-specific configuration became much easier:
- Generators are added for setting up
anyway_config
and creating new configs. - Autoloading configs work during the application initialization (so you can use config classes in Rails configuration files and initializers).
- Added credentials support.
Validation and callbacks (📖 Docs)
You can mark some attributes as required, which would made config load to fail if they're missing of blank:
attr_config :user, :password
required :user, :password
You can also add custom hooks to be run every time the configuration is loaded (i.e., during the initialization or when #reload
is called):
on_load do
raise_validation_error("Unknown log level: #{log_level}") unless LOG_LEVELS.include?(log_level)
end
Source tracing (📖 Docs)
It's now possible to get the information on where the config data came from:
conf = ExampleConfig.new
conf.to_source_trace
# returns the following hash
{
"host" => {value: "test.host", source: {type: :yml, path: "config/example.yml"}},
"user" => {
"name" => {value: "john", source: {type: :env, key: "EXAMPLE_USER__NAME"}},
"password" => {value: "root", source: {type: :credentials, store: "config/credentials/production.enc.yml"}}
},
"port" => {value: 9292, source: {type: :defaults}}
}
Breaking
-
Ruby >= 2.5.0 is required.
-
Changed the way of providing explicit values:
# BEFORE
Config.new(overrides: data)
# AFTER
Config.new(data)
- The accessors generated by
attr_config
are no longerattr_accessor
-s.
You cannot rely on instance variables anymore. Instead, you can use super
when overriding accessors or values[name]
. For example:
class MyConfig < Anyway::Config
attr_config :host, :port, :url, :meta
# override writer to handle type coercion
def meta=(val)
super JSON.parse(val)
end
# or override reader to handle missing values
def url
super || (self.url = "#{host}:#{port}")
end
# untill v2.1, it will still be possible to read instance variables,
# i.e. the following code would also work
def url
@url ||= "#{host}:#{port}"
end
end
We recommend to add a feature check and support both v1.x and v2.0 in gems for the time being:
# Check for the class method added in 2.0, e.g., `.on_load`
if respond_to?(:on_load)
def url
super || (self.url = "#{host}:#{port}")
end
else
def url
@url ||= "#{host}:#{port}"
end
end
We still set instance variables in writers (for backward compatibility) but that is to be removed in 2.1
- (only If you upgrading from v2.0.0.pre) Changed the way Rails application configs autoloading works.
In Rails 6, autoloading before initialization is deprecated. We can still make it work by using our own autoloading mechanism (custom Zeitwerk loader).
This forces us to use a custom directory (not app/
) for configs required at the boot time.
By default, we put static configs into config/configs
but you can still use app/configs
for dynamic (runtime) configs.
If you used app/configs
and relied on configs during initialization, you can set static configs path to app/configs
:
config.anyway_config.autoload_static_config_path = "app/configs"
You can do this by running the generator:
rails g anyway:install --configs-path=app/configs
Features
- Added
with_env
helper to test code in the context of the specified environment variables.
Included automatically in RSpec for examples with the type: :config
meta or with the spec/configs
path.
-
Added
Config#dig
method. -
Add
Config#deconstruct_keys
.
Now you can use configs in pattern matching:
case AWSConfig.new
in bucket:, region: "eu-west-1"
setup_eu_storage(bucket)
in bucket:, region: "us-east-1"
setup_us_storage(bucket)
end
- Add predicate methods for attributes with boolean defaults. ([@palkan][])
For example:
class MyConfig < Anyway::Config
attr_config :key, :secret, debug: false
end
MyConfig.new.debug? #=> false
MyConfig.new(debug: true).debug? #=> true
Changes
- Config attribute names are now validated.
Using reserved names (Anyway::Config
method names) is not allowed.
Only alphanumeric names (matching /^[a-z_]([\w]+)?$/
) are allowed.
- Updated config name inference logic.
Config name is automatically inferred only if the class name has a form of <Module>::Config
(SomeModule::Config => "some_module"
) or the class name has a form of <Something>Config
(SomeConfig => "some"
).
- Added ability to specify types for OptionParser options.
describe_options(
concurrency: {
desc: "number of threads to use",
type: String
}
)