configatron 2.13.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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