configru 0.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,4 @@
1
- *.gem
1
+ coverage
2
+ coverage.data
2
3
  .bundle
3
- Gemfile.lock
4
- pkg/*
4
+ pkg
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-18mode
7
+ - jruby-19mode
8
+ - rbx-18mode
9
+ #- rbx-19mode # SimpleCov breaks
10
+
11
+ notifications:
12
+ webhooks:
13
+ - http://rcmp.tenthbit.net/
data/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
- source "http://rubygems.org"
1
+ source :rubygems
2
2
 
3
3
  group :development do
4
- gem "riot", ">= 0"
5
- gem "bundler", "~> 1.0.0"
4
+ gem 'rake', '>= 0'
5
+ gem 'rspec', '~> 2.8.0'
6
+ gem 'simplecov', '~> 0.6.0'
6
7
  end
7
8
 
8
- # Specify your gem's dependencies in configru.gemspec
9
9
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ configru (2.0.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.3)
10
+ multi_json (1.3.6)
11
+ rake (0.9.2.2)
12
+ rspec (2.8.0)
13
+ rspec-core (~> 2.8.0)
14
+ rspec-expectations (~> 2.8.0)
15
+ rspec-mocks (~> 2.8.0)
16
+ rspec-core (2.8.0)
17
+ rspec-expectations (2.8.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.8.0)
20
+ simplecov (0.6.4)
21
+ multi_json (~> 1.0)
22
+ simplecov-html (~> 0.5.3)
23
+ simplecov-html (0.5.3)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ configru!
30
+ rake
31
+ rspec (~> 2.8.0)
32
+ simplecov (~> 0.6.0)
data/README.md CHANGED
@@ -1,195 +1,19 @@
1
1
  # Configru
2
2
 
3
- Versatile configuration file loader for Ruby
3
+ [![Build Status](https://secure.travis-ci.org/programble/configru.png?branch=master)](http://travis-ci.org/programble/configru)
4
4
 
5
- # Installation
5
+ YAML configuration file loader
6
6
 
7
- gem install configru
8
-
9
- # Usage
10
-
11
- Configru loads YAML configuration files and provides a simple way to access
12
- configuration options.
13
-
14
- ## Loading Configuration Files
15
-
16
- Configru provides a DSL for loading configuration files.
17
-
18
- ```ruby
19
- require 'configru'
20
-
21
- Configru.load do
22
- # Things
23
- end
24
- ```
25
-
26
- At the very least, the block passed to `Configru.load` must tell Configru which
27
- files it should load. There are two different methods of loading configuration
28
- files available.
29
-
30
- ### Just load a file already!
31
-
32
- This is the simplest method of loading. It just loads a file.
33
-
34
- ```ruby
35
- Configru.load do
36
- just 'foo.yml'
37
- end
38
- ```
39
-
40
- ### First-of Loading
41
-
42
- This method loads the first file that exists, ignoring all other files.
43
-
44
- ```ruby
45
- Configru.load do
46
- first_of 'foo.yml', '~/foo.yml', '/etc/foo.yml'
47
- end
48
- ```
49
-
50
- ### Cascading Loading
51
-
52
- This method loads every file that exists in reverse order. Files listed first
53
- overwrite the values from files listed later. (Files are listed in high to low
54
- cascade priority)
55
-
56
- ```ruby
57
- Configru.load do
58
- cascade '~/foo.yml', '/etc/foo.yml'
59
- end
60
- ```
61
-
62
- ## Accessing Options
63
-
64
- Configuration options can be accessed as methods of the `Configru` module, or
65
- `Configru` can be used as a Hash.
66
-
67
- `foo.yml`
68
-
69
- ```yaml
70
- nick: bob
71
- server:
72
- address: foo.net
73
- port: 6782
74
- ```
75
-
76
- `foo.rb`
77
-
78
- ```ruby
79
- require 'configru'
80
- require 'socket'
81
-
82
- Configru.load do
83
- just 'foo.yml'
84
- end
85
-
86
- s = TCPSocket.new(Configru.server.address, Configru['server']['port'])
87
- s.puts "Hello, I am #{Configru.nick}"
88
- ```
89
-
90
- Configuration options with hyphens can be accessed as methods by replacing the
91
- hyphens with underscores.
92
-
93
- ## Defaults
94
-
95
- Configru's load DSL allows for setting configuration defaults using a block.
96
- If no configuration files are found or if the configuration file omits an
97
- option, the values in `defaults` will be used.
98
-
99
-
100
- ```ruby
101
- require 'configru'
102
-
103
- Configru.load do
104
- just 'foo.yml'
105
- defaults do
106
- nick 'Dr. Nader'
107
- server do
108
- address 'abcd.com'
109
- port 1111
110
- end
111
- end
112
- end
113
- ```
114
-
115
- The above `defaults` block is equivalent to the following YAML:
116
-
117
- ```yaml
118
- nick: Dr. Nader
119
- server:
120
- address: abcd.com
121
- port: 1111
122
- ```
123
-
124
- Defaults can also be set using a Hash instead of a block.
125
-
126
- ```ruby
127
- Configru.load do
128
- just 'foo.yml'
129
- defaults 'nick' => 'Dr. Nader',
130
- 'server' => {'address' => 'abcd.com', 'port' => 1111}
131
- end
132
- ```
133
-
134
- Defaults can also be loaded from a YAML file by passing the filename to
135
- `defaults`.
136
-
137
- ```ruby
138
- Configru.load do
139
- just 'foo.yml'
140
- defaults 'foo.yml.dist'
141
- end
142
- ```
143
-
144
- ## Verifying options
145
-
146
- Configru provides a way to verify that configuration options meet certain
147
- requirements. This is done using a `verify` block in `Configru.load`.
7
+ ## Usage
148
8
 
149
9
  ```ruby
150
- Configru.load do
151
- just 'foo.yml'
152
- verify do
153
- foo Fixnum
154
- bar /^a+$/
155
- baz ['one', 'two']
156
- end
157
- end
10
+ # Gemfile
11
+ gem 'configru', '~> 2.0.0'
158
12
  ```
159
13
 
160
- Upon loading the configuration, Configru checks each option against this verify
161
- block. In most cases, the `===` operator is used to compare the values, but
162
- there are some special cases. If the verification value is a class, `is_a?` is
163
- used. If the verification value is an array, `include?` is used. This
164
- effectively means that with a class, the value must be an instance of that
165
- class, and with an array, the value must be one of the values in the array.
166
-
167
- FIXME: Talk about how Configru deals with invalid options
168
-
169
- ## Doing two things at once
170
-
171
- Configru also has an `options` block in `Configru.load` which allows for
172
- combining the `defaults` and `verify` blocks.
173
-
174
- ```ruby
175
- Configru.load do
176
- just 'foo.yml'
177
- options do
178
- nick String, 'Dr. Nader'
179
- server do
180
- address String, 'abcd.com'
181
- port (0..65535), 1111
182
- end
183
- end
184
- end
185
- ```
186
-
187
- In the `options` block, each option takes two arguments, the first being the
188
- verification value, and the second being the default value.
189
-
190
14
  # License
191
15
 
192
- Copyright (c) 2011, Curtis McEnroe <programble@gmail.com>
16
+ Copyright (c) 2011-2012, Curtis McEnroe <programble@gmail.com>
193
17
 
194
18
  Permission to use, copy, modify, and/or distribute this software for any
195
19
  purpose with or without fee is hereby granted, provided that the above
data/Rakefile CHANGED
@@ -1,15 +1,11 @@
1
+ require 'bundler/setup'
1
2
  require 'bundler/gem_tasks'
2
3
 
3
- require 'rake'
4
- require 'rake/testtask'
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
5
6
 
6
- desc "Run all tests"
7
- task :test do
8
- Rake::TestTask.new do |t|
9
- t.libs << "test"
10
- t.pattern = "test/**/*_test.rb"
11
- t.verbose = false
12
- end
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
9
  end
