dry-configurable 0.7.0 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eeb18b428640615a653b1e669bcbedf1130f83ef
4
- data.tar.gz: 294ec402fe8dbfb378c6a5e1d5d442c49ac7baf1
2
+ SHA256:
3
+ metadata.gz: e2952b22a9581b91b77a416925a150088ea715be486638e293beae10d5b493a8
4
+ data.tar.gz: 6cf8073234d53e391e25d03eb0b3548694ebbaa30742169895b8f1d519f258d7
5
5
  SHA512:
6
- metadata.gz: f3c268381efd9f202447a9785873ea151e5ce4edc004c87006a0c5b91165b3b29827d99799cf2f75a386214c5906b09d9b12983aec05502ad88591f1fa702896
7
- data.tar.gz: fd8c289e25a8fa28ec55e1f69ec5f569e2b6dbf0506ca7df49a80c6277c99510bc0505dc7c063fd97144f2723105bba62448472bc2db73c941dce1bca8db9cbf
6
+ metadata.gz: 441ba5b074dd577bd0e0d37b5a99e76dc1ab85068885832e791eba4cd7a61e5691683f96c93e930a29d59e838b294d82248074433c670466ad31f773e1994dab
7
+ data.tar.gz: 02f13c05320aca5bb6900dd831966c3edc760fd66b9bfe40f94d079da0f3af30ecbdd07cdd024807d305296caf55f1b1613c285cdec86db97fb57659c42c11a0
data/.gitignore CHANGED
@@ -2,8 +2,8 @@
2
2
  coverage
3
3
  /.bundle
4
4
  vendor/bundle
5
- bin/
6
5
  tmp/
7
6
  .idea/
8
7
  Gemfile.lock
9
8
  spec/examples.txt
9
+ pkg/
@@ -3,27 +3,21 @@ dist: trusty
3
3
  sudo: required
4
4
  cache: bundler
5
5
  bundler_args: --without console
6
- script:
7
- - bundle exec rake spec
8
6
  after_success:
9
7
  - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
10
8
  rvm:
11
- - 2.0
12
- - 2.1
13
- - 2.2
14
- - 2.3.1
15
- - rbx-3
16
- - jruby-9.1.5.0
17
- - ruby-head
18
- - jruby-head
9
+ - 2.4.6
10
+ - 2.5.5
11
+ - 2.6.3
12
+ - jruby-9.2.7.0
13
+ - truffleruby
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: truffleruby
19
17
  env:
20
18
  global:
21
19
  - JRUBY_OPTS='--dev -J-Xmx1024M'
22
20
  - COVERAGE='true'
23
- matrix:
24
- allow_failures:
25
- - rvm: ruby-head
26
- - rvm: jruby-head
27
21
  notifications:
28
22
  email: false
29
23
  webhooks:
