configurate 0.1.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Changelog.md +30 -0
- data/README.md +96 -20
- data/lib/configurate.rb +26 -15
- data/lib/configurate/lookup_chain.rb +19 -17
- data/lib/configurate/provider.rb +34 -27
- data/lib/configurate/provider/dynamic.rb +34 -17
- data/lib/configurate/provider/env.rb +18 -14
- data/lib/configurate/provider/string_hash.rb +46 -0
- data/lib/configurate/provider/toml.rb +39 -0
- data/lib/configurate/provider/yaml.rb +26 -32
- data/lib/configurate/proxy.rb +42 -13
- data/lib/configurate/setting_path.rb +20 -8
- data/spec/configurate/lookup_chain_spec.rb +11 -9
- data/spec/configurate/provider/dynamic_spec.rb +13 -5
- data/spec/configurate/provider/env_spec.rb +13 -11
- data/spec/configurate/provider/string_hash_spec.rb +82 -0
- data/spec/configurate/provider/toml_spec.rb +112 -0
- data/spec/configurate/provider/yaml_spec.rb +42 -18
- data/spec/configurate/provider_spec.rb +15 -2
- data/spec/configurate/proxy_spec.rb +33 -7
- data/spec/configurate/setting_path_spec.rb +39 -20
- data/spec/configurate_spec.rb +5 -3
- data/spec/spec_helper.rb +8 -5
- metadata +31 -13
- checksums.yaml.gz.asc +0 -11
- data.tar.gz.asc +0 -11
- metadata.gz.asc +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5917dff879c04bd7e35104f02ed093e0ade7628503b70eaa9ba9f988250ce89d
|
4
|
+
data.tar.gz: 0ac06ee31c43264bac9001e7dad1c4fa18e9116dd02adfd325f21281d65ac2a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eaf82b6d8a397b3473bf4abc11722a7fb43f98981ee25142786a37c7ba46c1d847324a43f6950ad8997b7fd6db1186d3cd0e7d9a554b28e4f3a5d07b742075bb
|
7
|
+
data.tar.gz: 28022b6871d3282a5c8283b701bc9a45b1e2519470cb4762e9cb0d4a1875c86c5d16648c8eead096bc0da0da4cc09d477b2c27ef398b9b8c55c0638a4c245b6c
|
data/Changelog.md
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
# 0.5.0
|
2
|
+
|
3
|
+
* Support and prefer `toml-rb` over `tomlrb` in the shipped TOML provider.
|
4
|
+
* Drop explicit support for Ruby < 2.4
|
5
|
+
|
6
|
+
# 0.4.0
|
7
|
+
|
8
|
+
* `Configurate::Proxy` returns its own singleton class if the target does not support creating one.
|
9
|
+
* Extract `Configurate::Provider::StringHash` as a new base class for hash based providers.
|
10
|
+
* Add `Configurate::Provider::TOML`.
|
11
|
+
|
12
|
+
# 0.3.1
|
13
|
+
|
14
|
+
* Configurate::Provider::Dynamic returns true when passed the special
|
15
|
+
`reset_dynamic!` call.
|
16
|
+
|
17
|
+
# 0.3.0
|
18
|
+
|
19
|
+
* Add new exception: Configurate::MissingSetting to be raised and bubble up to the user
|
20
|
+
if a setting wasn't found and the user requested to be informed.
|
21
|
+
* Configurate::Provider::YAML got the new option raise_on_missing to raise
|
22
|
+
Configurate::MissingSetting if the requested key is not in the YAML document.
|
23
|
+
|
24
|
+
# 0.2.0
|
25
|
+
|
26
|
+
* Dynamic provider listens to reset_dynamic! message and forgets all settings on it.
|
27
|
+
* Calls ending in ! call the providers directly.
|
28
|
+
* Added SettingPath#action?, remove is_ prefix from SettingPath methods.
|
29
|
+
* Add implicit converters to Proxy that call the explicit converters.
|
30
|
+
|
1
31
|
# 0.1.0
|
2
32
|
|
3
33
|
* Dynamic provider resolves nested assignments
|
data/README.md
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# Configurate - A flexible configuration system
|
2
|
-
[![Gem Version](https://badge.fury.io/rb/configurate.
|
3
|
-
[![Build Status](https://
|
4
|
-
[![
|
5
|
-
[![
|
6
|
-
[![Coverage Status](https://coveralls.io/repos/jhass/configurate/badge.png?branch=master)](https://coveralls.io/r/MrZYX/configurate)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/configurate.svg)](https://badge.fury.io/rb/configurate)
|
3
|
+
[![Build Status](https://travis-ci.org/jhass/configurate.svg?branch=master)](https://travis-ci.org/jhass/configurate)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/jhass/configurate.svg)](https://codeclimate.com/github/jhass/configurate)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/jhass/configurate/badge.svg?branch=master)](https://coveralls.io/r/jhass/configurate?branch=master)
|
7
6
|
|
8
7
|
Configurate allows you to specify a chain of configuration providers which are
|
9
8
|
queried in order until one returns a value. This allows scenarios like overriding
|
@@ -11,7 +10,7 @@ your default settings with a user configuration file and let those be overridden
|
|
11
10
|
by environment variables. The query interface allows to group and nest your configuration options
|
12
11
|
to a practically unlimited level.
|
13
12
|
|
14
|
-
Configurate
|
13
|
+
Configurate supports Ruby 2.0 or later.
|
15
14
|
|
16
15
|
## Installation
|
17
16
|
|
@@ -80,7 +79,7 @@ Ruby does not allow to metaprogram `false`, thus something like
|
|
80
79
|
puts "yep" if Config.enable_stuff
|
81
80
|
```
|
82
81
|
|
83
|
-
always outputs `yep`. The workaround is to append `.get
|
82
|
+
always outputs `yep`. The workaround is to append `.get`, or `?` to get the
|
84
83
|
real value:
|
85
84
|
|
86
85
|
```ruby
|
@@ -107,14 +106,6 @@ will always output `unknown`. Again use `.get`
|
|
107
106
|
|
108
107
|
## Shipped providers
|
109
108
|
|
110
|
-
### Configurate::Provider::Base
|
111
|
-
|
112
|
-
A convenience base class changing the interface for implementers. It provides a basic `#lookup` method
|
113
|
-
which just passes all parameters through to `#lookup_path`.
|
114
|
-
The result of `#lookup_path` is returned, unless it's `nil`
|
115
|
-
then `Configurate::SettingNotFoundError` is raised. Subclasses are expected to implement `#lookup_path`.
|
116
|
-
Do not use this class directly as a provider!
|
117
|
-
|
118
109
|
### Configurate::Provider::Env
|
119
110
|
|
120
111
|
This class transforms a query string into a name for a environment variable and looks up this variable then.
|
@@ -124,6 +115,40 @@ into arrays.
|
|
124
115
|
|
125
116
|
This provider does not take any additional initialization parameters.
|
126
117
|
|
118
|
+
### Configurate::Provider::TOML
|
119
|
+
|
120
|
+
This provider reads settings from a given [TOML](https://github.com/toml-lang/toml) file. It converts the sections of
|
121
|
+
query string to a nested value. For a given TOML file
|
122
|
+
|
123
|
+
```toml
|
124
|
+
[stuff]
|
125
|
+
enable = true
|
126
|
+
param = "foo"
|
127
|
+
|
128
|
+
[stuff.nested]
|
129
|
+
param = "bar"
|
130
|
+
```
|
131
|
+
|
132
|
+
the following queries would be valid:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
Config.stuff.enable? # => true
|
136
|
+
Config.stuff.param # => "foo"
|
137
|
+
Config.stuff.nested.param # => "bar"
|
138
|
+
```
|
139
|
+
|
140
|
+
This provider depends on the [toml-rb](https://github.com/emancu/toml-rb) or the [tomlrb](https://github.com/fbernier/tomlrb) gem.
|
141
|
+
This is why it is not loaded by default and needs an explicit `require 'configurate/provider/toml'` to be available. If both are available, toml-rb is preferred.
|
142
|
+
|
143
|
+
The initializer takes a path to the configuration file a the mandatory first argument and
|
144
|
+
the following optional parameters:
|
145
|
+
|
146
|
+
* *namespace:* Specify a alternative root. This is useful if you for example add the same file multiple
|
147
|
+
times through multiple providers, with different namespaces, letting you override settings depending on
|
148
|
+
the rails environment, without duplicating common settings. Defaults to none.
|
149
|
+
* *required:* Whether to raise an error if the the file isn't found or, if one is given, the namespace
|
150
|
+
doesn't exist in the file.
|
151
|
+
|
127
152
|
### Configurate::Provider::YAML
|
128
153
|
|
129
154
|
This provider reads settings from a given [YAML](http://www.yaml.org) file. It converts the sections of
|
@@ -145,8 +170,8 @@ Config.stuff.param # => "foo"
|
|
145
170
|
Config.stuff.nested.param # => "bar"
|
146
171
|
```
|
147
172
|
|
148
|
-
The initializer takes a path to the configuration file
|
149
|
-
the following optional parameters
|
173
|
+
The initializer takes a path to the configuration file a the mandatory first argument and
|
174
|
+
the following optional parameters:
|
150
175
|
|
151
176
|
* *namespace:* Specify a alternative root. This is useful if you for example add the same file multiple
|
152
177
|
times through multiple providers, with different namespaces, letting you override settings depending on
|
@@ -154,18 +179,67 @@ the following optional parameters, as a hash:
|
|
154
179
|
* *required:* Whether to raise an error if the the file isn't found or, if one is given, the namespace
|
155
180
|
doesn't exist in the file.
|
156
181
|
|
182
|
+
|
183
|
+
### Configurate::Provider::StringHash
|
184
|
+
|
185
|
+
A provider taking a (nested) `Hash` where all keys are strings. The query string is then looked up in this hash.
|
186
|
+
|
187
|
+
So for a given `Hash`
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
{
|
191
|
+
"stuff" => {
|
192
|
+
"enable" => true,
|
193
|
+
"param" => "foo",
|
194
|
+
"nested" => {
|
195
|
+
"param" => "bar"
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
```
|
200
|
+
|
201
|
+
the following queries would be valid:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
Config.stuff.enable? # => true
|
205
|
+
Config.stuff.param # => "foo"
|
206
|
+
Config.stuff.nested.param # => "bar"
|
207
|
+
```
|
208
|
+
|
209
|
+
The initializer takes the hash as the mandatory first argument and
|
210
|
+
the following optional parameters:
|
211
|
+
|
212
|
+
* *namespace:* Specify a alternative root. This is useful if you for example add the same file multiple
|
213
|
+
times through multiple providers, with different namespaces, letting you override settings depending on
|
214
|
+
the rails environment, without duplicating common settings. Defaults to none.
|
215
|
+
* *required:* Whether to raise an error if the namespace
|
216
|
+
doesn't exist in the hash.
|
217
|
+
* *source:* A hint text about the origin of the configuration data to be used in error messages.
|
218
|
+
|
219
|
+
As you may have noticed by now, `Configurate::Provider::YAML` and `Configurate::Provider::TOML` are merely convenience
|
220
|
+
subclasses of this provider, loading the file for you.
|
221
|
+
|
157
222
|
### Configurate::Provider::Dynamic
|
158
223
|
|
159
|
-
A provider which stores the first
|
160
|
-
return it later. This is mainly useful for testing but can be useful to temporarily
|
161
|
-
too. To clarify a small example:
|
224
|
+
A provider which stores the first additional parameter if the query string ends with an equal sign and can
|
225
|
+
return it later. This is mainly useful for testing but can be useful to temporarily override stuff too. To clarify a small example:
|
162
226
|
|
163
227
|
```ruby
|
164
228
|
Config.foo.bar # => nil
|
165
229
|
Config.foo.bar = "baz"
|
166
230
|
Config.foo.bar # => "baz"
|
231
|
+
Config.reset_dynamic!
|
232
|
+
Config.foo.bar # => nil
|
167
233
|
```
|
168
234
|
|
235
|
+
### Configurate::Provider::Base
|
236
|
+
|
237
|
+
A convenience base class changing the interface for implementers. It provides a basic `#lookup` method
|
238
|
+
which just passes all parameters through to `#lookup_path`.
|
239
|
+
The result of `#lookup_path` is returned, unless it's `nil`
|
240
|
+
then `Configurate::SettingNotFoundError` is raised. Subclasses are expected to implement `#lookup_path`.
|
241
|
+
Do not use this class directly as a provider!
|
242
|
+
|
169
243
|
## Writing a provider
|
170
244
|
|
171
245
|
...should be pretty easy. For example here is the `Configurate::Provider::Env` provider:
|
@@ -183,6 +257,8 @@ class Configurate::Provider::Env < Configurate::Provider::Base
|
|
183
257
|
end
|
184
258
|
```
|
185
259
|
|
260
|
+
`Configurate::Provider::StringHash` should also serve as a useful baseclass for most providers.
|
261
|
+
|
186
262
|
|
187
263
|
## Documentation
|
188
264
|
|
data/lib/configurate.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'configurate/lookup_chain'
|
5
|
-
require 'configurate/provider'
|
6
|
-
require 'configurate/proxy'
|
3
|
+
require "forwardable"
|
7
4
|
|
5
|
+
require "configurate/setting_path"
|
6
|
+
require "configurate/lookup_chain"
|
7
|
+
require "configurate/provider"
|
8
|
+
require "configurate/proxy"
|
8
9
|
|
9
10
|
# A flexible and extendable configuration system.
|
10
11
|
# The calling logic is isolated from the lookup logic
|
@@ -20,15 +21,15 @@ require 'configurate/proxy'
|
|
20
21
|
module Configurate
|
21
22
|
# This is your main entry point. Instead of lengthy explanations
|
22
23
|
# let an example demonstrate its usage:
|
23
|
-
#
|
24
|
+
#
|
24
25
|
# require 'configuration_methods'
|
25
|
-
#
|
26
|
+
#
|
26
27
|
# AppSettings = Configurate::Settings.create do
|
27
28
|
# add_provider Configurate::Provider::Env
|
28
29
|
# add_provider Configurate::Provider::YAML, '/etc/app_settings.yml',
|
29
30
|
# namespace: Rails.env, required: false
|
30
31
|
# add_provider Configurate::Provider::YAML, 'config/default_settings.yml'
|
31
|
-
#
|
32
|
+
#
|
32
33
|
# extend YourConfigurationMethods
|
33
34
|
# end
|
34
35
|
#
|
@@ -36,18 +37,17 @@ module Configurate
|
|
36
37
|
#
|
37
38
|
# Please also read the note at {Proxy}!
|
38
39
|
class Settings
|
39
|
-
|
40
40
|
attr_reader :lookup_chain
|
41
|
-
|
41
|
+
|
42
42
|
undef_method :method # Remove possible conflicts with common setting names
|
43
43
|
|
44
44
|
extend Forwardable
|
45
45
|
|
46
46
|
def initialize
|
47
47
|
@lookup_chain = LookupChain.new
|
48
|
-
|
48
|
+
warn "Warning you called Configurate::Settings.new with a block, you really meant to call #create" if block_given?
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# @!method lookup(setting)
|
52
52
|
# (see {LookupChain#lookup})
|
53
53
|
|
@@ -59,19 +59,30 @@ module Configurate
|
|
59
59
|
|
60
60
|
def_delegators :@lookup_chain, :lookup, :add_provider, :[]
|
61
61
|
|
62
|
+
# rubocop:disable Style/MethodMissingSuper we handle all calls
|
63
|
+
# rubocop:disable Style/MissingRespondToMissing we override respond_to? instead
|
64
|
+
|
62
65
|
# See description and {#lookup}, {#[]} and {#add_provider}
|
63
66
|
def method_missing(method, *args, &block)
|
64
67
|
Proxy.new(@lookup_chain).public_send(method, *args, &block)
|
65
68
|
end
|
66
|
-
|
69
|
+
# rubocop:enable all
|
70
|
+
|
67
71
|
# Create a new configuration object
|
68
72
|
# @yield the given block will be evaluated in the context of the new object
|
69
73
|
def self.create(&block)
|
70
|
-
config =
|
74
|
+
config = new
|
71
75
|
config.instance_eval(&block) if block_given?
|
72
76
|
config
|
73
77
|
end
|
74
78
|
end
|
75
|
-
|
79
|
+
|
80
|
+
# This is supposed to be raised by providers if the requested setting
|
81
|
+
# does not exist, (remember, nil is a valid value and thus rarely a sufficient check)
|
82
|
+
# and this should be communicated to the end user.
|
83
|
+
class MissingSetting < RuntimeError; end
|
84
|
+
|
85
|
+
# This is supposed to be raised by providers if the requested setting
|
86
|
+
# cannot be found and the next provider in the chain should be tried.
|
76
87
|
class SettingNotFoundError < RuntimeError; end
|
77
88
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Configurate
|
2
4
|
# This object builds a chain of configuration providers to try to find
|
3
5
|
# the value of a setting.
|
@@ -5,7 +7,7 @@ module Configurate
|
|
5
7
|
def initialize
|
6
8
|
@provider = []
|
7
9
|
end
|
8
|
-
|
10
|
+
|
9
11
|
# Adds a provider to the chain. Providers are tried in the order
|
10
12
|
# they are added, so the order is important.
|
11
13
|
#
|
@@ -17,11 +19,10 @@ module Configurate
|
|
17
19
|
unless provider.respond_to?(:instance_methods) && provider.instance_methods.include?(:lookup)
|
18
20
|
raise ArgumentError, "the given provider does not respond to lookup"
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
@provider << provider.new(*args)
|
22
24
|
end
|
23
|
-
|
24
|
-
|
25
|
+
|
25
26
|
# Tries all providers in the order they were added to provide a response
|
26
27
|
# for setting.
|
27
28
|
#
|
@@ -37,27 +38,28 @@ module Configurate
|
|
37
38
|
return special_value_or_string(provider.lookup(setting.clone, *args))
|
38
39
|
rescue SettingNotFoundError; end
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
nil
|
42
43
|
end
|
43
44
|
alias_method :[], :lookup
|
44
|
-
|
45
|
-
private
|
46
|
-
|
45
|
+
|
46
|
+
private
|
47
|
+
|
47
48
|
def special_value_or_string(value)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
case value
|
50
|
+
when TrueClass, FalseClass, NilClass, Array, Hash
|
51
|
+
value
|
52
|
+
else
|
53
|
+
if value.respond_to?(:to_s)
|
54
|
+
case value.to_s.strip
|
52
55
|
when "true" then true
|
53
56
|
when "false" then false
|
54
57
|
when "", "nil" then nil
|
55
|
-
else value
|
58
|
+
else value.to_s
|
59
|
+
end
|
60
|
+
else
|
61
|
+
value
|
56
62
|
end
|
57
|
-
elsif value.respond_to?(:to_s)
|
58
|
-
return value.to_s
|
59
|
-
else
|
60
|
-
return value
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
data/lib/configurate/provider.rb
CHANGED
@@ -1,32 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Configurate
|
4
|
+
module Provider
|
5
|
+
# This provides a basic {#lookup} method for other providers to build
|
6
|
+
# upon. Childs are expected to define +lookup_path(path, *args)+.
|
7
|
+
# The method should return nil if the setting
|
8
|
+
# wasn't found and {#lookup} will raise an {SettingNotFoundError} in that
|
9
|
+
# case.
|
10
|
+
class Base
|
11
|
+
def lookup(*args)
|
12
|
+
result = lookup_path(*args)
|
13
|
+
return result unless result.nil?
|
14
|
+
|
15
|
+
raise Configurate::SettingNotFoundError, "The setting #{args.first} was not found"
|
16
|
+
end
|
12
17
|
end
|
13
|
-
end
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
# Utility function to lookup a settings path in a hash
|
20
|
+
# @param setting_path [SettingPath]
|
21
|
+
# @param hash [Hash]
|
22
|
+
# @yield fallback value if not found
|
23
|
+
# @return [Object]
|
24
|
+
def self.lookup_in_hash setting_path, hash, &fallback
|
25
|
+
fallback ||= proc { nil }
|
26
|
+
while hash.is_a?(Hash) && hash.has_key?(setting_path.first) && !setting_path.empty?
|
27
|
+
hash = hash[setting_path.shift]
|
28
|
+
end
|
29
|
+
return fallback.call unless setting_path.empty?
|
30
|
+
|
31
|
+
hash
|
24
32
|
end
|
25
|
-
return fallback.call unless setting_path.empty?
|
26
|
-
hash
|
27
33
|
end
|
28
|
-
end
|
34
|
+
end
|
29
35
|
|
30
|
-
require
|
31
|
-
require
|
32
|
-
require
|
36
|
+
require "configurate/provider/string_hash"
|
37
|
+
require "configurate/provider/yaml"
|
38
|
+
require "configurate/provider/env"
|
39
|
+
require "configurate/provider/dynamic"
|