configru 3.3.1 → 3.4.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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/ChangeLog.md +5 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +16 -3
- data/README.md +202 -29
- data/lib/configru.rb +4 -105
- data/lib/configru/config.rb +78 -0
- data/lib/configru/exceptions.rb +29 -0
- data/lib/configru/version.rb +1 -1
- data/spec/config_spec.rb +202 -0
- data/spec/configru_spec.rb +2 -185
- data/spec/spec_helper.rb +5 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fe2eb4ab4567132c798bceaa960d6952f24f64f
|
4
|
+
data.tar.gz: 610aab18e8619ece1f85c3c5a6e2b4119375e7b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b5684f556040ba711ebeae9b71012cb775ebc62209b8e067de935e1146ea130b7841d755512686983171b8487b9e0bcf04c22c30a9d6dabe67a6de48f1844b1
|
7
|
+
data.tar.gz: 3927b8495c5402df1723a2ed18e96f23a74dafc587ee02c8253a247ee084a9834d60fae8c33632da984f60d58728885d9e18d7a06458fe4463bbcde4a827fa35
|
data/.travis.yml
CHANGED
data/ChangeLog.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
configru (3.
|
4
|
+
configru (3.4.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
coveralls (0.7.0)
|
10
|
+
multi_json (~> 1.3)
|
11
|
+
rest-client
|
12
|
+
simplecov (>= 0.7)
|
13
|
+
term-ansicolor
|
14
|
+
thor
|
9
15
|
diff-lcs (1.2.4)
|
10
|
-
|
16
|
+
mime-types (1.25)
|
17
|
+
multi_json (1.8.1)
|
11
18
|
rake (10.1.0)
|
19
|
+
rest-client (1.6.7)
|
20
|
+
mime-types (>= 1.16)
|
12
21
|
rspec (2.14.1)
|
13
22
|
rspec-core (~> 2.14.0)
|
14
23
|
rspec-expectations (~> 2.14.0)
|
@@ -21,12 +30,16 @@ GEM
|
|
21
30
|
multi_json (~> 1.0)
|
22
31
|
simplecov-html (~> 0.7.1)
|
23
32
|
simplecov-html (0.7.1)
|
33
|
+
term-ansicolor (1.2.2)
|
34
|
+
tins (~> 0.8)
|
35
|
+
thor (0.18.1)
|
36
|
+
tins (0.11.0)
|
24
37
|
|
25
38
|
PLATFORMS
|
26
39
|
ruby
|
27
40
|
|
28
41
|
DEPENDENCIES
|
29
42
|
configru!
|
43
|
+
coveralls
|
30
44
|
rake (~> 10.1.0)
|
31
45
|
rspec (~> 2.14.0)
|
32
|
-
simplecov (~> 0.7.0)
|
data/README.md
CHANGED
@@ -1,52 +1,225 @@
|
|
1
|
-
# Configru [](http://travis-ci.org/programble/configru) [](http://badge.fury.io/rb/configru) [](http://travis-ci.org/programble/configru) [](https://coveralls.io/r/programble/configru)
|
2
2
|
|
3
3
|
YAML configuration file loader
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
7
|
+
Install the gem or add it to your `Gemfile`:
|
8
|
+
|
7
9
|
```ruby
|
8
|
-
|
9
|
-
gem "configru", "~> 3.3.0"
|
10
|
+
gem 'configru', '~> 3.4.0'
|
10
11
|
```
|
11
|
-
|
12
|
+
|
13
|
+
Next, require it and load a configuration:
|
12
14
|
|
13
15
|
```ruby
|
14
16
|
require 'configru'
|
15
17
|
|
16
|
-
Configru.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
config = Configru::Config.new('config.yml')
|
19
|
+
```
|
20
|
+
|
21
|
+
This example loads `config.yml` if it exists. Or at least it would, if
|
22
|
+
we told Configru the configuration options we wanted to load.
|
23
|
+
|
24
|
+
### Options
|
25
|
+
|
26
|
+
Configru provides a DSL for specifying the options that should be
|
27
|
+
loaded. The main method to specify configuration options is `option`.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
config = Configru::Config.new('config.yml') do
|
31
|
+
option :username, String, 'example_user', /^[A-Za-z1-9_]+$/
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
`option` takes 4 arguments: the configuration key, the type of value,
|
36
|
+
the default value, and an optional validation check.
|
37
|
+
|
38
|
+
The configuration option above can then be accessed in two ways:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
config.username
|
42
|
+
config['username']
|
43
|
+
```
|
44
|
+
|
45
|
+
If the value in `config.yml` is a `String`, a
|
46
|
+
`Configru::OptionTypeError` will be raised. If the value does not pass
|
47
|
+
the validation check, a `Configru::OptionValidationError` will be
|
48
|
+
raised.
|
49
|
+
|
50
|
+
### Validation
|
51
|
+
|
52
|
+
Validations are checked against the value of the option using the `===`
|
53
|
+
operator. This allows validations to be Procs, Regexps and Ranges. If
|
54
|
+
the validation is an Array, the value is checked using `include?`.
|
55
|
+
|
56
|
+
`option` can also be passed a block which can be used to set the
|
57
|
+
validation for the option. This allows a more convenient way to write
|
58
|
+
Proc validations.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
config = Configru::Config.new('config.yml') do
|
62
|
+
option :username, String, 'example_user' do
|
63
|
+
validate {|o| o.length < 255 }
|
22
64
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
### Transformation
|
69
|
+
|
70
|
+
Configru also allows options to be transformed (using a Proc) as they
|
71
|
+
are loaded.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
config = Configru::Config.new('config.yml') do
|
75
|
+
option :username, String, 'example' do
|
76
|
+
transform {|o| o + '_user' }
|
26
77
|
end
|
27
|
-
option_array :channels, String, ['foo', 'bar']
|
28
|
-
option_bool :force, false
|
29
78
|
end
|
79
|
+
```
|
80
|
+
|
81
|
+
In the above example, if the username set in `config.yml` is
|
82
|
+
"winnifred", it will be transformed using the Proc and `config.username`
|
83
|
+
will be `"winnifred_user"`.
|
84
|
+
|
85
|
+
### Required options
|
86
|
+
|
87
|
+
For configuration options that have no default and must be set in the
|
88
|
+
loaded configuration file, there is `option_required`. It takes the same
|
89
|
+
arguments as `option`, except for a default value.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
config = Configru::Config.new('config.yml') do
|
93
|
+
option_required :username, String
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
If a required option is not set in the loaded file, a
|
98
|
+
`Configru::OptionRequiredError` will be raised.
|
99
|
+
|
100
|
+
### Array options
|
101
|
+
|
102
|
+
For options whose value should be a list, there is `option_array`. It
|
103
|
+
takes the same arguments as `option`, except the default value is
|
104
|
+
optional and defaults to an empty array. It behaves in the same way as
|
105
|
+
`option` except each element of the array is checked against the type
|
106
|
+
and the validation, and each element is transformed using the
|
107
|
+
transformation Proc.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
config = Configru::Config.new('config.yml') do
|
111
|
+
option_array :users, String, ['user1', 'user2']
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
### Boolean options
|
116
|
+
|
117
|
+
Since Ruby's `true` and `false` do not share a class such as `Boolean`,
|
118
|
+
Configru provides a convenience method for boolean options,
|
119
|
+
`option_bool`. It take only an option key and a default value as
|
120
|
+
arguments.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
config = Configru::Config.new('config.yml') do
|
124
|
+
option_bool :debug, false
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
The above example is equivalent to the following:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
config = Configru::Config.new('config.yml') do
|
132
|
+
option :debug, Object, false, [true, false]
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
(This works because Array validations are checked using `include?`)
|
137
|
+
|
138
|
+
### Option groups
|
30
139
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
140
|
+
Configru allows nesting options in groups.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
config = Configru::Config.new('config.yml') do
|
144
|
+
option_group :user do
|
145
|
+
option_required :name, String
|
146
|
+
option_required :password, String
|
147
|
+
end
|
35
148
|
end
|
36
149
|
```
|
37
150
|
|
38
|
-
|
151
|
+
The format for the configuration file would be:
|
39
152
|
|
40
153
|
```yaml
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
154
|
+
user:
|
155
|
+
name: example
|
156
|
+
password: example
|
157
|
+
```
|
158
|
+
|
159
|
+
The above options can then be accessed using either method described
|
160
|
+
above:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
config.user.name
|
164
|
+
config.user.password
|
165
|
+
config['user']['name']
|
166
|
+
config['user']['password']
|
167
|
+
```
|
168
|
+
|
169
|
+
Option groups can, of course, be nested in other option groups.
|
170
|
+
|
171
|
+
### Loading multiple files
|
172
|
+
|
173
|
+
Multiple files can be passed to `Configru::Config.new` and each will be
|
174
|
+
loaded sequentially, replacing any values from previous files with new
|
175
|
+
ones. This allows for loading a global configuration file and a user
|
176
|
+
configuration file that can override the global configuration.
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
config = Configru::Config.new('/etc/config.yml', File.expand_path('~/config.yml')) do
|
180
|
+
option :username, String, 'example_user'
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
### Reloading
|
185
|
+
|
186
|
+
To reload configuration files, call the `reload` method on the
|
187
|
+
`Configru::Config` object. Note that the entire DSL block will be
|
188
|
+
re-evaluated.
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
config = Configru::Config.new('config.yml') do
|
192
|
+
option :username, String, 'example_user'
|
193
|
+
end
|
194
|
+
|
195
|
+
config.reload
|
196
|
+
```
|
197
|
+
|
198
|
+
### Global loading
|
199
|
+
|
200
|
+
Since it can be tedious to pass around the `config` object all over an
|
201
|
+
application in order to have access to the configuration, the `Configru`
|
202
|
+
module itself can be used a `Configru::Config` object with the `load`
|
203
|
+
method.
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
Configru.load('config.yml') do
|
207
|
+
option :username, String, 'example_user'
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
Option values can then be accessed on the `Configru` module in the same
|
212
|
+
way as on a `Configru::Config` object:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
Configru.username
|
216
|
+
Configru['username']
|
217
|
+
```
|
218
|
+
|
219
|
+
The global configuration can also be reloaded in the same way:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
Configru.reload
|
50
223
|
```
|
51
224
|
|
52
225
|
# License
|
data/lib/configru.rb
CHANGED
@@ -1,112 +1,11 @@
|
|
1
|
-
require 'configru/
|
2
|
-
require 'configru/option'
|
3
|
-
require 'configru/structhash'
|
4
|
-
|
5
|
-
require 'yaml'
|
1
|
+
require 'configru/config'
|
6
2
|
|
7
3
|
module Configru
|
8
|
-
class OptionError < RuntimeError
|
9
|
-
def initialize(path, message)
|
10
|
-
super("#{path.join('.')}: #{message}")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class OptionRequiredError < OptionError
|
15
|
-
def initialize(path)
|
16
|
-
super(path, 'option required')
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class OptionTypeError < OptionError
|
21
|
-
def initialize(path, expected, got)
|
22
|
-
super(path, "expected #{expected}, got #{got}")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class OptionValidationError < OptionError
|
27
|
-
def initialize(path, validation = nil)
|
28
|
-
if validation.is_a?(Proc)
|
29
|
-
super(path, "failed validation")
|
30
|
-
else
|
31
|
-
super(path, "failed validation `#{validation.inspect}`")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
4
|
def self.load(*files, &block)
|
37
|
-
@
|
38
|
-
@options = DSL::OptionGroup.new(&block).options
|
39
|
-
@root = StructHash.new
|
40
|
-
self.reload
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.reload
|
44
|
-
loaded_files = []
|
45
|
-
@files.each do |file|
|
46
|
-
if File.file?(file) && !File.zero?(file)
|
47
|
-
self.load_file(file)
|
48
|
-
loaded_files << file
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Load all defaults if no files were loaded
|
53
|
-
# TODO: loaded_files as instance var?
|
54
|
-
# TODO: Better way to load defaults?
|
55
|
-
@option_path = []
|
56
|
-
self.load_group(@options, @root, {}) if loaded_files.empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.load_file(file)
|
60
|
-
@option_path = []
|
61
|
-
self.load_group(@options, @root, YAML.load_file(file) || {})
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.load_group(option_group, output, input)
|
65
|
-
option_group.each do |key, option|
|
66
|
-
@option_path << key
|
67
|
-
|
68
|
-
# option is a group
|
69
|
-
if option.is_a? Hash
|
70
|
-
if input.has_key?(key) && !input[key].is_a?(Hash)
|
71
|
-
raise OptionTypeError.new(@option_path, Hash, input[key].class)
|
72
|
-
end
|
73
|
-
group_output = output[key] || StructHash.new
|
74
|
-
self.load_group(option, group_output, input[key] || {})
|
75
|
-
output[key] = group_output
|
76
|
-
@option_path.pop
|
77
|
-
next
|
78
|
-
end
|
79
|
-
|
80
|
-
if input.include? key
|
81
|
-
value = input[key]
|
82
|
-
elsif output.include? key # option has already been set
|
83
|
-
@option_path.pop
|
84
|
-
next
|
85
|
-
elsif option.is_a? RequiredOption
|
86
|
-
raise OptionRequiredError.new(@option_path)
|
87
|
-
else # option has not been set
|
88
|
-
value = option.default
|
89
|
-
end
|
90
|
-
|
91
|
-
unless option.type?(value)
|
92
|
-
raise OptionTypeError.new(@option_path, option.type, value.class)
|
93
|
-
end
|
94
|
-
|
95
|
-
unless option.valid?(value)
|
96
|
-
raise OptionValidationError.new(@option_path, option.validation)
|
97
|
-
end
|
98
|
-
|
99
|
-
output[key] = option.transform(value)
|
100
|
-
|
101
|
-
@option_path.pop
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.[](key)
|
106
|
-
@root[key]
|
5
|
+
@config = Config.new(*files, &block)
|
107
6
|
end
|
108
7
|
|
109
|
-
def self.method_missing(
|
110
|
-
@
|
8
|
+
def self.method_missing(*args, &block)
|
9
|
+
@config.send(*args, &block)
|
111
10
|
end
|
112
11
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
%w[dsl option structhash exceptions].map {|r| require("configru/#{r}") }
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Configru
|
6
|
+
class Config < StructHash
|
7
|
+
def initialize(*files, &block)
|
8
|
+
@files = files.flatten
|
9
|
+
@dsl_block = block
|
10
|
+
reload
|
11
|
+
end
|
12
|
+
|
13
|
+
def reload
|
14
|
+
@options = DSL::OptionGroup.new(&@dsl_block).options
|
15
|
+
|
16
|
+
loaded_files = Array.new
|
17
|
+
@files.each do |file|
|
18
|
+
if File.file?(file) && !File.zero?(file)
|
19
|
+
load_file(file)
|
20
|
+
loaded_files << file
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Load all defaults if no files were loaded
|
25
|
+
# TODO: Some way to not special case this
|
26
|
+
@option_path = Array.new
|
27
|
+
load_group(@options, self, {}) if loaded_files.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def load_file(file)
|
33
|
+
@option_path = Array.new
|
34
|
+
load_group(@options, self, YAML.load_file(file) || {})
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_group(option_group, output, input)
|
38
|
+
option_group.each do |key, option|
|
39
|
+
@option_path << key
|
40
|
+
|
41
|
+
# option is a group
|
42
|
+
if option.is_a? Hash
|
43
|
+
if input.has_key?(key) && !input[key].is_a?(Hash)
|
44
|
+
raise OptionTypeError.new(@option_path, Hash, input[key].class)
|
45
|
+
end
|
46
|
+
group_output = output[key] || StructHash.new
|
47
|
+
load_group(option, group_output, input[key] || {})
|
48
|
+
output[key] = group_output
|
49
|
+
@option_path.pop
|
50
|
+
next
|
51
|
+
end
|
52
|
+
|
53
|
+
if input.include? key
|
54
|
+
value = input[key]
|
55
|
+
elsif output.include? key # option has already been set
|
56
|
+
@option_path.pop
|
57
|
+
next
|
58
|
+
elsif option.is_a? RequiredOption
|
59
|
+
raise OptionRequiredError.new(@option_path)
|
60
|
+
else # option has not been set
|
61
|
+
value = option.default
|
62
|
+
end
|
63
|
+
|
64
|
+
unless option.type?(value)
|
65
|
+
raise OptionTypeError.new(@option_path, option.type, value.class)
|
66
|
+
end
|
67
|
+
|
68
|
+
unless option.valid?(value)
|
69
|
+
raise OptionValidationError.new(@option_path, option.validation)
|
70
|
+
end
|
71
|
+
|
72
|
+
output[key] = option.transform(value)
|
73
|
+
|
74
|
+
@option_path.pop
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Configru
|
2
|
+
class OptionError < RuntimeError
|
3
|
+
def initialize(path, message)
|
4
|
+
super("#{path.join('.')}: #{message}")
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class OptionRequiredError < OptionError
|
9
|
+
def initialize(path)
|
10
|
+
super(path, 'option required')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class OptionTypeError < OptionError
|
15
|
+
def initialize(path, expected, got)
|
16
|
+
super(path, "expected #{expected}, got #{got}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class OptionValidationError < OptionError
|
21
|
+
def initialize(path, validation = nil)
|
22
|
+
if validation.is_a?(Proc)
|
23
|
+
super(path, "failed validation")
|
24
|
+
else
|
25
|
+
super(path, "failed validation `#{validation.inspect}`")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/configru/version.rb
CHANGED
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
describe Configru::Config do
|
2
|
+
def example_file(x)
|
3
|
+
"spec/example_files/example_#{x}.yml"
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'loads defaults if no files are given' do
|
7
|
+
c = described_class.new do
|
8
|
+
option :example, String, 'example'
|
9
|
+
end
|
10
|
+
|
11
|
+
c.example.should == 'example'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is a StructHash' do
|
15
|
+
c = described_class.new do
|
16
|
+
option :example, String, 'example'
|
17
|
+
end
|
18
|
+
|
19
|
+
c.is_a? Configru::StructHash
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'loads defaults if no files exist' do
|
23
|
+
c = described_class.new(example_file :z) do
|
24
|
+
option :example, String, 'example'
|
25
|
+
end
|
26
|
+
|
27
|
+
c.example.should == 'example'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'loads defaults if file is empty' do
|
31
|
+
c = described_class.new(example_file :e) do
|
32
|
+
option :example, String, 'example'
|
33
|
+
end
|
34
|
+
|
35
|
+
c.example.should == 'example'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'loads defaults if file contains only whitespace' do
|
39
|
+
c = described_class.new(example_file :f) do
|
40
|
+
option :example, String, 'example'
|
41
|
+
end
|
42
|
+
|
43
|
+
c.example.should == 'example'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'loads a file' do
|
47
|
+
c = described_class.new(example_file :a) do
|
48
|
+
option :example
|
49
|
+
end
|
50
|
+
|
51
|
+
c.example.should == 'example_a'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'loads files in order' do
|
55
|
+
c = described_class.new(example_file(:a), example_file(:b)) do
|
56
|
+
option :example
|
57
|
+
end
|
58
|
+
|
59
|
+
c.example.should == 'example_b'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'cascades loaded files' do
|
63
|
+
c = described_class.new(example_file(:g), example_file(:h)) do
|
64
|
+
option :option1
|
65
|
+
option :option2
|
66
|
+
end
|
67
|
+
|
68
|
+
c.option1.should == 'example_g'
|
69
|
+
c.option2.should == 'example_h'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'loads a file with a group' do
|
73
|
+
c = described_class.new(example_file :c) do
|
74
|
+
option_group :example_group do
|
75
|
+
option :example
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
c.example_group.example.should == 'example_c'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'checks that group values are Hashes' do
|
83
|
+
expect do
|
84
|
+
c = described_class.new(example_file :a) do
|
85
|
+
option_group :example do
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end.to raise_error(Configru::OptionTypeError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'checks option types' do
|
92
|
+
expect do
|
93
|
+
c = described_class.new(example_file :d) do
|
94
|
+
option :string, String, ''
|
95
|
+
end
|
96
|
+
end.to raise_error(Configru::OptionTypeError)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'validates options against values' do
|
100
|
+
expect do
|
101
|
+
c = described_class.new(example_file :d) do
|
102
|
+
option :example, String, 'test', /test/
|
103
|
+
end
|
104
|
+
end.to raise_error(Configru::OptionValidationError)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'validates options against blocks' do
|
108
|
+
expect do
|
109
|
+
c = described_class.new(example_file :d) do
|
110
|
+
option :example, String, '' do
|
111
|
+
validate { false }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end.to raise_error(Configru::OptionValidationError)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'validates options against arrays' do
|
118
|
+
c = described_class.new(example_file :d) do
|
119
|
+
option :example, String, '', ['example_d']
|
120
|
+
end
|
121
|
+
|
122
|
+
c.example.should == 'example_d'
|
123
|
+
|
124
|
+
expect do
|
125
|
+
c = described_class.new(example_file :d) do
|
126
|
+
option :example, String, '', ['foo', 'bar']
|
127
|
+
end
|
128
|
+
end.to raise_error(Configru::OptionValidationError)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'applies transformations to options' do
|
132
|
+
c = described_class.new(example_file :d) do
|
133
|
+
option :example, String, '' do
|
134
|
+
transform {|x| x + 't' }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
c.example.should == 'example_dt'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'checks that array option values are arrays' do
|
142
|
+
expect do
|
143
|
+
c = described_class.new(example_file :a) do
|
144
|
+
option_array :example
|
145
|
+
end
|
146
|
+
end.to raise_error(Configru::OptionTypeError)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'checks array option types' do
|
150
|
+
expect do
|
151
|
+
c = described_class.new(example_file :i) do
|
152
|
+
option_array :hetero, String
|
153
|
+
end
|
154
|
+
end.to raise_error(Configru::OptionTypeError)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'validates option arrays against values' do
|
158
|
+
expect do
|
159
|
+
c = described_class.new(example_file :i) do
|
160
|
+
option_array :example, Fixnum, [], 1..6
|
161
|
+
end
|
162
|
+
end.to raise_error(Configru::OptionValidationError)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'validates option arrays against blocks' do
|
166
|
+
expect do
|
167
|
+
c = described_class.new(example_file :i) do
|
168
|
+
option_array :example, Fixnum, [] do
|
169
|
+
validate {|x| x.even? }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end.to raise_error(Configru::OptionValidationError)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'applies transformations to option arrays' do
|
176
|
+
c = described_class.new(example_file :i) do
|
177
|
+
option_array :example, Fixnum, [] do
|
178
|
+
transform {|x| x + 1 }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
c.example.should == [3, 5, 7, 8]
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'requires required options' do
|
186
|
+
expect do
|
187
|
+
c = described_class.new(example_file :a) do
|
188
|
+
option_required :required
|
189
|
+
end
|
190
|
+
end.to raise_error(Configru::OptionRequiredError)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'executes DSL block on every reload' do
|
194
|
+
foo = 0
|
195
|
+
c = described_class.new do
|
196
|
+
foo += 1
|
197
|
+
end
|
198
|
+
c.reload
|
199
|
+
|
200
|
+
foo.should == 2
|
201
|
+
end
|
202
|
+
end
|
data/spec/configru_spec.rb
CHANGED
@@ -1,194 +1,11 @@
|
|
1
1
|
describe Configru do
|
2
|
-
|
3
|
-
"spec/example_files/example_#{x}.yml"
|
4
|
-
end
|
5
|
-
|
6
|
-
it 'loads defaults if no files are given' do
|
7
|
-
Configru.load do
|
8
|
-
option :example, String, 'example'
|
9
|
-
end
|
10
|
-
|
11
|
-
Configru.example.should == 'example'
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'behaves like a StructHash' do
|
2
|
+
it 'behaves like Config' do
|
15
3
|
Configru.load do
|
16
4
|
option :example, String, 'example'
|
17
5
|
end
|
18
6
|
|
19
7
|
Configru['example'].should == 'example'
|
20
8
|
Configru.example.should == 'example'
|
21
|
-
expect { Configru.
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'loads defaults if no files exist' do
|
25
|
-
Configru.load(example_file :z) do
|
26
|
-
option :example, String, 'example'
|
27
|
-
end
|
28
|
-
|
29
|
-
Configru.example.should == 'example'
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'loads defaults if file is empty' do
|
33
|
-
Configru.load(example_file :e) do
|
34
|
-
option :example, String, 'example'
|
35
|
-
end
|
36
|
-
|
37
|
-
Configru.example.should == 'example'
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'loads defaults if file contains only whitespace' do
|
41
|
-
Configru.load(example_file :f) do
|
42
|
-
option :example, String, 'example'
|
43
|
-
end
|
44
|
-
|
45
|
-
Configru.example.should == 'example'
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'loads a file' do
|
49
|
-
Configru.load(example_file :a) do
|
50
|
-
option :example
|
51
|
-
end
|
52
|
-
|
53
|
-
Configru.example.should == 'example_a'
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'loads files in order' do
|
57
|
-
Configru.load(example_file(:a), example_file(:b)) do
|
58
|
-
option :example
|
59
|
-
end
|
60
|
-
|
61
|
-
Configru.example.should == 'example_b'
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'cascades loaded files' do
|
65
|
-
Configru.load(example_file(:g), example_file(:h)) do
|
66
|
-
option :option1
|
67
|
-
option :option2
|
68
|
-
end
|
69
|
-
|
70
|
-
Configru.option1.should == 'example_g'
|
71
|
-
Configru.option2.should == 'example_h'
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'loads a file with a group' do
|
75
|
-
Configru.load(example_file :c) do
|
76
|
-
option_group :example_group do
|
77
|
-
option :example
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
Configru.example_group.example.should == 'example_c'
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'checks that group values are Hashes' do
|
85
|
-
expect do
|
86
|
-
Configru.load(example_file :a) do
|
87
|
-
option_group :example do
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end.to raise_error(Configru::OptionTypeError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'checks option types' do
|
94
|
-
expect do
|
95
|
-
Configru.load(example_file :d) do
|
96
|
-
option :string, String, ''
|
97
|
-
end
|
98
|
-
end.to raise_error(Configru::OptionTypeError)
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'validates options against values' do
|
102
|
-
expect do
|
103
|
-
Configru.load(example_file :d) do
|
104
|
-
option :example, String, 'test', /test/
|
105
|
-
end
|
106
|
-
end.to raise_error(Configru::OptionValidationError)
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'validates options against blocks' do
|
110
|
-
expect do
|
111
|
-
Configru.load(example_file :d) do
|
112
|
-
option :example, String, '' do
|
113
|
-
validate { false }
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end.to raise_error(Configru::OptionValidationError)
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'validates options against arrays' do
|
120
|
-
Configru.load(example_file :d) do
|
121
|
-
option :example, String, '', ['example_d']
|
122
|
-
end
|
123
|
-
|
124
|
-
Configru.example.should == 'example_d'
|
125
|
-
|
126
|
-
expect do
|
127
|
-
Configru.load(example_file :d) do
|
128
|
-
option :example, String, '', ['foo', 'bar']
|
129
|
-
end
|
130
|
-
end.to raise_error(Configru::OptionValidationError)
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'applies transformations to options' do
|
134
|
-
Configru.load(example_file :d) do
|
135
|
-
option :example, String, '' do
|
136
|
-
transform {|x| x + 't' }
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
Configru.example.should == 'example_dt'
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'checks that array option values are arrays' do
|
144
|
-
expect do
|
145
|
-
Configru.load(example_file :a) do
|
146
|
-
option_array :example
|
147
|
-
end
|
148
|
-
end.to raise_error(Configru::OptionTypeError)
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'checks array option types' do
|
152
|
-
expect do
|
153
|
-
Configru.load(example_file :i) do
|
154
|
-
option_array :hetero, String
|
155
|
-
end
|
156
|
-
end.to raise_error(Configru::OptionTypeError)
|
157
|
-
end
|
158
|
-
|
159
|
-
it 'validates option arrays against values' do
|
160
|
-
expect do
|
161
|
-
Configru.load(example_file :i) do
|
162
|
-
option_array :example, Fixnum, [], 1..6
|
163
|
-
end
|
164
|
-
end.to raise_error(Configru::OptionValidationError)
|
165
|
-
end
|
166
|
-
|
167
|
-
it 'validates option arrays against blocks' do
|
168
|
-
expect do
|
169
|
-
Configru.load(example_file :i) do
|
170
|
-
option_array :example, Fixnum, [] do
|
171
|
-
validate {|x| x.even? }
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end.to raise_error(Configru::OptionValidationError)
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'applies transformations to option arrays' do
|
178
|
-
Configru.load(example_file :i) do
|
179
|
-
option_array :example, Fixnum, [] do
|
180
|
-
transform {|x| x + 1 }
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
Configru.example.should == [3, 5, 7, 8]
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'requires required options' do
|
188
|
-
expect do
|
189
|
-
Configru.load(example_file :a) do
|
190
|
-
option_required :required
|
191
|
-
end
|
192
|
-
end.to raise_error(Configru::OptionRequiredError)
|
9
|
+
expect { Configru.idonotexist }.to raise_error(NoMethodError)
|
193
10
|
end
|
194
11
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
|
3
3
|
require 'simplecov'
|
4
|
+
require 'coveralls'
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
6
|
+
SimpleCov::Formatter::HTMLFormatter,
|
7
|
+
Coveralls::SimpleCov::Formatter
|
8
|
+
]
|
4
9
|
SimpleCov.start do
|
5
10
|
add_filter '/spec/'
|
6
11
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Curtis McEnroe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09
|
11
|
+
date: 2013-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: YAML configuration file loader
|
14
14
|
email:
|
@@ -27,10 +27,13 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- configru.gemspec
|
29
29
|
- lib/configru.rb
|
30
|
+
- lib/configru/config.rb
|
30
31
|
- lib/configru/dsl.rb
|
32
|
+
- lib/configru/exceptions.rb
|
31
33
|
- lib/configru/option.rb
|
32
34
|
- lib/configru/structhash.rb
|
33
35
|
- lib/configru/version.rb
|
36
|
+
- spec/config_spec.rb
|
34
37
|
- spec/configru_spec.rb
|
35
38
|
- spec/dsl_spec.rb
|
36
39
|
- spec/example_files/example_a.yml
|