rails / thor

Thor is a toolkit for building powerful command-line interfaces.
http://whatisthor.com/
MIT License
5.11k stars 552 forks source link

Default help task for subcommand shows the wrong command name #261

Open addiedx44 opened 11 years ago

addiedx44 commented 11 years ago

I have an executable, ziprecruiter, and it has a subcommand (group?) jobalerts. When I execute ziprecruiter, it displays jobalerts correctly (no underscore):

$ bundle exec bin/ziprecruiter
Tasks:
  ziprecruiter help [TASK]          # Describe available tasks or one specific task
  ziprecruiter jobalerts [COMMAND]  # Type ziprecruiter jobalerts for more help.

Options:
  -k, [--api-key=API_KEY]  # Specify your ZipRecruiter Job Alerts API key.

However, when I run jobalerts, it shows "c_l_i" instead of the correct "jobalerts":

$ bundle exec bin/ziprecruiter jobalerts
Tasks:
  ziprecruiter c_l_i help [COMMAND]      # Describe subcommands or one specific subcommand
  ziprecruiter c_l_i status [TASK_ID]    # A Status action returns the current status of a previously-submitted request.
  ziprecruiter c_l_i subscribe [PATH]    # A Subscribe action is used to upload a collection of job seekers to subscribe to the ZipRecruiter job alerts program.
  ziprecruiter c_l_i unsubscribe [PATH]  # An Unsubscribe action is used to upload a collection of job seekers to unsubscribe from the ZipRecruiter job alerts program.

But c_l_i doesn't exist:

$ bundle exec bin/ziprecruiter c_l_i
Could not find task "c_l_i".

I believe this has to do with the way I have my subcommand namespaced: ZipRecruiter::JobAlerts::CLI

erran-r7 commented 11 years ago

I'm seeing this too. Is there a way to override the subcommand name or is this a fixable issue with Thor's naming scheme?

I named a class SSH. The underscores denote camel casing, which normally okay. When using acronyms it breaks here though. As a temporary workaround I used Ssh, ugly as it is, for a the name.

joustava commented 11 years ago

You can do something like this:

  package_name "subcommand"

  def self.banner(command, namespace = nil, subcommand = false)
    "#{basename} #{@package_name} #{command.usage}"
  end

This is probably not the most elegant solution. It would be nice if Thor.register would take the subcommand name in the description and not the class name.

dekz commented 10 years ago

Any updates on this issue?

mattheworiordan commented 9 years ago

Defining self.banner above solved my issues of subcommands either not showing or showing twice with Thor, thank you very much. Here is an example to help anyone else.

#!/usr/bin/env ruby

require 'thor'

class SubCommandBase < Thor
  def self.banner(command, namespace = nil, subcommand = false)
    "#{basename} #{subcommand_prefix} #{command.usage}"
  end

  def self.subcommand_prefix
    self.name.gsub(%r{.*::}, '').gsub(%r{^[A-Z]}) { |match| match[0].downcase }.gsub(%r{[A-Z]}) { |match| "-#{match[0].downcase}" }
  end
end

module App
  class Docs < SubCommandBase
    desc "create", "create docs"
    def create
      # pubish
    end

    desc "publish", "publish docs"
    def publish
      # pubish
    end
  end

  class CLI < Thor
    desc "docs", "create and publish docs"
    subcommand "docs", Docs
  end
end

App::CLI.start

And this is what happens now with my CLI

$ ./test.rb
Commands:
  test.rb docs            # create and publish docs
  test.rb help [COMMAND]  # Describe available commands or one specific command

$ ./test.rb docs
Commands:
  test.rb docs create          # create docs
  test.rb docs help [COMMAND]  # Describe subcommands or one specific subcommand
  test.rb docs publish         # publish docs

$ ./test.rb help docs
Commands:
  test.rb docs create          # create docs
  test.rb docs help [COMMAND]  # Describe subcommands or one specific subcommand
  test.rb docs publish         # publish docs

$ ./test.rb docs help create
Usage:
  test.rb docs create

create docs

All available in this Gist

glennpratt commented 7 years ago

Thanks @mattheworiordan, this is my take on it that overrides namespace (I was getting duplication with your changes and not fixing the over-the-top underscore-ing):


require 'thor'
require 'active_support/inflector'

module MyMod
  class Base < ::Thor
    # Override banner method to correct missing subcommand.
    # @see https://github.com/erikhuda/thor/issues/261
    def self.banner(command, namespace = nil, subcommand = false)
      return super if subcommand
      "#{basename} #{self.namespace} #{command.formatted_usage(self, $thor_runner, subcommand)}"
    end

    # Override namespace inflection so acronyms don't get over underscored.
    # Previously CLI -> c_l_i
    # @see https://github.com/erikhuda/thor/issues/261
    def self.namespace
      ActiveSupport::Inflector.underscore(
        ActiveSupport::Inflector.demodulize(name)
      )
    end
  end
end
andyjeffries commented 4 years ago

@mattheworiordan solution doesn't work for me with sub-subcommands (I don't know if you were expecting it to). For example in my CLI civo I have subcommands k8s and a subcommand set of that called apps.

Cut down and cleaned up output:

$ civo k8s                                                                                                                                                                                                                                                       Commands:
  civo k8s apps                     # list and add marketplace applications to Kubernetes clusters
  civo k8s create [NAME] [...]      # create a new kubernetes cluster with the specified name and provided options

$ civo k8s apps                                                                                                                                                                                                                                                  Commands:
  civo apps list                        # list all available kubernetes applications
  civo apps add ID/NAME [--cluster-id]  # add application to Kubernetes cluster

The second set of commands is missing the k8s subcommand and doesn't work if you don't add it. I tried @mattheworiordan's patch-fix, but that doesn't make any difference. May be a separate bug, but seems related.