configru 3.3.1 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/programble/configru.png?branch=master)](http://travis-ci.org/programble/configru) [![
|
1
|
+
# Configru [![Gem Version](https://badge.fury.io/rb/configru.png)](http://badge.fury.io/rb/configru) [![Build Status](https://secure.travis-ci.org/programble/configru.png?branch=master)](http://travis-ci.org/programble/configru) [![Coverage Status](https://coveralls.io/repos/programble/configru/badge.png)](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
|