14
10
 
15
- task :default => :test
11
+ task :default => :spec
data/configru.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Curtis McEnroe"]
9
9
  s.email = ["programble@gmail.com"]
10
10
  s.homepage = "https://github.com/programble/configru"
11
- s.summary = %q{Versatile configuration file loader}
11
+ s.summary = %q{YAML configuration file loader}
12
12
  s.description = s.summary
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
data/lib/configru/dsl.rb CHANGED
@@ -1,106 +1,46 @@
1
+ require 'configru/option'
2
+
1
3
  module Configru
2
4
  module DSL
3
- class LoadDSL
4
- attr_reader :defaults_hash, :verify_hash, :files_array, :load_method
5
+ class OptionGroup
6
+ attr_reader :options
5
7
 
6
- def initialize(block)
7
- @defaults_hash = {}
8
- @verify_hash = {}
9
- @files_array = []
10
- @load_method = :first
8
+ def initialize(&block)
9
+ @options = {}
11
10
  instance_eval(&block)
12
11
  end
13
12
 
14
- def files(*args)
15
- if args[0].is_a?(String) && args[1].is_a?(Array)
16
- @files_array = args[1].map {|x| File.join(x, args[0])}
17
- else
18
- @files_array = args
19
- end
20
- end
21
-
22
- def method(m)
23
- @load_method = m
24
- end
25
-
26
- def first_of(*args)
27
- method(:first)
28
- files(*args)
29
- end
30
-
31
- alias :just :first_of
32
-
33
- def cascade(*args)
34
- method(:cascade)
35
- files(*args)
36
- end
37
-
38
- def defaults(arg=nil, &block)
39
- if arg.is_a? String
40
- @defaults_hash = YAML.load_file(arg)
41
- elsif arg
42
- @defaults_hash = arg
43
- elsif block
44
- @defaults_hash = HashDSL.new(block).hash
45
- end
46
- end
47
-
48
- def verify(hash=nil, &block)
49
- if hash
50
- @verify_hash = hash
51
- elsif block
52
- @verify_hash = HashDSL.new(block).hash
53
- end
13
+ def option(name, type = Object, default = nil, validate = nil, &block)
14
+ option = Configru::Option.new(type, default, validate, nil)
15
+ Option.new(option, &block) if block
16
+ @options[name.to_s] = option
54
17
  end
