From 74f65e92d1bf4c5f5cd30c7307b0b8bc2d0e4b79 Mon Sep 17 00:00:00 2001 From: Snehit Gajjar Date: Sat, 30 Sep 2017 13:41:11 -0500 Subject: [PATCH] Allow user to ignore class options for command --- lib/thor.rb | 15 ++++++++++++-- lib/thor/base.rb | 13 +++++++++---- lib/thor/command.rb | 6 +++--- lib/thor/group.rb | 2 +- spec/base_spec.rb | 26 +++++++++++++++++++++++++ spec/fixtures/ignore_class_options.thor | 17 ++++++++++++++++ spec/helper.rb | 1 + 7 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 spec/fixtures/ignore_class_options.thor diff --git a/lib/thor.rb b/lib/thor.rb index 1409623b3..65c76ea8f 100644 --- a/lib/thor.rb +++ b/lib/thor.rb @@ -121,6 +121,16 @@ def method_options(options = nil) alias_method :options, :method_options + + # Declares the class options which can be ignored for given command + # + # ==== Parameters + # list:: List of class options to be ignored + # + def ignore_class_options(list = nil) + @class_options_to_ignore ||= list + end + # Adds an option to the set of method options. If :for is given as option, # it allows you to change the options from a previous defined command. # @@ -172,7 +182,8 @@ def command_help(shell, command_name) shell.say "Usage:" shell.say " #{banner(command)}" shell.say - class_options_help(shell, nil => command.options.values) + class_options_help(shell, command.ignored_options, nil => command.options.values) + if command.long_description shell.say "Description:" shell.print_wrapped(command.long_description, :indent => 2) @@ -412,7 +423,7 @@ def create_command(meth) #:nodoc: if @usage && @desc base_class = @hide ? Thor::HiddenCommand : Thor::Command - commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options) + commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options, ignore_class_options) @usage, @desc, @long_desc, @method_options, @hide = nil true elsif all_commands[meth] || meth == "method_missing" diff --git a/lib/thor/base.rb b/lib/thor/base.rb index cdbf39ea8..6ce62897f 100644 --- a/lib/thor/base.rb +++ b/lib/thor/base.rb @@ -42,7 +42,11 @@ module Base # config:: Configuration for this Thor class. # def initialize(args = [], local_options = {}, config = {}) - parse_options = self.class.class_options + parse_options = self.class.class_options.dup + + ignored_options = config[:current_command] ? config[:current_command].ignored_options : [] + + parse_options.reject! { |k, _v| ignored_options.include?(k) } # The start method splits inbound arguments at the first argument # that looks like an option (starts with - or --). It then calls @@ -512,15 +516,16 @@ def handle_argument_error(command, error, args, arity) #:nodoc: # Prints the class options per group. If an option does not belong to # any group, it's printed as Class option. # - def class_options_help(shell, groups = {}) #:nodoc: + def class_options_help(shell, ignored_options = [], groups = {}) #:nodoc: # Group options by group - class_options.each do |_, value| + class_options.each do |key, value| groups[value.group] ||= [] - groups[value.group] << value + groups[value.group] << value unless ignored_options.include? key end # Deal with default group global_options = groups.delete(nil) || [] + print_options(shell, global_options) # Print all others diff --git a/lib/thor/command.rb b/lib/thor/command.rb index e3487ce5d..6b472030c 100644 --- a/lib/thor/command.rb +++ b/lib/thor/command.rb @@ -1,9 +1,9 @@ class Thor - class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name) + class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ignored_options, :ancestor_name) FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/ - def initialize(name, description, long_description, usage, options = nil) - super(name.to_s, description, long_description, usage, options || {}) + def initialize(name, description, long_description, usage, options = nil, ignored_options = nil) + super(name.to_s, description, long_description, usage, options || {}, ignored_options || []) end def initialize_copy(other) #:nodoc: diff --git a/lib/thor/group.rb b/lib/thor/group.rb index f6c9e20e1..a89b46c28 100644 --- a/lib/thor/group.rb +++ b/lib/thor/group.rb @@ -162,7 +162,7 @@ def class_options_help(shell, groups = {}) #:nodoc: get_options_from_invocations(groups, class_options) do |klass| klass.send(:get_options_from_invocations, groups, class_options) end - super(shell, groups) + super(shell, [], groups) end # Get invocations array and merge options from invocations. Those diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 4ba1f689f..3dd4f8a72 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -154,6 +154,32 @@ def hello content = capture(:stdout) { Enum.help(Thor::Base.shell.new) } expect(content).to match(/Possible values\: apple, banana/) end + + it "does not display class options in help if it has been ignored for a command" do + help = capture(:stdout) { IgnoreClassOptions.start(%w(help shake)) } + + expect(help).not_to match (/-c, --cheese=CHEESE/) + end + + it "displays class options in help if it has been not ignored for a command" do + help = capture(:stdout) { IgnoreClassOptions.start(%w(help snack)) } + + expect(help).to match (/-c, --cheese=CHEESE/) + end + end + + describe "#ignore_class_options" do + it "ignores class options when used ignore_class_options" do + options = IgnoreClassOptions.start(%w(shake --fruit apple --milk 1)) + + expect(options).to eq ({"fruit"=>"apple", "milk"=>1}) + end + + it "does not ignore class options when ignore_class_options is not used" do + options_when_not_ignored = IgnoreClassOptions.start(%w(snack --fruit apple --cheese provlone)) + + expect(options_when_not_ignored).to eq ({ "cheese" => "provlone", "fruit" => "apple" }) + end end describe "#namespace" do diff --git a/spec/fixtures/ignore_class_options.thor b/spec/fixtures/ignore_class_options.thor new file mode 100644 index 000000000..8c2d91bb7 --- /dev/null +++ b/spec/fixtures/ignore_class_options.thor @@ -0,0 +1,17 @@ +class IgnoreClassOptions < Thor + class_option :fruit, :aliases => "-f", :type => :string, :enum => %w(apple banana), :required => true + class_option :cheese, :aliases => "-c", :type => :string, :enum => %w(pepperjack provlone), :required => true + + desc "snack", "test" + method_option :vegetable, :aliases => "-v", :type => :string + def snack + options + end + + desc "shake", "test" + method_option :milk, :aliases => "-k", :type => :numeric + ignore_class_options [:cheese] + def shake + options + end +end diff --git a/spec/helper.rb b/spec/helper.rb index fa3bd0080..acb5aca56 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -38,6 +38,7 @@ load File.join(File.dirname(__FILE__), "fixtures", "script.thor") load File.join(File.dirname(__FILE__), "fixtures", "subcommand.thor") load File.join(File.dirname(__FILE__), "fixtures", "command.thor") +load File.join(File.dirname(__FILE__), "fixtures", "ignore_class_options.thor") RSpec.configure do |config| config.before do