Thor子命令在不同的宝石中

时间:2015-10-24 00:54:28

标签: ruby thor

我在Ruby中看过几个子命令的例子,但还没有找到任何使用Thor的例子,我想它可能无法完成,但我会感到惊讶。我想要做的是拥有一个程序foo,它有自己的gem,安装时它的命令可以通常的方式调用,然后我想要一个单独的gem bar注册foo 1}},在另一个存储库中维护,但安装时我可以使用foo bar调用它。

从Thor文档中我可以看出,foo要知道bar它需要这样做:

desc "bar ...", "do bar"
subcommand "bar", Bar

但我不希望foo必须知道bar,并且只是在调用它时才加载它。我真的不明白如何控制宝石的安装方式,这可能就是答案,可能子命令需要遵循一些安装规则,而父命令执行该路径的一般加载。有什么机会我可以指出一个惊人的例子吗?

2 个答案:

答案 0 :(得分:0)

这不是thor的工作原理。使用foobar,您所拥有的是module foo,其Cli类继承自Thor,即

class Cli < Thor

Cli课程中,您需要定义方法bar

这样的东西
module foo
  class Cli < Thor
    desc 'bar', 'do stuff'
    def bar 
      # all the rad stuff I do
    end
   end
 end

然后,您将构建并安装单个gem foo,该rbenv rehash将在$ foo bar arg1="bang" arg2="boom" 之后可用。一旦可用

lib

会做你告诉它要做的所有事情。

您也可以在单独的文件中编写命令。您可能具有lib | - foo.rb | - foo | | cli | | - bar_cli.rb | | - baz_cli.rb 结构,如下所示:

foo.rb

module Foo module Cli require_relative 'cli/bar_cli' require_relative 'cli/baz_cli' end class FooCli < Thor register(Foo::BarCli, 'bar', 'bar', 'bar commands') register(Foo::BazCli, 'baz', 'baz', 'baz commands') end end

bar_cli.rb

module Foo class BarCli < Thor desc 'display', 'Display the bar' def display # bar display stuff end end end

[Fri Oct 23 21:42:30.075831 2015] [:error] [pid 18652] [client ::1:64412] PHP Warning:move_uploaded_file(): Unable to move '/private/var/tmp/php0HlxVu' to 'images/photo.jpg' in /Users/ridgefrancis/Sites/examples/ch05/initial/guitarwars/addscore.php on line 32, referer: http://localhost/~ridgefrancis/examples/ch05/initial/guitarwars/addscore.php

答案 1 :(得分:0)

1。 Thor没问题

让我们拥有一个foo的gem,仅提供以下内容的一个具有相同名称foo的可执行文件:

require 'thor'

class FooCli < Thor
  desc 'hello', 'print a salutation'
  def hello
    puts 'hello'
  end
end

FooCli.start ARGV

如果执行它,我将得到这样的输出

Commands:
  foo.rb hello           # print a salutation
  foo.rb help [COMMAND]  # Describe available commands or one specific command

foo gem以外的代码中向可执行文件添加新的子命令没有问题。让我们来看看另一个bar的gem,仅提供以下内容的一个同名bar(.rb)的“库”文件:

require 'thor'

class BarCli < Thor
  desc 'hi', 'print another salutation'
  def hi
    puts 'hi'
  end
end

# Reopen the FooCli class and add the new subcommand
class FooCli < Thor
  desc 'bar', 'subcommand added by the foo-bar plugin'
  subcommand 'bar', BarCli
end

唯一的真正问题是执行bar命令时如何加载foo

2。解决代码加载问题

2.0手动解决方案

让我们开始使用bar解释器的-r选项手动加载ruby

$ ruby -r bar path/to/foo
Commands:
  foo.rb bar             # subcommand added by the foo-bar plugin
  foo.rb hello           # print a salutation
  foo.rb help [COMMAND]  # Describe available commands or one specific command

我们可以看到bar.rb中的代码已生效。由于它是在{em>之前 foo本身加载的(这就是-r选项的工作方式),bar子命令出现在命令列表 before 标准foo子命令。

我们的部分任务已经完成:foobar一无所知,但是bar设法向foo添加了一个子命令。一个明显的缺点是,用户必须在每次调用bar时显式提及foo(并通过其完整的文件系统路径来引用foo,这也不是很方便。 )

2.1具有配置的插件系统

只要有可用的gem,bar的加载就无法“神奇地”开箱即用,但是foo的用户将必须在某个地方(例如在配置文件中)指定每当执行bar时都将加载foo,并且您将向foo添加一段代码来加载配置文件,并随后需要在其中指定插件。

这与上面讨论的初始解决方案有一个共同点:bar的加载需要用户干预,但是在这种情况下,至少“一生一次”才需要干预,而不是每次调用都需要。

2.2宝石命名魔术

如果您真的想自动加载bar,但又foo不必(具体)了解它,则可以使用RubyGems设施结合使用来检查已安装的gem。命名约定。 bar宝石不会被称为bar,而是foo-bar,新名称表示它是foo的扩展,并且foo可执行文件将包含另一段代码查找名称以foo-开头的所有gem并加载它们:

Gem::Specification
  .select {|gemspec| gemspec.name =~ /^foo-/ }
  .collect(&:name)
  .uniq # multiple versions of a single gem may be installed at once
  .each {|name| require name }

该解决方案也有一个缺点:如果您的宝石是供通用使用并在Rubygems发行的,那么您将无法控制人们创建以foo-开头的宝石。因此,在尝试自动加载所有foo插件时,您可能会加载并执行您从未想要的第三方代码。更糟糕的是,如果发生此类问题,foo的用户即使很幸运地了解发生了什么,也没有其他方法来阻止加载有问题的foo-* gem并将其卸载。 / p>