55
18
 
56
- def options(&block)
57
- hashes = DoubleHashDSL.new(block)
58
- @defaults_hash = hashes.hash2
59
- @verify_hash = hashes.hash1
19
+ def option_group(name, &block)
20
+ @options[name.to_s] = OptionGroup.new(&block).options
60
21
  end
61
22
  end
62
23
 
63
- class HashDSL
64
- attr_reader :hash
65
-
66
- def initialize(block)
67
- @hash = {}
24
+ class Option
25
+ def initialize(option, &block)
26
+ @option = option
68
27
  instance_eval(&block)
69
28
  end
70
29
 
71
- def method_missing(method, *args, &block)
72
- key = method.to_s.gsub('_', '-')
73
- if block
74
- @hash[key] = HashDSL.new(block).hash
75
- else
76
- # Simulate method requiring 1 argument
77
- raise ArgumentError, "wrong number of arguments(#{args.length} for 1)" unless args.length == 1
78
- @hash[key] = args[0]
79
- end
30
+ def type(t)
31
+ @option.type = t
80
32
  end
81
- end
82
33
 
83
- class DoubleHashDSL
84
- attr_reader :hash1, :hash2
34
+ def default(d)
35
+ @option.default = d
36
+ end
85
37
 
86
- def initialize(block)
87
- @hash1 = {}
88
- @hash2 = {}
89
- instance_eval(&block)
38
+ def validate(v = nil, &block)
39
+ @option.validate = v || block
90
40
  end
91
41
 
92
- def method_missing(method, *args, &block)
93
- key = method.to_s.gsub('_', '-')
94
- if block
95
- child = DoubleHashDSL.new(block)
96
- @hash1[key] = child.hash1
97
- @hash2[key] = child.hash2
98
- else
99
- # Simulate method requiring 2 arguments
100
- raise ArgumentError, "wrong number of arguments(#{args.length} for 2)" unless args.length == 2
101
- @hash1[key] = args[0]
102
- @hash2[key] = args[1]
103
- end
42
+ def transform(&block)
43
+ @option.transform = block
104
44
  end
105
45
  end
106
46
  end
@@ -0,0 +1,3 @@
1
+ module Configru
2
+ Option = Struct.new(:type, :default, :validate, :transform)
3
+ end
@@ -0,0 +1,7 @@
1
+ module Configru
2
+ class StructHash < Hash
3
+ def method_missing(key)
4
+ self[key.to_s]
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module Configru
2
- VERSION = "0.5.0"
2
+ VERSION = "2.0.0"
3
3
  end
data/lib/configru.rb CHANGED
@@ -1,88 +1,110 @@
1
- $: << File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
2
-
3
- require 'configru/confighash'
4
1
  require 'configru/dsl'
2
+ require 'configru/option'
3
+ require 'configru/structhash'
5
4
 
6
5
  require 'yaml'
7
6
 
8
7
  module Configru
