如何在单独的类/模块/文件中组合Thor任务?

Nic*_*uer 21 ruby module thor

我在让托尔这么做时遇到了一些麻烦,所以希望有人可以指出我做错了什么.

我有一个主类class MyApp < Thor,我想分成多个名称空间的单独文件,比如thor create:app_typethor update:app_type.我找不到任何一个例子来说明如何将Thor应用程序拆分成碎片,而我尝试过的东西似乎不起作用.

举个例子,这个班我试图从主要的Thor类中脱颖而出:

module Things
  module Grouping

    desc "something", "Do something cool in this group"
    def something
      ....
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

当我尝试在我的主要课程中包含或要求时:

class App < Thor
  ....
  require 'grouping_file'
  include Things::Grouping
  ....
end
Run Code Online (Sandbox Code Playgroud)

我得到一个例外: '<module:Grouping>': undefined method 'desc' for Things::Grouping:Module (NoMethodError)

是否有可能为Thor任务设置多个名称空间,如果是,那么如何将其分解出来以便您没有一个需要几百行的单一类?

Ric*_*ruz 13

为什么它不起作用:当你descThor类中使用时,实际上是在调用类方法Thor.desc.当你在模块中执行此操作时,它会调用YourModule.desc显然不存在的模块.

我可以通过两种方式来解决这个问题.

修复一个:使用Module.included

您是否希望在多个Thor课程中重复使用这些任务?

当模块用作includeRuby时,included调用类方法.http://www.ruby-doc.org/core/classes/Module.html#M000458

module MyModule
  def self.included(thor)
    thor.class_eval do

      desc "Something", "Something cool"
      def something
        # ...
      end

    end
  end
end
Run Code Online (Sandbox Code Playgroud)

修复二:将Thor类分成多个文件

您是否只想在另一个文件中单独定义任务?

如果是这样,只需在另一个文件中重新打开App类.你的Thorfile看起来像:

# Thorfile
Dir['./lib/thor/**/*.rb'].sort.each { |f| load f }
Run Code Online (Sandbox Code Playgroud)

然后你lib/thor/app.rb将包含一些任务App,而另一个文件lib/thor/app-grouping.rb将包含同一个App类的更多任务.


sem*_*ros 13

使用一个覆盖模块,比方说Foo,您将在其中定义所有子模块和子类.

在单个foo.thor文件中启动此模块的定义,该文件位于运行所有Thor任务的目录中.在此Foo模块的顶部foo.thor,定义此方法:

# Load all our thor files
module Foo
  def self.load_thorfiles(dir)
    Dir.chdir(dir) do
      thor_files = Dir.glob('**/*.thor').delete_if { |x| not File.file?(x) }
      thor_files.each do |f|
        Thor::Util.load_thorfile(f)
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后在主foo.thor文件的底部添加:

Foo.load_thorfiles('directory_a')
Foo.load_thorfiles('directory_b')
Run Code Online (Sandbox Code Playgroud)

这将以递归方式包含*.thor这些目录中的所有文件.在主Foo模块中嵌套模块以命名您的任务.只要您通过上述方法包含所有与Thor相关的目录,无论文件位于何处或在此处调用它们都无关紧要.

  • 我要感谢你.Thor的文档非常糟糕,我不是专家.:) (2认同)

小智 5

我也遇到了同样的问题,几乎要放弃了,但后来我有了一个想法:

如果您将任务写入Thorfiles 而不是作为 ruby​​ 类,那么您可以简单地require在包含 Thor 子类的 Ruby 文件中,并且当您运行时它们将出现在可用任务列表中thor -T

这一切都是班级管理的Thor::Runner。如果您仔细查看此内容,您将看到一个#thorfiles负责查找Thorfile当前工作目录下命名的文件的方法。

我所要做的就是 a) 将我的 Thor 任务分解为多个文件,同时 b) 不必Thorfile创建一个 的本地子类Thor::Runner#thorfile用返回我的应用程序特定的 Thor 任务文件列表的方法覆盖其方法,然后调用它的#start方法和一切都有效:

class MyApp::Runner < ::Thor::Runner
  private
  def thorfiles(*args)
    Dir['thortasks/**/*.rb']
  end
end

MyApp::Runner.start
Run Code Online (Sandbox Code Playgroud)

所以我可以有任意数量的 Ruby 类定义 Thor 任务,thortasks例如

class MyApp::MyThorNamespace < ::Thor
  namespace :mynamespace

  # Unless you include the namespace in the task name the -T task list
  # will list everything under the top-level namespace
  # (which I think is a bug in Thor)
  desc "#{namespace}:task", "Does something"
  def task
    # do something
  end
end
Run Code Online (Sandbox Code Playgroud)

在我弄清楚这一点之前,我几乎放弃了 Thor,但是没有很多库可以处理创建生成器以及构建命名空间任务,所以我很高兴找到了一个解决方案。


Pab*_*zzi -4

desc是一个类方法,您需要使用extend而不是include。看看这里的解释。