Releases: palkan/anyway_config
2.4.0
Features
New loaders
- Doppler support.
Just specify your Doppler service token in the DOPPLER_TOKEN
env var, and Anyway would automatically download configuration from Doppler.
- ESJON support.
If you use EJSON to store encrypted secrets, Anyway would try to load configuration from config/secrets.ejson
(and environment-specific .ejson
files, too).
API enhancements
- You can now mark nested attributes as required:
class AppConfig < Anyway::Config
attr_config :assets_host, database: {host: nil, port: nil}
required :assets_host, database: [:host, :port]
end
-
Predicate methods are automatically defined for attributes with the
:boolean
type. -
Added ability to use
env_prefix ""
to load data rom unprefixed env vars. -
Added
Config#as_env
to convert config values into a ENV-like Hash.
This can be useful to export configuration to be used with legacy tools relying on ENV. So, for example, you can load data from credentials, secrets, whatever and make it available via ENV.
Experimental features
- Sub-configs support via types.
class AnotherConfig < Anyway::Config
attr_config foo: "bar"
end
class MyConfig < Anyway::Config
attr_config :another_config
coerce_types another_config: "AnotherConfig"
end
MyConfig.new.another_config.foo #=> "bar"
ENV["MY_ANOTHER_CONFIG__FOO"] = "baz"
MyConfig.new.another_config.foo #=> "baz"
2.2.0 "Types and types again"
Features
- Add type coercion support.
Example:
class CoolConfig < Anyway::Config
attr_config :port, :user
coerce_types port: :string, user: {dob: :date}
end
ENV["COOL_USER__DOB"] = "1989-07-01"
config = CoolConfig.new({port: 8080})
config.port == "8080" #=> true
config.user["dob"] == Date.new(1989, 7, 1) #=> true
You can also add .disable_auto_cast!
to your config class to disable automatic conversion.
- Add RBS signatures and generator.
Anyway Config now ships with the basic RBS support. To use config types with Steep, add library "anyway_config"
to your Steepfile.
We also provide an API to generate a signature for you config class: MyConfig.to_rbs
. You can use this method to generate a scaffold for your config class.
2.1.0 🎄
This release is dedicated to the Ruby 3.0 release.
Features
- Added ability to specify the default YAML configs directory as a plain string or Pathname.
For example:
Anyway::Settings.default_config_path = "path/to/configs"
# or in Rails
config.anyway_config.default_config_path = Rails.root.join("my/configs")
- Added ability to load environment-less YAML configs in Rails.
Useful for configs having similar values in any environment. For example:
# envless.yml
host: localhost
port: 3002
Rails.env #=> production or development — doesn't matter
Anyway::Config.for(:envless) => {host: "localhost", port: 3003}
NOTE: This feature will be enabled by default in the future versions; currently, you should opt-in to enable it:
# Add to you configuration
config.anyway_config.future.use :unwrap_known_environments
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
}
)
2.0.0.pre
RailsConf 2019 special.
The first, preview, release in 2.x series.
There is no more API changes plans, only new features, so it's safe to start using 2.0.0.pre
.
NOTE: Internal functionality is likely to change though.
Breaking changes
-
Ruby >= 2.5.0 is required.
-
Changed the way of providing explicit values:
# BEFORE Config.new(overrides: data) # AFTER Config.new(data)
Features
- Add Rails credentials support.
The data from credentials is loaded after the data from YAML config and secrets,
but before environmental variables (i.e. env variables are stronger).
- Add support for local configuration files and credentials.
Now users can store their personal configurations in local files:
<config_name>.local.yml
config/credentials/local.yml.enc
(for Rails 6).
Local configs are meant for using in development and only loaded if Anyway::Settings.use_local_files
is true
(which is true by default if RACK_ENV
or RAILS_ENV
env variable is equal to "development"
).
- Added test helpers.
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.
- Better Rails integration.
Anyway::Railtie
provides an access to Anyway::Settings
via Rails.applicaiton.configuration.anyway_config
.
It also adds app/configs
path to autoload paths (low-level, ActiveSupport::Dependencies
) to
make it possible to use configs in the app configuration files.
Changes
- 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"
) - the class name has a form of
<Something>Config
(SomeConfig => "some"
)
Fixes
- Fixed config classes inheritance.
Previously, inheritance didn't work due to the lack of proper handling of class-level configuration (naming, option parses settings, defaults).
Now it's possible to extend config classes without breaking the original classes functionality.
Other:
- if
config_name
is explicitly defined on class, it's inherited by subclasses:
class MyAppBaseConfig < Anyway::Config
config_name :my_app
end
class MyServiceConfig < MyAppBaseConfig
end
MyServiceConfig.config_name #=> "my_app"
- defaults are merged leaving the parent class defaults unchanged
- option parse extension are not overriden, but added to the parent class extensions.
v1.0.0
After two years in production, we're ready to release v1.0.0.
This release introduces no breaking changes but some new features and improvements:
-
Add support for ERB in YML configuration
-
Lazy load and parse ENV configuration
-
No dependencies.
And, of course, all known bugs have been fixed.