我在Ruby中看过几个子命令的例子,但还没有找到任何使用Thor的例子,我想它可能无法完成,但我会感到惊讶。我想要做的是拥有一个程序foo
,它有自己的gem,安装时它的命令可以通常的方式调用,然后我想要一个单独的gem bar
注册foo
1}},在另一个存储库中维护,但安装时我可以使用foo bar
调用它。
从Thor文档中我可以看出,foo
要知道bar
它需要这样做:
desc "bar ...", "do bar"
subcommand "bar", Bar
但我不希望foo
必须知道bar
,并且只是在调用它时才加载它。我真的不明白如何控制宝石的安装方式,这可能就是答案,可能子命令需要遵循一些安装规则,而父命令执行该路径的一般加载。有什么机会我可以指出一个惊人的例子吗?
答案 0 :(得分:0)
这不是thor
的工作原理。使用foo
和bar
,您所拥有的是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)
让我们拥有一个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
。
让我们开始使用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
子命令。
我们的部分任务已经完成:foo
对bar
一无所知,但是bar
设法向foo
添加了一个子命令。一个明显的缺点是,用户必须在每次调用bar
时显式提及foo
(并通过其完整的文件系统路径来引用foo
,这也不是很方便。 )
只要有可用的gem,bar
的加载就无法“神奇地”开箱即用,但是foo
的用户将必须在某个地方(例如在配置文件中)指定每当执行bar
时都将加载foo
,并且您将向foo
添加一段代码来加载配置文件,并随后需要在其中指定插件。
这与上面讨论的初始解决方案有一个共同点:bar
的加载需要用户干预,但是在这种情况下,至少“一生一次”才需要干预,而不是每次调用都需要。
如果您真的想自动加载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>