dry-configurable 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +12 -0
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/ci.yml +70 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +30 -0
- data/.gitignore +9 -0
- data/.rspec +4 -0
- data/.rubocop.yml +89 -0
- data/CHANGELOG.md +94 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +29 -0
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/docsite/source/index.html.md +55 -0
- data/docsite/source/testing.html.md +27 -0
- data/dry-configurable.gemspec +29 -0
- data/lib/dry-configurable.rb +1 -0
- data/lib/dry/configurable.rb +191 -0
- data/lib/dry/configurable/config.rb +185 -0
- data/lib/dry/configurable/error.rb +7 -0
- data/lib/dry/configurable/setting.rb +46 -0
- data/lib/dry/configurable/settings.rb +117 -0
- data/lib/dry/configurable/settings/argument_parser.rb +50 -0
- data/lib/dry/configurable/test_interface.rb +26 -0
- data/lib/dry/configurable/version.rb +6 -0
- data/rakelib/rubocop.rake +18 -0
- metadata +151 -0
@@ -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,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: []
|