dry-configurable 0.9.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -21
  3. data/LICENSE +1 -1
  4. data/README.md +15 -27
  5. data/dry-configurable.gemspec +27 -18
  6. data/lib/dry-configurable.rb +2 -0
  7. data/lib/dry/configurable.rb +21 -146
  8. data/lib/dry/configurable/class_methods.rb +103 -0
  9. data/lib/dry/configurable/compiler.rb +45 -0
  10. data/lib/dry/configurable/config.rb +78 -136
  11. data/lib/dry/configurable/constants.rb +12 -0
  12. data/lib/dry/configurable/dsl.rb +62 -0
  13. data/lib/dry/configurable/dsl/args.rb +58 -0
  14. data/lib/dry/configurable/{error.rb → errors.rb} +5 -1
  15. data/lib/dry/configurable/instance_methods.rb +46 -0
  16. data/lib/dry/configurable/methods.rb +32 -0
  17. data/lib/dry/configurable/setting.rb +91 -18
  18. data/lib/dry/configurable/settings.rb +42 -87
  19. data/lib/dry/configurable/test_interface.rb +3 -5
  20. data/lib/dry/configurable/version.rb +3 -1
  21. metadata +30 -25
  22. data/.codeclimate.yml +0 -12
  23. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  24. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
  25. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  26. data/.github/workflows/ci.yml +0 -70
  27. data/.github/workflows/docsite.yml +0 -34
  28. data/.github/workflows/sync_configs.yml +0 -30
  29. data/.gitignore +0 -9
  30. data/.rspec +0 -4
  31. data/.rubocop.yml +0 -89
  32. data/CODE_OF_CONDUCT.md +0 -13
  33. data/CONTRIBUTING.md +0 -29
  34. data/Gemfile +0 -20
  35. data/Rakefile +0 -12
  36. data/docsite/source/index.html.md +0 -55
  37. data/docsite/source/testing.html.md +0 -27
  38. data/lib/dry/configurable/settings/argument_parser.rb +0 -50
  39. data/rakelib/rubocop.rake +0 -18
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/configurable/config'
4
+ require 'dry/configurable/methods'
5
+
6
+ module Dry
7
+ module Configurable
8
+ # Instance-level API when `Dry::Configurable` is included in a class
9
+ #
10
+ # @api public
11
+ module InstanceMethods
12
+ include Methods
13
+
14
+ # Return object's configuration
15
+ #
16
+ # @return [Config]
17
+ #
18
+ # @api public
19
+ attr_reader :config
20
+
21
+ # @api private
22
+ def initialize(*)
23
+ @config = Config.new(self.class._settings.dup)
24
+ super
25
+ end
26
+
27
+ # Finalize the config and freeze the object
28
+ #
29
+ # @api public
30
+ def finalize!
31
+ return self if frozen?
32
+
33
+ super
34
+ freeze
35
+ end
36
+
37
+ private
38
+
39
+ # @api public
40
+ def initialize_copy(source)
41
+ super
42
+ @config = source.config.dup
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/configurable/errors'
4
+
5
+ module Dry
6
+ module Configurable
7
+ # Common API for both classes and instances
8
+ #
9
+ # @api public
10
+ module Methods
11
+ # @api public
12
+ def configure(&block)
13
+ raise FrozenConfig, 'Cannot modify frozen config' if frozen?
14
+
15
+ yield(config) if block
16
+ self
17
+ end
18
+
19
+ # Finalize and freeze configuration
20
+ #
21
+ # @return [Dry::Configurable::Config]
22
+ #
23
+ # @api public
24
+ def finalize!
25
+ return self if config.frozen?
26
+
27
+ config.finalize!
28
+ self
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,45 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ require 'dry/equalizer'
6
+
7
+ require 'dry/configurable/constants'
8
+ require 'dry/configurable/config'
9
+
1
10
  module Dry
2
11
  module Configurable
3
12
  # This class represents a setting and is used internally.
4
13
  #