@@ -1,4 +1,72 @@
1
- ## Unreleased
1
+ ## 0.8.3 - 2019-05-29
2
+
3
+ ## Fixed
4
+
5
+ * `Configurable#dup` and `Configurable#clone` make a copy of instance-level config so that it doesn't get mutated/shared across instances (flash-gordon)
6
+
7
+ [Compare v0.8.2...v0.8.3](https://github.com/dry-rb/dry-configurable/compare/v0.8.2...v0.8.3)
8
+
9
+ ## 0.8.2 - 2019-02-25
10
+
11
+ ## Fixed
12
+
13
+ * Test interface support for modules ([Neznauy](https://github.com/Neznauy))
14
+
15
+ [Compare v0.8.1...v0.8.2](https://github.com/dry-rb/dry-configurable/compare/v0.8.1...v0.8.2)
16
+
17
+ ## 0.8.1 - 2019-02-06
18
+
19
+ ## Fixed
20
+
21
+ * `.configure` doesn't require a block, this makes the behavior consistent with the previous versions ([flash-gordon](https://github.com/flash-gordon))
22
+
23
+ [Compare v0.8.0...v0.8.1](https://github.com/dry-rb/dry-configurable/compare/v0.8.0...v0.8.1)
24
+
25
+ ## 0.8.0 - 2019-02-05
26
+
27
+ ## Fixed
28
+
29
+ * 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))
30
+
31
+ ## Added
32
+
33
+ * Support for instance-level configuration landed. For usage, `include` the module instead of extending ([flash-gordon](https://github.com/flash-gordon))
34
+ ```ruby
35
+ class App
36
+ include Dry::Configurable
37
+
38
+ setting :database
39
+ end
40
+
41
+ production = App.new
42
+ production.config.database = ENV['DATABASE_URL']
43
+ production.finalize!
44
+
45
+ development = App.new
46
+ development.config.database = 'jdbc:sqlite:memory'
47
+ development.finalize!
48
+ ```
49
+ * Config values can be set from a hash with `.update`. Nested settings are supported ([flash-gordon](https://github.com/flash-gordon))
50
+ ```ruby
51
+ class App
52
+ extend Dry::Configurable
53
+
54
+ setting :db do
55
+ setting :host
56
+ setting :port
57
+ end
58
+
59
+ config.update(YAML.load(File.read("config.yml")))
60
+ end
61
+ ```
62
+
63
+ ## Changed
64
+
65
+ * [BREAKING] Minimal supported Ruby version is set to 2.3 ([flash-gordon](https://github.com/flash-gordon))
66
+
67
+ [Compare v0.7.0...v0.8.0](https://github.com/dry-rb/dry-configurable/compare/v0.7.0...v0.8.0)
68
+
69
+ ## 0.7.0 - 2017-04-25
2
70
 
3
71
  ## Added
4
72
 
@@ -10,4 +78,4 @@
10
78
  * Convert nested configs to nested hashes with `Config#to_h` ([saverio-kantox](https://github.com/saverio-kantox))
11
79
  * Disallow modification on frozen config ([qcam](https://github.com/qcam))
12
80
 
13
- [Compare v0.6.2...HEAD](https://github.com/dry-rb/dry-configurable/compare/v0.6.2...HEAD)
81
+ [Compare v0.6.2...v0.7.0](https://github.com/dry-rb/dry-configurable/compare/v0.6.2...v0.7.0)
@@ -0,0 +1,29 @@
1
+ # Issue Guidelines
2
+
3
+ ## Reporting bugs
4
+
5
+ If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
+
7
+ ## Reporting feature requests
8
+
9
+ Report a feature request **only after discussing it first on [discuss.dry-rb.org](https://discuss.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
10
+
11
+ ## Reporting questions, support requests, ideas, concerns etc.
12
+
13
+ **PLEASE DON'T** - use [discuss.dry-rb.org](http://discuss.dry-rb.org) instead.
14
+
15
+ # Pull Request Guidelines
16
+
17
+ A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
+
19
+ Other requirements:
20
+
21
+ 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
+ 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
+ 3) Add API documentation if it's a new feature
24
+ 4) Update API documentation if it changes an existing feature
25
+ 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
+
27
+ # Asking for help
28
+
29
+ If these guidelines aren't helpful, and you're stuck, please post a message on [discuss.dry-rb.org](https://discuss.dry-rb.org).
data/Gemfile CHANGED
@@ -13,4 +13,5 @@ group :tools do
13
13
  gem 'guard'
14
14
  gem 'guard-rspec'
15
15
  gem 'listen', '3.0.6'
16
+ gem 'pry-byebug', platform: :mri
16
17
  end
data/README.md CHANGED
@@ -1,47 +1,35 @@
1
1
  [gitter]: https://gitter.im/dry-rb/chat
2
2
  [gem]: https://rubygems.org/gems/dry-configurable
3
3
  [travis]: https://travis-ci.org/dry-rb/dry-configurable
4
- [code_climate]: https://codeclimate.com/github/dry-rb/dry-configurable
5
4
  [inch]: http://inch-ci.org/github/dry-rb/dry-configurable
5
+ [chat]: https://dry-rb.zulipchat.com
6
6
 
7
- # dry-configurable [![Join the Gitter chat](https://badges.gitter.im/Join%20Chat.svg)][gitter]
7
+ # dry-configurable [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
8
8
 
9
9
  [![Gem Version](https://img.shields.io/gem/v/dry-configurable.svg)][gem]
10
10
  [![Build Status](https://img.shields.io/travis/dry-rb/dry-configurable.svg)][travis]
11
- [![Code Climate](https://img.shields.io/codeclimate/github/dry-rb/dry-configurable.svg)][code_climate]
12
- [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/dry-rb/dry-configurable.svg)][code_climate]
11
+ [![Maintainability](https://api.codeclimate.com/v1/badges/25311e81391498d6b7c8/maintainability)](https://codeclimate.com/github/dry-rb/dry-configurable/maintainability)
12
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/25311e81391498d6b7c8/test_coverage)](https://codeclimate.com/github/dry-rb/dry-configurable/test_coverage)
13
13
  [![API Documentation Coverage](http://inch-ci.org/github/dry-rb/dry-configurable.svg)][inch]
14
14
 
15
- ## Synopsis
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
16
18
 
17
19
  ```ruby
18
- class App
19
- extend Dry::Configurable
20
-
21
- # Pass a block for nested configuration (works to any depth)
22
- setting :database do
23
- # Can pass a default value
24
- setting :dsn, 'sqlite:memory'
25
- end
26
- # Defaults to nil if no default value is given
27
- setting :adapter
28
- # Passing the reader option as true will create reader method for the class
29
- setting :pool, 5, reader: true
30
- # Passing the reader attributes works with nested configuration
31
- setting :uploader, reader: true do
32
- setting :bucket, 'dev'
33
- end
34
- end
35
-
36
- App.configure do |config|
37
- config.database.dsn = 'jdbc:sqlite:memory'
38
- end
39
-
40
- App.config.database.dsn
41
- # => 'jdbc:sqlite:memory'
42
- App.config.adapter # => nil
43
- App.pool # => 5
44
- App.uploader.bucket # => 'dev'
20
+ gem 'dry-configurable'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```sh
26
+ $ bundle
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```sh
32
+ $ gem install dry-configurable
45
33
  ```
46
34
 
47
35
  ## Links
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  require File.expand_path('../lib/dry/configurable/version', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |spec|
@@ -7,15 +6,22 @@ Gem::Specification.new do |spec|
7
6
  spec.authors = ['Andy Holland']
8
7
  spec.email = ['andyholland1991@aol.com']
9
8
  spec.summary = 'A mixin to add configuration functionality to your classes'
10
- spec.homepage = 'https://github.com/dryrb/dry-configurable'
9
+ spec.homepage = 'https://github.com/dry-rb/dry-configurable'
11
10
  spec.license = 'MIT'
12
11
 
13
- spec.files = `git ls-files -z`.split("\x0")
14
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
12
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|bin)/}) }
13
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
15
14
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
15
  spec.require_paths = ['lib']
17
16
 
17
+ spec.metadata = {
18
+ 'source_code_uri' => 'https://github.com/dry-rb/dry-configurable',
19
+ 'changelog_uri' => 'https://github.com/dry-rb/dry-configurable/blob/master/CHANGELOG.md'
20
+ }
21
+
22
+ spec.required_ruby_version = ">= 2.3.0"
18
23
  spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
24
+ spec.add_runtime_dependency 'dry-core', '~> 0.4', '>= 0.4.7'
19
25
 
20
26
  spec.add_development_dependency 'bundler'
21
27
  spec.add_development_dependency 'rake'
@@ -1,9 +1,6 @@
1
- require 'concurrent'
2
- require 'dry/configurable/config'
1
+ require 'dry/core/constants'
2
+ require 'dry/configurable/settings'
3
3
  require 'dry/configurable/error'
4
- require 'dry/configurable/nested_config'
5
- require 'dry/configurable/argument_parser'
6
- require 'dry/configurable/config/value'
7
4
  require 'dry/configurable/version'
8
5
 
9
6
  # A collection of micro-libraries, each intended to encapsulate
@@ -11,7 +8,7 @@ require 'dry/configurable/version'
11
8
  module Dry
12
9
  # A simple configuration mixin
13
10
  #
14
- # @example
11
+ # @example class-level configuration
15
12
  #
16
13
  # class App
17
14
  # extend Dry::Configurable
@@ -21,30 +18,123 @@ module Dry
21
18
  # end
22
19
  # end
23
20
  #
24
- # App.configure do |config|
25
- # config.database.dsn = 'jdbc:sqlite:memory'
21
+ # App.config.database.dsn = 'jdbc:sqlite:memory'
22
+ # App.config.database.dsn
23
+ # # => "jdbc:sqlite:memory"
24
+ #
25
+ # @example instance-level configuration
26
+ #
27
+ # class App
28
+ # include Dry::Configurable
29
+ #
30
+ # setting :database
26
31
  # end
27
32
  #
28
- # App.config.database.dsn
29
- # # => "jdbc:sqlite:memory'"
33
+ # production = App.new
34
+ # production.config.database = ENV['DATABASE_URL']
35
+ # production.finalize!
36
+ #
37
+ # development = App.new
38
+ # development.config.database = 'jdbc:sqlite:memory'
39
+ # development.finalize!
30
40
  #
31
41
  # @api public
32
42
  module Configurable
33
- # @private
34
- def self.extended(base)
35
- base.class_eval do
36
- @_config_mutex = ::Mutex.new
37
- @_settings = ::Concurrent::Array.new
38
- @_reader_attributes = ::Concurrent::Array.new
43
+ include Dry::Core::Constants
44
+
45
+ module ClassMethods
46
+ # @private
47
+ def self.extended(base)
48
+ base.instance_exec do
49
+ @settings = Settings.new
50
+ end
51
+ end
52
+
53
+ # Add a setting to the configuration
54
+ #
55
+ # @param [Mixed] key
56
+ # The accessor key for the configuration value
57
+ # @param [Mixed] default
58
+ # The default config value
59
+ #
60
+ # @yield
61
+ # If a block is given, it will be evaluated in the context of
62
+ # and new configuration class, and bound as the default value
63
+ #
64
+ # @return [Dry::Configurable::Config]
65
+ #
66
+ # @api public
67
+ def setting(key, value = Undefined, options = Undefined, &block)
68
+ extended = singleton_class < Configurable
69
+ raise_already_defined_config(key) if _settings.config_defined?
70
+
71
+ setting = _settings.add(key, value, options, &block)
72
+
73
+ if setting.reader?
74
+ readers = extended ? singleton_class : self
75
+ readers.send(:define_method, setting.name) { config[setting.name] }
76
+ end
77
+ end
78
+
79
+ # Return an array of setting names
80
+ #
81
+ # @return [Set]
82
+ #
83
+ # @api public
84
+ def settings
85
+ _settings.names
86
+ end
87
+
88
+ # @private no, really...
89
+ def _settings
90
+ @settings
91
+ end
92
+
93
+ private
94
+
95
+ # @private
96
+ def raise_already_defined_config(key)
97
+ raise AlreadyDefinedConfig,
98
+ "Cannot add setting +#{key}+, #{self} is already configured"
99
+ end
100
+
101
+ # @private
102
+ def inherited(subclass)
103
+ parent = self
104
+ subclass.instance_exec do
105
+ @settings = parent._settings.dup
106
+ end
107
+
108
+ if singleton_class < Configurable
109
+ parent_config = @config
110
+ subclass.instance_exec do
111
+ @config = _settings.create_config
112
+ @config.define!(parent_config.to_h) if parent_config.defined?
113
+ end
114
+ end
115
+
116
+ super
117
+ end
118
+ end
119
+
120
+ class << self
121
+ # @private
122
+ def extended(base)
123
+ base.extend(ClassMethods)
124
+ base.class_eval do
125
+ @config = _settings.create_config
126
+ end
127
+ end
128
+
129
+ # @private
130
+ def included(base)
131
+ base.extend(ClassMethods)
39
132
  end
40
133
  end
41
134
 
42
135
  # @private
43
- def inherited(subclass)
44
- subclass.instance_variable_set(:@_config_mutex, ::Mutex.new)
45
- subclass.instance_variable_set(:@_settings, @_settings.clone)
46
- subclass.instance_variable_set(:@_reader_attributes, @_reader_attributes.clone)
47
- subclass.instance_variable_set(:@_config, @_config.clone) if defined?(@_config)
136
+ def initialize(*)
137
+ @config = self.class._settings.create_config
48
138
  super
49
139
  end
50
140
 
@@ -54,8 +144,8 @@ module Dry
54
144
  #
55
145
  # @api public
56
146
  def config
57
- return @_config if defined?(@_config)
58
- create_config
147
+ return @config if @config.defined?
148
+ @config.define!
59
149
  end
60
150
 
61
151
  # Return configuration
@@ -66,8 +156,9 @@ module Dry
66
156
  #
67
157
  # @api public
68
158
  def configure
69
- raise_frozen_config if frozen?
159
+ raise FrozenConfig, 'Cannot modify frozen config' if frozen?
70
160
  yield(config) if block_given?
161
+ self
71
162
  end
72
163
 
73
164
  # Finalize and freeze configuration
@@ -80,106 +171,22 @@ module Dry
80
171
  config.finalize!
81
172
  end
82
173
 
83
- # Add a setting to the configuration
84
- #
85
- # @param [Mixed] key
86
- # The accessor key for the configuration value
87
- # @param [Mixed] default
88
- # The default config value
89
- #
90
- # @yield
91
- # If a block is given, it will be evaluated in the context of
92
- # and new configuration class, and bound as the default value
93
- #
94
- # @return [Dry::Configurable::Config]
95
- #
96
174
  # @api public
97
- def setting(key, *args, &block)
98
- raise_already_defined_config(key) if defined?(@_config)
99
- value, options = ArgumentParser.call(args)
100
- if block
101
- if block.parameters.empty?
102
- value = _config_for(&block)
103
- else
104
- processor = block
105
- end
175
+ def dup
176
+ super.tap do |copy|
177
+ copy.instance_variable_set(:@config, config.dup)
106
178
  end
107
-
108
- _settings << ::Dry::Configurable::Config::Value.new(
109
- key,
110
- !value.nil? ? value : ::Dry::Configurable::Config::Value::NONE,
111
- processor || ::Dry::Configurable::Config::DEFAULT_PROCESSOR
112
- )
113
- store_reader_options(key, options) if options.any?
114
179
  end
115
180
 
116
- # Return an array of setting names
117
- #
118
- # @return [Array]
119
- #
120
181
  # @api public
121
- def settings
122
- _settings.map(&:name)
123
- end
124
-
125
- # @private no, really...
126
- def _settings
127
- @_settings
128
- end
129
-
130
- def _reader_attributes
131
- @_reader_attributes
132
- end
133
-
134
- private
135
-
136
- # @private
137
- def _config_for(&block)
138
- ::Dry::Configurable::NestedConfig.new(&block)
139
- end
140
-
141
- # @private
142
- def create_config
143
- @_config_mutex.synchronize do
144
- create_config_for_nested_configurations
145
- @_config = ::Dry::Configurable::Config.create(_settings) unless _settings.empty?
182
+ def clone
183
+ if frozen?
184
+ super
185
+ else
186
+ super.tap do |copy|
187
+ copy.instance_variable_set(:@config, config.dup)
188
+ end
146
189
  end
147
190
  end
148
-
149
- # @private
150
- def create_config_for_nested_configurations
151
- nested_configs.map(&:create_config)
152
- end
153
-
154
- # @private
155
- def nested_configs
156
- _settings.select { |setting| setting.value.is_a?(::Dry::Configurable::NestedConfig) }.map(&:value)
157
- end
158
-
159
- # @private
160
- def raise_already_defined_config(key)
161
- raise AlreadyDefinedConfig,
162
- "Cannot add setting +#{key}+, #{self} is already configured"
163
- end
164
-
165
- # @private
166
- def raise_frozen_config
167
- raise FrozenConfig, 'Cannot modify frozen config'
168
- end
169
-
170
- # @private
171
- def store_reader_options(key, options)
172
- _reader_attributes << key if options.fetch(:reader, false)
173
- end
174
-
175
- # @private
176
- def method_missing(method, *args, &block)
177
- _reader_attributes.include?(method) ? config.public_send(method, *args, &block) : super
178
- end
179
-
180
- # @private
181
- def respond_to_missing?(method, _include_private = false)
182
- _reader_attributes.include?(method) || super
183
- end
184
191
  end
185
192
  end