Search code examples
rubyrubygemsthor

How do I get Thor to display options?


This is my Ruby code:

require 'thor'
require 'thor/group'

module CLI

    class Greet < Thor
        desc 'hi', 'Say hi!'
        method_option :name, :type => :string, :description => 'Name to greet', :default => 'there'
        def hi
            puts "Hi, #{options[:name]}!"
        end

        desc 'bye', 'say bye!'
        def bye
            puts "Bye!"
        end
    end


    class Root < Thor
        register CLI::Greet, 'greet', 'greet [COMMAND]', 'Greet with a command'
    end
end


CLI::Root.start

This is the output:

C:\temp>ruby greet.rb help greet
Usage:
  greet.rb greet [COMMAND]

Greet with a command

How do I get that to look something like this?

C:\temp>ruby greet.rb help greet
Usage:
  greet.rb greet [COMMAND]
    --name Name to greet

Greet with a command

Solution

  • You've got two things going on here. First, you've assigned --name to a method, not to the entire CLI::Greet class. So if you use the command:

    ruby greet.rb greet help hi
    

    you get

    Usage:
      greet.rb hi
    
    Options:
      [--name=NAME]  
                     # Default: there
    
    Say hi!
    

    Which, yes, is wrong-- it doesn't have the subcommand in the help. There's a bug filed for this in Thor. It, however, is showing the method option properly.

    What it seems like you're looking for, however, is a class method. This is a method defined for the entire CLI::Greet class, not just for the #hi method.

    You'd do this as such:

    require 'thor'
    require 'thor/group'
    
    module CLI
    
        class Greet < Thor
            desc 'hi', 'Say hi!'
            class_option :number, :type => :string, :description => 'Number to call', :default => '555-1212'
            method_option :name, :type => :string, :description => 'Name to greet', :default => 'there'
            def hi
                puts "Hi, #{options[:name]}! Call me at #{options[:number]}"
            end
    
            desc 'bye', 'say bye!'
            def bye
                puts "Bye! Call me at #{options[:number]}"
            end
        end
    
        class Root < Thor
            register CLI::Greet, 'greet', 'greet [COMMAND]', 'Greet with a command'        
            tasks["greet"].options = CLI::Greet.class_options
        end
    end
    
    CLI::Root.start
    

    With this, ruby greet.rb help greet returns

    Usage:
      greet.rb greet [COMMAND]
    
    Options:
      [--number=NUMBER]  
                         # Default: 555-1212
    
    Greet with a command
    

    Note there is still a hack needed here: the tasks["greet"].options = CLI::Greet.class_options line in CLI::Root. There's a bug filed for this in Thor, too.