dry-configurable 0.9.0

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.
@@ -0,0 +1,7 @@
1
+ module Dry
2
+ module Configurable
3
+ Error = Class.new(::StandardError)
4
+ AlreadyDefinedConfig = ::Class.new(Error)
5
+ FrozenConfig = ::Class.new(Error)
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ module Dry
2
+ module Configurable
3
+ # This class represents a setting and is used internally.
4
+ #
5
+ # @private
6
+ class Setting
7
+ VALID_NAME = /\A[a-z_]\w*\z/i
8
+
9
+ attr_reader :name
10
+
11
+ attr_reader :options
12
+
13
+ attr_reader :processor
14
+
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"
18
+ end
19
+ @name = name.to_sym
20
+ @value = value
21
+ @processor = processor
22
+ @options = options
23
+ end
24
+
25
+ def value
26
+ Undefined.default(@value, nil)
27
+ end
28
+
29
+ def undefined?
30
+ Undefined.equal?(@value)
31
+ end
32
+
33
+ def reader?
34
+ options[:reader]
35
+ end
36
+
37
+ def node?
38
+ Settings === @value
39
+ end
40
+
41
+ def reserved?
42
+ options[:reserved]
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,117 @@
1
+ require 'set'
2
+ require 'concurrent/array'
3
+ require 'dry/configurable/settings/argument_parser'
4
+ require 'dry/configurable/setting'
5
+ require 'dry/configurable/config'
6
+
7
+ module Dry
8
+ module Configurable
9
+ # A collection of settings. This is not part of the public API.
10
+ #
11
+ # @private
12
+ 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
40
+
41
+ attr_reader :config_class
42
+
43
+ attr_reader :index
44
+ private :index
45
+
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?
51
+ end
52
+
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
73
+ end
74
+
75
+ def [](name)
76
+ index[name]
77
+ end
78
+
79
+ def empty?
80
+ settings.empty?
81
+ end
82
+
83
+ def name?(name)
84
+ index.key?(name)
85
+ end
86
+
87
+ def dup
88
+ Settings.new(settings.dup)
89
+ end
90
+
91
+ def freeze
92
+ settings.freeze
93
+ super
94
+ end
95
+
96
+ def create_config
97
+ config_class.new
98
+ end
99
+
100
+ def config_defined?
101
+ config_class.config_defined?
102
+ end
103
+
104
+ def reserved?(name)
105
+ reserved_names.include?(name)
106
+ end
107
+
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(:+)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,50 @@
1
+ module Dry
2
+ # Argument parser
3
+ #
4
+ # Passing and array or arguments, it will decide which one are arguments
5
+ # and which one are options.
6
+ #
7
+ # We have a limitation if setting the value without options, as a hash
8
+ # having the same key as one of the valid options, will parse the value
9
+ # as options. In this case, all unknown options will be reject with an exception.
10
+ #
11
+ # @example
12
+ # p = Dry::Configurable::ArgumentParser.new.('db:sqlite', reader: true)
13
+ #
14
+ # p[0] # => 'db:sqlite'
15
+ # p[1] # => ArgumentParser::DEFAULT_PROCESSOR
16
+ # p[2] # => { reader: true }
17
+ module Configurable
18
+ class Settings
19
+ # @private
20
+ class ArgumentParser
21
+ DEFAULT_PROCESSOR = ->(v) { v }
22
+
23
+ # @private
24
+ def call(val, opts, block)
25
+ if block && block.parameters.empty?
26
+ raise ArgumentError unless Undefined.equal?(opts)
27
+
28
+ processor = DEFAULT_PROCESSOR
29
+
30
+ value, options = Settings.capture(&block), val
31
+ else
32
+ processor = block || DEFAULT_PROCESSOR
33
+
34
+ if Undefined.equal?(opts) && val.is_a?(Hash) && val.key?(:reader)
35
+ value, options = Undefined, val
36
+ else
37
+ value, options = val, opts
38
+ end
39
+ end
40
+
41
+ [value, processor, options(**Undefined.default(options, EMPTY_HASH))]
42
+ end
43
+
44
+ def options(reader: false)
45
+ { reader: reader }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ module Dry
2
+ module Configurable
3
+ # Methods meant to be used in a testing scenario
4
+ module TestInterface
5
+ # Resets configuration to default values
6
+ #
7
+ # @return [Dry::Configurable::Config]
8
+ #
9
+ # @api public
10
+ def reset_config
11
+ @config = if self.is_a?(Module)
12
+ _settings.create_config
13
+ else
14
+ self.class._settings.create_config
15
+ end
16
+ end
17
+ end
18
+
19
+ # Mixes in test interface into the configurable module
20
+ #
21
+ # @api public
22
+ def enable_test_interface
23
+ extend Dry::Configurable::TestInterface
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ module Dry
2
+ module Configurable
3
+ # @api public
4
+ VERSION = '0.9.0'.freeze
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'rubocop/rake_task'
3
+
4
+ Rake::Task[:default].enhance [:rubocop]
5
+
6
+ RuboCop::RakeTask.new do |task|
7
+ task.options << '--display-cop-names'
8
+ end
9
+
10
+ namespace :rubocop do
11
+ desc 'Generate a configuration file acting as a TODO list.'
12
+ task :auto_gen_config do
13
+ exec 'bundle exec rubocop --auto-gen-config'
14
+ end
15
+ end
16
+
17
+ rescue LoadError
18
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dry-configurable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Andy Holland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-11-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.4.7
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '0.4'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.4.7
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description:
90
+ email:
91
+ - andyholland1991@aol.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ 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
+ - CHANGELOG.md
107
+ - CODE_OF_CONDUCT.md
108
+ - CONTRIBUTING.md
109
+ - Gemfile
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - docsite/source/index.html.md
114
+ - docsite/source/testing.html.md
115
+ - dry-configurable.gemspec
116
+ - lib/dry-configurable.rb
117
+ - lib/dry/configurable.rb
118
+ - lib/dry/configurable/config.rb
119
+ - lib/dry/configurable/error.rb
120
+ - lib/dry/configurable/setting.rb
121
+ - lib/dry/configurable/settings.rb
122
+ - lib/dry/configurable/settings/argument_parser.rb
123
+ - lib/dry/configurable/test_interface.rb
124
+ - lib/dry/configurable/version.rb
125
+ - rakelib/rubocop.rake
126
+ homepage: https://github.com/dry-rb/dry-configurable
127
+ licenses:
128
+ - MIT
129
+ metadata:
130
+ source_code_uri: https://github.com/dry-rb/dry-configurable
131
+ changelog_uri: https://github.com/dry-rb/dry-configurable/blob/master/CHANGELOG.md
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: 2.4.0
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubygems_version: 3.0.6
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: A mixin to add configuration functionality to your classes
151
+ test_files: []