9
- class ConfigurationError < RuntimeError; end
10
-
11
- def self.load(load_method=:first, files=[], defaults={}, verify={}, &block)
12
- if block
13
- dsl = DSL::LoadDSL.new(block)
14
- @load_method = dsl.load_method
15
- @files = dsl.files_array.map {|x| File.expand_path(x)}
16
- @defaults = dsl.defaults_hash
17
- @verify = dsl.verify_hash
18
- else
19
- @load_method = load_method
20
- @files = files
21
- @defaults = defaults
22
- @verify = verify
8
+ class OptionError < RuntimeError
9
+ def initialize(path, message)
10
+ super("#{path.join('.')}: #{message}")
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
23
+ super(path, "failed validation `#{validation.inspect}`")
24
+ else
25
+ super(path, "failed validation")
26
+ end
23
27
  end
28
+ end
29
+
30
+ def self.load(*files, &block)
31
+ @files = files.flatten
32
+ @options = DSL::OptionGroup.new(&block).options
33
+ @root = StructHash.new
24
34
  self.reload
25
35
  end
26
36
 
27
37
  def self.reload
28
- @config = ConfigHash.new(@defaults)
29
- @loaded_files = []
30
-
31
- case @load_method
32
- when :first
33
- if file = @files.find {|file| File.file?(file)} # Intended
34
- @config.merge!(YAML.load_file(file) || {})
35
- @loaded_files << file
36
- end
37
- when :cascade
38
- @files.reverse_each do |file|
39
- if File.file?(file)
40
- @config.merge!(YAML.load_file(file) || {})
41
- @loaded_files << file
42
- end
38
+ loaded_files = []
39
+ @files.each do |file|
40
+ if File.file?(file) && !File.zero?(file)
41
+ self.load_file(file)
42
+ loaded_files << file
43
43
  end
44
44
  end
45
45
 
46
- self.verify(@config, @verify)
46
+ # Load all defaults if no files were loaded
47
+ # TODO: loaded_files as instance var?
48
+ # TODO: Better way to load defaults?
49
+ @option_path = []
50
+ self.load_group(@options, @root, {}) if loaded_files.empty?
47
51
  end
48
52
 
49
- @verify_stack = []
50
- def self.verify(hash, criteria)
51
- hash.each do |key, value|
52
- next unless criteria[key]
53
- @verify_stack.unshift(key)
54
-
55
- result = case criteria[key]
56
- when Hash
57
- self.verify(value, criteria[key])
58
- true # If it failed, an exception will have been raised
59
- when Array
60
- criteria[key].include?(value)
53
+ def self.load_file(file)
54
+ @option_path = []
55
+ self.load_group(@options, @root, YAML.load_file(file) || {})
56
+ end
57
+
58
+ def self.load_group(option_group, output, input)
59
+ option_group.each do |key, option|
60
+ @option_path << key
61
+
62
+ # option is a group
63
+ if option.is_a? Hash
64
+ if input.has_key?(key) && !input[key].is_a?(Hash)
65
+ raise OptionTypeError.new(@option_path, Hash, input[key].class)
66
+ end
67
+ group_output = output[key] || StructHash.new
68
+ self.load_group(option, group_output, input[key] || {})
69
+ output[key] = group_output
70
+ @option_path.pop
71
+ next
72
+ end
73
+
74
+ if input.include? key
75
+ value = input[key]
61
76
  else
62
- criteria[key] === value
77
+ value = option.default
63
78
  end
64
79
 
65
- raise ConfigurationError, "configuration option '#{@verify_stack.reverse.join('.')}' is invalid" unless result
80
+ unless value.is_a? option.type
81
+ raise OptionTypeError.new(@option_path, option.type, value.class)
82
+ end
66
83
 
67
- @verify_stack.shift
68
- end
69
- end
84
+ if option.validate.is_a? Proc
85
+ unless option.validate[value]
86
+ raise OptionValidationError.new(@option_path)
87
+ end
88
+ elsif option.validate
89
+ unless option.validate === value
90
+ raise OptionValidationError.new(@option_path, option.validate)
91
+ end
92
+ end
70
93
 
71
- def self.loaded_files
72
- @loaded_files
73
- end
94
+ output[key] = option.transform ? option.transform[value] : value
74
95
 
75
- def self.raw
76
- @config
96
+ @option_path.pop
97
+ end
77
98
  end
78
99
 
79
100
  def self.[](key)
80
- @config[key]
101
+ @root[key]
81
102
  end
