bar_1

contents_map

2018年12月21日金曜日

Thor ジェネレータ Generators

ジェネレータ Generators

Thorのすぐれた利用方法のひとつは, カスタムのコード・ジェネレータを作ることだ.
Thor::Group, Thor::Actions そしてERBテンプレート群とを組み合わせれば, これをとても簡単に実現できる (訳注: Thorはもともとrakeやsakeの代替えとして開発されていたようだ. ). ここに例を示そう:
A great use for Thor is creating custom generators. Combining Thor::Group,
Thor::Actions and ERB templates makes this very easy. Here is an example:
class Newgem < Thor::Group
  include Thor::Actions

  # もろもろの引数とオプションを定義する
  # Define arguments and options
  argument :name
  class_option :test_framework, :default => :test_unit

  def self.source_root
    File.dirname(__FILE__)
  end

  def create_lib_file
    template('templates/newgem.tt', "#{name}/lib/#{name}.rb")
  end

  def create_test_file
    test = options[:test_framework] == "rspec" ? :spec : :test
    create_file "#{name}/#{test}/#{name}_#{test}.rb"
  end

  def copy_licence
    if yes?("Use MIT license?")
      # source rootディレクトリでMITLICENSEファイルをコピーする
      # Make a copy of the MITLICENSE file at the source root
      copy_file "MITLICENSE", "#{name}/MITLICENSE"
    else
      say "Shame on you…", :red
    end
  end
end
thor -T を実行すると, このジェネレータの使い方を表示する. それは thor newgem NAME を読むはずだ. これはジェネレータを実行するのに, われわれはNAMEという引数を与えなければならないことを示している.
Doing a thor -T will show how to run our generator. It should read:
thor newgem NAME. This shows that we have to supply a NAME
argument for our generator to run.
create_lib_file はERBテンプレートのひとつを使っている. これはこのようになる:
The create_lib_file uses an ERB template. This is what it looks like:
class <%= name.capitalize %>
end
あなたがジェネレータの中で設定した引数たちは template が呼び出されたときに, 自動で渡される. その他のオプション詳細は ドキュメント を読んで確認せよ.
The arguments that you set in your generator will automatically be passed in
when template gets called. Be sure to read the documentation for more options.
ジェネレータを thor newgem devise で実行すると, ふたつのファイルが作られる: “devise/lib/devise.rb” と “devise/test/devise_test.rb” だ. その次にユーザは, (yes? メソッドを使ったプロンプトで) MITライセンスのファイルをコピーしたいかどうかたずねられる.
もしテスト・フレームワークを変えたいなら, オプションを: thor newgem devise --test-framework=rspec のように追加できる. これはふたつのファイル: “devise/lib/devise.rb” と “devise/spec/devise_spec.rb” を生成する.
Running the generator with thor newgem devise will create two files: “devise/lib/devise.rb”, and “devise/test/devise_test.rb”. The user will then be asked (via a prompt by the yes? method) whether or not they would like to copy the MIT License. If you want to change the test framework, you can add the option: thor newgem devise --test-framework=rspec.
This will generate two files: “devise/lib/devise.rb” and “devise/spec/devise_spec.rb”.

Thor 実行ファイルを作る Making An Executable

実行ファイルを作る Making An Executable

