diff options
author | Thom May <thom@may.lt> | 2016-05-04 18:45:17 +0100 |
---|---|---|
committer | Thom May <thom@may.lt> | 2016-05-04 18:45:17 +0100 |
commit | d4a68ec78296443a2a08495de18c7a944d30dd71 (patch) | |
tree | 4cf178ec12c1ff73ab24f9d251e28dae4a4c76cd | |
parent | ce357df7c2e418fc7543a1a4f105e8edbf35f6f8 (diff) | |
parent | a32834ee7755b6668047af4683c4384fb45c93ab (diff) | |
download | mixlib-cli-d4a68ec78296443a2a08495de18c7a944d30dd71.tar.gz |
Merge pull request #13 from chrisroberts/enhancement/option-inheritance
[MIXLIB-14] Option inheritance
-rw-r--r-- | lib/mixlib/cli.rb | 41 | ||||
-rw-r--r-- | spec/mixlib/cli_spec.rb | 48 |
2 files changed, 88 insertions, 1 deletions
diff --git a/lib/mixlib/cli.rb b/lib/mixlib/cli.rb index 887d05f..9d7d596 100644 --- a/lib/mixlib/cli.rb +++ b/lib/mixlib/cli.rb @@ -38,8 +38,46 @@ module Mixlib # #parse_options. After calling this method, the attribute #config will # contain a hash of `:option_name => value` pairs. module CLI - module ClassMethods + module InheritMethods + def inherited(receiver) + receiver.options = deep_dup(self.options) + receiver.extend(Mixlib::CLI::InheritMethods) + end + + # object:: Instance to clone + # This method will return a "deep clone" of the provided + # `object`. If the provided `object` is an enumerable type the + # contents will be iterated and cloned as well. + def deep_dup(object) + cloned_object = object.respond_to?(:dup) ? object.dup : object + if(cloned_object.kind_of?(Enumerable)) + if(cloned_object.kind_of?(Hash)) + new_hash = cloned_object.class.new + cloned_object.each do |key, value| + cloned_key = deep_dup(key) + cloned_value = deep_dup(value) + new_hash[cloned_key] = cloned_value + end + cloned_object.replace(new_hash) + else + cloned_object.map! do |shallow_instance| + deep_dup(shallow_instance) + end + end + end + cloned_object + rescue TypeError + # Symbol will happily provide a `#dup` method even though + # attempts to clone it will result in an exception (atoms!). + # So if we run into an issue of TypeErrors, just return the + # original object as we gave our "best effort" + object + end + + end + + module ClassMethods # When this setting is set to +true+, default values supplied to the # mixlib-cli DSL will be stored in a separate Hash def use_separate_default_options(true_or_false) @@ -273,6 +311,7 @@ module Mixlib def self.included(receiver) receiver.extend(Mixlib::CLI::ClassMethods) + receiver.extend(Mixlib::CLI::InheritMethods) end end diff --git a/spec/mixlib/cli_spec.rb b/spec/mixlib/cli_spec.rb index cd07435..034fe25 100644 --- a/spec/mixlib/cli_spec.rb +++ b/spec/mixlib/cli_spec.rb @@ -262,6 +262,54 @@ describe Mixlib::CLI do end + context "when subclassed" do + before do + TestCLI.options = {:arg1 => {:boolean => true}} + end + + it "should retain previously defined options from parent" do + class T1 < TestCLI + option :arg2, :boolean => true + end + T1.options[:arg1].should be_a(Hash) + T1.options[:arg2].should be_a(Hash) + TestCLI.options[:arg2].should be_nil + end + + it "should not be able to modify parent classes options" do + class T2 < TestCLI + option :arg2, :boolean => true + end + T2.options[:arg1][:boolean] = false + T2.options[:arg1][:boolean].should be_false + TestCLI.options[:arg1][:boolean].should be_true + end + + it "should pass its options onto child" do + class T3 < TestCLI + option :arg2, :boolean => true + end + class T4 < T3 + option :arg3, :boolean => true + end + 3.times do |i| + T4.options["arg#{i + 1}".to_sym].should be_a(Hash) + end + end + + it "should also work with an option that's an array" do + class T5 < TestCLI + option :arg2, :default => [] + end + + class T6 < T5 + end + + T6.options[:arg2].should be_a(Hash) + end + + end + end # option :config_file, |