dry-configurable 0.7.0 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
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