Permalink
Browse files

Fixed issue #16 in regards to configure_from_hash/yaml

  • Loading branch information...
1 parent 6039cd1 commit 7bad6b926153ae6ff7ef9d5b5e815a42afac9c3c @markbates committed Jun 28, 2011
Showing with 48 additions and 202 deletions.
  1. +0 −189 README
  2. +3 −5 README.textile
  3. +2 −2 Rakefile
  4. +3 −3 configatron.gemspec
  5. +16 −1 lib/configatron/configatron.rb
  6. +3 −2 lib/configatron/store.rb
  7. +13 −0 spec/lib/complex.yml
  8. +7 −0 spec/lib/configatron_spec.rb
  9. +1 −0 spec/support/rails.rb
View
189 README
@@ -1,189 +0,0 @@
-=Configatron
-
-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!
-
-==Installation
-
-Installation of Configatron is easy, as it is just a RubyGem:
-
- $ sudo gem install configatron
-
-If you'd like to live on the bleedin' edge you can install the development version from GitHub:
-
- $ sudo gem install markbates-configatron --source=http://gems.github.com
-
-Once installed you just need to require it:
-
- require 'configatron'
-
-==Examples
-
-===Simple
-
- configatron.email = 'me@example.com'
- configatron.database_url = "postgres://localhost/mack_framework_rocks"
-
-Now, anywhere in your code you can do the following:
-
- configatron.email # => "me@example.com"
- configatron.database_url # => "postgres://localhost/mack_framework_rocks"
-
-Viola! Simple as can be.
-
-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 <tt>database_url</tt> option to be <tt>postgres://localhost/mack_framework_rocks</tt>. 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:
-
- configatron.database_url = "postgres://localhost/mack_framework_rocks_development"
-
-becomes:
-
- configatron.email # => "me@example.com"
- configatron.database_url # => "postgres://localhost/mack_framework_rocks_development"
-
-Notice how our other configuration parameters haven't changed? Cool, eh?
-
-===Hash/YAML
-
-You can configure configatron from a hash as well:
-
- configatron.configure_from_hash({:email => {:pop => {:address => 'pop.example.com', :port => 110}}, :smtp => {:address => 'smtp.example.com'}})
-
- configatron.email.pop.address # => 'pop.example.com'
- configatron.email.pop.port # => 110
- # and so on...
-
-Notice how they're all namespaced for your as well. The same holds true for YAML files:
-
- configatron.configure_from_yaml('/path/to/file.yml')
-
-===Namespaces
-
-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.
-
- configatron.website_url = "http://www.mackframework.com"
- configatron.email.pop.address = "pop.example.com"
- configatron.email.pop.port = 110
- configatron.email.smtp.address = "smtp.example.com"
- configatron.email.smtp.port = 25
-
-becomes:
-
- configatron.email.pop.address # => "pop.example.com"
- configatron.email.smtp.address # => "smtp.example.com"
- configatron.website_url # => "http://www.mackframework.com"
-
-Configatron allows you to nest namespaces to your hearts content! Just keep going, it's that easy.
-
-Of course you can update a single parameter n levels deep as well:
-
- configatron.email.pop.address = "pop2.example.com"
-
- configatron.email.pop.address # => "pop2.example.com"
- configatron.email.smtp.address # => "smtp.example.com"
-
-===Temp Configurations
-
-Sometimes in testing, or other situations, you want to temporarily change some settings. You can do this with the <tt>temp</tt> method:
-
- configatron.one = 1
- configatron.letters.a = 'A'
- configatron.letters.b = 'B'
- configatron.temp do
- configatron.letters.b = 'bb'
- configatron.letters.c = 'c'
- configatron.one # => 1
- configatron.letters.a # => 'A'
- configatron.letters.b # => 'bb'
- configatron.letters.c # => 'c'
- end
- configatron.one # => 1
- configatron.letters.a # => 'A'
- configatron.letters.b # => 'B'
- configatron.letters.c # => nil
-
-You can also pass in an optional Hash to the <tt>temp</tt>:
-
- configatron.one = 1
- configatron.letters.a = 'A'
- configatron.letters.b = 'B'
- configatron.temp(:letters => {:b => 'bb', :c => 'c'}) do
- configatron.one == 1
- configatron.letters.a # => 'A'
- configatron.letters.b # => 'bb'
- configatron.letters.c # => 'c'
- end
- configatron.one == 1
- configatron.letters.a # => 'A'
- configatron.letters.b # => 'B'
- configatron.letters.c # => nil
-
-===Delayed and Dynamic Configurations
-
-There are times when you want to refer to one configuration setting in another configuration setting. Let's look at a fairly contrived example:
-
- configatron.memcached.servers = ['127.0.0.1:11211']
- configatron.page_caching.servers = configatron.memcached.servers
- configatron.object_caching.servers = configatron.memcached.servers
-
- if Rails.env == 'production'
- configatron.memcached.servers = ['192.168.0.1:11211']
- configatron.page_caching.servers = configatron.memcached.servers
- configatron.object_caching.servers = configatron.memcached.servers
- elsif Rails.env == 'staging'
- configatron.memcached.servers = ['192.168.0.2:11211']
- configatron.page_caching.servers = configatron.memcached.servers
- configatron.object_caching.servers = configatron.memcached.servers
- end
-
-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.
-
-====Delayed
-
-With <code>Delayed</code> settings execution of the setting doesn't happen until the first time it is executed.
-
- configatron.memcached.servers = ['127.0.0.1:11211']
- configatron.page_caching.servers = Configatron::Delayed.new {configatron.memcached.servers}
- configatron.object_caching.servers = Configatron::Delayed.new {configatron.memcached.servers}
-
- if Rails.env == 'production'
- configatron.memcached.servers = ['192.168.0.1:11211']
- elsif Rails.env == 'staging'
- configatron.memcached.servers = ['192.168.0.2:11211']
- end
-
-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>.
-
-====Dynamic
-
-<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:
-
- configatron.current.time = Configatron::Dynamic.new {Time.now}
-
-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.
-
-===Misc.
-
-Even if parameters haven't been set, you can still call them, but you'll get a <tt>Configatron::Store</tt> object back. The Configatron::Store class, however, will respond true to <tt>.nil?</tt> if there are no parameters configured on it.
-
- configatron.i.dont.exist.nil? # => true
- configatron.i.dont.exist # => Configatron::Store
-
-If you want to get back an actual <tt>nil</tt> then you can use the <tt>retrieve</tt> method:
-
- configatron.i.do.exist = [:some, :array]
- configatron.i.dont.retrieve(:exist, nil) # => nil
- configatron.i.do.retrieve(:exist, :foo) # => [:some, :array]
-
-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.
-
- configatron.set_default(:name, 'Mark Bates')
- configatron.name # => 'Mark Bates'
- configatron.set_default(:name, 'Me')
- configatron.name # => 'Mark Bates'
-
-Enjoy!
-
-==Contact
-
-Please mail bugs, suggestions and patches to "development@metabates.com":mailto:development@metabates.com
-
-On the web at: "http://www.metabates.com":http://www.metabates.com
View
@@ -57,7 +57,7 @@ Notice how our other configuration parameters haven't changed? Cool, eh?
h3. Hash/YAML
-You can configure configatron from a hash as well:
+You can configure configatron from a hash as well (this is really only useful in testing or for data driven configurat, it's not recommended for actual configuration):
<pre><code>
configatron.configure_from_hash({:email => {:pop => {:address => 'pop.example.com', :port => 110}}, :smtp => {:address => 'smtp.example.com'}})
@@ -67,11 +67,9 @@ You can configure configatron from a hash as well:
# and so on...
</code></pre>
-Notice how they're all namespaced for your as well. The same holds true for YAML files:
+h4. YAML
-<pre><code>
- configatron.configure_from_yaml('/path/to/file.yml')
-</code></pre>
+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?
h3. Namespaces
View
@@ -17,13 +17,13 @@ Bundler.require
Gemstub.test_framework = :rspec
Gemstub.gem_spec do |s|
- s.version = "2.8.1"
+ s.version = "2.8.2"
s.summary = "A powerful Ruby configuration system."
s.rubyforge_project = "magrathea"
s.add_dependency('yamler', '>=0.1.0')
s.email = 'mark@markbates.com'
s.homepage = 'http://www.metabates.com'
- s.files = FileList['lib/**/*.*', 'README', 'LICENSE', 'bin/**/*.*', 'generators/**/*.*']
+ s.files = FileList['lib/**/*.*', 'README.textile', 'LICENSE', 'bin/**/*.*', 'generators/**/*.*']
end
Gemstub.rdoc do |rd|
View
@@ -2,15 +2,15 @@
Gem::Specification.new do |s|
s.name = %q{configatron}
- s.version = "2.8.1.20110617105939"
+ s.version = "2.8.2.20110628103123"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["markbates"]
- s.date = %q{2011-06-17}
+ s.date = %q{2011-06-28}
s.description = %q{configatron was developed by: markbates}
s.email = %q{mark@markbates.com}
s.extra_rdoc_files = ["LICENSE"]
- s.files = ["lib/configatron/configatron.rb", "lib/configatron/core_ext/class.rb", "lib/configatron/core_ext/kernel.rb", "lib/configatron/core_ext/object.rb", "lib/configatron/core_ext/string.rb", "lib/configatron/errors.rb", "lib/configatron/proc.rb", "lib/configatron/rails.rb", "lib/configatron/store.rb", "lib/configatron.rb", "README", "LICENSE", "generators/configatron_generator.rb", "generators/templates/configatron/cucumber.rb", "generators/templates/configatron/defaults.rb", "generators/templates/configatron/development.rb", "generators/templates/configatron/production.rb", "generators/templates/configatron/test.rb", "generators/templates/initializers/configatron.rb"]
+ s.files = ["lib/configatron/configatron.rb", "lib/configatron/core_ext/class.rb", "lib/configatron/core_ext/kernel.rb", "lib/configatron/core_ext/object.rb", "lib/configatron/core_ext/string.rb", "lib/configatron/errors.rb", "lib/configatron/proc.rb", "lib/configatron/rails.rb", "lib/configatron/store.rb", "lib/configatron.rb", "README.textile", "LICENSE", "generators/configatron_generator.rb", "generators/templates/configatron/cucumber.rb", "generators/templates/configatron/defaults.rb", "generators/templates/configatron/development.rb", "generators/templates/configatron/production.rb", "generators/templates/configatron/test.rb", "generators/templates/initializers/configatron.rb"]
s.homepage = %q{http://www.metabates.com}
s.require_paths = ["lib"]
s.rubyforge_project = %q{magrathea}
@@ -1,15 +1,30 @@
require 'singleton'
+require 'logger'
class Configatron
include Singleton
alias_method :send!, :send
+
+ class << self
+
+ def log
+ unless @logger
+ if defined?(::Rails)
+ @logger = ::Rails.logger
+ end
+ @logger = ::Logger.new(STDOUT) if @logger.nil?
+ end
+ return @logger
+ end
+
+ end
def initialize # :nodoc:
@_namespace = [:default]
reset!
end
-
+
# Forwards the method call onto the 'namespaced' Configatron::Store
def method_missing(sym, *args, &block)
@_store[@_namespace.last].send(sym, *args, &block)
View
@@ -99,6 +99,7 @@ def configure_from_hash(options)
# <tt>:hash</tt>, that indicates a specific hash that should be
# loaded from the file.
def configure_from_yaml(path, opts = {})
+ Configatron.log.warn "DEPRECATED! (configure_from_yaml) Please stop using YAML and use Ruby instead. This method will be removed in 2.9."
begin
yml = ::Yamler.load(path)
yml = yml[opts[:hash]] unless opts[:hash].nil?
@@ -303,12 +304,12 @@ def parse_options(options)
options.each do |k,v|
if v.is_a?(Hash)
if v.keys.length == 1 && v.keys.first.is_a?(SYCK_CONSTANT)
- self.method_missing("#{k.to_sym}=", v.values.first.flatten)
+ self.method_missing("#{k}=", v.values.first.flatten)
else
self.method_missing(k.to_sym).configure_from_hash(v)
end
else
- self.method_missing("#{k.to_sym}=", v)
+ self.method_missing("#{k}=", v)
end
end
else
View
@@ -0,0 +1,13 @@
+complex_default: &default
+ access_key_id: access_key
+ secret_access_key: secret_access_key
+
+complex_development:
+ bucket: develop
+ <<: *default
+
+complex_production:
+ bucket: production
+ <<: *default
+
+complex_test: &test
@@ -357,6 +357,13 @@
configatron.food.list.should == [:apple, :banana, :tomato, :brocolli, :spinach]
end
+ it "should handle complex yaml" do
+ configatron.complex_development.bucket.should be_nil
+ configatron.configure_from_yaml(File.join(File.dirname(__FILE__), 'complex.yml'))
+ configatron.complex_development.bucket.should == 'develop'
+ configatron.complex_development.access_key_id.should == 'access_key'
+ end
+
end
it 'should return a parameter' do
View
@@ -2,5 +2,6 @@ module Rails
class << self
attr_accessor :env
attr_accessor :root
+ attr_accessor :logger
end
end

1 comment on commit 7bad6b9

agross commented on 7bad6b9 Jul 3, 2011

Just a quick question: Why is it preferred to configure from Ruby and not use Yaml? I like how easy it is to define hierarchical data in Yaml. Can you please post an example why/how Ruby is much nicer than Yaml with a bit of Ruby included?

Thanks!

Please sign in to comment.