82
103
 
83
- def self.method_missing(key, *args)
84
- # Simulate NoMethodError if it looks like they really wanted a method
85
- raise NoMethodError, "undefined method `#{key.to_s}' for #{self.inspect}:#{self.class}" unless args.empty?
86
- self[key]
104
+ def self.method_missing(method, *args)
105
+ # Let super raise the appropriate exception if it looks like the caller
106
+ # wants a real method
107
+ super(method, *args) unless args.empty?
108
+ @root.send(method)
87
109
  end
88
110
  end
@@ -0,0 +1,116 @@
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 hash' do
15
+ Configru.load do
16
+ option :example, String, 'example'
17
+ end
18
+
19
+ Configru['example'].should == 'example'
20
+ end
21
+
22
+ it 'loads defaults if no files exist' do
23
+ Configru.load(example_file :z) do
24
+ option :example, String, 'example'
25
+ end
26
+
27
+ Configru.example.should == 'example'
28
+ end
29
+
30
+ it 'loads defaults if file is empty' do
31
+ Configru.load(example_file :e) do
32
+ option :example, String, 'example'
33
+ end
34
+
35
+ Configru.example.should == 'example'
36
+ end
37
+
38
+ it 'loads defaults if file contains only whitespace' do
39
+ Configru.load(example_file :f) do
40
+ option :example, String, 'example'
41
+ end
42
+
43
+ Configru.example.should == 'example'
44
+ end
45
+
46
+ it 'loads a file' do
47
+ Configru.load(example_file :a) do
48
+ option :example
49
+ end
50
+
51
+ Configru.example.should == 'example_a'
52
+ end
53
+
54
+ it 'loads files in order' do
55
+ Configru.load(example_file(:a), example_file(:b)) do
56
+ option :example
57
+ end
58
+
59
+ Configru.example.should == 'example_b'
60
+ end
61
+
62
+ it 'loads a file with a group' do
63
+ Configru.load(example_file :c) do
64
+ option_group :example_group do
65
+ option :example
66
+ end
67
+ end
68
+
69
+ Configru.example_group.example.should == 'example_c'
70
+ end
71
+
72
+ it 'checks that group values are Hashes' do
73
+ expect do
74
+ Configru.load(example_file :a) do
75
+ option_group :example do
76
+ end
77
+ end
78
+ end.to raise_error(Configru::OptionTypeError)
79
+ end
80
+
81
+ it 'checks option types' do
82
+ expect do
83
+ Configru.load(example_file :d) do
84
+ option :string, String, ''
85
+ end
86
+ end.to raise_error(Configru::OptionTypeError)
87
+ end
88
+
89
+ it 'validates options against values' do
90
+ expect do
91
+ Configru.load(example_file :d) do
92
+ option :example, String, 'test', /test/
93
+ end
94
+ end.to raise_error(Configru::OptionValidationError)
95
+ end
96
+
97
+ it 'validates options against blocks' do
98
+ expect do
99
+ Configru.load(example_file :d) do
100
+ option :example, String, '' do
101
+ validate { false }
102
+ end
103
+ end
104
+ end.to raise_error(Configru::OptionValidationError)
105
+ end
106
+
107
+ it 'applies transformations to options' do
108
+ Configru.load(example_file :d) do
109
+ option :example, String, '' do
110
+ transform {|x| x + 't' }
111
+ end
112
+ end
113
+
114
+ Configru.example.should == 'example_dt'
115
+ end
116
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,111 @@
1
+ describe Configru::DSL::Option do
2
+ before do
3
+ @option = Configru::Option.new(:type, :default, :validate, :transform)
4
+ end
5
+
6
+ it 'sets option type' do
7
+ described_class.new(@option) do
8
+ type String
9
+ end
10
+
11
+ @option.type.should == String
12
+ end
13
+
14
+ it 'sets option default' do
15
+ described_class.new(@option) do
16
+ default 'Example'
17
+ end
18
+
19
+ @option.default.should == 'Example'
20
+ end
21
+
22
+ it 'sets option validate value' do
23
+ described_class.new(@option) do
24
+ validate /example/
25
+ end
26
+
27
+ @option.validate.should == /example/
28
+ end
29
+
30
+ it 'sets option validate block' do
31
+ described_class.new(@option) do
32
+ validate do
33
+ :example
34
+ end
35
+ end
36
+
37
+ @option.validate.should be_a(Proc)
38
+ @option.validate.call.should == :example
39
+ end
40
+
41
+ it 'sets option transofmr block' do
42
+ described_class.new(@option) do
43
+ transform do
44
+ :example
45
+ end
46
+ end
47
+
48
+ @option.transform.should be_a(Proc)
49
+ @option.transform.call.should == :example
50
+ end
51
+ end
52
+
53
+ describe Configru::DSL::OptionGroup do
54
+ it 'creates an option' do
55
+ group = described_class.new do
56
+ option 'example'
57
+ end
58
+
59
+ group.options.should have_key('example')
60
+ group.options['example'].should be_a(Configru::Option)
61
+ end
62
+
63
+ it 'converts option names to strings' do
64
+ group = described_class.new do
65
+ option :example
66
+ end
67
+
68
+ group.options.should have_key('example')
69
+ end
70
+
71
+ it 'creates a default option' do
72
+ group = described_class.new do
73
+ option 'example'
74
+ end
75
+
76
+ group.options['example'].type.should == Object
77
+ group.options['example'].default.should be_nil
78
+ group.options['example'].validate.should be_nil
79
+ group.options['example'].transform.should be_nil
80
+ end
81
+
82
+ it 'runs the Option DSL' do
83
+ group = described_class.new do
84
+ option 'example' do
85
+ type String
86
+ end
87
+ end
88
+
89
+ group.options['example'].type.should == String
90
+ end
91
+
92
+ it 'creates a group' do
93
+ group = described_class.new do
94
+ option_group 'example' do
95
+ option 'nested'
96
+ end
97
+ end
98
+
99
+ group.options['example'].should be_a(Hash)
100
+ group.options['example'].should have_key('nested')
101
+ end
102
+
103
+ it 'converts group names to strings' do
104
+ group = described_class.new do
105
+ option_group :example do
106
+ end
107
+ end
108
+
109
+ group.options.should have_key('example')
110
+ end
111
+ end
@@ -0,0 +1 @@
1
+ example: example_a
@@ -0,0 +1 @@
1
+ example: example_b
@@ -0,0 +1,2 @@
1
+ example_group:
2
+ example: example_c
@@ -0,0 +1,2 @@
1
+ string: 1
2
+ example: example_d
File without changes
@@ -0,0 +1,2 @@
1
+
2
+
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ add_filter '/spec/'
6
+ end
7
+
8
+ require 'rspec'
9
+ require 'configru'
@@ -0,0 +1,18 @@
1
+ describe Configru::StructHash do
2
+ before do
3
+ @hash = Configru::StructHash.new
4
+ end
5
+
6
+ it 'is a hash' do
7
+ @hash.should be_a_kind_of(Hash)
8
+ end
9
+
10
+ it 'returns nil for missing method key' do
11
+ @hash.example.should be_nil
12
+ end
13
+
14
+ it 'returns value for method key' do
15
+ @hash['example'] = :example
16
+ @hash.example.should == :example
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: configru
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,9 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-28 00:00:00.000000000 Z
12
+ date: 2012-06-20 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: Versatile configuration file loader
14
+ description: YAML configuration file loader
15
15
  email:
16
16
  - programble@gmail.com
17
17
  executables: []
@@ -19,19 +19,29 @@ extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
21
  - .gitignore
22
+ - .rspec
23
+ - .travis.yml
22
24
  - ChangeLog.md
23
25
  - Gemfile
26
+ - Gemfile.lock
24
27
  - README.md
25
28
  - Rakefile
26
29
  - configru.gemspec
27
30
  - lib/configru.rb
28
- - lib/configru/confighash.rb
29
31
  - lib/configru/dsl.rb
32
+ - lib/configru/option.rb
33
+ - lib/configru/structhash.rb
30
34
  - lib/configru/version.rb
31
- - test/confighash_test.rb
32
- - test/hashdsl_test.rb
33
- - test/loaddsl_test.rb
34
- - test/teststrap.rb
35
+ - spec/configru_spec.rb
36
+ - spec/dsl_spec.rb
37
+ - spec/example_files/example_a.yml
38
+ - spec/example_files/example_b.yml
39
+ - spec/example_files/example_c.yml
40
+ - spec/example_files/example_d.yml
41
+ - spec/example_files/example_e.yml
42
+ - spec/example_files/example_f.yml
43
+ - spec/spec_helper.rb
44
+ - spec/structhash_spec.rb
35
45
  homepage: https://github.com/programble/configru
