Search code examples
rubyrubygemscommand-line-interfacethor

Creating nested subcommands using Thor


I'd like to create a CLI tool which has commands in a format something like this:

clitool jobs execute some-job --arg1 value --arg2 another_value

Is it possible to have a subcommand of a subcommand within Thor? I would also like to preserve the class_options that I have defined in the class for the clitool jobs execute subcommand for any other subcommands under execute.


Solution

  • I have successfully used subcommands of subcommands, although there is a small bug. I haven't tried preserving class_options for subcommands, so I don't have an answer for that.

    For nested subcommands, the following works:

    class Execute < Thor
      desc 'some_job', 'Execute something'
      option :arg1, type: :string, desc: 'First option'
      option :arg2, type: :string, desc: 'Second option'
      def some_job
        puts "Executing some_job:"
        puts "  --arg1 = #{options[:arg1]}"
        puts "  --arg2 = #{options[:arg2]}"
      end
    end # class Execute
    
    class Jobs < Thor
      # Other task definitions
      desc 'execute', 'Execute jobs'
      subcommand 'execute', Execute
    end # class Jobs
    
    class CliTool < Thor
      # Other task definitions
      desc 'jobs', 'Do stuff with jobs'
      subcommand 'jobs', Jobs
    end
    
    CliTool.start
    

    This seems to do what you want:

    $ clitool jobs execute some-job --arg1 value --arg2 another_value
    Executing some_job:
      --arg1 = value
      --arg2 = another_value
    
    $
    

    There appears to be a bug: the help text for subcommands of subcommands doesn't work properly:

    $ clitool help
    Commands:
      clitool help [COMMAND] # Describe subcommands or one specific subcommand
      clitool jobs           # Do stuff with jobs
    
    $ clitool jobs help
    Commands:
      clitool jobs execute        # Execute jobs
      clitool jobs help [COMMAND] # Describe subcommands or one specific subcommand
    
    $ clitool jobs help execute
    Commands:
      clitool execute help [COMMAND] # Describe subcommands or one specific subcommand
      clitool execute some_job       # Execute something
    
    $
    

    The last help text should show "clitool jobs execute some_job...", but the prefix jobs gets omitted. Perhaps there's a guru out there who can show me how to correct that.