Merge branch 'main' into master
This commit is contained in:
commit
a44afe8999
|
@ -1 +1 @@
|
|||
github: [jodosha, solnic, timriley]
|
||||
github: hanami
|
||||
|
|
|
@ -15,7 +15,7 @@ on:
|
|||
- "project.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
create:
|
||||
|
||||
jobs:
|
||||
|
@ -26,18 +26,18 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby:
|
||||
- "3.1"
|
||||
- "3.0"
|
||||
- "2.7"
|
||||
- "2.6"
|
||||
include:
|
||||
- ruby: "3.0"
|
||||
- ruby: "3.1"
|
||||
coverage: "true"
|
||||
env:
|
||||
COVERAGE: ${{matrix.coverage}}
|
||||
COVERAGE_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
- name: Install package dependencies
|
||||
run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
|
||||
- name: Set up Ruby
|
||||
|
@ -47,12 +47,6 @@ jobs:
|
|||
bundler-cache: true
|
||||
- name: Run all tests
|
||||
run: bundle exec rake
|
||||
- name: Run codacy-coverage-reporter
|
||||
uses: codacy/codacy-coverage-reporter-action@master
|
||||
if: env.COVERAGE == 'true' && env.COVERAGE_TOKEN != ''
|
||||
with:
|
||||
project-token: ${{secrets.CODACY_PROJECT_TOKEN}}
|
||||
coverage-reports: coverage/coverage.xml
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.ref, 'tags') && github.event_name == 'create'
|
||||
|
@ -61,13 +55,13 @@ jobs:
|
|||
GITHUB_LOGIN: dry-bot
|
||||
GITHUB_TOKEN: ${{secrets.GH_PAT}}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install package dependencies
|
||||
run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
ruby-version: 2.7
|
||||
- name: Install dependencies
|
||||
run: gem install ossy --no-document
|
||||
- name: Trigger release workflow
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# this file is managed by dry-rb/devtools project
|
||||
# This file is synced from dry-rb/template-gem repo
|
||||
|
||||
name: docsite
|
||||
|
||||
|
@ -8,7 +8,7 @@ on:
|
|||
- docsite/**
|
||||
- .github/workflows/docsite.yml
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- release-**
|
||||
tags:
|
||||
|
||||
|
@ -24,7 +24,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: "2.6.x"
|
||||
ruby-version: "2.7.x"
|
||||
- name: Set up git user
|
||||
run: |
|
||||
git config --local user.email "dry-bot@dry-rb.org"
|
||||
|
@ -51,7 +51,7 @@ jobs:
|
|||
|
||||
git push --all "https://dry-bot:${{secrets.GH_PAT}}@github.com/$GITHUB_REPOSITORY.git"
|
||||
|
||||
git checkout master
|
||||
git checkout main
|
||||
else
|
||||
echo "no need to update branches"
|
||||
fi
|
||||
|
|
|
@ -6,7 +6,7 @@ on:
|
|||
repository_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "main"
|
||||
|
||||
jobs:
|
||||
main:
|
||||
|
@ -17,7 +17,7 @@ jobs:
|
|||
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||
steps:
|
||||
- name: Checkout ${{github.repository}}
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout devtools
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
@ -30,7 +30,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: "2.6"
|
||||
ruby-version: "2.7"
|
||||
- name: Install dependencies
|
||||
run: gem install ossy --no-document
|
||||
- name: Update changelog.yml from commit
|
||||
|
@ -43,5 +43,5 @@ jobs:
|
|||
git commit -m "[devtools] sync" || echo "nothing to commit"
|
||||
- name: Push changes
|
||||
run: |
|
||||
git pull --rebase origin master
|
||||
git push https://dry-bot:${{secrets.GH_PAT}}@github.com/${{github.repository}}.git HEAD:master
|
||||
git pull --rebase origin main
|
||||
git push https://dry-bot:${{secrets.GH_PAT}}@github.com/${{github.repository}}.git HEAD:main
|
||||
|
|
81
.rubocop.yml
81
.rubocop.yml
|
@ -1,9 +1,10 @@
|
|||
# This is a config synced from dry-rb/template-gem repo
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.6
|
||||
NewCops: enable
|
||||
TargetRubyVersion: 2.7
|
||||
NewCops: disable
|
||||
Exclude:
|
||||
- benchmarks/*.rb
|
||||
- spec/support/coverage.rb
|
||||
- spec/support/warnings.rb
|
||||
- spec/support/rspec_options.rb
|
||||
|
@ -56,6 +57,10 @@ Lint/SuppressedException:
|
|||
Exclude:
|
||||
- "spec/spec_helper.rb"
|
||||
|
||||
Lint/LiteralAsCondition:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Naming/PredicateName:
|
||||
Enabled: false
|
||||
|
||||
|
@ -67,9 +72,7 @@ Naming/MethodName:
|
|||
Enabled: false
|
||||
|
||||
Naming/MethodParameterName:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
Enabled: false
|
||||
|
||||
Naming/MemoizedInstanceVariableName:
|
||||
Enabled: false
|
||||
|
@ -134,6 +137,9 @@ Style/EachWithObject:
|
|||
Style/FormatString:
|
||||
Enabled: false
|
||||
|
||||
Style/FormatStringToken:
|
||||
Enabled: false
|
||||
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
|
||||
|
@ -174,10 +180,58 @@ Style/MultipleComparison:
|
|||
Style/Next:
|
||||
Enabled: false
|
||||
|
||||
Style/AccessorGrouping:
|
||||
Enabled: false
|
||||
|
||||
Style/EmptyLiteral:
|
||||
Enabled: false
|
||||
|
||||
Style/Semicolon:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Style/HashAsLastArrayItem:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Style/CaseEquality:
|
||||
Exclude:
|
||||
- "lib/dry/monads/**/*.rb"
|
||||
- "lib/dry/struct/**/*.rb"
|
||||
- "lib/dry/types/**/*.rb"
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Style/ExplicitBlockArgument:
|
||||
Exclude:
|
||||
- "lib/dry/types/**/*.rb"
|
||||
|
||||
Style/CombinableLoops:
|
||||
Enabled: false
|
||||
|
||||
Style/EmptyElse:
|
||||
Enabled: false
|
||||
|
||||
Style/DoubleNegation:
|
||||
Enabled: false
|
||||
|
||||
Style/MultilineBlockChain:
|
||||
Enabled: false
|
||||
|
||||
Style/NumberedParametersLimit:
|
||||
Max: 2
|
||||
|
||||
Lint/UnusedBlockArgument:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Lint/Debugger:
|
||||
Exclude:
|
||||
- "bin/console"
|
||||
|
||||
Lint/BinaryOperatorWithIdenticalOperands:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Metrics/ParameterLists:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
@ -186,6 +240,23 @@ Lint/EmptyBlock:
|
|||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Lint/UselessMethodDefinition:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Lint/SelfAssignment:
|
||||
Enabled: false
|
||||
|
||||
Lint/EmptyClass:
|
||||
Enabled: false
|
||||
|
||||
Naming/ConstantName:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Naming/VariableNumber:
|
||||
Exclude:
|
||||
- "spec/**/*.rb"
|
||||
|
||||
Naming/BinaryOperatorParameterName:
|
||||
Enabled: false
|
||||
|
|
80
CHANGELOG.md
80
CHANGELOG.md
|
@ -1,19 +1,81 @@
|
|||
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
||||
|
||||
## unreleased
|
||||
## 0.15.0 2022-04-21
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `ArgumentError` for classes including `Dry::Configurable` whose `initializer` has required kwargs. (#113 by @timriley)
|
||||
- Remove implicit `to_hash` conversion from `Config`. (#114 by @timriley)
|
||||
|
||||
### Changed
|
||||
|
||||
- Deprecate constructor as a block. Providing `constructor:` kwarg is now the only accepted way. (#111 by @waiting-for-dev & @timriley)
|
||||
- Use `default:` kwarg instead of second positional argument for the default value. (#112 by @waiting-for-dev & @timriley)
|
||||
- The `finalize!` method (as class or instance method, depending on whether you extend or include `Dry::Configurable` respectively) now accepts a boolean `freeze_values:` argument, which if true, will recursively freeze all config values in addition to the `config` itself. (#105 by @ojab)
|
||||
|
||||
[Compare v0.12.1...master](https://github.com/dry-rb/dry-configurable/compare/v0.12.1...master)
|
||||
```ruby
|
||||
class MyConfigurable
|
||||
include Dry::Configurable
|
||||
|
||||
setting :db, default: "postgre"
|
||||
end
|
||||
|
||||
my_obj = MyConfigurable.new
|
||||
my_obj.finalize!(freeze_values: true)
|
||||
my_obj.config.db << "sql" # Will raise FrozenError
|
||||
```
|
||||
- `Dry::Configurable::Config#update` will set hashes as values for non-nested settings (#131 by @ojab)
|
||||
|
||||
```ruby
|
||||
class MyConfigurable
|
||||
extend Dry::Configurable
|
||||
|
||||
setting :sslcert, constructor: ->(v) { v&.values_at(:pem, :pass)&.join }
|
||||
end
|
||||
|
||||
MyConfigurable.config.update(sslcert: {pem: "cert", pass: "qwerty"})
|
||||
MyConfigurable.config.sslcert # => "certqwerty"
|
||||
```
|
||||
- `Dry::Configurable::Config#update` will accept any values implicitly convertible to hash via `#to_hash` (#133 by @timriley)
|
||||
|
||||
[Compare v0.14.0...v0.15.0](https://github.com/dry-rb/dry-configurable/compare/v0.14.0...v0.15.0)
|
||||
|
||||
## 0.14.0 2022-01-14
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Settings defined after an access to `config` will still be made available on that `config`. (#130 by @timriley)
|
||||
- Cloneable settings are cloned immediately upon assignment. (#130 by @timriley)
|
||||
- Changes to config values in parent classes after subclasses have already been created will not be propogated to those subclasses. Subclasses created _after_ config values have been changed in the parent _will_ receive those config values. (#130 by @timriley)
|
||||
|
||||
[Compare v0.13.0...v0.14.0](https://github.com/dry-rb/dry-configurable/compare/v0.13.0...v0.14.0)
|
||||
|
||||
## 0.13.0 2021-09-12
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- Added flags to determine whether to warn on the API usage deprecated in this release (see "Changed" section below). Set these to `false` to suppress the warnings. (#124 by @timriley)
|
||||
|
||||
```ruby
|
||||
Dry::Configurable.warn_on_setting_constructor_block false
|
||||
Dry::Configurable.warn_on_setting_positional_default false
|
||||
```
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `ArgumentError` for classes including `Dry::Configurable` whose `initializer` has required kwargs. (#113 by @timriley)
|
||||
|
||||
### Changed
|
||||
|
||||
- Deprecated the setting constructor provided as a block. Provide it via the `constructor:` keyword argument instead. (#111 by @waiting-for-dev & @timriley)
|
||||
|
||||
```ruby
|
||||
setting :path, constructor: -> path { Pathname(path) }
|
||||
```
|
||||
- Deprecated the setting default provided as the second positional argument. Provide it via the `default:` keyword argument instead. (#112 and #121 by @waiting-for-dev & @timriley)
|
||||
|
||||
```ruby
|
||||
setting :path, default: "some/default/path"
|
||||
```
|
||||
- [BREAKING] Removed implicit `to_hash` conversion from `Config`. (#114 by @timriley)
|
||||
|
||||
[Compare v0.12.1...v0.13.0](https://github.com/dry-rb/dry-configurable/compare/v0.12.1...v0.13.0)
|
||||
|
||||
## 0.12.1 2021-02-15
|
||||
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
## 0.9.0 - 2019-11-06
|
||||
|
||||
## Fixed
|
||||
|
||||
- Support for reserved names in settings. Some Kernel methods (`public_send` and `class` specifically) are not available if you use access settings via method call. Same for methods of the `Config` class. You can still access them with `[]` and `[]=`. Ruby keywords are fully supported. Invalid names containing special symbols (including `!` and `?`) are rejected. Note that these changes don't affect the `reader` option, if you define a setting named `:class` and pass `reader: true` ... well ... (flash-gordon)
|
||||
- Settings can be redefined in subclasses without a warning about overriding exsting methods (flash-gordon)
|
||||
- Fix warnings about using keyword arguments in 2.7 (koic)
|
||||
|
||||
[Compare v0.8.3...v0.9.0](https://github.com/dry-rb/dry-configurable/compare/v0.8.3...v0.9.0)
|
||||
|
||||
## 0.8.3 - 2019-05-29
|
||||
|
||||
## Fixed
|
||||
|
||||
- `Configurable#dup` and `Configurable#clone` make a copy of instance-level config so that it doesn't get mutated/shared across instances (flash-gordon)
|
||||
|
||||
[Compare v0.8.2...v0.8.3](https://github.com/dry-rb/dry-configurable/compare/v0.8.2...v0.8.3)
|
||||
|
||||
## 0.8.2 - 2019-02-25
|
||||
|
||||
## Fixed
|
||||
|
||||
- Test interface support for modules ([Neznauy](https://github.com/Neznauy))
|
||||
|
||||
[Compare v0.8.1...v0.8.2](https://github.com/dry-rb/dry-configurable/compare/v0.8.1...v0.8.2)
|
||||
|
||||
## 0.8.1 - 2019-02-06
|
||||
|
||||
## Fixed
|
||||
|
||||
- `.configure` doesn't require a block, this makes the behavior consistent with the previous versions ([flash-gordon](https://github.com/flash-gordon))
|
||||
|
||||
[Compare v0.8.0...v0.8.1](https://github.com/dry-rb/dry-configurable/compare/v0.8.0...v0.8.1)
|
||||
|
||||
## 0.8.0 - 2019-02-05
|
||||
|
||||
## Fixed
|
||||
|
||||
- A number of bugs related to inheriting settings from parent class were fixed. Ideally, new behavior will be :100: predictable but if you observe any anomaly, please report ([flash-gordon](https://github.com/flash-gordon))
|
||||
|
||||
## Added
|
||||
|
||||
- Support for instance-level configuration landed. For usage, `include` the module instead of extending ([flash-gordon](https://github.com/flash-gordon))
|
||||
|
||||
```ruby
|
||||
class App
|
||||
include Dry::Configurable
|
||||
|
||||
setting :database
|
||||
end
|
||||
|
||||
production = App.new
|
||||
production.config.database = ENV['DATABASE_URL']
|
||||
production.finalize!
|
||||
|
||||
development = App.new
|
||||
development.config.database = 'jdbc:sqlite:memory'
|
||||
development.finalize!
|
||||
```
|
||||
|
||||
- Config values can be set from a hash with `.update`. Nested settings are supported ([flash-gordon](https://github.com/flash-gordon))
|
||||
|
||||
```ruby
|
||||
class App
|
||||
extend Dry::Configurable
|
||||
|
||||
setting :db do
|
||||
setting :host
|
||||
setting :port
|
||||
end
|
||||
|
||||
config.update(YAML.load(File.read("config.yml")))
|
||||
end
|
||||
```
|
||||
|
||||
## Changed
|
||||
|
||||
- [BREAKING] Minimal supported Ruby version is set to 2.3 ([flash-gordon](https://github.com/flash-gordon))
|
||||
|
||||
[Compare v0.7.0...v0.8.0](https://github.com/dry-rb/dry-configurable/compare/v0.7.0...v0.8.0)
|
||||
|
||||
## 0.7.0 - 2017-04-25
|
||||
|
||||
## Added
|
||||
|
||||
- Introduce `Configurable.finalize!` which freezes config and its dependencies ([qcam](https://github.com/qcam))
|
||||
|
||||
## Fixed
|
||||
|
||||
- Allow for boolean false as default setting value ([yuszuv](https://github.com/yuszuv))
|
||||
- Convert nested configs to nested hashes with `Config#to_h` ([saverio-kantox](https://github.com/saverio-kantox))
|
||||
- Disallow modification on frozen config ([qcam](https://github.com/qcam))
|
||||
|
||||
[Compare v0.6.2...v0.7.0](https://github.com/dry-rb/dry-configurable/compare/v0.6.2...v0.7.0)
|
10
Gemfile
10
Gemfile
|
@ -1,16 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
source "https://rubygems.org"
|
||||
|
||||
eval_gemfile 'Gemfile.devtools'
|
||||
eval_gemfile "Gemfile.devtools"
|
||||
|
||||
gemspec
|
||||
|
||||
group :benchmarks do
|
||||
gem 'benchmark-ips'
|
||||
gem "benchmark-ips"
|
||||
end
|
||||
|
||||
group :tools do
|
||||
gem 'hotch'
|
||||
gem 'pry-byebug', platform: :mri
|
||||
gem "hotch", platform: :mri
|
||||
gem "pry-byebug", platform: :mri
|
||||
end
|
||||
|
|
|
@ -13,6 +13,5 @@ group :test do
|
|||
end
|
||||
|
||||
group :tools do
|
||||
# this is the same version that we use on codacy
|
||||
gem "rubocop", "1.16.0"
|
||||
gem "rubocop", "~> 1.27.0"
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[![CI Status](https://github.com/dry-rb/dry-configurable/workflows/ci/badge.svg)][actions]
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/0276a97990e04eb0ac722b3e7f3620b5)][codacy]
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/0276a97990e04eb0ac722b3e7f3620b5)][codacy]
|
||||
[![Inline docs](http://inch-ci.org/github/dry-rb/dry-configurable.svg?branch=master)][inchpages]
|
||||
[![Inline docs](http://inch-ci.org/github/dry-rb/dry-configurable.svg?branch=main)][inchpages]
|
||||
|
||||
## Links
|
||||
|
||||
|
@ -22,8 +22,8 @@
|
|||
|
||||
This library officially supports the following Ruby versions:
|
||||
|
||||
* MRI `>= 2.6.0`
|
||||
* ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
|
||||
* MRI `>= 2.7.0`
|
||||
* jruby `>= 9.3` (postponed until 2.7 is supported)
|
||||
|
||||
## License
|
||||
|
||||
|
|
4
Rakefile
4
Rakefile
|
@ -1,8 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
desc 'Run all specs in spec directory'
|
||||
desc "Run all specs in spec directory"
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
task default: :spec
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'bundler/setup'
|
||||
require 'dry/configurable'
|
||||
require "bundler/setup"
|
||||
require "dry/configurable"
|
||||
|
||||
begin
|
||||
require 'pry-byebug'
|
||||
require "pry-byebug"
|
||||
Pry.start
|
||||
rescue LoadError
|
||||
require 'irb'
|
||||
require "irb"
|
||||
IRB.start
|
||||
end
|
||||
|
|
|
@ -1,17 +1,74 @@
|
|||
---
|
||||
- version: unreleased
|
||||
- version: 0.15.0
|
||||
summary:
|
||||
date:
|
||||
fixed:
|
||||
- 'Fix `ArgumentError` for classes including `Dry::Configurable` whose
|
||||
`initializer` has required kwargs. (#113 by @timriley)'
|
||||
- 'Remove implicit `to_hash` conversion from `Config`. (#114 by @timriley)'
|
||||
added:
|
||||
date: '2022-04-21'
|
||||
changed:
|
||||
- 'Deprecate constructor as a block. Providing `constructor:` kwarg is now
|
||||
the only accepted way. (#111 by @waiting-for-dev & @timriley)'
|
||||
- 'Use `default:` kwarg instead of second positional argument for the
|
||||
default value. (#112 by @waiting-for-dev & @timriley)'
|
||||
- |-
|
||||
The `finalize!` method (as class or instance method, depending on whether you extend or include `Dry::Configurable` respectively) now accepts a boolean `freeze_values:` argument, which if true, will recursively freeze all config values in addition to the `config` itself. (#105 by @ojab)
|
||||
|
||||
```ruby
|
||||
class MyConfigurable
|
||||
include Dry::Configurable
|
||||
|
||||
setting :db, default: "postgre"
|
||||
end
|
||||
|
||||
my_obj = MyConfigurable.new
|
||||
my_obj.finalize!(freeze_values: true)
|
||||
my_obj.config.db << "sql" # Will raise FrozenError
|
||||
```
|
||||
- |-
|
||||
`Dry::Configurable::Config#update` will set hashes as values for non-nested settings (#131 by @ojab)
|
||||
|
||||
```ruby
|
||||
class MyConfigurable
|
||||
extend Dry::Configurable
|
||||
|
||||
setting :sslcert, constructor: ->(v) { v&.values_at(:pem, :pass)&.join }
|
||||
end
|
||||
|
||||
MyConfigurable.config.update(sslcert: {pem: "cert", pass: "qwerty"})
|
||||
MyConfigurable.config.sslcert # => "certqwerty"
|
||||
```
|
||||
- |-
|
||||
`Dry::Configurable::Config#update` will accept any values implicitly convertible to hash via `#to_hash` (#133 by @timriley)
|
||||
- version: 0.14.0
|
||||
summary:
|
||||
date: '2022-01-14'
|
||||
changed:
|
||||
- |-
|
||||
Settings defined after an access to `config` will still be made available on that `config`. (#130 by @timriley)
|
||||
- |-
|
||||
Cloneable settings are cloned immediately upon assignment. (#130 by @timriley)
|
||||
- |-
|
||||
Changes to config values in parent classes after subclasses have already been created will not be propogated to those subclasses. Subclasses created _after_ config values have been changed in the parent _will_ receive those config values. (#130 by @timriley)
|
||||
- version: 0.13.0
|
||||
summary:
|
||||
date: '2021-09-12'
|
||||
fixed:
|
||||
- Fixed `ArgumentError` for classes including `Dry::Configurable` whose `initializer` has required kwargs. (#113 by @timriley)
|
||||
added:
|
||||
- |-
|
||||
Added flags to determine whether to warn on the API usage deprecated in this release (see "Changed" section below). Set these to `false` to suppress the warnings. (#124 by @timriley)
|
||||
|
||||
```ruby
|
||||
Dry::Configurable.warn_on_setting_constructor_block false
|
||||
Dry::Configurable.warn_on_setting_positional_default false
|
||||
```
|
||||
changed:
|
||||
- |-
|
||||
Deprecated the setting constructor provided as a block. Provide it via the `constructor:` keyword argument instead. (#111 by @waiting-for-dev & @timriley)
|
||||
|
||||
```ruby
|
||||
setting :path, constructor: -> path { Pathname(path) }
|
||||
```
|
||||
- |-
|
||||
Deprecated the setting default provided as the second positional argument. Provide it via the `default:` keyword argument instead. (#112 and #121 by @waiting-for-dev & @timriley)
|
||||
|
||||
```ruby
|
||||
setting :path, default: "some/default/path"
|
||||
```
|
||||
- '[BREAKING] Removed implicit `to_hash` conversion from `Config`. (#114 by @timriley)'
|
||||
- version: 0.12.1
|
||||
summary:
|
||||
date: '2021-02-15'
|
||||
|
|
|
@ -26,17 +26,17 @@ class App
|
|||
# Pass a block for nested configuration (works to any depth)
|
||||
setting :database do
|
||||
# Can pass a default value
|
||||
setting :dsn, 'sqlite:memory'
|
||||
setting :dsn, default: 'sqlite:memory'
|
||||
end
|
||||
# Defaults to nil if no default value is given
|
||||
setting :adapter
|
||||
# Construct values
|
||||
setting(:path, 'test') { |value| Pathname(value) }
|
||||
setting :path, default: 'test', constructor: proc { |value| Pathname(value) }
|
||||
# Passing the reader option as true will create attr_reader method for the class
|
||||
setting :pool, 5, reader: true
|
||||
setting :pool, default: 5, reader: true
|
||||
# Passing the reader attributes works with nested configuration
|
||||
setting :uploader, reader: true do
|
||||
setting :bucket, 'dev'
|
||||
setting :bucket, default: 'dev'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ Gem::Specification.new do |spec|
|
|||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
||||
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-configurable/blob/master/CHANGELOG.md"
|
||||
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-configurable/blob/main/CHANGELOG.md"
|
||||
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-configurable"
|
||||
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-configurable/issues"
|
||||
|
||||
spec.required_ruby_version = ">= 2.6.0"
|
||||
spec.required_ruby_version = ">= 2.7.0"
|
||||
|
||||
# to update dependencies edit project.yml
|
||||
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
||||
|
|
|
@ -13,12 +13,11 @@ module Dry
|
|||
include Methods
|
||||
|
||||
# @api private
|
||||
def inherited(klass)
|
||||
def inherited(subclass)
|
||||
super
|
||||
|
||||
parent_settings = (respond_to?(:config) ? config._settings : _settings)
|
||||
|
||||
klass.instance_variable_set("@_settings", parent_settings)
|
||||
subclass.instance_variable_set("@_settings", _settings.dup)
|
||||
subclass.instance_variable_set("@_config", config.dup) if respond_to?(:config)
|
||||
end
|
||||
|
||||
# Add a setting to the configuration
|
||||
|
@ -71,12 +70,17 @@ module Dry
|
|||
#
|
||||
# @api public
|
||||
def config
|
||||
# The _settings provided to the Config remain shared between the class and the
|
||||
# Config. This allows settings defined _after_ accessing the config to become
|
||||
# available in subsequent accesses to the config. The config is duped when
|
||||
# subclassing to ensure it remains distinct between subclasses and parent classes
|
||||
# (see `.inherited` above).
|
||||
@config ||= Config.new(_settings)
|
||||
end
|
||||
|
||||
# @api private
|
||||
def __config_dsl__
|
||||
@dsl ||= DSL.new
|
||||
@__config_dsl__ ||= DSL.new
|
||||
end
|
||||
|
||||
# @api private
|
||||
|
|
|
@ -23,7 +23,7 @@ module Dry
|
|||
|
||||
# @api private
|
||||
def initialize(settings)
|
||||
@_settings = settings.dup
|
||||
@_settings = settings
|
||||
@_resolved = Concurrent::Map.new
|
||||
end
|
||||
|
||||
|
@ -50,16 +50,19 @@ module Dry
|
|||
|
||||
# Update config with new values
|
||||
#
|
||||
# @param values [Hash] A hash with new values
|
||||
# @param values [Hash, #to_hash] A hash with new values
|
||||
#
|
||||
# @return [Config]
|
||||
#
|
||||
# @api public
|
||||
def update(values)
|
||||
values.each do |key, value|
|
||||
case value
|
||||
when Hash
|
||||
self[key].update(value)
|
||||
if self[key].is_a?(self.class)
|
||||
unless value.respond_to?(:to_hash)
|
||||
raise ArgumentError, "#{value.inspect} is not a valid setting value"
|
||||
end
|
||||
|
||||
self[key].update(value.to_hash)
|
||||
else
|
||||
self[key] = value
|
||||
end
|
||||
|
@ -81,8 +84,8 @@ module Dry
|
|||
alias_method :to_h, :values
|
||||
|
||||
# @api private
|
||||
def finalize!
|
||||
_settings.freeze
|
||||
def finalize!(freeze_values: false)
|
||||
_settings.finalize!(freeze_values: freeze_values)
|
||||
freeze
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "dry/configurable/constants"
|
||||
require "dry/configurable/flags"
|
||||
require "dry/configurable/setting"
|
||||
require "dry/configurable/settings"
|
||||
require "dry/configurable/compiler"
|
||||
|
@ -27,33 +28,105 @@ module Dry
|
|||
instance_exec(&block) if block
|
||||
end
|
||||
|
||||
# Register a new setting node and compile it into a setting object
|
||||
# Registers a new setting node and compile it into a setting object
|
||||
#
|
||||
# @see ClassMethods.setting
|
||||
# @api public
|
||||
# @api private
|
||||
# @return Setting
|
||||
def setting(name, default = Undefined, **options, &block)
|
||||
def setting(name, default = Undefined, **options, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
||||
unless VALID_NAME.match?(name.to_s)
|
||||
raise ArgumentError, "#{name} is not a valid setting name"
|
||||
end
|
||||
|
||||
if default != Undefined
|
||||
Dry::Core::Deprecations.announce(
|
||||
"default value as positional argument to settings",
|
||||
"Provide a `default:` keyword argument instead",
|
||||
tag: "dry-configurable",
|
||||
uplevel: 2
|
||||
)
|
||||
if Dry::Configurable.warn_on_setting_positional_default
|
||||
Dry::Core::Deprecations.announce(
|
||||
"default value as positional argument to settings",
|
||||
"Provide a `default:` keyword argument instead",
|
||||
tag: "dry-configurable",
|
||||
uplevel: 2
|
||||
)
|
||||
end
|
||||
|
||||
options = options.merge(default: default)
|
||||
end
|
||||
|
||||
if RUBY_VERSION < "3.0" &&
|
||||
default == Undefined &&
|
||||
(valid_opts, invalid_opts = valid_and_invalid_options(options)) &&
|
||||
invalid_opts.any? &&
|
||||
valid_opts.none?
|
||||
# In Ruby 2.6 and 2.7, when a hash is given as the second positional argument
|
||||
# (i.e. the hash is intended to be the setting's default value), and there are
|
||||
# no other keyword arguments given, the hash is assigned to the `options`
|
||||
# variable instead of `default`.
|
||||
#
|
||||
# For example, for this setting:
|
||||
#
|
||||
# setting :hash_setting, {my_hash: true}
|
||||
#
|
||||
# We'll have a `default` of `Undefined` and an `options` of `{my_hash: true}`
|
||||
#
|
||||
# If any additional keyword arguments are provided, e.g.:
|
||||
#
|
||||
# setting :hash_setting, {my_hash: true}, reader: true
|
||||
#
|
||||
# Then we'll have a `default` of `{my_hash: true}` and an `options` of `{reader:
|
||||
# true}`, which is what we want.
|
||||
#
|
||||
# To work around that first case and ensure our (deprecated) backwards
|
||||
# compatibility holds for Ruby 2.6 and 2.7, we extract all invalid options from
|
||||
# `options`, and if there are no remaining valid options (i.e. if there were no
|
||||
# keyword arguments given), then we can infer the invalid options to be a
|
||||
# default hash value for the setting.
|
||||
#
|
||||
# This approach also preserves the behavior of raising an ArgumentError when a
|
||||
# distinct hash is _not_ intentionally provided as the second positional
|
||||
# argument (i.e. it's not enclosed in braces), and instead invalid keyword
|
||||
# arguments are given alongside valid ones. So this setting:
|
||||
#
|
||||
# setting :some_setting, invalid_option: true, reader: true
|
||||
#
|
||||
# Would raise an ArgumentError as expected.
|
||||
#
|
||||
# However, the one case we can't catch here is when invalid options are supplied
|
||||
# without hash literal braces, but there are no other keyword arguments
|
||||
# supplied. In this case, a setting like:
|
||||
#
|
||||
# setting :hash_setting, my_hash: true
|
||||
#
|
||||
# Is parsed identically to the first case described above:
|
||||
#
|
||||
# setting :hash_setting, {my_hash: true}
|
||||
#
|
||||
# So in both of these cases, the default value will become `{my_hash: true}`. We
|
||||
# consider this unlikely to be a problem in practice, since users are not likely
|
||||
# to be providing invalid options to `setting` and expecting them to be ignored.
|
||||
# Additionally, the deprecation messages will make the new behavior obvious, and
|
||||
# encourage the users to upgrade their setting definitions.
|
||||
|
||||
if Dry::Configurable.warn_on_setting_positional_default
|
||||
Dry::Core::Deprecations.announce(
|
||||
"default value as positional argument to settings",
|
||||
"Provide a `default:` keyword argument instead",
|
||||
tag: "dry-configurable",
|
||||
uplevel: 2
|
||||
)
|
||||
end
|
||||
|
||||
options = {default: invalid_opts}
|
||||
end
|
||||
|
||||
if block && !block.arity.zero?
|
||||
Dry::Core::Deprecations.announce(
|
||||
"passing a constructor as a block",
|
||||
"Provide a `constructor:` keyword argument instead",
|
||||
tag: "dry-configurable",
|
||||
uplevel: 2
|
||||
)
|
||||
if Dry::Configurable.warn_on_setting_constructor_block
|
||||
Dry::Core::Deprecations.announce(
|
||||
"passing a constructor as a block",
|
||||
"Provide a `constructor:` keyword argument instead",
|
||||
tag: "dry-configurable",
|
||||
uplevel: 2
|
||||
)
|
||||
end
|
||||
|
||||
options = options.merge(constructor: block)
|
||||
block = nil
|
||||
end
|
||||
|
@ -77,8 +150,15 @@ module Dry
|
|||
return if options.none?
|
||||
|
||||
invalid_keys = options.keys - Setting::OPTIONS
|
||||
|
||||
raise ArgumentError, "Invalid options: #{invalid_keys.inspect}" unless invalid_keys.empty?
|
||||
end
|
||||
|
||||
# Returns a tuple of valid and invalid options hashes derived from the options hash
|
||||
# given to the setting
|
||||
def valid_and_invalid_options(options)
|
||||
options.partition { |k, _| Setting::OPTIONS.include?(k) }.map(&:to_h)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "dry/core/class_attributes"
|
||||
|
||||
module Dry
|
||||
module Configurable
|
||||
extend Core::ClassAttributes
|
||||
|
||||
# Set to false to suppress deprecation warning when a setting default is provided as a
|
||||
# positional argument
|
||||
defines :warn_on_setting_positional_default
|
||||
warn_on_setting_positional_default true
|
||||
|
||||
# Set to false to suppress deprecation warning when a setting constructor is provided
|
||||
# as a block
|
||||
defines :warn_on_setting_constructor_block
|
||||
warn_on_setting_constructor_block true
|
||||
end
|
||||
end
|
|
@ -12,7 +12,11 @@ module Dry
|
|||
module Initializer
|
||||
# @api private
|
||||
def initialize(*)
|
||||
# Dup settings at time of initializing to ensure setting values are specific to
|
||||
# this instance. This does mean that any settings defined on the class _after_
|
||||
# initialization will not be available on the instance.
|
||||
@config = Config.new(self.class._settings.dup)
|
||||
|
||||
super
|
||||
end
|
||||
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
||||
|
@ -34,9 +38,7 @@ module Dry
|
|||
# Finalize the config and freeze the object
|
||||
#
|
||||
# @api public
|
||||
def finalize!
|
||||
return self if frozen?
|
||||
|
||||
def finalize!(freeze_values: false)
|
||||
super
|
||||
freeze
|
||||
end
|
||||
|
|
|
@ -21,10 +21,8 @@ module Dry
|
|||
# @return [Dry::Configurable::Config]
|
||||
#
|
||||
# @api public
|
||||
def finalize!
|
||||
return self if config.frozen?
|
||||
|
||||
config.finalize!
|
||||
def finalize!(freeze_values: false)
|
||||
config.finalize!(freeze_values: freeze_values)
|
||||
self
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,9 +62,17 @@ module Dry
|
|||
def initialize(name, input: Undefined, default: Undefined, **options)
|
||||
@name = name
|
||||
@writer_name = :"#{name}="
|
||||
@options = options
|
||||
|
||||
# Setting collections (see `Settings`) are shared between the configurable class
|
||||
# and its `config` object, so for cloneable individual settings, we duplicate
|
||||
# their _values_ as early as possible to ensure no impact from unintended mutation
|
||||
@input = input
|
||||
@default = default
|
||||
@options = options
|
||||
if cloneable?
|
||||
@input = input.dup
|
||||
@default = default.dup
|
||||
end
|
||||
|
||||
evaluate if input_defined?
|
||||
end
|
||||
|
@ -76,8 +84,12 @@ module Dry
|
|||
|
||||
# @api private
|
||||
def value
|
||||
@value ||= evaluate
|
||||
return @value if evaluated?
|
||||
|
||||
@value = constructor[Undefined.coalesce(input, default, nil)]
|
||||
end
|
||||
alias_method :evaluate, :value
|
||||
private :evaluate
|
||||
|
||||
# @api private
|
||||
def evaluated?
|
||||
|
@ -94,6 +106,16 @@ module Dry
|
|||
with(input: Undefined)
|
||||
end
|
||||
|
||||
# @api private
|
||||
def finalize!(freeze_values: false)
|
||||
if value.is_a?(Config)
|
||||
value.finalize!(freeze_values: freeze_values)
|
||||
elsif freeze_values
|
||||
value.freeze
|
||||
end
|
||||
freeze
|
||||
end
|
||||
|
||||
# @api private
|
||||
def with(new_opts)
|
||||
self.class.new(name, input: input, default: default, **options, **new_opts)
|
||||
|
@ -141,11 +163,6 @@ module Dry
|
|||
@value = source.value.dup if source.evaluated?
|
||||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def evaluate
|
||||
@value = constructor[Undefined.coalesce(input, default, nil)]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,6 +54,12 @@ module Dry
|
|||
self.class.new(map(&:pristine))
|
||||
end
|
||||
|
||||
# @api private
|
||||
def finalize!(freeze_values: false)
|
||||
each { |element| element.finalize!(freeze_values: freeze_values) }
|
||||
freeze
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @api private
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
module Dry
|
||||
module Configurable
|
||||
# @api public
|
||||
VERSION = "0.13.0"
|
||||
VERSION = "0.15.0"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,6 +35,27 @@ RSpec.describe Dry::Configurable::Config do
|
|||
expect(klass.config.db.user).to eql("jane")
|
||||
expect(klass.config.db.pass).to eql("supersecret")
|
||||
end
|
||||
|
||||
it "runs constructors" do
|
||||
klass.setting :db do
|
||||
setting :user, default: "root", constructor: ->(v) { v.upcase }
|
||||
setting :sslcert, constructor: ->(v) { v&.values_at(:pem, :pass)&.join }
|
||||
end
|
||||
|
||||
klass.config.update(db: {user: "jane", sslcert: {pem: "cert", pass: "qwerty"}})
|
||||
|
||||
expect(klass.config.db.user).to eql("JANE")
|
||||
expect(klass.config.db.sslcert).to eql("certqwerty")
|
||||
end
|
||||
|
||||
it "raises ArgumentError when setting value is not a Hash" do
|
||||
klass.setting :db do
|
||||
setting :user
|
||||
end
|
||||
|
||||
expect { klass.config.update(db: "string") }
|
||||
.to raise_error(ArgumentError, '"string" is not a valid setting value')
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_h" do
|
||||
|
|
|
@ -147,7 +147,7 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
|
||||
context "with a ruby keyword" do
|
||||
before do
|
||||
klass.setting :if, true
|
||||
klass.setting :if, default: true
|
||||
end
|
||||
|
||||
it "works" do
|
||||
|
@ -185,6 +185,15 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
|
||||
include_context "configurable behavior"
|
||||
|
||||
specify "settings defined after accessing config are still available in the config" do
|
||||
klass.setting :before, default: "defined before"
|
||||
klass.config
|
||||
klass.setting :after, default: "defined after"
|
||||
|
||||
expect(klass.config.before).to eq "defined before"
|
||||
expect(klass.config.after).to eq "defined after"
|
||||
end
|
||||
|
||||
context "with a subclass" do
|
||||
let(:subclass) do
|
||||
Class.new(klass)
|
||||
|
@ -205,7 +214,7 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
it "allows defining more settings" do
|
||||
klass.setting :db, default: "sqlite"
|
||||
|
||||
subclass.setting :username, "root"
|
||||
subclass.setting :username, default: "root"
|
||||
subclass.setting :password
|
||||
|
||||
subclass.config.password = "secret"
|
||||
|
@ -225,7 +234,7 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
expect(subclass.settings).to eql(Set[:db])
|
||||
end
|
||||
|
||||
it "configured parent copies config to the child" do
|
||||
specify "configuring the parent before subclassing copies the config to the child" do
|
||||
klass.setting :db
|
||||
|
||||
object.config.db = "mariadb"
|
||||
|
@ -233,6 +242,16 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
expect(subclass.config.db).to eql("mariadb")
|
||||
end
|
||||
|
||||
specify "configuring the parent after subclassing does not copy the config to the child" do
|
||||
klass.setting :db
|
||||
|
||||
subclass = Class.new(klass)
|
||||
|
||||
object.config.db = "mariadb"
|
||||
|
||||
expect(subclass.config.db).to be nil
|
||||
end
|
||||
|
||||
it "not configured parent does not set child config" do
|
||||
klass.setting :db
|
||||
|
||||
|
@ -308,13 +327,13 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
end
|
||||
|
||||
it "defines a constructor that sets the config" do
|
||||
klass.setting :db, "sqlite"
|
||||
klass.setting :db, default: "sqlite"
|
||||
|
||||
expect(object.config.db).to eql("sqlite")
|
||||
end
|
||||
|
||||
it "creates distinct setting values across instances" do
|
||||
klass.setting(:path, "test", constructor: ->(m) { Pathname(m) })
|
||||
klass.setting(:path, default: "test", constructor: ->(m) { Pathname(m) })
|
||||
|
||||
new_object = klass.new
|
||||
|
||||
|
@ -323,13 +342,29 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
expect(object.config.path).not_to be(new_object.config.path)
|
||||
end
|
||||
|
||||
it "makes only settings defined before instantiation available" do
|
||||
klass.setting :before, default: "defined before"
|
||||
|
||||
object_1 = klass.new
|
||||
|
||||
klass.setting :after, default: "defined after"
|
||||
|
||||
object_2 = klass.new
|
||||
|
||||
expect(object_1.config.before).to eq "defined before"
|
||||
expect(object_1.config).not_to respond_to(:after)
|
||||
|
||||
expect(object_2.config.before).to eq "defined before"
|
||||
expect(object_2.config.after).to eq "defined after"
|
||||
end
|
||||
|
||||
shared_examples "copying" do
|
||||
before do
|
||||
klass.setting :env
|
||||
|
||||
klass.setting :db do
|
||||
setting :user, "root"
|
||||
setting :pass, "secret"
|
||||
setting :user, default: "root".dup
|
||||
setting :pass, default: "secret"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -365,7 +400,7 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
end
|
||||
|
||||
it "can be configured" do
|
||||
klass.setting :db, "sqlite"
|
||||
klass.setting :db, default: "sqlite"
|
||||
|
||||
object.configure do |config|
|
||||
config.db = "mariadb"
|
||||
|
@ -375,13 +410,35 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
end
|
||||
|
||||
it "can be finalized" do
|
||||
klass.setting :db, "sqlite"
|
||||
klass.setting :kafka, default: "kafka://127.0.0.1:9092"
|
||||
|
||||
object.finalize!
|
||||
# becomes a no-op
|
||||
object.finalize!
|
||||
|
||||
expect(object).to be_frozen
|
||||
expect(object.config.db).to be_frozen
|
||||
expect(object.config.db.user).not_to be_frozen
|
||||
|
||||
object.config.db.user << "foo"
|
||||
expect(object.config.db.user).to eq("rootfoo")
|
||||
|
||||
# does not allow configure block anymore
|
||||
expect { object.configure {} }.to raise_error(Dry::Configurable::FrozenConfig)
|
||||
end
|
||||
|
||||
it "can be finalized with freezing values" do
|
||||
klass.setting :kafka, "kafka://127.0.0.1:9092"
|
||||
|
||||
object.finalize!(freeze_values: true)
|
||||
# becomes a no-op
|
||||
object.finalize!(freeze_values: true)
|
||||
|
||||
expect(object).to be_frozen
|
||||
expect(object.config.db).to be_frozen
|
||||
expect(object.config.db.user).to be_frozen
|
||||
|
||||
expect { object.config.db.user << "foo" }.to raise_error(FrozenError)
|
||||
|
||||
# does not allow configure block anymore
|
||||
expect { object.configure {} }.to raise_error(Dry::Configurable::FrozenConfig)
|
||||
|
@ -389,7 +446,7 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
|
||||
it "defines a reader shortcut for nested config" do
|
||||
klass.setting :dsn, reader: true do
|
||||
setting :pool, 5
|
||||
setting :pool, default: 5
|
||||
end
|
||||
|
||||
expect(object.dsn.pool).to be(5)
|
||||
|
@ -398,10 +455,10 @@ RSpec.describe Dry::Configurable, ".setting" do
|
|||
context "Test Interface" do
|
||||
describe "reset_config" do
|
||||
it "resets configuration to default values" do
|
||||
klass.setting :dsn, nil
|
||||
klass.setting :dsn, default: nil
|
||||
|
||||
klass.setting :pool do
|
||||
setting :size, nil
|
||||
setting :size, default: nil
|
||||
end
|
||||
|
||||
object.enable_test_interface
|
||||
|
|
|
@ -29,7 +29,67 @@ RSpec.describe Dry::Configurable::DSL do
|
|||
expect(setting.name).to be(:user)
|
||||
expect(setting.value).to eql("root")
|
||||
logger.rewind
|
||||
expect(logger.string).to match(/#{FileUtils.pwd}.*default value as positional argument to settings is deprecated/)
|
||||
expect(logger.string).to match(/default value as positional argument to settings is deprecated/)
|
||||
end
|
||||
|
||||
it "compiles when giving a default as positional argument, and suppresses the warning when flagged off" do
|
||||
Dry::Configurable.warn_on_setting_positional_default false
|
||||
|
||||
logger = StringIO.new
|
||||
Dry::Core::Deprecations.set_logger!(logger)
|
||||
setting = dsl.setting :user, "root"
|
||||
|
||||
expect(setting.name).to be(:user)
|
||||
expect(setting.value).to eql("root")
|
||||
logger.rewind
|
||||
expect(logger.string).to be_empty
|
||||
|
||||
Dry::Configurable.warn_on_setting_positional_default true
|
||||
end
|
||||
|
||||
it "compiles but deprecates giving a defalt hash value as a positional argument (without any keyword args)" do
|
||||
# This test is necessary for behavior specific to Ruby 2.6 and 2.7
|
||||
|
||||
logger = StringIO.new
|
||||
Dry::Core::Deprecations.set_logger!(logger)
|
||||
|
||||
setting = dsl.setting :default_options, {foo: "bar"}
|
||||
|
||||
expect(setting.name).to be(:default_options)
|
||||
expect(setting.value).to eq(foo: "bar")
|
||||
logger.rewind
|
||||
expect(logger.string).to match(/default value as positional argument to settings is deprecated/)
|
||||
|
||||
if RUBY_VERSION < "3.0"
|
||||
logger = StringIO.new
|
||||
Dry::Core::Deprecations.set_logger!(logger)
|
||||
|
||||
setting = dsl.setting :default_options, foo: "bar"
|
||||
|
||||
expect(setting.name).to be(:default_options)
|
||||
expect(setting.value).to eq(foo: "bar")
|
||||
logger.rewind
|
||||
expect(logger.string).to match(/default value as positional argument to settings is deprecated/)
|
||||
end
|
||||
end
|
||||
|
||||
it "compiles but deprecates giving a defalt hash value as a positional argument (with keyword args)" do
|
||||
# This test is necessary for behavior specific to Ruby 2.6 and 2.7
|
||||
|
||||
logger = StringIO.new
|
||||
Dry::Core::Deprecations.set_logger!(logger)
|
||||
setting = dsl.setting :default_options, {foo: "bar"}, reader: true
|
||||
|
||||
expect(setting.name).to be(:default_options)
|
||||
expect(setting.value).to eq(foo: "bar")
|
||||
logger.rewind
|
||||
expect(logger.string).to match(/default value as positional argument to settings is deprecated/)
|
||||
end
|
||||
|
||||
it "does not infer a default hash value when non-valid keyword arguments are mixed in with valid keyword arguments" do
|
||||
# This test is necessary for behavior specific to Ruby 2.6 and 2.7
|
||||
|
||||
expect { dsl.setting :default_options, foo: "bar", reader: true }.to raise_error ArgumentError, "Invalid options: [:foo]"
|
||||
end
|
||||
|
||||
it "compiles a setting with a reader set" do
|
||||
|
@ -71,7 +131,23 @@ RSpec.describe Dry::Configurable::DSL do
|
|||
expect(setting.name).to be(:dsn)
|
||||
expect(setting.value).to eql("jdbc:sqlite")
|
||||
logger.rewind
|
||||
expect(logger.string).to match(/#{FileUtils.pwd}.*constructor as a block is deprecated/)
|
||||
expect(logger.string).to match(/constructor as a block is deprecated/)
|
||||
end
|
||||
|
||||
it "supports but deprecates giving a constructor as a block, and suppresses the warning when flagged off" do
|
||||
Dry::Configurable.warn_on_setting_constructor_block false
|
||||
|
||||
logger = StringIO.new
|
||||
Dry::Core::Deprecations.set_logger!(logger)
|
||||
|
||||
setting = dsl.setting(:dsn, default: "sqlite") { |value| "jdbc:#{value}" }
|
||||
|
||||
expect(setting.name).to be(:dsn)
|
||||
expect(setting.value).to eql("jdbc:sqlite")
|
||||
logger.rewind
|
||||
expect(logger.string).to be_empty
|
||||
|
||||
Dry::Configurable.warn_on_setting_constructor_block true
|
||||
end
|
||||
|
||||
it "compiles a nested list of settings" do
|
||||
|
|
Loading…
Reference in New Issue