configru 0.5.0 → 2.0.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.
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
-