36
46
  licenses: []
37
47
  post_install_message:
@@ -44,20 +54,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
44
54
  - - ! '>='
45
55
  - !ruby/object:Gem::Version
46
56
  version: '0'
57
+ segments:
58
+ - 0
59
+ hash: -2633773784802344253
47
60
  required_rubygems_version: !ruby/object:Gem::Requirement
48
61
  none: false
49
62
  requirements:
50
63
  - - ! '>='
51
64
  - !ruby/object:Gem::Version
52
65
  version: '0'
66
+ segments:
67
+ - 0
68
+ hash: -2633773784802344253
53
69
  requirements: []
54
70
  rubyforge_project:
55
71
  rubygems_version: 1.8.11
56
72
  signing_key:
57
73
  specification_version: 3
58
- summary: Versatile configuration file loader
74
+ summary: YAML configuration file loader
59
75
  test_files:
60
- - test/confighash_test.rb
61
- - test/hashdsl_test.rb
62
- - test/loaddsl_test.rb
63
- - test/teststrap.rb
76
+ - spec/configru_spec.rb
77
+ - spec/dsl_spec.rb
78
+ - spec/example_files/example_a.yml
79
+ - spec/example_files/example_b.yml
80
+ - spec/example_files/example_c.yml
81
+ - spec/example_files/example_d.yml
82
+ - spec/example_files/example_e.yml
83
+ - spec/example_files/example_f.yml
84
+ - spec/spec_helper.rb
85
+ - spec/structhash_spec.rb
@@ -1,33 +0,0 @@
1
- module Configru
2
- class ConfigHash < Hash
3
- def initialize(hash={})
4
- super
5
- merge!(hash)
6
- end
7
-
8
- def merge!(hash)
9
- hash.each do |key, value|
10
- if value.is_a?(Hash) && self[key].is_a?(ConfigHash)
11
- self[key].merge!(value)
12
- elsif value.is_a?(Hash)
13
- self[key] = ConfigHash.new(value)
14
- else
15
- self[key] = value
16
- end
17
- end
18
- end
19
-
20
- def [](key)
21
- key = key.to_s if key.is_a?(Symbol)
22
- # Allow for accessing keys with hyphens using underscores
23
- key = key.gsub('_', '-') unless self.include?(key)
24
- # For some reason, super(key) returns {} instead of nil when the key
25
- # doesn't exist :\
26
- super(key) if self.include?(key)
27
- end
28
-
29
- def method_missing(key, *args)
30
- self[key]
31
- end
32
- end
33
- end
@@ -1,63 +0,0 @@
1
- require 'teststrap'
2
-
3
- context 'ConfigHash - ' do
4
- setup { Configru::ConfigHash.new }
5
-
6
- context 'empty' do
7
- asserts('[:quux]') { topic[:quux] }.nil
8
- asserts(:quux).nil
9
- end
10
-
11
- context 'non-empty' do
12
- hookup do
13
- topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
14
- end
15
-
16
- # Testing access methods
17
- asserts("['foo']") { topic['foo'] }.equals(1)
18
- asserts('[:foo]') { topic[:foo] }.equals(1)
19
- asserts(:foo).equals(1)
20
- end
21
-
22
- context 'overwriting a value by merge' do
23
- hookup do
24
- topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
25
- topic.merge!({'bar' => 4})
26
- end
27
- asserts(:bar).equals(4)
28
- end
29
-
30
- context 'merging a nested Hash' do
31
- hookup do
32
- topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
33
- topic.merge!({'bar' => 4})
34
- topic.merge!({'baz' => {'quux' => 5}})
35
- end
36
-
37
- asserts(:baz).kind_of(Configru::ConfigHash)
38
- asserts('baz.quux') { topic.baz.quux }.equals(5)
39
- end
40
-
41
- context 'recursively merging a nested Hash' do
42
- hookup do
43
- topic.merge!({'foo' => 1, 'bar' => 2, 'baz' => 3})
44
- topic.merge!({'bar' => 4})
45
- topic.merge!({'baz' => {'quux' => 5}})
46
- topic.merge!({'baz' => {'apple' => 6}})
47
- end
48
-
49
- asserts(:baz).kind_of(Configru::ConfigHash)
50
- asserts('baz.apple') { topic.baz.apple }.equals(6)
51
- asserts('baz.quux') { topic.baz.quux }.equals(5)
52
- end
53
-
54
- context 'keys with hyphens' do
55
- hookup do
56
- topic.merge!({'foo-bar-baz' => 1})
57
- end
58
-
59
- asserts('foo_bar_baz') { topic.foo_bar_baz }.equals(1)
60
- asserts('[:foo_bar_baz]') { topic[:foo_bar_baz] }.equals(1)
61
- asserts("['foo_bar_baz']") { topic['foo_bar_baz'] }.equals(1)
62
- end
63
- end
data/test/hashdsl_test.rb DELETED
@@ -1,83 +0,0 @@
1
- require 'teststrap'
2
- require 'configru/dsl'
3
-
4
- context 'HashDSL - flat' do
5
- setup do
6
- block = proc do
7
- foo 1
8
- bar 2
9
- end
10
- Configru::DSL::HashDSL.new(block).hash
11
- end
12
-
13
- asserts_topic.equals({'foo' => 1, 'bar' => 2})
14
- end
15
-
16
- context 'HashDSL - nested' do
17
- setup do
18
- block = proc do
19
- foo 1
20
- bar do
21
- baz 2
22
- quux 3
23
- end
24
- end
25
- Configru::DSL::HashDSL.new(block).hash
26
- end
27
-
28
- asserts_topic.equals({'foo' => 1, 'bar' => {'baz' => 2, 'quux' => 3}})
29
- end
30
-
31
- context 'HashDSL - keys with underscores' do
32
- setup do
33
- block = proc do
34
- foo_bar 1
35
- baz_quux 2
36
- end
37
- Configru::DSL::HashDSL.new(block).hash
38
- end
39
-
40
- asserts_topic.equals({'foo-bar' => 1, 'baz-quux' => 2})
41
- end
42
-
43
- context 'DoubleHashDSL - flat' do
44
- setup do
45
- block = proc do
46
- foo 1, 2
47
- bar 3, 4
48
- end
49
- Configru::DSL::DoubleHashDSL.new(block)
50
- end
51
-
52
- asserts(:hash1).equals({'foo' => 1, 'bar' => 3})
53
- asserts(:hash2).equals({'foo' => 2, 'bar' => 4})
54
- end
55
-
56
- context 'DoubleHashDSL - nested' do
57
- setup do
58
- block = proc do
59
- foo 1, 2
60
- bar do
61
- baz 3, 4
62
- quux 5, 6
63
- end
64
- end
65
- Configru::DSL::DoubleHashDSL.new(block)
66
- end
67
-
68
- asserts(:hash1).equals({'foo' => 1, 'bar' => {'baz' => 3, 'quux' => 5}})
69
- asserts(:hash2).equals({'foo' => 2, 'bar' => {'baz' => 4, 'quux' => 6}})
70
- end
71
-
72
- context 'DoubleHashDSL - keys with underscores' do
73
- setup do
74
- block = proc do
75
- foo_bar 1, 2
76
- baz_quux 3, 4
77
- end
78
- Configru::DSL::DoubleHashDSL.new(block)
79
- end
80
-
81
- asserts(:hash1).equals({'foo-bar' => 1, 'baz-quux' => 3})
82
- asserts(:hash2).equals({'foo-bar' => 2, 'baz-quux' => 4})
83
- end
data/test/loaddsl_test.rb DELETED
@@ -1,24 +0,0 @@
1
- require 'teststrap'
2
- require 'configru/dsl'
3
-
4
- context 'LoadDSL - Files' do
5
- setup do
6
- block = proc do
7
- cascade 'a', 'b', 'c'
8
- end
9
- Configru::DSL::LoadDSL.new(block).files_array
10
- end
11
-
12
- asserts_topic.equals(['a', 'b', 'c'])
13
- end
14
-
15
- context 'LoadDSL - File-directories' do
16
- setup do
17
- block = proc do
18
- cascade 'a', ['b', 'c']
19
- end
20
- Configru::DSL::LoadDSL.new(block).files_array
21
- end
22
-
23
- asserts_topic.equals([File.join('b', 'a'), File.join('c', 'a')])
24
- end
data/test/teststrap.rb DELETED
@@ -1,11 +0,0 @@
1
- require 'bundler'
2
- begin
3
- Bundler.setup(:default, :development)
4
- rescue Bundler::BundlerError => e
5
- $stderr.puts e.message
6
- $stderr.puts "Run `bundle install` to install missing gems"
7
- exit e.status_code
8
- end
9
- require 'riot'
10
- require 'configru'
11
-