configatron 2.13.0 → 3.0.0.rc1

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +0 -0
  3. data/.rvmrc +0 -1
  4. data/.travis.yml +5 -2
  5. data/Gemfile +5 -1
  6. data/Gemfile.lock +30 -13
  7. data/Guardfile +24 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +122 -112
  10. data/Rakefile +6 -4
  11. data/V2-README.md +243 -0
  12. data/configatron.gemspec +4 -31
  13. data/lib/configatron/core.rb +3 -94
  14. data/lib/configatron/deep_clone.rb +69 -0
  15. data/lib/configatron/errors.rb +5 -9
  16. data/lib/configatron/rails.rb +8 -8
  17. data/lib/configatron/store.rb +66 -339
  18. data/lib/configatron/version.rb +1 -1
  19. data/lib/configatron.rb +8 -16
  20. data/lib/generators/configatron/install/install_generator.rb +0 -0
  21. data/lib/generators/configatron/install/templates/configatron/defaults.rb +0 -0
  22. data/lib/generators/configatron/install/templates/configatron/development.rb +0 -0
  23. data/lib/generators/configatron/install/templates/configatron/production.rb +0 -0
  24. data/lib/generators/configatron/install/templates/configatron/test.rb +0 -0
  25. data/lib/generators/configatron/install/templates/initializers/configatron.rb +0 -0
  26. data/test/configatron/store_test.rb +191 -0
  27. data/test/configatron_test.rb +5 -0
  28. data/test/test_helper.rb +14 -0
  29. metadata +27 -54
  30. data/LICENSE +0 -21
  31. data/lib/configatron/core_ext/class.rb +0 -25
  32. data/lib/configatron/core_ext/kernel.rb +0 -8
  33. data/lib/configatron/core_ext/object.rb +0 -13
  34. data/lib/configatron/core_ext/string.rb +0 -90
  35. data/lib/configatron/proc.rb +0 -104
  36. data/spec/configatron/proc_spec.rb +0 -67
  37. data/spec/configatron/rails_spec.rb +0 -66
  38. data/spec/lib/class_spec.rb +0 -46
  39. data/spec/lib/complex.yml +0 -13
  40. data/spec/lib/configatron_spec.rb +0 -630
  41. data/spec/lib/futurama.yml +0 -6
  42. data/spec/lib/lost.yml +0 -14
  43. data/spec/lib/math.yml +0 -2
  44. data/spec/lib/merge.yml +0 -14
  45. data/spec/spec_helper.rb +0 -4
  46. data/spec/support/rails.rb +0 -7
