rafasoares
rafasoares

Reputation: 425

How to add --help, -h flag to Thor command?

I created a Thor class inside a Ruby executable, and it correctly shows the help when using ./foo help bar.

To make it more intuitive (for the sanity of my users), I'd also like to support ./foo bar --help and ./foo bar -h. When I do that, I get:

ERROR: "foo bar" was called with arguments ["--help"]
Usage: "foo bar"

I could manually do method_option :help, ... and handle it inside the bar method, but I hope there would be an easier way to do that (redirecting that command to ./foo help bar).

Does anyone know a simple and easy way to do this?

Upvotes: 2

Views: 991

Answers (4)

npf
npf

Reputation: 11

To complement the answer from max pleaner, the following handles subcommands, because subcommands help is broken if the trick is applied to them.

Also, I choose to overload Thor start command.

def self.start(*args)
  if (Thor::HELP_MAPPINGS & ARGV).any? and subcommands.grep(/^#{ARGV[0]}/).empty?
    Thor::HELP_MAPPINGS.each do |cmd|
      if match = ARGV.delete(cmd)
        ARGV.unshift match
      end
    end
  end
  super
end

Upvotes: 1

Mazungu
Mazungu

Reputation: 31

Building on what @max-pleaner listed. This will support subcommands also:

help_commands = Thor::HELP_MAPPINGS + ["help"]
 (help_commands & ARGV).each do |cmd|
  match = ARGV.delete(cmd)
  ARGV.size > 1 ? ARGV.insert(-2, match) : ARGV.unshift(match)
end

Upvotes: 2

max pleaner
max pleaner

Reputation: 26768

Assuming Foo is your class that inherits from Thor, you can call the following somewhere before Foo.start:

help_commands = Thor::HELP_MAPPINGS + ["help"]
# => ["-h", "-?", "--help", "-D"]

if help_commands.any? { |cmd| ARGV.include? cmd }
  help_commands.each do |cmd|
    if match = ARGV.delete(cmd)
      ARGV.unshift match
    end
  end
end

Rather than going into Thor and patching some method to have different ARGV-parsing behavior, this kind of cheats by moving any help commands to the front of the list.

Upvotes: 3

Shimu
Shimu

Reputation: 1147

You can achive this with class_option. If you set a class option this option is availiable for every method in your cli and you can just check if it is set and then call the help method.

Something like this:

class CLI < Thor
  class_option :help, type: :boolean

  desc "foo PARAM", "foo"
  def foo(param)
    handle_help_option(:foo)
    # your logic
  end

  def handle_help_option(method_name)
    help(method_name) if options[:help]
  end
end

Upvotes: 2

Related Questions