5
- # @private
14
+ # @api private
6
15
  class Setting
7
- VALID_NAME = /\A[a-z_]\w*\z/i
16
+ include Dry::Equalizer(:name, :value, :options)
17
+
18
+ OPTIONS = %i[input default reader constructor settings].freeze
19
+
20
+ DEFAULT_CONSTRUCTOR = -> v { v }.freeze
8
21
 
22
+ CLONABLE_VALUE_TYPES = [Array, Hash, Set, Config].freeze
23
+
24
+ # @api private
9
25
  attr_reader :name
10
26
 
27
+ # @api private
28
+ attr_reader :writer_name
29
+
30
+ # @api private
31
+ attr_reader :input
32
+
33
+ # @api private
34
+ attr_reader :default
35
+
36
+ # @api private
37
+ attr_reader :value
38
+
39
+ # @api private
11
40
  attr_reader :options
12
41
 
13
- attr_reader :processor
42
+ # Specialized Setting which includes nested settings
43
+ #
44
+ # @api private
45
+ class Nested < Setting
46
+ CONSTRUCTOR = Config.method(:new)
47
+
48
+ # @api private
49
+ def pristine
50
+ with(input: input.pristine)
51
+ end
14
52
 
15
- def initialize(name, value, processor, options = EMPTY_HASH)
16
- unless VALID_NAME =~ name.to_s
17
- raise ArgumentError, "+#{name}+ is not a valid setting name"
53
+ # @api private
54
+ def constructor
55
+ CONSTRUCTOR
18
56
  end
19
- @name = name.to_sym
20
- @value = value
21
- @processor = processor
57
+ end
58
+
59
+ # @api private
60
+ def initialize(name, input: Undefined, default: Undefined, **options)
61
+ @name = name
62
+ @writer_name = :"#{name}="
63
+ @input = input.equal?(Undefined) ? default : input
64
+ @default = default
22
65
  @options = options
66
+ set!
67
+ end
68
+
69
+ # @api private
70
+ def nested(settings)
71
+ Nested.new(name, input: settings, **options)
72
+ end
73
+
74
+ # @api private
75
+ def pristine
76
+ with(input: Undefined)
23
77
  end
24
78
 
25
- def value
26
- Undefined.default(@value, nil)
79
+ # @api private
80
+ def with(new_opts)
81
+ self.class.new(name, input: input, default: default, **options, **new_opts)
27
82
  end
28
83
 
29
- def undefined?
30
- Undefined.equal?(@value)
84
+ # @api private
85
+ def constructor
86
+ options[:constructor] || DEFAULT_CONSTRUCTOR
31
87
  end
32
88
 
89
+ # @api private
33
90
  def reader?
34
- options[:reader]
91
+ options[:reader].equal?(true)
92
+ end
93
+
94
+ # @api private
95
+ def writer?(meth)
96
+ writer_name.equal?(meth)
35
97
  end
36
98
 
37
- def node?
38
- Settings === @value
99
+ # @api private
100
+ def clonable_value?
101
+ CLONABLE_VALUE_TYPES.any? { |type| value.is_a?(type) }
102
+ end
103
+
104
+ private
105
+
106
+ # @api private
107
+ def initialize_copy(source)
108
+ super
109
+ @value = source.value.dup if source.clonable_value?
110
+ @options = source.options.dup
39
111
  end
40
112
 
41
- def reserved?
42
- options[:reserved]
113
+ # @api private
114
+ def set!
115
+ @value = constructor[input.equal?(Undefined) ? nil : input]
43
116
  end
44
117
  end
45
118
  end
@@ -1,116 +1,71 @@
1
- require 'set'
2
- require 'concurrent/array'
3
- require 'dry/configurable/settings/argument_parser'
4
- require 'dry/configurable/setting'
5
- require 'dry/configurable/config'
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent/map'
4
+
5
+ require 'dry/equalizer'
6
+ require 'dry/configurable/constants'
6
7
 
7
8
  module Dry
8
9
  module Configurable
