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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c07fa85118f6ae2cdf6732f59c88c29c2cf3e04d
4
- data.tar.gz: 1567cac755d01f457703f8a4bc0a58eaef7e31a0
3
+ metadata.gz: 4fe2eb4ab4567132c798bceaa960d6952f24f64f
4
+ data.tar.gz: 610aab18e8619ece1f85c3c5a6e2b4119375e7b9
5
5
  SHA512:
6
- metadata.gz: 5ec8dc807cdfb82290da302f4fe6187af246e9c27317cd467ee69f9e4ce754544f1dd8ff37b4c604a1a74e5174f6cfbd8568e4adb584fb725eb0c93111e88cfc
7
- data.tar.gz: e2ab059aade8ae09bfa47002127b5875ab266f1b84ab29542da3f50aaa1e11a22b5813a69ae1a0f8073dd5744795e43397ea2fd93295859863f9d945716a4de0
6
+ metadata.gz: 1b5684f556040ba711ebeae9b71012cb775ebc62209b8e067de935e1146ea130b7841d755512686983171b8487b9e0bcf04c22c30a9d6dabe67a6de48f1844b1
7
+ data.tar.gz: 3927b8495c5402df1723a2ed18e96f23a74dafc587ee02c8253a247ee084a9834d60fae8c33632da984f60d58728885d9e18d7a06458fe4463bbcde4a827fa35
data/.travis.yml CHANGED
@@ -3,11 +3,12 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ - 2.0.0
6
7
  - jruby-18mode
7
8
  - jruby-19mode
8
9
  - rbx-18mode
9
- #- rbx-19mode # SimpleCov breaks
10
+ - rbx-19mode
10
11
 
11
12
  notifications:
12
13
  webhooks:
13
- - http://rcmp.tenthbit.net/
14
+ - http://rcmp.pw/
data/ChangeLog.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.4.0 (8 October 2013)
4
+
5
+ * Added `Configru::Config` class
6
+ * Re-evaluate DSL block on reload
7
+
3
8
  ## 3.3.1 (29 September 2013)
4
9
 
5
10
  * Added license to Gemspec
data/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  group :development do
4
- gem "rake", "~> 10.1.0"
5
- gem "rspec", "~> 2.14.0"
6
- gem "simplecov", "~> 0.7.0"
4
+ gem 'rake', '~> 10.1.0'
5
+ gem 'rspec', '~> 2.14.0'
6
+ gem 'coveralls', :require => false
7
7
  end
8
8
 
9
9
  gemspec
data/Gemfile.lock CHANGED
@@ -1,14 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- configru (3.3.1)
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
- multi_json (1.3.6)
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) [![Dependency Status](https://gemnasium.com/programble/configru.png?travis)](https://gemnasium.com/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
- # Gemfile
9
- gem "configru", "~> 3.3.0"
10
+ gem 'configru', '~> 3.4.0'
10
11
  ```
11
- ### Example
12
+
13
+ Next, require it and load a configuration:
12
14
 
13
15
  ```ruby
14
16
  require 'configru'
15
17
 
16
- Configru.load('config.yml') do
17
- option :username, String, 'example_user'
18
- option_required :token, Fixnum
19
- option_group :connection do
20
- option :server, String, 'example.com'
21
- option :port, Fixnum, 42
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
- option :path, String, Dir.home do
24
- transform {|x| File.expand_path(x) }
25
- validate {|x| File.directory?(x) }
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
- example = Example.new(Configru.connection.server, Configru.connection.port)
32
- example.login(Configru.username, Configru.token)
33
- Configru.channels.each do |x|
34
- example.sync(x, Configru.path, :force => Configru.force)
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
- These defaults are equivalent to the following YAML:
151
+ The format for the configuration file would be:
39
152
 
40
153
  ```yaml
41
- username: example_user
42
- connection:
43
- server: example.com
44
- port: 42
45
- path: ~
46
- channels:
47
- - foo
48
- - bar
49
- force: false
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/dsl'
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
- @files = files.flatten
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(method, *args)
110
- @root.send(method, *args)
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
@@ -1,3 +1,3 @@
1
1
  module Configru
2
- VERSION = "3.3.1"
2
+ VERSION = "3.4.0"
3
3
  end
@@ -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
@@ -1,194 +1,11 @@
1
1
  describe Configru 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
- 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.example2 }.to raise_error(NoMethodError)
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.3.1
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-30 00:00:00.000000000 Z
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