mixlib-config-2.2.1/0000755000004100000410000000000012536710134014275 5ustar www-datawww-datamixlib-config-2.2.1/Rakefile0000644000004100000410000000100512536710134015736 0ustar www-datawww-datarequire 'bundler' require 'rubygems' require 'rubygems/package_task' require 'rdoc/task' require 'rspec/core/rake_task' Bundler::GemHelper.install_tasks task :default => :spec desc "Run specs" RSpec::Core::RakeTask.new(:spec) do |spec| spec.pattern = 'spec/**/*_spec.rb' end gem_spec = eval(File.read("mixlib-config.gemspec")) RDoc::Task.new do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = "mixlib-config #{gem_spec.version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('lib/**/*.rb') end mixlib-config-2.2.1/spec/0000755000004100000410000000000012536710134015227 5ustar www-datawww-datamixlib-config-2.2.1/spec/spec_helper.rb0000644000004100000410000000051712536710134020050 0ustar www-datawww-data$TESTING=true $:.push File.join(File.dirname(__FILE__), '..', 'lib') require 'rspec' require 'mixlib/config' class ConfigIt extend Mixlib::Config end RSpec.configure do |config| config.filter_run :focus => true config.run_all_when_everything_filtered = true config.treat_symbols_as_metadata_keys_with_true_values = true end mixlib-config-2.2.1/spec/mixlib/0000755000004100000410000000000012536710134016513 5ustar www-datawww-datamixlib-config-2.2.1/spec/mixlib/config_spec.rb0000644000004100000410000006547012536710134021333 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper")) class ConfigIt extend ::Mixlib::Config end describe Mixlib::Config do before(:each) do ConfigIt.configure do |c| c[:alpha] = 'omega' c[:foo] = nil end end it "should load a config file" do File.stub(:exists?).and_return(true) File.stub(:readable?).and_return(true) IO.stub(:read).with('config.rb').and_return("alpha = 'omega'\nfoo = 'bar'") lambda { ConfigIt.from_file('config.rb') }.should_not raise_error end it "should not raise an ArgumentError with an explanation if you try and set a non-existent variable" do lambda { ConfigIt[:foobar] = "blah" }.should_not raise_error end it "should raise an Errno::ENOENT if it can't find the file" do lambda { ConfigIt.from_file("/tmp/timmytimmytimmy") }.should raise_error(Errno::ENOENT) end it "should allow the error to bubble up when it's anything other than IOError" do IO.stub(:read).with('config.rb').and_return("@#asdf") lambda { ConfigIt.from_file('config.rb') }.should raise_error(SyntaxError) end it "should allow you to reference a value by index" do ConfigIt[:alpha].should == 'omega' end it "should allow you to reference a value by string index" do ConfigIt['alpha'].should == 'omega' end it "should allow you to set a value by index" do ConfigIt[:alpha] = "one" ConfigIt[:alpha].should == "one" end it "should allow you to set a value by string index" do ConfigIt['alpha'] = "one" ConfigIt[:alpha].should == "one" end it "should allow setting a value with attribute form" do ConfigIt.arbitrary_value = 50 ConfigIt.arbitrary_value.should == 50 ConfigIt[:arbitrary_value].should == 50 end it "should allow setting a value with method form" do ConfigIt.arbitrary_value 50 ConfigIt.arbitrary_value.should == 50 ConfigIt[:arbitrary_value].should == 50 end describe "when strict mode is on" do class StrictClass extend ::Mixlib::Config config_strict_mode true default :x, 1 end it "allows you to get and set configured values" do StrictClass.x = StrictClass.x * 2 StrictClass[:x] = StrictClass[:x] * 2 end it "raises an error when you get an arbitrary config option with .y" do lambda { StrictClass.y }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Reading unsupported config value y.") end it "raises an error when you get an arbitrary config option with [:y]" do lambda { StrictClass[:y] }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Reading unsupported config value y.") end it "raises an error when you set an arbitrary config option with .y = 10" do lambda { StrictClass.y = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "raises an error when you set an arbitrary config option with .y 10" do lambda { StrictClass.y 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "raises an error when you set an arbitrary config option with [:y] = 10" do lambda { StrictClass[:y] = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end end describe "when a block has been used to set config values" do before do ConfigIt.configure { |c| c[:cookbook_path] = "monkey_rabbit"; c[:otherthing] = "boo" } end {:cookbook_path => "monkey_rabbit", :otherthing => "boo"}.each do |k,v| it "should allow you to retrieve the config value for #{k} via []" do ConfigIt[k].should == v end it "should allow you to retrieve the config value for #{k} via method_missing" do ConfigIt.send(k).should == v end end end it "should not raise an ArgumentError if you access a config option that does not exist" do lambda { ConfigIt[:snob_hobbery] }.should_not raise_error end it "should return true or false with has_key?" do ConfigIt.has_key?(:monkey).should eql(false) ConfigIt[:monkey] = "gotcha" ConfigIt.has_key?(:monkey).should eql(true) end describe "when a class method override writer exists" do before do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_attr_writer :test_method do |blah| blah.is_a?(Integer) ? blah * 1000 : blah end end end it "should multiply an integer by 1000" do @klass[:test_method] = 53 @klass[:test_method].should == 53000 end it "should multiply an integer by 1000 with the method_missing form" do @klass.test_method = 63 @klass.test_method.should == 63000 end it "should multiply an integer by 1000 with the instance_eval DSL form" do @klass.instance_eval("test_method 73") @klass.test_method.should == 73000 end it "should multiply an integer by 1000 via from-file, too" do IO.stub(:read).with('config.rb').and_return("test_method 99") @klass.from_file('config.rb') @klass.test_method.should == 99000 end it "should receive internal_set with the method name and config value" do @klass.should_receive(:internal_set).with(:test_method, 53).and_return(true) @klass[:test_method] = 53 end end describe "When a configurable exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable :daemonizeme default :a, 1 config_attr_writer(:b) { |v| v } config_context(:c) end end it "Getter methods are created for the configurable" do @klass.respond_to?(:daemonizeme).should == true @klass.respond_to?(:a).should == true @klass.respond_to?(:b).should == true @klass.respond_to?(:c).should == true @klass.respond_to?(:z).should == false end it "Setter methods are created for the configurable" do @klass.respond_to?("daemonizeme=".to_sym).should == true @klass.respond_to?("a=".to_sym).should == true @klass.respond_to?("b=".to_sym).should == true @klass.respond_to?("c=".to_sym).should == true @klass.respond_to?("z=".to_sym).should == false end describe "and extra methods have been dumped into Object" do class NopeError < StandardError end before :each do Object.send :define_method, :daemonizeme do raise NopeError, "NOPE" end Object.send :define_method, "daemonizeme=".to_sym do raise NopeError, "NOPE" end end it 'Normal classes call the extra method' do normal_class = Class.new normal_class.extend(::Mixlib::Config) lambda { normal_class.daemonizeme }.should raise_error(NopeError) end it 'Configurables with the same name as the extra method can be set' do @klass.daemonizeme = 10 @klass[:daemonizeme].should == 10 end it 'Configurables with the same name as the extra method can be retrieved' do @klass[:daemonizeme] = 10 @klass.daemonizeme.should == 10 end end end describe "When config has a default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, 4 } end it "should default to that value" do @klass.attr.should == 4 end it "should default to that value when retrieved as a hash" do @klass[:attr].should == 4 end it "should be settable to another value" do @klass.attr 5 @klass.attr.should == 5 end it "should still default to that value after delete" do @klass.attr 5 @klass.delete(:attr) @klass.attr.should == 4 end it "should still default to that value after reset" do @klass.attr 5 @klass.reset @klass.attr.should == 4 end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 4 } end it "save should save the new value if it gets set" do @klass.attr 5 (saved = @klass.save).should == { :attr => 5 } @klass.reset @klass.attr.should == 4 @klass.restore(saved) @klass.attr.should == 5 end it "save should save the new value even if it is set to its default value" do @klass.attr 4 (saved = @klass.save).should == { :attr => 4 } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 4 } end end describe "When config has a default value block" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do default :x, 4 default(:attr) { x*2 } end end it "should default to that value" do @klass.attr.should == 8 end it "should be recalculated each time it is retrieved" do @klass.attr.should == 8 @klass.x = 2 @klass.attr.should == 4 end it "should default to that value when retrieved as a hash" do @klass[:attr].should == 8 end it "should be settable to another value" do @klass.attr 5 @klass.attr.should == 5 end it "should still default to that value after delete" do @klass.attr 5 @klass.delete(:attr) @klass.attr.should == 8 end it "should still default to that value after reset" do @klass.attr 5 @klass.reset @klass.attr.should == 8 end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 8, :x => 4 } end it "save should save the new value if it gets set" do @klass.attr 5 (saved = @klass.save).should == { :attr => 5 } @klass.reset @klass.attr.should == 8 @klass.restore(saved) @klass.attr.should == 5 end it "save should save the new value even if it is set to its default value" do @klass.attr 8 (saved = @klass.save).should == { :attr => 8 } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 8 } end end describe "When config has an array default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, [] } end it "reset clears it to its default" do @klass.attr << 'x' @klass.attr.should == [ 'x' ] @klass.reset @klass.attr.should == [] end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => [] } end it "save should save the new value if it gets set" do @klass.attr << 'x' (saved = @klass.save).should == { :attr => [ 'x' ] } @klass.reset @klass.attr.should == [] @klass.restore(saved) @klass.attr.should == [ 'x' ] end it "save should save the new value even if it is set to its default value" do @klass.attr = [] (saved = @klass.save).should == { :attr => [] } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => [] } end end describe "When config has a hash default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, {} } end it "reset clears it to its default" do @klass.attr[:x] = 10 @klass.attr[:x].should == 10 @klass.reset @klass.attr[:x].should == nil end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => {} } end it "save should save the new value if it gets set" do @klass.attr[:hi] = 'lo' (saved = @klass.save).should == { :attr => { :hi => 'lo' } } @klass.reset @klass.attr.should == {} @klass.restore(saved) @klass.save.should == { :attr => { :hi => 'lo' } } end it "save should save the new value even if it is set to its default value" do @klass.attr = {} (saved = @klass.save).should == { :attr => {} } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => {} } end end describe "When config has a string default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval { default :attr, 'hello' } end it "reset clears it to its default" do @klass.attr << ' world' @klass.attr.should == 'hello world' @klass.reset @klass.attr.should == 'hello' end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 'hello' } end it "save should save the new value if it gets set" do @klass.attr << ' world' (saved = @klass.save).should == { :attr => 'hello world' } @klass.reset @klass.attr.should == 'hello' @klass.restore(saved) @klass.attr.should == 'hello world' end it "save should save the new value even if it is set to its default value" do @klass.attr 'hello world' (saved = @klass.save).should == { :attr => 'hello world' } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 'hello world' } end end describe "When config has a a default value block" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do default(:attr) { 4 } end end it "should default to that value" do @klass.attr.should == 4 end it "should default to that value when retrieved as a hash" do @klass[:attr].should == 4 end it "should be settable to another value" do @klass.attr 5 @klass.attr.should == 5 @klass[:attr].should == 5 end it "should still default to that value after delete" do @klass.attr 5 @klass.delete(:attr) @klass.attr.should == 4 end it "should still default to that value after reset" do @klass.attr 5 @klass.reset @klass.attr.should == 4 end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 4 } end it "save should save the new value if it gets set" do @klass.attr 5 (saved = @klass.save).should == { :attr => 5 } @klass.reset @klass.attr.should == 4 @klass.restore(saved) @klass.attr.should == 5 end it "save should save the new value even if it is set to its default value" do @klass.attr 4 (saved = @klass.save).should == { :attr => 4 } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 4 } end end describe "When a configurable exists with writer and default value" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable(:attr) do |c| c.defaults_to(4) c.writes_value { |value| value*2 } end end end it "should default to that value" do @klass.attr.should == 4 end it "should default to that value when retrieved as a hash" do @klass[:attr].should == 4 end it "should be settable to another value" do @klass.attr 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should be settable to another value with attr=" do @klass.attr = 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should be settable to another value with [:attr]=" do @klass[:attr] = 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should still default to that value after delete" do @klass.attr 5 @klass.delete(:attr) @klass.attr.should == 4 end it "should still default to that value after reset" do @klass.attr 5 @klass.reset @klass.attr.should == 4 end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 4 } end it "save should save the new value if it gets set" do @klass.attr 5 (saved = @klass.save).should == { :attr => 10 } @klass.reset @klass.attr.should == 4 @klass.restore(saved) @klass.attr.should == 10 end it "save should save the new value even if it is set to its default value" do @klass.attr 4 (saved = @klass.save).should == { :attr => 8 } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 8 } end end describe "When a configurable exists with writer and default value set in chained form" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable(:attr).defaults_to(4).writes_value { |value| value*2 } end end it "should default to that value" do @klass.attr.should == 4 end it "should default to that value when retrieved as a hash" do @klass[:attr].should == 4 end it "should be settable to another value" do @klass.attr 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should be settable to another value with attr=" do @klass.attr = 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should be settable to another value with [:attr]=" do @klass[:attr] = 5 @klass.attr.should == 10 @klass[:attr].should == 10 end it "should still default to that value after delete" do @klass.attr 5 @klass.delete(:attr) @klass.attr.should == 4 end it "should still default to that value after reset" do @klass.attr 5 @klass.reset @klass.attr.should == 4 end it "save should not save anything for it" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :attr => 4 } end it "save should save the new value if it gets set" do @klass.attr 5 (saved = @klass.save).should == { :attr => 10 } @klass.reset @klass.attr.should == 4 @klass.restore(saved) @klass.attr.should == 10 end it "save should save the new value even if it is set to its default value" do @klass.attr 2 (saved = @klass.save).should == { :attr => 4 } @klass.reset @klass.save.should == {} @klass.restore(saved) @klass.save.should == { :attr => 4 } end end describe "When a configurable exists with a context" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do configurable :x config_context(:blah) do default :x, 5 end end end it "configurable defaults in that context work" do @klass.blah.x.should == 5 end it "after setting values in the context, the values remain set" do @klass.blah.x = 10 @klass.blah.x.should == 10 end it "setting values with the same name in the parent context do not affect the child context" do @klass.x = 10 @klass.x.should == 10 @klass.blah.x.should == 5 end it "setting the entire context to a hash with default value overridden sets the value" do @klass.blah = { :x => 10 } @klass.blah.x.should == 10 end it "setting the entire context to a hash sets non-default values" do @klass.blah = { :y => 10 } @klass.blah.x.should == 5 @klass.blah.y.should == 10 end it "setting the entire context to a hash deletes any non-default values and resets default values" do @klass.blah.x = 10 @klass.blah.y = 10 @klass.blah = { :z => 10 } @klass.blah.x.should == 5 @klass.blah.y.should == nil @klass.blah.z.should == 10 end it "after reset of the parent class, children are reset" do @klass.blah.x = 10 @klass.blah.x.should == 10 @klass.reset @klass.blah.x.should == 5 end it "save should not save anything for it by default" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :blah => { :x => 5 } } end it "save should save any new values that are set in the context" do @klass.blah.x = 10 (saved = @klass.save).should == { :blah => { :x => 10 } } @klass.reset @klass.blah.x.should == 5 @klass.restore(saved) @klass.blah.x.should == 10 @klass.save.should == { :blah => { :x => 10 } } end end describe "When a configurable exists with a nested context" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do config_context(:yarr) do default :x, 5 end end configurable :x end end it "configurable defaults in that context work" do @klass.blah.yarr.x.should == 5 end it "after setting values in the context, the values remain set" do @klass.blah.yarr.x = 10 @klass.blah.yarr.x.should == 10 end it "setting values with the same name in the parent context do not affect the child context" do @klass.x = 10 @klass.x.should == 10 @klass.blah.yarr.x.should == 5 end it "after reset of the parent class, children are reset" do @klass.blah.yarr.x = 10 @klass.blah.yarr.x.should == 10 @klass.reset @klass.blah.yarr.x.should == 5 end it "save should not save anything for it by default" do @klass.save.should == {} end it "save with include_defaults should save all defaults" do @klass.save(true).should == { :blah => { :yarr => { :x => 5 } } } end it "save should save any new values that are set in the context" do @klass.blah.yarr.x = 10 (saved = @klass.save).should == { :blah => { :yarr => { :x => 10 } } } @klass.reset @klass.blah.yarr.x.should == 5 @klass.restore(saved) @klass.blah.yarr.x.should == 10 @klass.save.should == { :blah => { :yarr => { :x => 10 } } } end end describe "When a config_context with no defaulted values exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do configurable(:x) end end end it "save does not save the hash for the config_context" do @klass.save.should == {} end it "save with defaults saves the hash for the config_context" do @klass.save(true).should == { :blah => {} } end end describe "When a config_context with no configurables exists" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) end end it "save does not save the hash for the config_context" do @klass.save.should == {} end it "save with defaults saves the hash for the config_context" do @klass.save(true).should == { :blah => {} } end end describe "When a nested context has strict mode on" do class StrictClass2 extend ::Mixlib::Config config_context :c do config_strict_mode true default :x, 1 end end it "The parent class allows you to set arbitrary config options" do StrictClass2.y = 10 end it "The nested class does not allow you to set arbitrary config options" do lambda { StrictClass2.c.y = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end end describe "When strict mode is on but a nested context has strict mode unspecified" do class StrictClass3 extend ::Mixlib::Config config_strict_mode true default :x, 1 config_context :c end it "The parent class does not allow you to set arbitrary config options" do lambda { StrictClass3.y = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end it "The nested class does not allow you to set arbitrary config options" do lambda { StrictClass3.y = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError, "Cannot set unsupported config value y.") end end describe "When a config_context is opened twice" do before :each do @klass = Class.new @klass.extend(::Mixlib::Config) @klass.class_eval do config_context(:blah) do default :x, 10 end config_context(:blah) do default :y, 20 end end end it "Both config_context blocks are honored" do @klass.blah.x == 10 @klass.blah.y == 20 end end it "When a config_context is opened in place of a regular configurable, an error is raised" do klass = Class.new klass.extend(::Mixlib::Config) lambda do klass.class_eval do default :blah, 10 config_context(:blah) do default :y, 20 end end end.should raise_error(Mixlib::Config::ReopenedConfigurableWithConfigContextError) end it "When a config_context is opened in place of a regular configurable, an error is raised" do klass = Class.new klass.extend(::Mixlib::Config) lambda do klass.class_eval do config_context(:blah) do default :y, 20 end default :blah, 10 end end.should raise_error(Mixlib::Config::ReopenedConfigContextWithConfigurableError) end end mixlib-config-2.2.1/lib/0000755000004100000410000000000012536710134015043 5ustar www-datawww-datamixlib-config-2.2.1/lib/mixlib/0000755000004100000410000000000012536710134016327 5ustar www-datawww-datamixlib-config-2.2.1/lib/mixlib/config.rb0000644000004100000410000003466512536710134020137 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'mixlib/config/version' require 'mixlib/config/configurable' require 'mixlib/config/unknown_config_option_error' require 'mixlib/config/reopened_config_context_with_configurable_error' require 'mixlib/config/reopened_configurable_with_config_context_error' module Mixlib module Config def self.extended(base) class << base; attr_accessor :configuration; end class << base; attr_accessor :configurables; end class << base; attr_accessor :config_contexts; end class << base; attr_accessor :config_parent; end base.configuration = Hash.new base.configurables = Hash.new base.config_contexts = Hash.new end # Loads a given ruby file, and runs instance_eval against it in the context of the current # object. # # Raises an IOError if the file cannot be found, or is not readable. # # === Parameters # filename:: A filename to read from def from_file(filename) self.instance_eval(IO.read(filename), filename, 1) end # Pass Mixlib::Config.configure() a block, and it will yield itself # # === Parameters # block:: A block that is called with self.configuration as the argument. def configure(&block) block.call(self.configuration) end # Get the value of a config option # # === Parameters # config_option:: The config option to return # # === Returns # value:: The value of the config option # # === Raises # :: If the config option does not exist and strict mode is on. def [](config_option) internal_get(config_option.to_sym) end # Set the value of a config option # # === Parameters # config_option:: The config option to set (within the []) # value:: The value for the config option # # === Returns # value:: The new value of the config option # # === Raises # :: If the config option does not exist and strict mode is on. def []=(config_option, value) internal_set(config_option.to_sym, value) end # Check if Mixlib::Config has a config option. # # === Parameters # key:: The config option to check for # # === Returns # :: If the config option exists # :: If the config option does not exist def has_key?(key) self.configuration.has_key?(key.to_sym) end # Resets a config option to its default. # # === Parameters # symbol:: Name of the config option def delete(symbol) self.configuration.delete(symbol) end # Resets all config options to their defaults. def reset self.configuration = Hash.new self.config_contexts.values.each { |config_context| config_context.reset } end # Makes a copy of any non-default values. # # This returns a shallow copy of the hash; while the hash itself is # duplicated a la dup, modifying data inside arrays and hashes may modify # the original Config object. # # === Returns # # Hash of values the user has set. # # === Examples # # For example, this config class: # # class MyConfig < Mixlib::Config # default :will_be_set, 1 # default :will_be_set_to_default, 1 # default :will_not_be_set, 1 # configurable(:computed_value) { |x| x*2 } # config_context :group do # default :will_not_be_set, 1 # end # config_context :group_never_set # end # # MyConfig.x = 2 # MyConfig.will_be_set = 2 # MyConfig.will_be_set_to_default = 1 # MyConfig.computed_value = 2 # MyConfig.group.x = 3 # # produces this: # # MyConfig.save == { # :x => 2, # :will_be_set => 2, # :will_be_set_to_default => 1, # :computed_value => 4, # :group => { # :x => 3 # } # } # def save(include_defaults = false) result = self.configuration.dup if include_defaults (self.configurables.keys - result.keys).each do |missing_default| # Ask any configurables to save themselves into the result array if self.configurables[missing_default].has_default result[missing_default] = self.configurables[missing_default].default end end end self.config_contexts.each_pair do |key, context| context_result = context.save(include_defaults) result[key] = context_result if context_result.size != 0 || include_defaults end result end # Restore non-default values from the given hash. # # This method is the equivalent of +reset+ followed by +merge!(hash)+. # # === Parameters # hash: a hash in the same format as output by save. # # === Returns # self def restore(hash) reset merge!(hash) end # Merge an incoming hash with our config options # # === Parameters # hash: a hash in the same format as output by save. # # === Returns # self def merge!(hash) hash.each do |key, value| if self.config_contexts.has_key?(key) # Grab the config context and let internal_get cache it if so desired self.config_contexts[key].restore(value) else self.configuration[key] = value end end self end # Return the set of config hash keys. # This *only* returns hash keys which have been set by the user. In future # versions this will likely be removed in favor of something more explicit. # For now though, we want this to match has_key? # # === Returns # result of Hash#keys def keys self.configuration.keys end # Creates a shallow copy of the internal hash # NOTE: remove this in 3.0 in favor of save. This is completely useless # with default values and configuration_context. # # === Returns # result of Hash#dup def hash_dup save end # metaprogramming to ensure that the slot for method_symbol # gets set to value after any other logic is run # # === Parameters # method_symbol:: Name of the method (variable setter) # blk:: logic block to run in setting slot method_symbol to value # value:: Value to be set in config hash # def config_attr_writer(method_symbol, &block) configurable(method_symbol).writes_value(&block) end # metaprogramming to set the default value for the given config option # # === Parameters # symbol:: Name of the config option # default_value:: Default value (can be unspecified) # block:: Logic block that calculates default value def default(symbol, default_value = nil, &block) configurable(symbol).defaults_to(default_value, &block) end # metaprogramming to set information about a config option. This may be # used in one of two ways: # # 1. Block-based: # configurable(:attr) do # defaults_to 4 # writes_value { |value| 10 } # end # # 2. Chain-based: # configurable(:attr).defaults_to(4).writes_value { |value| 10 } # # Currently supported configuration: # # defaults_to(value): value returned when configurable has no explicit value # defaults_to BLOCK: block is run when the configurable has no explicit value # writes_value BLOCK: block that is run to filter a value when it is being set # # === Parameters # symbol:: Name of the config option # default_value:: Default value [optional] # block:: Logic block that calculates default value [optional] # # === Returns # The value of the config option. def configurable(symbol, &block) unless configurables[symbol] if config_contexts.has_key?(symbol) raise ReopenedConfigContextWithConfigurableError, "Cannot redefine config_context #{symbol} as a configurable value" end configurables[symbol] = Configurable.new(symbol) define_attr_accessor_methods(symbol) end if block block.call(configurables[symbol]) end configurables[symbol] end # Allows you to create a new config context where you can define new # options with default values. # # This method allows you to open up the configurable more than once. # # For example: # # config_context :server_info do # configurable(:url).defaults_to("http://localhost") # end # # === Parameters # symbol: the name of the context # block: a block that will be run in the context of this new config # class. def config_context(symbol, &block) if configurables.has_key?(symbol) raise ReopenedConfigurableWithConfigContextError, "Cannot redefine config value #{symbol} with a config context" end if config_contexts.has_key?(symbol) context = config_contexts[symbol] else context = Class.new context.extend(::Mixlib::Config) context.config_parent = self config_contexts[symbol] = context define_attr_accessor_methods(symbol) end if block context.instance_eval(&block) end context end NOT_PASSED = Object.new # Gets or sets strict mode. When strict mode is on, only values which # were specified with configurable(), default() or writes_with() may be # retrieved or set. Getting or setting anything else will cause # Mixlib::Config::UnknownConfigOptionError to be thrown. # # If this is set to :warn, unknown values may be get or set, but a warning # will be printed with Chef::Log.warn if this occurs. # # === Parameters # value:: pass this value to set strict mode [optional] # # === Returns # Current value of config_strict_mode # # === Raises # :: if value is set to something other than true, false, or :warn # def config_strict_mode(value = NOT_PASSED) if value == NOT_PASSED if @config_strict_mode.nil? if config_parent config_parent.config_strict_mode else false end else @config_strict_mode end else self.config_strict_mode = value end end # Sets strict mode. When strict mode is on, only values which # were specified with configurable(), default() or writes_with() may be # retrieved or set. All other values # # If this is set to :warn, unknown values may be get or set, but a warning # will be printed with Chef::Log.warn if this occurs. # # === Parameters # value:: pass this value to set strict mode [optional] # # === Raises # :: if value is set to something other than true, false, or :warn # def config_strict_mode=(value) if ![ true, false, :warn, nil ].include?(value) raise ArgumentError, "config_strict_mode must be true, false, nil or :warn" end @config_strict_mode = value end # Allows for simple lookups and setting of config options via method calls # on Mixlib::Config. If there any arguments to the method, they are used to set # the value of the config option. Otherwise, it's a simple get operation. # # === Parameters # method_symbol:: The method called. Must match a config option. # *args:: Any arguments passed to the method # # === Returns # value:: The value of the config option. # # === Raises # :: If the config option does not exist and strict mode is on. def method_missing(method_symbol, *args) method_symbol = $1.to_sym if method_symbol.to_s =~ /(.+)=$/ internal_get_or_set(method_symbol, *args) end private # Internal dispatch setter for config values. # # === Parameters # symbol:: Name of the method (variable setter) # value:: Value to be set in config hash # def internal_set(symbol,value) if configurables.has_key?(symbol) configurables[symbol].set(self.configuration, value) elsif config_contexts.has_key?(symbol) config_contexts[symbol].restore(value) else if config_strict_mode == :warn Chef::Log.warn("Setting unsupported config value #{symbol}.") elsif config_strict_mode raise UnknownConfigOptionError, "Cannot set unsupported config value #{symbol}." end configuration[symbol] = value end end def internal_get(symbol) if configurables.has_key?(symbol) configurables[symbol].get(self.configuration) elsif config_contexts.has_key?(symbol) config_contexts[symbol] else if config_strict_mode == :warn Chef::Log.warn("Reading unsupported config value #{symbol}.") elsif config_strict_mode raise UnknownConfigOptionError, "Reading unsupported config value #{symbol}." end configuration[symbol] end end def internal_get_or_set(symbol,*args) num_args = args.length # Setting if num_args > 0 internal_set(symbol, num_args == 1 ? args[0] : args) end # Returning internal_get(symbol) end def define_attr_accessor_methods(symbol) # When Ruby 1.8.7 is no longer supported, this stuff can be done with define_singleton_method! meta = class << self; self; end # Setter meta.send :define_method, "#{symbol.to_s}=".to_sym do |value| internal_set(symbol, value) end # Getter meta.send :define_method, symbol do |*args| internal_get_or_set(symbol, *args) end end end end mixlib-config-2.2.1/lib/mixlib/config/0000755000004100000410000000000012536710134017574 5ustar www-datawww-datamixlib-config-2.2.1/lib/mixlib/config/unknown_config_option_error.rb0000644000004100000410000000142012536710134025743 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class UnknownConfigOptionError < StandardError end end end mixlib-config-2.2.1/lib/mixlib/config/version.rb0000644000004100000410000000135212536710134021607 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config VERSION = "2.2.1" end end mixlib-config-2.2.1/lib/mixlib/config/reopened_config_context_with_configurable_error.rb0000644000004100000410000000144212536710134032000 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class ReopenedConfigContextWithConfigurableError < StandardError end end end mixlib-config-2.2.1/lib/mixlib/config/configurable.rb0000644000004100000410000000360212536710134022562 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class Configurable def initialize(symbol) @symbol = symbol @default_block = nil @has_default = false @default_value = nil @writes_value = nil end attr_reader :has_default def defaults_to(default_value = nil, &block) @has_default = true @default_block = block @default_value = default_value self end def writes_value(&block) @writes_value = block self end def get(config) if config.has_key?(@symbol) config[@symbol] elsif @default_block @default_block.call else begin # Some things cannot be dup'd, and you won't know this till after the fact # because all values implement dup config[@symbol] = @default_value.dup rescue TypeError @default_value end end end def set(config, value) config[@symbol] = @writes_value ? @writes_value.call(value) : value end def default if @default_block @default_block.call else @default_value end end end end end mixlib-config-2.2.1/lib/mixlib/config/reopened_configurable_with_config_context_error.rb0000644000004100000410000000144212536710134032000 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # module Mixlib module Config class ReopenedConfigurableWithConfigContextError < StandardError end end end mixlib-config-2.2.1/metadata.yml0000644000004100000410000000455112536710134016605 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: mixlib-config version: !ruby/object:Gem::Version version: 2.2.1 platform: ruby authors: - Chef Software, Inc. autorequire: bindir: bin cert_chain: [] date: 2015-05-12 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.99' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.99' - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: A class based configuration library email: legal@chef.io executables: [] extensions: [] extra_rdoc_files: - LICENSE - README.md files: - LICENSE - NOTICE - README.md - Rakefile - lib/mixlib/config.rb - lib/mixlib/config/configurable.rb - lib/mixlib/config/reopened_config_context_with_configurable_error.rb - lib/mixlib/config/reopened_configurable_with_config_context_error.rb - lib/mixlib/config/unknown_config_option_error.rb - lib/mixlib/config/version.rb - spec/mixlib/config_spec.rb - spec/spec_helper.rb homepage: http://www.chef.io licenses: - Apache-2.0 metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.5 signing_key: specification_version: 4 summary: A class based configuration library test_files: [] has_rdoc: mixlib-config-2.2.1/NOTICE0000644000004100000410000000167412536710134015211 0ustar www-datawww-dataMixin::Config NOTICE ================= Developed at Opscode (http://www.opscode.com). * Copyright 2009, Opscode, Inc. Mixin::Config incorporates code from Chef. The Chef notice file follows: Chef NOTICE =========== Developed at Opscode (http://www.opscode.com). Contributors and Copyright holders: * Copyright 2008, Adam Jacob * Copyright 2008, Arjuna Christensen * Copyright 2008, Bryan McLellan * Copyright 2008, Ezra Zygmuntowicz * Copyright 2009, Sean Cribbs * Copyright 2009, Christopher Brown * Copyright 2009, Thom May Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard. Chef incorporates code modified from Merb (http://www.merbivore.com), which is Copyright (c) 2008 Engine Yard. mixlib-config-2.2.1/LICENSE0000644000004100000410000002514212536710134015306 0ustar www-datawww-data Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mixlib-config-2.2.1/README.md0000644000004100000410000001024212536710134015553 0ustar www-datawww-data# Mixlib::Config # Mixlib::Config provides a class-based configuration object, as used in Chef. To use in your project: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :first_value, 'something' default :other_value, 'something_else' end ``` You can use this to provide a configuration file for a user. For example, if you do this: ```ruby MyConfig.from_file('~/.myconfig.rb') ``` A user could write a Ruby config file that looked like this: ```ruby first_value 'hi' second_value "#{first_value}! 10 times 10 is #{10*10}!" ``` Inside your app, you can check configuration values with this syntax: ```ruby MyConfig.first_value # returns 'something' MyConfig[:first_value] # returns 'something' ``` And you can modify configuration values with this syntax: ```ruby MyConfig.first_value('foobar') # sets first_value to 'foobar' MyConfig.first_value = 'foobar' # sets first_value to 'foobar' MyConfig[:first_value] = 'foobar' # sets first_value to 'foobar' ``` ## Nested Configuration ## Often you want to be able to group configuration options to provide a common context. Mixlib::Config supports this thus: ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_context :logging do default :base_filename, 'mylog' default :max_log_files, 10 end end ``` The user can write their config file like this: ```ruby logging.base_filename 'superlog' logging.max_log_files 2 ``` You can access these variables thus: ```ruby MyConfig.logging.base_filename MyConfig[:logging][:max_log_files] ``` ## Default Values ## Mixlib::Config has a powerful default value facility. In addition to being able to specify explicit default values, you can even specify Ruby code blocks that will run if the config value is not set. This can allow you to build options whose values are based on other options. ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :verbosity, 1 default(:print_network_requests) { verbosity >= 2 } default(:print_ridiculously_unimportant_stuff) { verbosity >= 10 } end ``` This allows the user to quickly specify a number of values with one default, while still allowing them to override anything: ```ruby verbosity 5 print_network_requests false ``` ## Strict Mode ## Misspellings are a common configuration problem, and Mixlib::Config has an answer: `config_strict_mode`. Setting `config_strict_mode` to `true` will cause any misspelled or incorrect configuration option references to throw `Mixlib::Config::UnknownConfigOptionError`. ```ruby require 'mixlib/config' module MyConfig extend Mixlib::Config config_strict_mode true default :filename, '~/output.txt' configurable :server_url # configurable declares an option with no default value config_context :logging do default :base_name, 'log' default :max_files, 20 end end ``` Now if a user types `fielname "~/output-mine.txt"` in their configuration file, it will toss an exception telling them that the option "fielname" is unknown. If you do not set config_strict_mode, the fielname option will be merrily set and the application just won't know about it. Different config_contexts can have different strict modes; but they inherit the strict mode of their parent if you don't explicitly set it. So setting it once at the top level is sufficient. In the above example, `logging.base_naem 'mylog'` will raise an error. In conclusion: *always set config_strict_mode to true*. You know you want to. ## Testing and Reset ## Testing your application with different sets of arguments can by simplified with `reset`. Call `MyConfig.reset` before each test and all configuration will be reset to its default value. There's no need to explicitly unset all your options between each run. NOTE: if you have arrays of arrays, or other deep nesting, we suggest you use code blocks to set up your default values (`default(:option) { [ [ 1, 2 ], [ 3, 4 ] ] }`). Deep children will not always be reset to their default values. Report bugs [here](https://tickets.opscode.com). Enjoy!