9
- # A collection of settings. This is not part of the public API.
10
+ # A settings map
10
11
  #
11
- # @private
12
+ # @api private
12
13
  class Settings
13
- Parser = ArgumentParser.new.freeze
14
-
15
- class DSL
16
- def self.call(&block)
17
- new.instance_exec do
18
- instance_exec(&block)
19
- @settings
20
- end
21
- end
22
-
23
- def initialize
24
- @settings = Settings.new
25
- end
26
-
27
- def setting(*args, &block)
28
- @settings.add(*args, &block)
29
- end
30
- end
31
-
32
- # Capture nested config definition
33
- #
34
- # @return [Dry::Configurable::Setting]
35
- def self.capture(&block)
36
- DSL.(&block)
37
- end
38
-
39
- attr_reader :settings
14
+ include Dry::Equalizer(:elements)
40
15
 
41
- attr_reader :config_class
16
+ include Enumerable
42
17
 
43
- attr_reader :index
44
- private :index
18
+ # @api private
19
+ attr_reader :elements
45
20
 
46
- def initialize(settings = ::Concurrent::Array.new)
47
- @settings = settings
48
- @config_class = Config[self]
49
- @index = settings.map { |s| [s.name, s] }.to_h
50
- yield(self) if block_given?
21
+ # @api private
22
+ def initialize(elements = EMPTY_ARRAY)
23
+ initialize_elements(elements)
51
24
  end
52
25
 
53
- def add(key, value = Undefined, options = Undefined, &block)
54
- extended = singleton_class < Configurable
55
- raise_already_defined_config(key) if extended && configured?
56
-
57
- *args, opts = Parser.(value, options, block)
58
-
59
- Setting.new(key, *args, { **opts, reserved: reserved?(key) }).tap do |s|
60
- settings.delete_if { |e| e.name.eql?(s.name) }
61
- settings << s
62
- index[s.name] = s
63
- @names = nil
64
- end
65
- end
66
-
67
- def each
68
- settings.each { |s| yield(s) }
69
- end
70
-
71
- def names
72
- @names ||= index.keys.to_set
26
+ # @api private
27
+ def <<(setting)
28
+ elements[setting.name] = setting
29
+ self
73
30
  end
74
31
 
32
+ # @api private
75
33
  def [](name)
76
- index[name]
77
- end
78
-
79
- def empty?
80
- settings.empty?
34
+ elements[name]
81
35
  end
82
36
 
83
- def name?(name)
84
- index.key?(name)
37
+ # @api private
38
+ def key?(name)
39
+ keys.include?(name)
85
40
  end
86
41
 
87
- def dup
88
- Settings.new(settings.dup)
42
+ # @api private
43
+ def keys
44
+ elements.keys
89
45
  end
90
46
 
91
- def freeze
92
- settings.freeze
93
- super
47
+ # @api private
48
+ def each(&block)
49
+ elements.values.each(&block)
94
50
  end
95
51
 
96
- def create_config
97
- config_class.new
52
+ # @api private
53
+ def pristine
54
+ self.class.new(map(&:pristine))
98
55
  end
99
56
 
100
- def config_defined?
101
- config_class.config_defined?
102
- end
57
+ private
103
58
 
104
- def reserved?(name)
105
- reserved_names.include?(name)
59
+ # @api private
60
+ def initialize_copy(source)
61
+ initialize_elements(source.map(&:dup))
106
62
  end
107
63
 
108
- def reserved_names
109
- @reserved_names ||= [
110
- config_class.instance_methods(false),
111
- config_class.superclass.instance_methods(false),
112
- %i(class public_send)
113
- ].reduce(:+)
64
+ # @api private
65
+ def initialize_elements(elements)
66
+ @elements = elements.each_with_object(Concurrent::Map.new) { |s, m|
67
+ m[s.name] = s
68
+ }
114
69
  end
115
70
  end
116
71
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Configurable
3
5
  # Methods meant to be used in a testing scenario
@@ -8,11 +10,7 @@ module Dry
8
10
  #