あなたはスクリプトをひとつの実行可能コマンドとして作りたいかもしれない. これをThorで行うには:
You may want to make a script as an executable command. To do this with Thor:
  • RubyのShebang行 (訳注: #! で始まる実行スクリプトの最初の一行目) を入れる.
  • スクリプトの中で require "thor" する.
  • あなたのThorクラスを定義する.
  • #{YourThorClassname}.start を最下行に書く (訳注: .start(ary)とすると明示的に渡せる. この例のようにaryを指定しないとARGVが自動で使われる).
  • include the ruby shebang line.
  • require “thor” in your script.
  • define your Thor class.
  • add #{YourThorClassname}.start to the bottom of your script.
例: mythorcommand.rb
Example: mythorcommand.rb
#!/usr/bin/env ruby
require "rubygems" # ruby1.9 doesn't "require" it though
require "thor"

class MyThorCommand < Thor
  desc "foo", "Prints foo"
  def foo
    puts "foo"
  end
end

MyThorCommand.start
スクリプトを実行可能にする:
Make the script executable:
chmod a+x mythorcommand.rb
今このようにタイプして実行できる:
Now you can type:
./mythorcommand.rb foo

Thor 名前空間 Namespaces

名前空間 Namespaces

デフォルトでは, あなたのThorタスクはRubyの名前空間を使って実行される. このクラスは名前空間を持たない:
By default, your Thor tasks are invoked using Ruby namespace. This class has no namespace:
class App < Thor
  desc 'install', 'Install something'
  def install
    # task code
  end
  # other tasks
end
このクラスのもろもろのタスクは以下のように実行される:
Its tasks are invoked as:
thor app:install
しかしながら, あなたはクラスに名前空間を付けることもできる:
However, you could namespace your class as:
module Sinatra
  class App < Thor
    desc 'install', 'Install something'
    def install
      # task code
    end
    # other tasks
  end
end
そうしたらこのようにこのタスクを実行すればよい:
And then you should invoke your tasks as:
thor sinatra:app:install
お望みならば, 名前空間をこのように変えることもできる:
If desired, you can change the namespace:
module Sinatra
  class App < Thor
    namespace :myapp
    def install
      # task code
    end
    # other tasks
  end
end
そうしたときは, このようにして, あなたのもろもろのタスクは実行されるはずだ.
And then your tasks should be invoked as:
thor myapp:install

Thor アクション Actions

アクション Actions

Thorには, スクリプトやジェネレータといったタスクに役立つ, 5,6個のアクションがある. いくつかはRailsのテンプレートとしてあるので, あなたはそれらに親しんでいるかもしれない. 列挙すると: say, ask, yes?, no?, add_file, remove_file, copy_file, template, directory, inside, run, inject_into_file や, その他にも2,3ある.
Thor comes with several actions that help with script and generator tasks. You might be familiar with them since some came from Rails Templates. They are: say, ask, yes?, no?, add_file, remove_file, copy_file, template, directory, inside, run, inject_into_file and a couple more.
これらを使うには, あなたのThorクラスたちの中で Thor::Actions をincludeするだけだ:
To use them, you just need to include Thor::Actions in your Thor classes:
class App < Thor
  include Thor::Actions
  # tasks
end
ファイルをコピーするアクションなどように, アクションによっては source_root と呼ばれる, クラスメソッドがひとつ必要となるアクションもある. このクラスメソッドはあなたのテンプレートたちが配置されているべきディレクトリだ. Thor::ActionsThor::Shell::Basic のドキュメントを確認すること. たとえば:
Some actions like copy file require that a class method called source_root be defined in your class. This is the directory where your templates should be placed. Be sure to check the documentation on Thor::Actions and Thor::Shell::Basic. For instance:
class App < Thor
  include Thor::Actions

  def self.source_root
    File.dirname(__FILE__)
  end
end

Thor グループ Groups

グループ Groups

Thorには Thor::Group という特別なクラスがある. ひとつの Thor::Group に 定義されたもろもろのタスクはすべて, それらが定義された順に, ひとつのシーケンスとして実行される. [[実行 Invocations]] で使った例は Thor::Group を使って, このように書ける:
Thor has a special class called Thor::Group. All of the tasks defined in a Thor::Group are invoked together as a sequence, in the order that they were defined. The example from [[Invocations]] could be rewritten using
Thor::Group as:
myawesomegem/lib/mycounter_file.rb
require 'thor/group'

module MyAwesomeGem                 # 訳注: 名前空間のためのmodule
  class MyCounter < Thor::Group     # 訳注: ThorではなくThor::Group
    desc "Prints 1 2 3"

    def one
      puts 1
    end

    def two
      puts 2
    end

    def three
      puts 3
    end
  end
end
実行すると:
When invoked:
thor my_awesome_gem:my_counter
# prints "1 2 3"

実行ファイルexecutableのコマンド・リストに, サブクラスThor::Groupを追加するためには, 一番最初に, あなたはこの登録をしなければならないという点に, 注意すること.
Note that in order to add the Thor::Group subclass to the commands list of your executable, you have to register it first.
実行ファイルを利用するには, 説明が [[実行ファイルの作成 Making An Executable]] にあり, たとえばこのようなファイルがあるとする:
Building on the executables explanation found in [[Making An Executable]], let’s say that you have a file:
myawesomegem/bin/command
#!/usr/bin/env ruby
require File.expand_path('lib/command', Dir.pwd)
MyAwesomeGem::MyCommand.start
そうして, コマンドの実装を含むファイルは以下:
And then, the file containing the actual command:
myawesomegem/lib/command.rb
require "thor"
module MyAwesomeGem
  class MyCommand < Thor
    desc "foo", "Prints foo"
    def foo
      puts "foo"
    end
  end
end
実行ファイルをテストする:
Test executable file:
cd myawesomegem
chmod a+x bin/command # make permission
bin/command foo
クラス MyCounterサブコマンドとして 使えるようにするには, Thor.registerメソッド をコールする必要がある:
To make MyCounter available as a subcommand, you need to call the register method:
myawesomegem/lib/command.rb
require "thor"
require File.expand_path("lib/mycounter_file", Dir.pwd)
module MyAwesomeGem
  class MyCommand < Thor
    desc "foo", "Prints foo"
    def foo
      puts "foo"
    end

    # register(class_name, subcommand_alias, usage_list_string, description_string)
    register(MyAwesomeGem::MyCounter, "counter", "counter", "Prints some numbers in sequence")
  end
end
今, クラス MyAwesomeGem::MyCounter < Thor::Group は, mycommand の中のサブタスクとして現れ, そのエイリアスは counter となり, 使い方は:
Now the class MyCounter < Thor::Group will appear as a sub-task within mycommand with the alias counter, usage:
bin/command
# Commands:
#  command counter         # Prints numbers in sequence
#  command foo             # Prints foo

bin/command counter
#=> 1 2 3

注意: Thor::Group を使う場合は, あなたが (descメソッドで) 用意した説明書きは, それぞれのタスク毎にひとつの説明が用意されるのではなく, クラスそのものの説明書きとなる.
Note: when using Thor::Group, the description you provide (using the method desc) is for the entire class, as opposed to providing a description for each task.
また, Thor::Group はもろもろの引数 arguments とオプションをThorのタスクとしてパースできる:
Also, Thor::Group can parse arguments and options as Thor tasks:
class Counter < Thor::Group
  # number will be available as attr_accessor
  argument :number, :type => :numeric, :desc => "The number to start counting"
  desc "Prints the 'number' given upto 'number+2'"

  def one
    puts number + 0
  end

  def two
    puts number + 1
  end

  def three
    puts number + 2
  end
end
上記counterはひとつのパラメータを期待するものであり, 下記のような出力が得られる:
The counter above expects one parameter and has the following outputs:
thor counter 5
# Prints "5 6 7"

thor counter 11
# Prints "11 12 13"
あなたはまた, もろもろのオプションを Thor::Group に与えることができるが, method_optionmethod_options の代わりに, class_optionclass_options を使ってもいい. argument メソッドと class_optionsメソッドは両方とも, Thorクラスにも使用可能だ.
You can also give options to Thor::Group, but instead of using method_option
and method_options, you should use class_option and class_options.
Both argument and class_options methods are available to Thor class as well.
Thor::Group は, 定義された順に実行される5,6個のステップで定義できるので, ジェネレータを作るのにすぐれたツールのひとつだ (Thor::Group は Rails 4.x のジェネレータに使われているツールだ. 訳注: Rails 5.xでもジェネレータとして使われている痕跡が残っている)
Thor::Group is a great tool to create generators, since you can define several steps which are invoked in the order they are defined (Thor::Group is the tool used for generators in Rails 4.x).

Thor 実行 Invocations

実行 Invocations

Thorにはまた実行依存性システムinvocation-dependency systemもあり, この仕組みで, タスクの発動を一度だけにすることもできる. たとえば:
Thor comes with an invocation-dependency system as well, that allows a task to be invoked only once. For example:
class Counter < Thor
  desc "one", "Prints 1 2 3"
  def one
    puts 1
    invoke :two     # 訳注: タスクtwoの中のthreeは実行されない!
    invoke :three
  end

  desc "two", "Prints 2 3"
  def two
    puts 2
    invoke :three
  end

  desc "three", "Prints 3"
  def three
    puts 3
  end
end
タスクoneを実行すると:
When invoking the task one:
thor counter:one
その出力は
The output is
1
2
3
となり, これはつまり, タスク three一度だけ実行されるということだ. 他のクラスからでも, この機能を使ったタスクの実行はできるので, Thorクラスについて ドキュメント を確認すること.
which means that the three task was invoked only once.
You can even invoke tasks from another class, so be sure to check the
documentation for the Thor class.
もろもろの実行invocationsは, 同一のオブジェクトを共有しないことに気づくだろう. すなわち, Thorはタスク one を実行するために Counter を一度インスタンス化し, その次に, タスク two の実行にもうひとつ, タスク three を実行するためにまたひとつ Counter をインスタンス化する. このことはもろもろのオプションと引数を, もう一度パースし直すことができるということだ. たとえば, もし twothree がそれぞれ異なったもろもろのオプションを持ち, 両方のオプション群がコマンドラインに与えられたような場合, invoke をコールすることで, それぞれのタスクに従って, タスク毎に毎回それらがパースされ, 使用される.
Notice invocations do not share the same object. i.e, Thor will instantiate Counter once to invoke the task one, then, it instantiates another to invoke the task two and another for task three. This allows options and arguments to be parsed again. For example, if two and three have different options and both of them were given to the command line, calling invoke enables them to be parsed each time and used accordingly by each task.