以下, 下書き
2018年12月25日火曜日
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
argument for our generator to run.
thor -T
will show how to run our generator. It should read:thor newgem NAME
. This shows that we have to supply a NAMEargument 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
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:
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
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:
Make the script executable:
chmod a+x mythorcommand.rb
今このようにタイプして実行できる:
Now you can type:
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:
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:
Its tasks are invoked as:
thor app:install
しかしながら, あなたはクラスに名前空間を付けることもできる:
However, you could namespace your class as:
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:
And then you should invoke your tasks as:
thor sinatra:app:install
お望みならば, 名前空間をこのように変えることもできる:
If desired, you can change the namespace:
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:
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クラスたちの中で
To use them, you just need to include
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::Actions と Thor::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 usingThor::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:
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:
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:
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
注意:
Note: when using
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.
また,
Also,
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:
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_option
と method_options
の代わりに, class_option
と class_options
を使ってもいい. argument
メソッドと class_options
メソッドは両方とも, Thorクラスにも使用可能だ.
You can also give options to
and
Both argument and
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:
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:
When invoking the task one:
thor counter:one
その出力は
The output is
The output is
1
2
3
となり, これはつまり, タスク
which means that the
You can even invoke tasks from another class, so be sure to check the
documentation for the Thor class.
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はタスク
Notice invocations do not share the same object. i.e, Thor will instantiate
one
を実行するために Counter
を一度インスタンス化し, その次に, タスク two
の実行にもうひとつ, タスク three
を実行するためにまたひとつ Counter
をインスタンス化する. このことはもろもろのオプションと引数を, もう一度パースし直すことができるということだ. たとえば, もし two
と three
がそれぞれ異なったもろもろのオプションを持ち, 両方のオプション群がコマンドラインに与えられたような場合, 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.
登録:
投稿 (Atom)