dry-configurable 0.9.0

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