summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2013-12-03 00:42:25 -0800
committerJohn Keiser <jkeiser@opscode.com>2013-12-03 00:42:25 -0800
commited46272e4dcf47a2600d28aee83b72f4ea656f0a (patch)
tree29c177831164e3847ebd72d99ba2124d6478bb35
parent24eb243b25d75f8cbd1bf2955509bad6dfe3af5b (diff)
downloadmixlib-config-ed46272e4dcf47a2600d28aee83b72f4ea656f0a.tar.gz
Add ability to reopen config_context, add setter for config_context
-rw-r--r--lib/mixlib/config.rb51
-rw-r--r--lib/mixlib/config/configurable.rb33
-rw-r--r--lib/mixlib/config/reopened_config_context_with_configurable_error.rb24
-rw-r--r--lib/mixlib/config/reopened_configurable_with_config_context_error.rb24
-rw-r--r--spec/mixlib/config_spec.rb67
5 files changed, 166 insertions, 33 deletions
diff --git a/lib/mixlib/config.rb b/lib/mixlib/config.rb
index 7b96fe0..7e48393 100644
--- a/lib/mixlib/config.rb
+++ b/lib/mixlib/config.rb
@@ -21,6 +21,8 @@
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
@@ -152,9 +154,17 @@ module Mixlib
#
def save(include_defaults = false)
result = self.configuration.dup
- (self.configurables.keys - result.keys).each do |missing_default|
- # Ask any configurables to save themselves into the result array
- self.configurables[missing_default].save(self.configuration, result, include_defaults)
+ 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
@@ -184,7 +194,7 @@ module Mixlib
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
- internal_get(key).restore(value)
+ self.config_contexts[key].restore(value)
else
self.configuration[key] = value
end
@@ -262,6 +272,9 @@ module Mixlib
# 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
@@ -274,6 +287,8 @@ module Mixlib
# 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
@@ -285,16 +300,25 @@ module Mixlib
# block<Block>: a block that will be run in the context of this new config
# class.
def config_context(symbol, &block)
- context = Class.new
- context.extend(::Mixlib::Config)
- context.config_parent = self
- config_contexts[symbol] = context
+ 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
- configurable(symbol).defaults_to(context).writes_value do |value|
- raise "config context #{symbol} cannot be modified"
- end
+
+ context
end
NOT_PASSED = Object.new
@@ -373,6 +397,7 @@ module Mixlib
private
# Internal dispatch setter for config values.
+ #
# === Parameters
# symbol<Symbol>:: Name of the method (variable setter)
# value<Object>:: Value to be set in config hash
@@ -380,6 +405,8 @@ module Mixlib
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 #{method_name}..")
@@ -393,6 +420,8 @@ module Mixlib
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}.")
diff --git a/lib/mixlib/config/configurable.rb b/lib/mixlib/config/configurable.rb
index 02081df..4a1bd46 100644
--- a/lib/mixlib/config/configurable.rb
+++ b/lib/mixlib/config/configurable.rb
@@ -21,15 +21,17 @@ module Mixlib
class Configurable
def initialize(symbol)
@symbol = symbol
- @default = nil
+ @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
+ @default_block = block
@default_value = default_value
self
end
@@ -42,11 +44,8 @@ module Mixlib
def get(config)
if config.has_key?(@symbol)
config[@symbol]
- elsif @default
- @default.call
- elsif @default_value.is_a?(::Mixlib::Config)
- # Don't dup config_contexts
- @default_value
+ elsif @default_block
+ @default_block.call
else
begin
# Some things cannot be dup'd, and you won't know this till after the fact
@@ -62,21 +61,11 @@ module Mixlib
config[@symbol] = @writes_value ? @writes_value.call(value) : value
end
- # Sets the saved value into the result hash. Don't bother stashing defaults away or duping them.
- def save(config, result, include_defaults)
- if config.has_key?(@symbol)
- result[@symbol] = config[@symbol]
- elsif @default_value.is_a?(::Mixlib::Config)
- saved_context = @default_value.save(include_defaults)
- if saved_context != {} || include_defaults
- result[@symbol] = saved_context
- end
- elsif include_defaults && @has_default
- if @default
- result[@symbol] = @default.call
- else
- result[@symbol] = @default_value
- end
+ def default
+ if @default_block
+ @default_block.call
+ else
+ @default_value
end
end
end
diff --git a/lib/mixlib/config/reopened_config_context_with_configurable_error.rb b/lib/mixlib/config/reopened_config_context_with_configurable_error.rb
new file mode 100644
index 0000000..3f3351f
--- /dev/null
+++ b/lib/mixlib/config/reopened_config_context_with_configurable_error.rb
@@ -0,0 +1,24 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# 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
diff --git a/lib/mixlib/config/reopened_configurable_with_config_context_error.rb b/lib/mixlib/config/reopened_configurable_with_config_context_error.rb
new file mode 100644
index 0000000..47ffb70
--- /dev/null
+++ b/lib/mixlib/config/reopened_configurable_with_config_context_error.rb
@@ -0,0 +1,24 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# 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
diff --git a/spec/mixlib/config_spec.rb b/spec/mixlib/config_spec.rb
index b58dc97..b5c753b 100644
--- a/spec/mixlib/config_spec.rb
+++ b/spec/mixlib/config_spec.rb
@@ -734,6 +734,26 @@ describe Mixlib::Config do
@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
@@ -887,4 +907,51 @@ describe Mixlib::Config do
lambda { StrictClass3.y = 10 }.should raise_error(Mixlib::Config::UnknownConfigOptionError)
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