configuru 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +282 -3
- data/lib/configuru/config_methods.rb +2 -2
- data/lib/configuru/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9afa59fbf6810cce708f1d83b2c10f0c66023072
|
4
|
+
data.tar.gz: 7db11437ea98c4b7d884bd5ac33f3323dc851f79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c3153582db20d9bccebf17ee2648af211b66bc8ba6a23c5373aea1f09d0630f3f062c7fd1d0aea90059f008be44af8ef58bccedba11a2572543854279d2d095
|
7
|
+
data.tar.gz: b54582a521c9a7ea4525ef4966b05ceb55a8a721955655e41f47dce8a894a5b7c692d67ef42765d1e14948828e279478eea6ebf3fd53162f37fa9f5fe549de0a
|
data/README.md
CHANGED
@@ -8,12 +8,22 @@ Requires Ruby version >= 2.1.
|
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
|
11
|
+
To add to an application, add this line to your application's Gemfile:
|
12
12
|
|
13
13
|
```ruby
|
14
14
|
gem 'configuru'
|
15
15
|
```
|
16
16
|
|
17
|
+
To add to a gem, add the following line to your gemspec file:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Gem::Specification.new do |spec|
|
21
|
+
...
|
22
|
+
spec.add_dependency 'configuru'
|
23
|
+
...
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
17
27
|
And then execute:
|
18
28
|
|
19
29
|
$ bundle
|
@@ -24,7 +34,11 @@ Or install it yourself as:
|
|
24
34
|
|
25
35
|
## Usage
|
26
36
|
|
27
|
-
|
37
|
+
### Overview
|
38
|
+
|
39
|
+
This gem allows to add convenient configuration API to modules, classes and instances in your gem or application. It is intentially designed to minimize "behind-the-scenes auto-magic" and yet keep it easy to use and the calling code concise.
|
40
|
+
|
41
|
+
Here is an example of how Configuru can be used to provide configuration for `MyClass`:
|
28
42
|
|
29
43
|
```ruby
|
30
44
|
require 'configuru'
|
@@ -55,7 +69,255 @@ my_inst.configuration.secret_key #=> "VERY-SECR-ETKY"
|
|
55
69
|
my_inst.configuration.percentage #=> 100
|
56
70
|
```
|
57
71
|
|
72
|
+
### Making your objects configurable
|
73
|
+
|
74
|
+
To make your class or module configurable you need to do two things:
|
75
|
+
|
76
|
+
1. `include Configuru::Configurable`
|
77
|
+
2. then call `provide_configuration` with an optional parameter as defined below:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
provide_configuration :base # Using one of these three options will add configuration API
|
81
|
+
provide_configuration :class # only to your class/module. The individual instances of that class
|
82
|
+
provide_configuration :module # will not be given any configuration API.
|
83
|
+
|
84
|
+
provide_configuration :instances # Using one of these two options will add configuration API to
|
85
|
+
provide_configuration :instance # individual instances of the class, but not for the class itself.
|
86
|
+
|
87
|
+
provide_configuration # Using these options will add configuration API both to the class
|
88
|
+
provide_configuration :all # and to the instances of that class
|
89
|
+
```
|
90
|
+
|
91
|
+
### Configuration API
|
92
|
+
|
93
|
+
#### Defining possible configuration parameters
|
94
|
+
The class module, inside which you called `provide_configuration`, will get a `def_config_param` method for defining possible configuration parameters. This method takes a parameter name and various options for it:
|
95
|
+
|
96
|
+
* Provide default value for the configuration parameter. The value is evaluated at the time `def_config_param` is called. The checks and conversions specified for the parameter (see below) are *not* applied to the default value.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
def_config_param :some_name, default: ""
|
100
|
+
```
|
101
|
+
|
102
|
+
* Prevent the parameter from changing once configuration is locked (see section "Locking configuration" below)
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
def_config_param :some_name, lockable: true
|
106
|
+
```
|
107
|
+
|
108
|
+
* When setting, check that the value is not nil or not empty. "Not empty" means that both `.nil?` and `.empty?` for it return `false`. Raise ArgumentError exception if the check fails.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
def_config_param :some_name, not_nil: true # Check for "not nil"
|
112
|
+
def_config_param :some_name, not_empty: true # Check for "not empty"
|
113
|
+
```
|
114
|
+
|
115
|
+
* When setting, check that the value is of a certain type (`is_a?` returns true). If an array of types is passed, the value must be of *any* of the types from that array. Raise ArgumentError exception if the check fails.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
def_config_param :some_name, must_be: String
|
119
|
+
def_config_param :some_name, must_be: [IO,File,StringIO]
|
120
|
+
```
|
121
|
+
|
122
|
+
* When setting, perform duck-type-checking. Check that the value resonds to a certain method. If an array of method names is passed, the value must respond to *all* specified methods. Raise ArgumentError exception if the check fails.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
def_config_param :some_name, must_respond_to: :read
|
126
|
+
def_config_param :some_name, must_respond_to: [:read,:seek]
|
127
|
+
```
|
128
|
+
|
129
|
+
* When setting, convert the value to a specific type
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
def_config_param :some_name, make_hash: true # Hash(value)
|
133
|
+
def_config_param :some_name, make_array: true # Array(value)
|
134
|
+
def_config_param :some_name, make_string: true # String(value)
|
135
|
+
def_config_param :some_name, make_int: true # value.to_i
|
136
|
+
def_config_param :some_name, make_float: true # value.to_f
|
137
|
+
def_config_param :some_name, make_bool: true # !!value
|
138
|
+
```
|
139
|
+
|
140
|
+
* When setting, check that the value is within the specified boundaries. Raise ArgumentError exception if the check fails.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
def_config_param :some_name, max: 10 # Raise exception if trying to set value > 10
|
144
|
+
def_config_param :some_name, min: 0.01 # Raise exception if trying to set value < 0.01
|
145
|
+
def_config_param :some_name, in: ('a'..'z') # Raise exception unless ('a'..'z').include?(value)
|
146
|
+
```
|
147
|
+
|
148
|
+
* When setting, perform call the conversion method. The original value is passed as the only parameter. The method should either return the converted value, or raise some exception. If a symbol is passed, the method with that name is called on the object under configuration.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
class MyClass {
|
152
|
+
def_config_param :some_name1, convert: :some_conversion
|
153
|
+
def_config_param :some_name2, convert: ->(x) { x.abs }
|
154
|
+
}
|
155
|
+
|
156
|
+
my_inst = MyClass.new
|
157
|
+
my_inst.configure( some_name1: "abc" ) # will call my_inst.some_conversion("abc") and assign the result to some_name1 parameter
|
158
|
+
```
|
159
|
+
|
160
|
+
A single parameter may have several checks and conversions associated with it. If several are defined, they will be applied in the order they are defined in the list above.
|
161
|
+
For example, if the parameter is defined as
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
class MyClass {
|
165
|
+
include Configuru::Configurable
|
166
|
+
provide_configuration :class
|
167
|
+
|
168
|
+
def_config_param :myparam, lockable: true, not_nil: true, make_int: true, in: (-3..3), convert: ->(x) { x.abs }
|
169
|
+
}
|
170
|
+
```
|
171
|
+
|
172
|
+
If you call `MyClass.configure( myparam: "-1" )` then Configuru will:
|
173
|
+
1. Check that `MyClass.configuration` is not locked yet (and raise exception if it is).
|
174
|
+
2. Check that the provided value is not nil (and raise exception if it is).
|
175
|
+
3. Convert the value to int (and raise exception if it can't do that).
|
176
|
+
4. Check that it is included in the -3..3 range (and raise exception if it is not).
|
177
|
+
5. Convert it: get the absolute value as specifed in the provided lambda.
|
178
|
+
6. Assign the resulting value to the `myparam` configuration parameter.
|
179
|
+
|
180
|
+
In this case (unless the configuration was locked) the parameter will eventually be set to 1.
|
181
|
+
|
182
|
+
|
183
|
+
#### Working with configuration parameters through configuration object
|
184
|
+
The object that you made configurable using `provide_configuration` will get a `configuration` method that returns its configuration object. The configuration object has all the parameters defined through `def_config_param` as its attributes and allows reading and writing them. The same parameter can be set several times, and each later value replaces the one set earlier.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
require 'configuru'
|
188
|
+
|
189
|
+
class MyClass
|
190
|
+
include Configuru::Configurable
|
191
|
+
provide_configuration :instance
|
192
|
+
|
193
|
+
def_config_param :secret_key, make_string: true, default: (ENV['SECRET_KEY_'] || '???')
|
194
|
+
def_config_param :color, default: :green,
|
195
|
+
convert: ->(val) { raise "Huh?" unless [:red,:green].include?(val); val }
|
196
|
+
def_config_param :percentage, make_float:true, min:0, max:100, default:100
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
my_inst = MyClass.new
|
201
|
+
|
202
|
+
my_inst.configuration.secret_key = "VERY-SECR-ETKY"
|
203
|
+
my_inst.configuration.color = :red
|
204
|
+
|
205
|
+
my_inst.configuration.color #=> :red
|
206
|
+
my_inst.configuration.secret_key #=> "VERY-SECR-ETKY"
|
207
|
+
my_inst.configuration.percentage #=> 100
|
208
|
+
```
|
209
|
+
|
210
|
+
##### Configure method
|
211
|
+
The object that you made configurable using `provide_configuration` also gets a `configure` convenience method. The method allows you to either provide configuration parameters as a hash or call the provided block with the configuration object.
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
require 'configuru'
|
215
|
+
|
216
|
+
class MyClass
|
217
|
+
include Configuru::Configurable
|
218
|
+
provide_configuration :instance
|
219
|
+
|
220
|
+
def_config_param :secret_key, make_string: true, default: (ENV['SECRET_KEY_'] || '???')
|
221
|
+
def_config_param :color, default: :green,
|
222
|
+
convert: ->(val) { raise "Huh?" unless [:red,:green].include?(val); val }
|
223
|
+
def_config_param :percentage, make_float:true, min:0, max:100, default:100
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
my_inst = MyClass.new
|
228
|
+
|
229
|
+
# Setting parameters using Hash
|
230
|
+
my_inst.configure secret_key: "VERY-SECR-ETKY", color: :red
|
231
|
+
|
232
|
+
# Setting parameters using the block called on the configuration object
|
233
|
+
my_inst.configure do |config|
|
234
|
+
config.secret_key = "VERY-SECR-ETKY"
|
235
|
+
config.color = :red
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
It is also possible to use Hash and block in the same call to configure. In this case first the Hash will be precessed, then the block will be called. So, any values set in the block will supersede the values set through Hash.
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
my_inst.configure(color: :red) do |config|
|
243
|
+
config.secret_key = "VERY-SECR-ETKY"
|
244
|
+
end
|
245
|
+
```
|
246
|
+
|
247
|
+
##### Reading configuration from file
|
248
|
+
The configuration object can also read configuration from a YAML file using `options_source=` call on the configuration object or `options_source` key in the Hash provided to configure. The `options_source=` can be called several times for a configuration object, and the parameters will be loaded from files in the order they are called. The file reading can also be nested: YAML files themselves may have the `options_source` parameter defined inside. As with direct parameter setting, if a parameter is set several times in multiple files, the latest value replaces all previous values.
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
require 'configuru'
|
252
|
+
|
253
|
+
class MyClass
|
254
|
+
include Configuru::Configurable
|
255
|
+
provide_configuration :instance
|
256
|
+
|
257
|
+
# bunch of def_config_param calls ...
|
258
|
+
end
|
58
259
|
|
260
|
+
my_inst = MyClass.new
|
261
|
+
|
262
|
+
# Directly call on the configuraton object - this will load the parameters from the three
|
263
|
+
# files in the order they are specified
|
264
|
+
my_inst.configuration.options_source = "/my/path/to/file/with/options1.yml"
|
265
|
+
my_inst.configuration.options_source = "/my/path/to/file/with/options2.yml"
|
266
|
+
my_inst.configure do |config|
|
267
|
+
config.options_source = "/my/path/to/file/with/options3.yml"
|
268
|
+
end
|
269
|
+
|
270
|
+
# Or, pass it as a part of Hash to configure
|
271
|
+
my_inst.configure options_source: "/my/path/to/file/with/options1.yml"
|
272
|
+
```
|
273
|
+
|
274
|
+
Using `options_source` may be combined with directly setting the parameters. And, again, the values provided later overwrite previously provided values for the same parameter.
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
my_inst = MyClass.new do |config|
|
278
|
+
config.secret_key = "VERY-SECR-ETKY"
|
279
|
+
config.color = :red
|
280
|
+
config.options_source = "/my/path/to/file/with/options.yml" # will overwrite color and secret_key if defined in YAML
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
##### Locking configuration
|
285
|
+
The configuration object also has a `lock` method. Calling this method prevents the parameters defined as lockable from further changes. The parameters, for which the `lockable` option was not set, are not affected. Locking is useful if you somehow cache configuration parameters in other parts of your application/gem, and further changes to the parameter will not affect the configuration behavior.
|
286
|
+
|
287
|
+
For example, if one of your parameters is a database name or an AWS access key, once you use this parameter at the beginning of your applicaton to establish connection to the database or get access to your AWS resources, further changes to it won't make your application to reconnect to a different database or start accessing AWS using a different set of credentials. In this case, locking helps to catch configuraton bugs, when the parameter is set or changed too late.
|
288
|
+
|
289
|
+
Locking affects all parameters marked as `lockable`. There is no locking at individual parameter level.
|
290
|
+
|
291
|
+
If a lockable parameter is accessed after `lock` has been called, `ArgumentError` is raised.
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
require 'configuru'
|
295
|
+
|
296
|
+
class MyClass
|
297
|
+
include Configuru::Configurable
|
298
|
+
provide_configuration :instance
|
299
|
+
|
300
|
+
def_config_param :database, lockable: true
|
301
|
+
end
|
302
|
+
|
303
|
+
my_inst = MyClass.new
|
304
|
+
|
305
|
+
my_inst.configuration.database = 'db_production'
|
306
|
+
my_inst.configuration.lock
|
307
|
+
my_inst.configuration.database = 'db_staging' # Raises ArgumentError
|
308
|
+
```
|
309
|
+
|
310
|
+
It is also possible to unlock the parameters after they were locked by calling `lock(false)`. Using the previous example:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
my_inst.configuration.database = 'db_production'
|
314
|
+
my_inst.configuration.lock
|
315
|
+
my_inst.configuration.database = 'db_staging' # Raises ArgumentError
|
316
|
+
my_inst.configuration.lock(false)
|
317
|
+
my_inst.configuration.database = 'db_development' # Works fine
|
318
|
+
```
|
319
|
+
|
320
|
+
Both `lock` and `lock(false)` can be called several times. But there is no counter: after calling `lock` multiple times, a single `lock(false)` would unlock all parameters.
|
59
321
|
|
60
322
|
## Versioning
|
61
323
|
|
@@ -74,9 +336,26 @@ The public API should not be considered stable.
|
|
74
336
|
|
75
337
|
Requires Ruby version >= 2.1
|
76
338
|
|
339
|
+
## Backlog
|
340
|
+
|
341
|
+
The following features may be included in the future versions of this gem, if a need for them is identified.
|
342
|
+
If you'd like to see one of these features or something else implemented in Configuru, please let the authors know.
|
343
|
+
|
344
|
+
* Provide callbacks for when parameters are changed (would allow reconnecting to a DB, for example when a database name is changed)
|
345
|
+
* Provide a choice for locked parameters: throw an exception or silently ignore, may be with a callback
|
346
|
+
* Add logging and make it configurable (simplify life for people who want to see the parameter values logged)
|
347
|
+
* Lock at parameter level (are there any real-life scenarios when that is needed?)
|
348
|
+
* Dump parameters to Hash/YAML file (allows saving/restoring configuration)
|
349
|
+
* Add write-once parameters: auto-locking after setting for the 1st time (does anybody need that?)
|
350
|
+
* Add required parameters, when reqding it w/o setting it first would raise an exception rather than using the default value
|
351
|
+
* Allow iterating through all parameters/parameter names (useful for alt storage mechanisms - e.g. store in DB)
|
352
|
+
* Better integration with ENV - automatically add variables as parameters using a defined list of names
|
353
|
+
* Other formats besides Hash & YAML? - probably not, it's easy to add on top after dumping and/or iterating are implemented
|
354
|
+
* Use gem-specific exceptions, not ArgumentError for all cases
|
355
|
+
|
77
356
|
## Contributing
|
78
357
|
|
79
|
-
1. Fork it ( https://github.com/
|
358
|
+
1. Fork it ( https://github.com/moonfly/configuru/fork )
|
80
359
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
81
360
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
82
361
|
4. Push to the branch (`git push origin my-new-feature`)
|
@@ -51,10 +51,10 @@ module Configuru
|
|
51
51
|
value = value.to_f if options[:make_float]
|
52
52
|
value = !!value if options[:make_bool]
|
53
53
|
if options.has_key?(:max) && (value > options[:max])
|
54
|
-
raise ArgumentError.new("'#{name.to_s}' must
|
54
|
+
raise ArgumentError.new("'#{name.to_s}' must be not more than #{options[:max]}")
|
55
55
|
end
|
56
56
|
if options.has_key?(:min) && (value < options[:min])
|
57
|
-
raise ArgumentError.new("'#{name.to_s}' must
|
57
|
+
raise ArgumentError.new("'#{name.to_s}' must be not less than #{options[:min]}")
|
58
58
|
end
|
59
59
|
if options.has_key?(:in) && !options[:in].include?(value)
|
60
60
|
raise ArgumentError.new("'#{name.to_s}' is out of range")
|
data/lib/configuru/version.rb
CHANGED