sugarfree-config 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +22 -0
- data/LICENSE +1 -1
- data/README.rdoc +47 -44
- data/Rakefile +9 -0
- data/lib/sugarfree-config/config.rb +128 -0
- data/lib/sugarfree-config/exceptions.rb +27 -0
- data/lib/sugarfree-config/version.rb +3 -0
- data/lib/sugarfree-config.rb +10 -141
- data/specs/config_spec.rb +155 -0
- data/specs/exceptions_spec.rb +8 -0
- data/specs/spec_helper.rb +9 -0
- data/specs/sugarfree_spec.rb +64 -0
- data/sugarfree-config.gemspec +21 -0
- metadata +59 -41
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sugarfree-config (2.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ansi (1.3.0)
|
10
|
+
metaclass (0.0.1)
|
11
|
+
mocha (0.10.0)
|
12
|
+
metaclass (~> 0.0.1)
|
13
|
+
turn (0.8.2)
|
14
|
+
ansi (>= 1.2.2)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
mocha
|
21
|
+
sugarfree-config!
|
22
|
+
turn
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,51 +1,64 @@
|
|
1
|
-
=
|
1
|
+
= sugarfree-config
|
2
2
|
|
3
3
|
Configuration handling the easy way.
|
4
4
|
|
5
|
-
|
6
|
-
stored in a YAML file.
|
7
|
-
|
8
|
-
SugarfreeConfig only works with Rails! since SugarfreecConfig 1.1.0 works
|
9
|
-
with rails 3 and ruby 1.9.1
|
5
|
+
sugarfree-config allows easy access to per environment config values
|
6
|
+
stored in a YAML file in Rails and non Rails applications.
|
10
7
|
|
11
8
|
== Installation
|
12
9
|
|
13
|
-
Just install the gem from
|
14
|
-
|
15
|
-
$ gem install sugarfree-config --source http://gemcutter.org
|
16
|
-
|
17
|
-
== Notes on rails 3
|
18
|
-
|
19
|
-
In rails 2.x gems were required after Rails.root was initialized. Default rails 3.0
|
20
|
-
application generator uses Bundler, and auto-requires all gems before application
|
21
|
-
initialization. This could be solved forcing the bundler not to require the gem.
|
22
|
-
In your Gemfile:
|
23
|
-
|
24
|
-
gem 'problematic-gem', :require => false
|
10
|
+
Just install the gem manually from rubygems.org or add it to your bundle.
|
25
11
|
|
26
|
-
|
27
|
-
|
28
|
-
require 'problematic-gem'
|
12
|
+
$ gem install sugarfree-config
|
29
13
|
|
30
14
|
== Usage
|
31
15
|
|
32
|
-
|
33
|
-
at least a section for each RAILS_ENV
|
34
|
-
|
35
|
-
Configuration can be accessed like this
|
16
|
+
Configuration can be accessed using method calls:
|
36
17
|
|
37
18
|
SugarfreeConfig.a.b.c #=> 'value'
|
38
19
|
|
39
|
-
which will expect a config file like (given development env)
|
20
|
+
which will expect a config.yml file like the one below (given development env)
|
21
|
+
stored in the config folder (in Rails apps) or the root folder (in non Rails apps):
|
40
22
|
|
41
23
|
development:
|
42
24
|
a:
|
43
25
|
b:
|
44
26
|
c: 'value'
|
45
27
|
|
46
|
-
|
28
|
+
If asking for akey that does not exists ConfigKeyException will be raised.
|
29
|
+
|
30
|
+
A convinience to_hash method is also provided:
|
31
|
+
|
32
|
+
SugarfreeConfig.a.to_hash #=> { 'b' => { 'c' => 'value' } }
|
33
|
+
|
34
|
+
== Configuration
|
47
35
|
|
48
|
-
|
36
|
+
sugarfree-config can be used with or without Rails. Default configurations are
|
37
|
+
provided for each case. Default configurations can be overriden the explicit use
|
38
|
+
of the SugarfreeConfig::init method.
|
39
|
+
|
40
|
+
To set the configuration you need to initialize the SugarfreeConfig class:
|
41
|
+
|
42
|
+
SugarfreeConfig.init :env => 'development', :file => 'my_config.yml', :reload => true
|
43
|
+
|
44
|
+
# Default options in Rails apps
|
45
|
+
SugarfreeConfig.init({
|
46
|
+
:env => Rails.env,
|
47
|
+
:file => Rails.root.join('config', 'config.yml'),
|
48
|
+
:reload => Rails.env.development?
|
49
|
+
})
|
50
|
+
|
51
|
+
# Default options in non Rails apps
|
52
|
+
SugarfreeConfig.init({
|
53
|
+
:env => 'development',
|
54
|
+
:file => File.expand_path('config.yml'),
|
55
|
+
:reload => false
|
56
|
+
})
|
57
|
+
|
58
|
+
|
59
|
+
== Gotchas
|
60
|
+
|
61
|
+
Configuration is accessed through a ConfigIterator class which (as its name says) is
|
49
62
|
an iterator and cannot be reused. However there is a workaround to allow the
|
50
63
|
repeated use of scoped iterators.
|
51
64
|
|
@@ -59,25 +72,15 @@ repeated use of scoped iterators.
|
|
59
72
|
a_config.dup.b.c #=> 'value'
|
60
73
|
a_config.dup.b.c #=> 'value'
|
61
74
|
|
62
|
-
== Further customization
|
63
|
-
|
64
|
-
By default Sugarfree-config caches in memory the YAML file. If you want the gem
|
65
|
-
to reload this file each time a value is accessed (like in development mode)
|
66
|
-
you must force the initialization of the SugarfreeConfig module.
|
67
75
|
|
68
|
-
|
76
|
+
== Compatibility
|
69
77
|
|
70
|
-
|
71
|
-
|
72
|
-
class Object
|
73
|
-
# For people who prefer app_config.a.b.c instead of SugarfreeConfig.a.b.c
|
74
|
-
def app_config
|
75
|
-
SugarfreeConfig
|
76
|
-
end
|
77
|
-
end
|
78
|
+
SugarfreeConfig 2.0.0 has been developed and tested against Ruby 1.9.2 and Rails 3.x.
|
79
|
+
Older versions of Ruby and Rails may also work. Just give it a try ;)
|
78
80
|
|
79
81
|
== Contact
|
80
82
|
|
81
|
-
Please
|
82
|
-
|
83
|
+
Please use GitHub (https://github.com/davidbarral/sugarfree-config) to report bugs,
|
84
|
+
make suggestions or send patches.
|
85
|
+
|
83
86
|
|
data/Rakefile
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SugarfreeConfig
|
4
|
+
|
5
|
+
#
|
6
|
+
# Config base object. Caches the configuration in memory an acts as a factory
|
7
|
+
# for the ConfigIterators needed to get config values
|
8
|
+
#
|
9
|
+
class Config
|
10
|
+
|
11
|
+
#
|
12
|
+
# Creates a new config object and load the config file into memory
|
13
|
+
#
|
14
|
+
def initialize(options)
|
15
|
+
options = default_options.merge(options)
|
16
|
+
|
17
|
+
@file = options[:file]
|
18
|
+
@reload = options[:reload]
|
19
|
+
@env = options[:env]
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Returns all the config as a big hash
|
24
|
+
#
|
25
|
+
def to_hash
|
26
|
+
values
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Here is the magic. The first request to config returns a new
|
31
|
+
# ConfigIterator that will handle the first +symbol+
|
32
|
+
#
|
33
|
+
def method_missing(symbol, *args)
|
34
|
+
ConfigIterator.new(values, symbol).next
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def values
|
40
|
+
@config = fetch_config unless @config && !@reload
|
41
|
+
@config
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Fetch the config from the file
|
46
|
+
#
|
47
|
+
def fetch_config
|
48
|
+
Rails.logger.debug "Loading #{@file}::#{@env}" if Object.const_defined?('Rails')
|
49
|
+
YAML::load_file(@file)[@env.to_s]
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Default configuration options for Rails and non Rails applications
|
54
|
+
#
|
55
|
+
def default_options
|
56
|
+
if Object.const_defined?('Rails')
|
57
|
+
{
|
58
|
+
:file => Rails.root.join('config', 'config.yml'),
|
59
|
+
:reload => Rails.env.development?,
|
60
|
+
:env => Rails.env
|
61
|
+
}
|
62
|
+
else
|
63
|
+
{
|
64
|
+
:file => File.expand_path("config.yml"),
|
65
|
+
:reload => false,
|
66
|
+
:env => "development"
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Config Iterator. Given a configuration hash it can navigate trough the
|
74
|
+
# values using method calls that will be translated into hash keys and
|
75
|
+
# indexed
|
76
|
+
#
|
77
|
+
class ConfigIterator
|
78
|
+
|
79
|
+
#
|
80
|
+
# Create a new iterator with a given +configuration+ and the first
|
81
|
+
# element of the path to be iterated (+first_path_element+)
|
82
|
+
#
|
83
|
+
def initialize(configuration, first_path_element)
|
84
|
+
@scoped_config = configuration
|
85
|
+
@path_elements = [first_path_element.to_s]
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Returns the current scope as a hash. Usefull to get a Big hash of config
|
90
|
+
# that will be used later.
|
91
|
+
#
|
92
|
+
def to_hash
|
93
|
+
@scoped_config
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Here is the magic. When an unknown symbol is passed this symbol is set
|
98
|
+
# as the last path element of this iteration, and the iterator is then
|
99
|
+
# forced to make that movement
|
100
|
+
#
|
101
|
+
def method_missing(symbol, *args)
|
102
|
+
@path_elements << symbol.to_s
|
103
|
+
self.next
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Iterate to the next element in the path
|
108
|
+
#
|
109
|
+
# Algorithm:
|
110
|
+
# 1. Get the last element of the key path
|
111
|
+
# 2. Try to find it in the scoped config
|
112
|
+
# 3. If not present raise an error
|
113
|
+
# 4. If present and is a hash we are not in a config leaf, so the scoped
|
114
|
+
# config is reset to this new value and self is returned
|
115
|
+
# 5. If present and is a value then return the value
|
116
|
+
#
|
117
|
+
def next
|
118
|
+
if (value = @scoped_config[@path_elements.last]).nil?
|
119
|
+
raise ConfigKeyException.new(@path_elements)
|
120
|
+
elsif value.is_a?(Hash)
|
121
|
+
@scoped_config = value
|
122
|
+
self
|
123
|
+
else
|
124
|
+
value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SugarfreeConfig
|
2
|
+
#
|
3
|
+
# Exception raised by the module on unexpected behaviors
|
4
|
+
#
|
5
|
+
class ConfigException < Exception
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# Exception raised by the Config Iterator when a key is not found
|
10
|
+
#
|
11
|
+
class ConfigKeyException < ConfigException
|
12
|
+
|
13
|
+
#
|
14
|
+
# Config key path (as a key collection) that failed
|
15
|
+
#
|
16
|
+
attr_accessor :key_path_elements
|
17
|
+
|
18
|
+
#
|
19
|
+
# Create a new exception with the not found key paths (+key_path_elements+
|
20
|
+
# Array)
|
21
|
+
#
|
22
|
+
def initialize(key_path_elements)
|
23
|
+
self.key_path_elements = [*key_path_elements].map(&:to_s)
|
24
|
+
super("Cannot find key #{self.key_path_elements.join('.')}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/sugarfree-config.rb
CHANGED
@@ -1,155 +1,24 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
require 'sugarfree-config/exceptions'
|
3
|
+
require 'sugarfree-config/config'
|
4
|
+
|
2
5
|
# Sugarfree config allows easy access to the config values.
|
3
6
|
#
|
4
|
-
# See README.
|
7
|
+
# See README.rdoc for usage info
|
5
8
|
#
|
6
9
|
module SugarfreeConfig
|
7
10
|
|
8
11
|
class << self
|
9
12
|
attr_reader :config
|
10
|
-
def init(force_reload = false)
|
11
|
-
@config = Config.new(force_reload)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.method_missing(*args)
|
16
|
-
init unless SugarfreeConfig.config
|
17
|
-
SugarfreeConfig.config.send(*args)
|
18
|
-
end
|
19
|
-
|
20
|
-
#
|
21
|
-
# Exception raised by the module on unexpected behaviors
|
22
|
-
#
|
23
|
-
class ConfigException < Exception
|
24
|
-
end
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
class ConfigKeyException < ConfigException
|
30
|
-
|
31
|
-
#
|
32
|
-
# Config key path (as a key collection) that failed
|
33
|
-
#
|
34
|
-
attr_accessor :key_path_elements
|
35
|
-
|
36
|
-
#
|
37
|
-
# Create a new exception with the not found key paths (+key_path_elements+
|
38
|
-
# Array)
|
39
|
-
#
|
40
|
-
def initialize(key_path_elements)
|
41
|
-
self.key_path_elements = [*key_path_elements].map(&:to_s)
|
42
|
-
super("Cannot find key #{self.key_path_elements.join('.')}")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
#
|
47
|
-
# Config base object. Caches the configuration in memory an acts as a factory
|
48
|
-
# for the ConfigIterators needed to get config values
|
49
|
-
#
|
50
|
-
class Config
|
51
|
-
|
52
|
-
#
|
53
|
-
# Conifg file is expected at "#{RAILS_ROOT}/config/config.yml"
|
54
|
-
#
|
55
|
-
DEFAULT_CONFIG_FILE = Rails.root.join('config', 'config.yml')
|
56
|
-
|
57
|
-
def values
|
58
|
-
@values = fetch_config unless @values && !@force_reload
|
59
|
-
@values
|
14
|
+
def init(options = {})
|
15
|
+
@config = Config.new(options)
|
60
16
|
end
|
61
17
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def initialize(force_reload = false)
|
66
|
-
@force_reload = force_reload
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# Returns all the config as a big hash
|
71
|
-
#
|
72
|
-
def to_hash
|
73
|
-
@values
|
74
|
-
end
|
75
|
-
|
76
|
-
#
|
77
|
-
# Here is the magic. The first request to config returns a new
|
78
|
-
# ConfigIterator that will handle the first +symbol+
|
79
|
-
#
|
80
|
-
def method_missing(symbol, *args)
|
81
|
-
ConfigIterator.new(values, symbol).next
|
82
|
-
end
|
83
|
-
|
84
|
-
protected
|
85
|
-
|
86
|
-
#
|
87
|
-
# Fetch the config from the file
|
88
|
-
#
|
89
|
-
def fetch_config
|
90
|
-
if Object.const_defined?('RAILS_DEFAULT_LOGGER') && RAILS_DEFAULT_LOGGER.debug?
|
91
|
-
RAILS_DEFAULT_LOGGER.debug "Loading #{DEFAULT_CONFIG_FILE}::#{RAILS_ENV}"
|
92
|
-
end
|
93
|
-
HashWithIndifferentAccess.new(YAML::load(File.new(DEFAULT_CONFIG_FILE))[RAILS_ENV])
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
#
|
98
|
-
# Config Iterator. Given a configuration hash it can navigate trough the
|
99
|
-
# values using method calls that will be translated into hash keys and
|
100
|
-
# indexed
|
101
|
-
#
|
102
|
-
class ConfigIterator
|
103
|
-
|
104
|
-
#
|
105
|
-
# Create a new iterator with a given +configuration+ and the first
|
106
|
-
# element of the path to be iterated (+first_path_element+)
|
107
|
-
#
|
108
|
-
def initialize(configuration, first_path_element)
|
109
|
-
@scoped_config = configuration
|
110
|
-
@path_elements = [first_path_element]
|
111
|
-
end
|
112
|
-
|
113
|
-
#
|
114
|
-
# Returns the current scope as a hash. Usefull to get a Big hash of config
|
115
|
-
# that will be used later.
|
116
|
-
#
|
117
|
-
def to_hash
|
118
|
-
@scoped_config
|
119
|
-
end
|
120
|
-
|
121
|
-
#
|
122
|
-
# Iterate to the next element in the path
|
123
|
-
#
|
124
|
-
# Algorithm:
|
125
|
-
# 1. Get the last element of the key path
|
126
|
-
# 2. Try to find it in the scoped config.
|
127
|
-
# 3. If not present raise an error
|
128
|
-
# 4. If present and is a hash we are not in a config leaf, so the scoped
|
129
|
-
# config is reset to this new value and self is returned
|
130
|
-
# 5. If present and is a value then return the value
|
131
|
-
#
|
132
|
-
def next
|
133
|
-
if (value = @scoped_config[@path_elements.last]).nil?
|
134
|
-
raise ConfigKeyException.new(@path_elements)
|
135
|
-
elsif value.is_a?(Hash)
|
136
|
-
@scoped_config = value
|
137
|
-
self
|
138
|
-
else
|
139
|
-
value
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
#
|
144
|
-
# Here is the magic. When an unknown symbol is passed this symbol is set
|
145
|
-
# as the last path element of this iteration, and the iterator is then
|
146
|
-
# forced to make that movement
|
147
|
-
#
|
148
|
-
def method_missing(symbol, *args)
|
149
|
-
@path_elements << symbol
|
150
|
-
self.next
|
18
|
+
def method_missing(*args)
|
19
|
+
init unless SugarfreeConfig.config
|
20
|
+
SugarfreeConfig.config.send(*args)
|
151
21
|
end
|
152
22
|
end
|
153
|
-
|
154
23
|
end
|
155
24
|
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Config" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config = {
|
7
|
+
'an_env' => {
|
8
|
+
'l1' => {
|
9
|
+
'l2' => 'a'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "initialize with no params for non rails apps" do
|
16
|
+
it "should return default values" do
|
17
|
+
Object.stubs(:const_defined?).with('Rails').returns(false)
|
18
|
+
h = mock()
|
19
|
+
h.expects(:'[]').with('development').once().returns({})
|
20
|
+
YAML.expects(:load_file).with(File.expand_path("config.yml")).once().returns(h)
|
21
|
+
|
22
|
+
c = SugarfreeConfig::Config.new({})
|
23
|
+
c.to_hash
|
24
|
+
c.to_hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "initialize with no params for rails apps" do
|
29
|
+
|
30
|
+
#
|
31
|
+
# Yehaaaa! I know it's awful
|
32
|
+
#
|
33
|
+
it "should return default values" do
|
34
|
+
Object.stubs(:const_defined?).with('Rails').returns(true)
|
35
|
+
|
36
|
+
rails_root = mock()
|
37
|
+
rails_root.expects(:join).once().with('config', 'config.yml').returns("/rails_root/config/config.yml")
|
38
|
+
|
39
|
+
rails_logger = mock()
|
40
|
+
rails_logger.expects(:debug).once().with("Loading /rails_root/config/config.yml::production")
|
41
|
+
|
42
|
+
String.any_instance.stubs(:development?).returns(false)
|
43
|
+
|
44
|
+
Rails = mock()
|
45
|
+
Rails.stubs(:root).returns(rails_root)
|
46
|
+
Rails.stubs(:env).returns("production")
|
47
|
+
Rails.stubs(:logger).returns(rails_logger)
|
48
|
+
|
49
|
+
h = mock()
|
50
|
+
h.expects(:'[]').with('production').once().returns({})
|
51
|
+
YAML.expects(:load_file).with("/rails_root/config/config.yml").once.returns(h)
|
52
|
+
|
53
|
+
c = SugarfreeConfig::Config.new({})
|
54
|
+
c.to_hash
|
55
|
+
c.to_hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "reloading" do
|
60
|
+
it "should reload the configuration if set to" do
|
61
|
+
Object.stubs(:const_defined?).with('Rails').returns(false)
|
62
|
+
YAML.expects(:load_file).twice().returns(@config)
|
63
|
+
|
64
|
+
c = SugarfreeConfig::Config.new(:reload => true, :env => 'an_env')
|
65
|
+
c.to_hash
|
66
|
+
c.to_hash
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not reload the configuration" do
|
70
|
+
Object.stubs(:const_defined?).with('Rails').returns(false)
|
71
|
+
YAML.expects(:load_file).once.returns(@config)
|
72
|
+
|
73
|
+
SugarfreeConfig::Config.new(:reload => false, :env => 'an_env').to_hash
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "to_hash" do
|
78
|
+
it "should return the base config for a given env" do
|
79
|
+
Object.stubs(:const_defined?).with('Rails').returns(false)
|
80
|
+
YAML.stubs(:load_file).returns(@config)
|
81
|
+
|
82
|
+
c = SugarfreeConfig::Config.new(:env => 'an_env')
|
83
|
+
c.to_hash.must_equal @config['an_env']
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "method_missing" do
|
88
|
+
it "should return an scoped iterator config" do
|
89
|
+
Object.stubs(:const_defined?).with('Rails').returns(false)
|
90
|
+
YAML.stubs(:load_file).returns(@config)
|
91
|
+
|
92
|
+
c = SugarfreeConfig::Config.new(:env => 'an_env')
|
93
|
+
ci = c.l1
|
94
|
+
ci.must_be_instance_of SugarfreeConfig::ConfigIterator
|
95
|
+
ci.to_hash.must_equal @config['an_env']['l1']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
describe "ConfigIterator" do
|
102
|
+
|
103
|
+
before do
|
104
|
+
@config = {
|
105
|
+
'l1' => {
|
106
|
+
'l2a' => {
|
107
|
+
'l3' => 'a'
|
108
|
+
},
|
109
|
+
'l2b' => 'b'
|
110
|
+
}
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def iterator(config,key)
|
115
|
+
SugarfreeConfig::ConfigIterator.new(config, key)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
describe "to_hash" do
|
120
|
+
it "should return the scoped config" do
|
121
|
+
ci = iterator(@config, :l1)
|
122
|
+
|
123
|
+
ci.to_hash.must_equal @config
|
124
|
+
ci.next.to_hash.must_equal @config['l1']
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "method_missing" do
|
129
|
+
it "should move the iterator" do
|
130
|
+
ci = iterator(@config, :l1)
|
131
|
+
ci.to_hash.wont_equal ci.next.to_hash
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "next" do
|
137
|
+
|
138
|
+
it "should raise an exception when key is not available" do
|
139
|
+
ci = iterator(@config, :unknown_key)
|
140
|
+
lambda { ci.next }.must_raise SugarfreeConfig::ConfigKeyException
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should return a value if iterated node is a leaf" do
|
144
|
+
iterator(@config['l1'], :l2b).next.must_equal 'b'
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return self and change iterator state if iterated node is not leaf" do
|
148
|
+
ci = iterator(@config, :l1)
|
149
|
+
cii = ci.next
|
150
|
+
cii.must_be_same_as ci
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ConfigKeyException" do
|
4
|
+
it "keeps the path elements that caused the exception as a String array" do
|
5
|
+
SugarfreeConfig::ConfigKeyException.new(:el1).key_path_elements.must_equal(["el1"])
|
6
|
+
SugarfreeConfig::ConfigKeyException.new([:el1, :el2]).key_path_elements.must_equal(["el1", "el2"])
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "SugarfreeConfig" do
|
4
|
+
|
5
|
+
describe "config" do
|
6
|
+
it "should create a Config with the given options" do
|
7
|
+
opts = { :o1 => 2, :o2 => 2 }
|
8
|
+
SugarfreeConfig::Config.expects(:new).once().with(opts)
|
9
|
+
SugarfreeConfig.init(opts)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "method_missing" do
|
14
|
+
it "should create a Config and delegate" do
|
15
|
+
config = mock()
|
16
|
+
config.expects(:send).with(:test1)
|
17
|
+
config.expects(:send).with(:test2)
|
18
|
+
SugarfreeConfig::Config.expects(:new).once().returns(config)
|
19
|
+
|
20
|
+
SugarfreeConfig.test1
|
21
|
+
SugarfreeConfig.test2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
describe "SugarfreeConfig delegation" do
|
28
|
+
|
29
|
+
before do
|
30
|
+
@config = {
|
31
|
+
'development' => {
|
32
|
+
'simple_config_key' => 1234,
|
33
|
+
'nested_config_keys' => {
|
34
|
+
'nested_key' => "the nested key"
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
YAML.stubs(:load_file).returns(@config)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "to_hash" do
|
43
|
+
it "should return the environment config as a hash" do
|
44
|
+
SugarfreeConfig.to_hash.must_equal(@config['development'])
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should honor the scope" do
|
48
|
+
SugarfreeConfig.nested_config_keys.to_hash.must_equal(@config['development']['nested_config_keys'])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "asking for keys" do
|
53
|
+
|
54
|
+
it "should return the configuration values" do
|
55
|
+
SugarfreeConfig.simple_config_key.must_equal 1234
|
56
|
+
SugarfreeConfig.nested_config_keys.nested_key.must_equal 'the nested key'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should fail when aksing for non existent key" do
|
60
|
+
lambda { SugarfreeConfig.non_existent_key }.must_raise SugarfreeConfig::ConfigKeyException
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sugarfree-config/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sugarfree-config"
|
7
|
+
s.version = SugarfreeConfig::VERSION
|
8
|
+
s.authors = ["David Barral"]
|
9
|
+
s.email = ["contact@davidbarral.com"]
|
10
|
+
s.homepage = "http://github.com/davidbarral/sugarfree-config"
|
11
|
+
s.summary = "Configuration handling the easy way"
|
12
|
+
s.description = "Access to per Rails environment configuration stored in a YAML file"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_development_dependency('mocha')
|
20
|
+
s.add_development_dependency('turn')
|
21
|
+
end
|
metadata
CHANGED
@@ -1,65 +1,83 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: sugarfree-config
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: 1.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- David Barral
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
date: 2011-10-04 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mocha
|
16
|
+
requirement: &20817940 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *20817940
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: turn
|
27
|
+
requirement: &20817520 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *20817520
|
21
36
|
description: Access to per Rails environment configuration stored in a YAML file
|
22
|
-
email:
|
37
|
+
email:
|
38
|
+
- contact@davidbarral.com
|
23
39
|
executables: []
|
24
|
-
|
25
40
|
extensions: []
|
26
|
-
|
27
41
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
30
|
-
-
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- Gemfile
|
45
|
+
- Gemfile.lock
|
31
46
|
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
32
49
|
- init.rb
|
33
50
|
- lib/sugarfree-config.rb
|
34
|
-
|
51
|
+
- lib/sugarfree-config/config.rb
|
52
|
+
- lib/sugarfree-config/exceptions.rb
|
53
|
+
- lib/sugarfree-config/version.rb
|
54
|
+
- specs/config_spec.rb
|
55
|
+
- specs/exceptions_spec.rb
|
56
|
+
- specs/spec_helper.rb
|
57
|
+
- specs/sugarfree_spec.rb
|
58
|
+
- sugarfree-config.gemspec
|
35
59
|
homepage: http://github.com/davidbarral/sugarfree-config
|
36
60
|
licenses: []
|
37
|
-
|
38
61
|
post_install_message:
|
39
62
|
rdoc_options: []
|
40
|
-
|
41
|
-
require_paths:
|
63
|
+
require_paths:
|
42
64
|
- lib
|
43
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
- 0
|
56
|
-
version: "0"
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
57
77
|
requirements: []
|
58
|
-
|
59
78
|
rubyforge_project:
|
60
|
-
rubygems_version: 1.
|
79
|
+
rubygems_version: 1.8.6
|
61
80
|
signing_key:
|
62
81
|
specification_version: 3
|
63
82
|
summary: Configuration handling the easy way
|
64
83
|
test_files: []
|
65
|
-
|