Thor CLI:在帮助输出中设置命令的自定义顺序

时间:2017-08-16 14:20:11

标签: ruby command-line-interface thor

thor gem似乎总是在打印其帮助输出时按字母顺序排序已定义的命令。例如:

#!/usr/bin/env ruby

require "thor"

class MyCLI < Thor
  desc "z", "this should go first"
  def z; end

  desc "a", "this should go second"
  def a; end
end

MyCLI.start(ARGV)

将此脚本保存为thor-test并在不带参数的情况下调用它会产生以下结果:

Commands:
  thor-test a               # this should go second
  thor-test help [COMMAND]  # Describe available commands or one specific command
  thor-test z               # this should go first

问题:我如何告诉Thor以不同方式订购这些条目?

2 个答案:

答案 0 :(得分:3)

好像Thor没有为此提供配置选项。所以我现在要解决一些猴子修补问题。 aristotll's answer将我指向Thor的source code中的正确位置。

但是我决定更改<=>方法的实现,而不是攻击help方法。这对我来说似乎更清晰,并且有一个优点,我可以进一步影响帮助输出的行为:

#!/usr/bin/env ruby

require "thor"

class MyCLI < Thor
  class << self
    def help(shell, subcommand = false)
      list = printable_commands(true, subcommand)
      Thor::Util.thor_classes_in(self).each do |klass|
        list += klass.printable_commands(false)
      end

      # Remove this line to disable alphabetical sorting
      # list.sort! { |a, b| a[0] <=> b[0] }

      # Add this line to remove the help-command itself from the output
      list.reject! {|l| l[0].split[1] == 'help'}

      if defined?(@package_name) && @package_name
        shell.say "#{@package_name} commands:"
      else
        shell.say "Commands:"
      end

      shell.print_table(list, :indent => 2, :truncate => true)
      shell.say
      class_options_help(shell)

      # Add this line if you want to print custom text at the end of your help output.
      # (similar to how Rails does it)
      shell.say 'All commands can be run with -h (or --help) for more information.'
    end
  end

  desc "z", "this should go first"
  def z; end

  desc "a", "this should go second"
  def a; end
end

MyCLI.start(ARGV)

答案 1 :(得分:2)

来自help source code

list.sort! { |a, b| a[0] <=> b[0] }

按预期按字母顺序排序。

当然,总是允许使用邪恶的猴子补丁,在MyCLI之前添加以下代码。

SCRIPT = File.basename $PROGRAM_NAME
class String
  alias old_compare <=>
  # @param [String]  other_string
  # @return [Fixnum]
  def <=>(other_string)
    # currently the command name is like `script_name+space+usage`
    # a monkey patch to make z goes first
    if other_string.start_with?(SCRIPT)
      index = SCRIPT.size + 1
      if other_string[index] == 'z'
        return 1
      elsif self[index] =='z'
        return -1
      end
    end
    old_compare other_string
  end
end

输出:

Commands:
  thor-test z               # this should go first
  thor-test a               # this should go second
  thor-test help [COMMAND]  # Describe available commands or one specific command