9
11
  # @api public
10
12
  def reset_config
11
- @config = if self.is_a?(Module)
12
- _settings.create_config
13
- else
14
- self.class._settings.create_config
15
- end
13
+ @config = config.pristine
16
14
  end
17
15
  end
18
16
 
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Configurable
3
5
  # @api public
4
- VERSION = '0.9.0'.freeze
6
+ VERSION = '0.11.0'
5
7
  end
6
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-configurable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Holland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-06 00:00:00.000000000 Z
11
+ date: 2020-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -44,6 +44,20 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 0.4.7
47
+ - !ruby/object:Gem::Dependency
48
+ name: dry-equalizer
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: bundler
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -86,49 +100,40 @@ dependencies:
86
100
  - - ">="
87
101
  - !ruby/object:Gem::Version
88
102
  version: '0'
89
- description:
103
+ description: A mixin to add configuration functionality to your classes
90
104
  email:
91
105
  - andyholland1991@aol.com
92
106
  executables: []
93
107
  extensions: []
94
108
  extra_rdoc_files: []
95
109
  files:
96
- - ".codeclimate.yml"
97
- - ".github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md"
98
- - ".github/ISSUE_TEMPLATE/---bug-report.md"
99
- - ".github/ISSUE_TEMPLATE/---feature-request.md"
100
- - ".github/workflows/ci.yml"
101
- - ".github/workflows/docsite.yml"
102
- - ".github/workflows/sync_configs.yml"
103
- - ".gitignore"
104
- - ".rspec"
105
- - ".rubocop.yml"
106
110
  - CHANGELOG.md
107
- - CODE_OF_CONDUCT.md
108
- - CONTRIBUTING.md
109
- - Gemfile
110
111
  - LICENSE
111
112
  - README.md
112
- - Rakefile
113
- - docsite/source/index.html.md
114
- - docsite/source/testing.html.md
115
113
  - dry-configurable.gemspec
116
114
  - lib/dry-configurable.rb
117
115
  - lib/dry/configurable.rb
116
+ - lib/dry/configurable/class_methods.rb
117
+ - lib/dry/configurable/compiler.rb
118
118
  - lib/dry/configurable/config.rb
119
- - lib/dry/configurable/error.rb
119
+ - lib/dry/configurable/constants.rb
120
+ - lib/dry/configurable/dsl.rb
121
+ - lib/dry/configurable/dsl/args.rb
122
+ - lib/dry/configurable/errors.rb
123
+ - lib/dry/configurable/instance_methods.rb
124
+ - lib/dry/configurable/methods.rb
120
125
  - lib/dry/configurable/setting.rb
121
126
  - lib/dry/configurable/settings.rb
122
- - lib/dry/configurable/settings/argument_parser.rb
123
127
  - lib/dry/configurable/test_interface.rb
124
128
  - lib/dry/configurable/version.rb
125
- - rakelib/rubocop.rake
126
- homepage: https://github.com/dry-rb/dry-configurable
129
+ homepage: https://dry-rb.org/gems/dry-configurable
127
130
  licenses:
128
131
  - MIT
129
132
  metadata:
130
- source_code_uri: https://github.com/dry-rb/dry-configurable
133
+ allowed_push_host: https://rubygems.org
131
134
  changelog_uri: https://github.com/dry-rb/dry-configurable/blob/master/CHANGELOG.md
135
+ source_code_uri: https://github.com/dry-rb/dry-configurable
136
+ bug_tracker_uri: https://github.com/dry-rb/dry-configurable/issues
132
137
  post_install_message:
133
138
  rdoc_options: []
134
139
  require_paths:
@@ -144,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
149
  - !ruby/object:Gem::Version
145
150
  version: '0'
146
151
  requirements: []
147
- rubygems_version: 3.0.6
152
+ rubygems_version: 3.0.3
148
153
  signing_key:
149
154
  specification_version: 4
150
155
  summary: A mixin to add configuration functionality to your classes