Skip to content

Releases: palkan/anyway_config

2.4.0

05 Apr 03:16
Compare
Choose a tag to compare

Features

New loaders

Just specify your Doppler service token in the DOPPLER_TOKEN env var, and Anyway would automatically download configuration from Doppler.

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"

28 Sep 13:15
Compare
Choose a tag to compare

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.

📖 Documentation

  • 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.

📖 Documentation

2.1.0 🎄

28 Dec 21:51
Compare
Choose a tag to compare

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 🐙

14 Apr 13:13
Compare
Choose a tag to compare

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 longer attr_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

26 Apr 21:53
Compare
Choose a tag to compare
2.0.0.pre Pre-release
Pre-release

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

20 Jun 15:31
Compare
Choose a tag to compare

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.