data/V2-README.md ADDED
@@ -0,0 +1,243 @@
1
+ h1. Configatron
2
+
3
+ Configatron makes configuring your applications and scripts incredibly easy. No longer is a there a need to use constants or global variables. Now you can use a simple and painless system to configure your life. And, because it's all Ruby, you can do any crazy thing you would like to!
4
+
5
+ h2. Installation
6
+
7
+ Installation of Configatron is easy, as it is just a RubyGem:
8
+
9
+ <pre><code>
10
+ $ sudo gem install configatron
11
+ </code></pre>
12
+
13
+ If you'd like to live on the bleedin' edge you can install the development version from GitHub:
14
+
15
+ <pre><code>
16
+ $ sudo gem install markbates-configatron --source=http://gems.github.com
17
+ </code></pre>
18
+
19
+ Once installed you just need to require it:
20
+
21
+ <pre><code>
22
+ require 'configatron'
23
+ </code></pre>
24
+
25
+ h2. Examples
26
+
27
+ h3. Simple
28
+
29
+ <pre><code>
30
+ configatron.email = 'me@example.com'
31
+ configatron.database_url = "postgres://localhost/mack_framework_rocks"
32
+ </code></pre>
33
+
34
+ Now, anywhere in your code you can do the following:
35
+
36
+ <pre><code>
37
+ configatron.email # => "me@example.com"
38
+ configatron.database_url # => "postgres://localhost/mack_framework_rocks"
39
+ </code></pre>
40
+
41
+ Viola! Simple as can be.
42
+
43
+ Now you're saying, what if I want to have a 'default' set of options, but then override them later, based on other information? Simple again. Let's use our above example. We've configured our @database_url@ option to be @postgres://localhost/mack_framework_rocks@. The problem with that is that is our production database url, not our development url. Fair enough, all you have to do is redeclare it:
44
+
45
+ <pre><code>
46
+ configatron.database_url = "postgres://localhost/mack_framework_rocks_development"
47
+ </code></pre>
48
+
49
+ becomes:
50
+
51
+ <pre><code>
52
+ configatron.email # => "me@example.com"
53
+ configatron.database_url # => "postgres://localhost/mack_framework_rocks_development"
54
+ </code></pre>
55
+
56
+ Notice how our other configuration parameters haven't changed? Cool, eh?
57
+
58
+ h3. Hash/YAML
59
+
60
+ You can configure configatron from a hash as well (this is really only useful in testing or for data driven configuration, it's not recommended for actual configuration):
61
+
62
+ <pre><code>
63
+ configatron.configure_from_hash({:email => {:pop => {:address => 'pop.example.com', :port => 110}}, :smtp => {:address => 'smtp.example.com'}})
64
+
65
+ configatron.email.pop.address # => 'pop.example.com'
66
+ configatron.email.pop.port # => 110
67
+ # and so on...
68
+ </code></pre>
69
+
70
+ h4. YAML
71
+
72
+ Support for YAML has been deprecated and will be removed in version 2.9 of Configatron. Please switch to Ruby based configuration of Configatron. Trust me, it's a lot nicer and easier to use. Why would you _not_ want to?
73
+
74
+ h3. Namespaces
75
+
76
+ The question that should be on your lips is what I need to have namespaced configuration parameters. It's easy! Configatron allows you to create namespaces.
77
+
78
+ <pre><code>
79
+ configatron.website_url = "http://www.mackframework.com"
80
+ configatron.email.pop.address = "pop.example.com"
81
+ configatron.email.pop.port = 110
82
+ configatron.email.smtp.address = "smtp.example.com"
83
+ configatron.email.smtp.port = 25
84
+ </code></pre>
85
+
86
+ becomes:
87
+
88
+ <pre><code>
89
+ configatron.email.pop.address # => "pop.example.com"
90
+ configatron.email.smtp.address # => "smtp.example.com"
91
+ configatron.website_url # => "http://www.mackframework.com"
92
+ </code></pre>
93
+
94
+ Configatron allows you to nest namespaces to your hearts content! Just keep going, it's that easy.
95
+
96
+ Of course you can update a single parameter n levels deep as well:
97
+
98
+ <pre><code>
99
+ configatron.email.pop.address = "pop2.example.com"
100
+
101
+ configatron.email.pop.address # => "pop2.example.com"
102
+ configatron.email.smtp.address # => "smtp.example.com"
103
+ </code></pre>
104
+
105
+ h3. Temp Configurations
106
+
107
+ Sometimes in testing, or other situations, you want to temporarily change some settings. You can do this with the @temp@ method:
108
+
109
+ <pre><code>
110
+ configatron.one = 1
111
+ configatron.letters.a = 'A'
112
+ configatron.letters.b = 'B'
113
+ configatron.temp do
114
+ configatron.letters.b = 'bb'
115
+ configatron.letters.c = 'c'
116
+ configatron.one # => 1
117
+ configatron.letters.a # => 'A'
118
+ configatron.letters.b # => 'bb'
119
+ configatron.letters.c # => 'c'
120
+ end
121
+ configatron.one # => 1
122
+ configatron.letters.a # => 'A'
123
+ configatron.letters.b # => 'B'
124
+ configatron.letters.c # => nil
125
+ </code></pre>
126
+
127
+ You can also pass in an optional Hash to the @temp@:
128
+
129
+ <pre><code>
130
+ configatron.one = 1
131
+ configatron.letters.a = 'A'
132
+ configatron.letters.b = 'B'
133
+ configatron.temp(:letters => {:b => 'bb', :c => 'c'}) do
134
+ configatron.one == 1
135
+ configatron.letters.a # => 'A'
136
+ configatron.letters.b # => 'bb'
137
+ configatron.letters.c # => 'c'
138
+ end
139
+ configatron.one == 1
140
+ configatron.letters.a # => 'A'
141
+ configatron.letters.b # => 'B'
142
+ configatron.letters.c # => nil
143
+ </code></pre>
144
+
145
+ h3. Delayed and Dynamic Configurations
146
+
147
+ There are times when you want to refer to one configuration setting in another configuration setting. Let's look at a fairly contrived example:
148
+
149
+ <pre><code>
150
+ configatron.memcached.servers = ['127.0.0.1:11211']
151
+ configatron.page_caching.servers = configatron.memcached.servers
152
+ configatron.object_caching.servers = configatron.memcached.servers
153
+
154
+ if Rails.env == 'production'
155
+ configatron.memcached.servers = ['192.168.0.1:11211']
156
+ configatron.page_caching.servers = configatron.memcached.servers
157
+ configatron.object_caching.servers = configatron.memcached.servers
158
+ elsif Rails.env == 'staging'
159
+ configatron.memcached.servers = ['192.168.0.2:11211']
160
+ configatron.page_caching.servers = configatron.memcached.servers
161
+ configatron.object_caching.servers = configatron.memcached.servers
162
+ end
163
+ </code></pre>
164
+
165
+ Now, we could've written that slightly differently, but it helps to illustrate the point. With Configatron you can create <code>Delayed</code> and <code>Dynamic</code> settings.
166
+
167
+ h4. Delayed
168
+
169
+ With <code>Delayed</code> settings execution of the setting doesn't happen until the first time it is executed.
170
+
171
+ <pre><code>
172
+ configatron.memcached.servers = ['127.0.0.1:11211']
173
+ configatron.page_caching.servers = Configatron::Delayed.new {configatron.memcached.servers}
174
+ configatron.object_caching.servers = Configatron::Delayed.new {configatron.memcached.servers}
175
+
176
+ if Rails.env == 'production'
177
+ configatron.memcached.servers = ['192.168.0.1:11211']
178
+ elsif Rails.env == 'staging'
179
+ configatron.memcached.servers = ['192.168.0.2:11211']
180
+ end
181
+ </code></pre>
182
+
183
+ Execution occurs once and after that the result of that execution is returned. So in our case the first time someone calls the setting <code>configatron.page_caching.servers</code> it will find the <code>configatron.memcached.servers</code> setting and return that. After that point if the <code>configatron.memcached.servers</code> setting is changed, the original settings are returned by <code>configatron.page_caching.servers</code>.
184
+
185
+ h4. Dynamic
186
+
187
+ <code>Dynamic</code> settings are very similar to <code>Delayed</code> settings, but with one big difference. Every time you call a <code>Dynamic</code> setting is executed. Take this example:
188
+
189
+ <pre><code>
190
+ configatron.current.time = Configatron::Dynamic.new {Time.now}
191
+ </code></pre>
192
+
193
+ Each time you call <code>configatron.current.time</code> it will return a new value to you. While this seems a bit useless, it is pretty useful if you have ever changing configurations.
194
+
195
+ h3. Misc.
196
+
197
+ Even if parameters haven't been set, you can still call them, but you'll get a @Configatron::Store@ object back. The Configatron::Store class, however, will respond true to @.nil?@ if there are no parameters configured on it.
198
+
199
+ <pre><code>
200
+ configatron.i.dont.exist.nil? # => true
201
+ configatron.i.dont.exist # => Configatron::Store
202
+ </code></pre>
203
+
204
+ If you want to get back an actual @nil@ then you can use the @retrieve@ method:
205
+
206
+ <pre><code>
207
+ configatron.i.do.exist = [:some, :array]
208
+ configatron.i.dont.retrieve(:exist, nil) # => nil
209
+ configatron.i.do.retrieve(:exist, :foo) # => [:some, :array]
210
+ </code></pre>
211
+
212
+ You can set 'default' values for parameters. If there is already a setting, it won't be replaced. This is useful if you've already done your 'configuration' and you call a library, that needs to have parameters set. The library can set its defaults, without worrying that it might have overridden your custom settings.
213
+
214
+ <pre><code>
215
+ configatron.set_default(:name, 'Mark Bates')
216
+ configatron.name # => 'Mark Bates'
217
+ configatron.set_default(:name, 'Me')
218
+ configatron.name # => 'Mark Bates'
219
+ </code></pre>
220
+
221
+ Enjoy!
222
+
223
+ h2. Contributors
224
+
225
+ * Mark Bates
226
+ * Kurtis Rainbolt-Greene
227
+ * Rob Sanheim
228
+ * Cody Maggard
229
+ * Jean-Denis Vauguet
230
+ * Torsten Schönebaum
231
+ * Mat Brown
232
+ * Simon Menke
233
+ * chatgris
234
+ * Gleb Pomykalov
235
+ * Casper Gripenberg
236
+ * mattelacchiato
237
+ * Artiom Diomin
238
+ * Tim Riley
239
+ * Rick Fletcher
240
+ * joe miller
241
+ * Brandon Dimcheff
242
+ * Dan Pickett
243
+ * Josh Nichols
data/configatron.gemspec CHANGED
@@ -10,40 +10,13 @@ Gem::Specification.new do |gem|
10
10
  gem.email = ["mark@markbates.com"]
11
11
  gem.description = %q{A powerful Ruby configuration system.}
12
12
  gem.summary = %q{A powerful Ruby configuration system.}
13
- gem.homepage = "http://www.metabates.com"
13
+ gem.homepage = "https://github.com/markbates/configatron"
14
+ gem.license = "MIT"
14
15
 
15
16
  gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
19
  gem.require_paths = ["lib"]
19
20
 
20
- gem.add_dependency("yamler", ">= 0.1.0")
21
+ gem.add_development_dependency "rake"
21
22
  end
22
-
23
-
24
-
25
- # # -*- encoding: utf-8 -*-
26
- # require File.expand_path('../lib/configatron/version', __FILE__)
27
-
28
- # Gem::Specification.new do |s|
29
- # s.name = "configatron"
30
- # s.version = Configatron::VERSION
31
-
32
- # s.authors = ["markbates"]
33
- # s.description = "configatron was developed by: markbates"
34
- # s.email = "mark@markbates.com"
35
- # s.extra_rdoc_files = ["LICENSE"]
36
-
37
- # ignored_files = File.read('.gitignore').split("\n").compact.reject(&:empty?) + ["Rakefile", "Gemfile", "configatron.gemspec"]
38
- # test_files = Dir['spec/**/*'].reject {|f| File.directory?(f)}
39
- # library_files = Dir['**/*'].reject{|f| File.directory?(f)}
40
- # s.files = library_files - test_files - ignored_files
41
- # s.homepage = "http://www.metabates.com"
42
- # s.require_paths = ["lib"]
43
- # s.summary = "A powerful Ruby configuration system."
44
-
45
- # s.add_runtime_dependency "yamler", ">= 0.1.0"
46
- # s.add_development_dependency 'rake'
47
- # s.add_development_dependency 'rspec'
48
- # s.add_development_dependency 'gemstub'
49
- # end
@@ -1,94 +1,3 @@
1
- require 'fileutils'
2
- require 'singleton'
3
- require 'logger'
4
- require 'yamler'
5
-
6
- base = File.dirname(__FILE__)
7
-
8
- require File.join(base, 'store')
9
- require File.join(base, 'errors')
10
- require File.join(base, 'rails')
11
- require File.join(base, 'proc')
12
-
13
- class Configatron
14
- include Singleton
15
-
16
- alias_method :send!, :send
17
-
18
- class << self
19
-
20
- attr_accessor :strict, :disable_monkey_patching
21
-
22
- def log
23
- unless @logger
24
- if defined?(::Rails)
25
- @logger = ::Rails.logger
26
- end
27
- @logger = ::Logger.new(STDOUT) if @logger.nil?
28
- end
29
- return @logger
30
- end
31
-
32
- def reset!
33
- @strict = false
34
- end
35
- end
36
-
37
- def initialize # :nodoc:
38
- @_namespace = [:default]
39
- reset!
40
- end
41
-
42
- # Forwards the method call onto the 'namespaced' Configatron::Store
43
- def method_missing(sym, *args, &block)
44
- @_store[@_namespace.last].send(sym, *args, &block)
45
- end
46
-
47
- # respond_to to respond_to
48
- def respond_to?(method)
49
- !@_store[@_namespace.last].send(method).nil? || super
50
- end
51
-
52
- # Removes ALL configuration parameters
53
- def reset!
54
- self.class.reset!
55
- @_store = {:default => Configatron::Store.new}
56
- end
57
-
58
- # Allows for the temporary overriding of parameters in a block.
59
- # Takes an optional Hash of parameters that will be applied before
60
- # the block gets called. At the end of the block, the temporary
61
- # settings are deleted and the original settings are reinstated.
62
- def temp(options = nil)
63
- begin
64
- temp_start(options)
65
- yield @_store[@_namespace.last]
66
- rescue Exception => e
67
- raise e
68
- ensure
69
- temp_end
70
- end
71
- end
72
-
73
- def temp_start(options = nil)
74
- n_space = rand
75
- @_store[n_space] = @_store[@_namespace.last].deep_clone
76
- @_namespace << n_space
77
- if options
78
- self.method_missing(:configure_from_hash, options)
79
- end
80
- end
81
-
82
- def temp_end
83
- @_store.delete(@_namespace.pop)
84
- end
85
-
86
- begin
87
- undef :inspect # :nodoc:
88
- undef :nil? # :nodoc:
89
- undef :test # :nodoc:
90
- rescue Exception => e
91
- end
92
-
93
-
94
- end
1
+ require_relative "deep_clone"
2
+ require_relative "store"
3
+ require_relative "errors"
@@ -0,0 +1,69 @@
1
+ module DeepClone
2
+ # = DeepClone
3
+ #
4
+ # == Version
5
+ # 1.2006.05.23 (change of the first number means Big Change)
6
+ #
7
+ # == Description
8
+ # Adds deep_clone method to an object which produces deep copy of it. It means
9
+ # if you clone a Hash, every nested items and their nested items will be cloned.
10
+ # Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
11
+ #
12
+ # == Usage
13
+ #
14
+ # (see examples directory under the ruby gems root directory)
15
+ #
16
+ # require 'rubygems'
17
+ # require 'deep_clone'
18
+ #
19
+ # include DeepClone
20
+ #
21
+ # obj = []
22
+ # a = [ true, false, obj ]
23
+ # b = a.deep_clone
24
+ # obj.push( 'foo' )
25
+ # p obj # >> [ 'foo' ]
26
+ # p b[2] # >> []
27
+ #
28
+ # == Source
29
+ # http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
30
+ #
31
+ # == Author
32
+ # jan molic (/mig/at_sign/1984/dot/cz/)
33
+ #
34
+ # == Licence
35
+ # You can redistribute it and/or modify it under the same terms of Ruby's license;
36
+ # either the dual license version in 2003, or any later version.
37
+ #
38
+ def deep_clone( obj=self, cloned={} )
39
+ if cloned.has_key?( obj.object_id )
40
+ return cloned[obj.object_id]
41
+ else
42
+ begin
43
+ cl = obj.clone
44
+ rescue Exception
45
+ # unclonnable (TrueClass, Fixnum, ...)
46
+ cloned[obj.object_id] = obj
47
+ return obj
48
+ else
49
+ cloned[obj.object_id] = cl
50
+ cloned[cl.object_id] = cl
51
+ if cl.is_a?( Hash )
52
+ cl.clone.each { |k,v|
53
+ cl[k] = deep_clone( v, cloned )
54
+ }
55
+ elsif cl.is_a?( Array )
56
+ cl.collect! { |v|
57
+ deep_clone( v, cloned )
58
+ }
59
+ end
60
+ cl.instance_variables.each do |var|
61
+ v = cl.instance_eval( var.to_s )
62
+ v_cl = deep_clone( v, cloned )
63
+ cl.instance_eval( "#{var} = v_cl" )
64
+ end
65
+ return cl
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,13 +1,9 @@
1
1
  class Configatron
2
- class ProtectedParameter < StandardError
3
- def intialize(name)
4
- super("Can not modify protected parameter: '#{name}'")
2
+ class UndefinedKeyError < StandardError
3
+ def initialize(msg)
4
+ super(msg)
5
5
  end
6
6
  end
7
-
8
- class LockedNamespace < StandardError
9
- def initialize(name)
10
- super("Cannot add new parameters to locked namespace: #{name.inspect}")
11
- end
7
+ class LockedError < StandardError
12
8
  end
13
- end
9
+ end
@@ -1,14 +1,14 @@
1
1
  class Configatron
2
2
  # Helpful for making using configatron with Rails even easier!
3
- #
3
+ #
4
4
  # To get started you can use the generator to generate
5
5
  # the necessary stub files.
6
- #
7
- # $ ruby script/generate configatron
6
+ #
7
+ # $ rails g configatron:install
8
8
  module Rails
9
-
9
+
10
10
  # Loads configatron files in the following order:
11
- #
11
+ #
12
12
  # Example:
13
13
  # <Rails.root>/config/configatron/defaults.rb
14
14
  # <Rails.root>/config/configatron/<Rails.env>.rb
@@ -22,11 +22,11 @@ class Configatron
22
22
  root = defined?(Rails) ? ::Rails.root : FileUtils.pwd
23
23
  base_dir = File.expand_path(File.join(root, 'config', 'configatron'))
24
24
  end
25
-
25
+
26
26
  if env.nil?
27
27
  env = defined?(Rails) ? ::Rails.env : 'development'
28
28
  end
29
-
29
+
30
30
  config_files = []
31
31
 
32
32
  config_files << File.join(base_dir, 'defaults.rb')
@@ -48,6 +48,6 @@ class Configatron
48
48
  end
49
49
  end
50
50
  end
51
-
51
+
52
52
  end # Rails
53
53
  end # Configatron