使用Thor,可以使用method_option
为特定任务设置选项。要为类中的所有任务设置选项,可以使用class_option
。但是,如果一个人想要一个班级的某些任务,而不是全部,那么分享选项呢?
在以下task1
和task2
分享选项中,但它们不会共享所有选项,并且它们与task3
不共享任何选项。
require 'thor'
class Cli < Thor
desc 'task1', 'Task 1'
method_option :type, :type => :string, :required => true, :default => 'foo'
def task1
end
desc 'task2', 'Task 2'
method_option :type, :type => :string, :required => true, :default => 'foo'
method_option :value, :type => :numeric
def task2
end
desc 'task3', 'Task 3'
method_option :verbose, :type => :boolean, :aliases => '-v'
def task3
end
end
Cli.start(ARGV)
method_option :type, :type => :string, :required => true, :default => 'foo'
和task1
task2
的陈述问题在于它违反了the DRY principle。是否有一种惯用的处理方式?
答案 0 :(得分:14)
method_option
在thor.rb中定义,并根据文档采用以下参数:
name<Symbol>::
参数的名称。options<Hash>::
如下所述。了解这一点,您可以将参数存储到数组中的method_option
,并调用method_option
require 'thor'
class Cli < Thor
shared_options = [:type, {:type => :string, :required => true, :default => 'foo'}]
desc 'task1', 'Task 1'
method_option *shared_options
def task1
end
desc 'task2', 'Task 2'
method_option *shared_options
method_option :value, :type => :numeric
def task2
end
desc 'task3', 'Task 3'
method_option :verbose, :type => :boolean, :aliases => '-v'
def task3
end
end
Cli.start(ARGV)
。
{{1}}
我不知道这是否是惯用的,我不认为它是那么优雅。不过,这比违反DRY原则要好。
答案 1 :(得分:3)
我会使用这样的超类:
require 'thor'
class CliBase < Thor
def self.shared_options
method_option :verbose,
:aliases => '-v',
:type => :boolean,
:desc => 'Verbose',
:default => false,
:required => false
end
end
...然后子类如下:
require 'cli_base'
class Cli < CliBase
desc 'task1', 'Task 1'
shared_options
def task1
end
desc 'task2', 'Task 2'
shared_options
method_option :value, :type => :numeric
def task2
end
desc 'task3', 'Task 3'
method_option :colors, :type => :boolean, :aliases => '-c'
def task3
end
end
Cli.start(ARGV)
答案 2 :(得分:2)
我遇到了同样的问题而且我使用的是N.N.回答。 但我发现了一些问题:
如果您想在示例中共享多个选项,则效果不佳。想象一下,您想在task2和task3之间共享:value
。您可以创建另一个shared_options
,也可以使用共享选项创建一个数组,并使用shared_option名称访问它。
这有效,但它很冗长,难以阅读。我已经实现了一些小东西来分享选项。
Cli < Thor
class << self
def add_shared_option(name, options = {})
@shared_options = {} if @shared_options.nil?
@shared_options[name] = options
end
def shared_options(*option_names)
option_names.each do |option_name|
opt = @shared_options[option_name]
raise "Tried to access shared option '#{option_name}' but it was not previously defined" if opt.nil?
option option_name, opt
end
end
end
#...commands
end
这将创建一个散列,其中选项名称为键,“定义”(必需,默认等)为值(这是一个散列)。之后很容易获得。
有了这个,您可以执行以下操作:
require 'thor'
class Cli < Thor
add_shared_option :type, :type => :string, :required => true, :default => 'foo'
add_shared_option :value, :type => :numeric
desc 'task1', 'Task 1'
shared_options :type
def task1
end
desc 'task2', 'Task 2'
shared_options :type, :value
def task2
end
desc 'task3', 'Task 3'
shared_options :value
def task3
end
end
Cli.start(ARGV)
对我而言,它看起来更具可读性,如果命令数量大于3或4,那么这是一个很大的进步。
答案 3 :(得分:2)
所以现在有一个很好的干燥方法,但可能不会落入惯用的要求,尽管我想为那些寻找更新答案的人提及它。 / p>
您可以先使用class_options设置方法之间的大部分共享选项:
module MyModule
class Hello < Thor
class_option :name, :desc => "name", :required => true
class_option :greet, :desc => "greeting to use", :required => true
desc "Hello", "Saying hello"
def say
puts "#{options[:greet]}, #{options[:name]}!"
end
desc "Say", "Saying anything"
remove_class_option :greet
def hello
puts "Hello, #{options[:name]}!"
end
def foo
puts "Foo, #{options[:name]}!"
end
end
end
关于此的最好的部分是,它与声明后的所有方法有关。设置为必需,您可以看到第一种方法需要 greet 和 name ,但说和 foo 只需要名称。
答案 4 :(得分:0)
为了不一直输入“shared_options”,你也可以这样做:
require 'thor'
class Cli < Thor
class << self
private
def shared_options!
# list your shared options here
method_option :opt1, type: :boolean
method_option :opt2, type: :numeric
# etc
end
# alias original desc so we can call it from inside new desc
alias_method :orig_desc, :desc
# redefine desc, calling original desc, and then applying shared_options!
def desc(*args)
orig_desc(*args)
shared_options!
end
end
desc 'task1', 'Task 1'
def task1
end
desc 'task2', 'Task 2'
def task2
end
desc 'task3', 'Task 3'
def task3
end
end
或者如果你不想要杂技与方法别名,你可以只定义你自己的方法“my_desc”并调用它而不是“desc”。