Rubyに限った話ではないけども, コマンドラインから実行するスクリプトを書く際, コマンドラインオプションのパース部分をもっときれいに書けないか, わたしはいつも悩む.
これまで, べた書きをしてみたり, GNU由来のgetopt, getopt_long, 標準で用意されているOptionParserといったライブラリを使ってみたりした. またいろいろなOSSのオプション解析ルーチンを探っては読んでみたりもした. 今まで書いたり読んだりした中で自分が比較的しっくりきたのはOptionParserだけれども, 処理のスタイルはコードによって皆バラバラで, どうも「コレ」と言ったものが見当たらない…….
さて, 書いているソフトがある程度複雑になり仕様も大きくなってくると, オプション指定の形式として, gitのようなサブコマンドを受け付ける方式を導入したくなってくる. なぜなら, 仕様を整理したり実際にソフトを使用したりする際に, 機能的なまとまりがはっきりしてわかりやすいからだ.
そこで今回わたしは, サブコマンド形式を受け付けるようなオプション解析ライブラリがないか, Web上にあるコマンドライン・オプションのパーサに関する記事やRubyGems(とりあえずはRubyで入り用なので)を調査してみた. 候補は多数あったが, 現時点では以下の2つがわたしには魅力的に映った:
- thor (トール, またはソー. 語源は北欧神話の戦神, 雷神, 農耕神からだろう) - これはRubyGemsの説明によればCommand-line User Interface(CUI)のためのツールキットである. githubにあるソースの履歴を見てみると, もともとはrakeやsakeの代替えを意識していたようだ. またコードジェネレーターのニュアンスが強い. ThorのHPによれば, Bundler, Vagrant, Railsで使われているとのことだ (githubでコード検索したところRails 5でも使われていた)
- gli (Git-Like Interface Command Line Parser) - これはコマンドライン・オプションの処理を重きをおいているようだ. ヘルプの半自動作成の他, Bashの補完のための機能まであるらしい.
見たところgliも魅力的に思える. が, 今回はthorを試してみようと思う. 著名なライブラリでも使われているからだ. そこでまずThorのWikiを日本語訳してみたのがこの記事だ. 対象は以下の通り:
- thor version 0.19.4
- Copyright (c) 2008 Yehuda Katz, José Valim, et al.
- ライセンス - MIT LICENSE
ツアー・ガイド Guided Tour
このページで, Thorを始めるにあたって基本的な説明については見つけられるだろう (訳注: とりあえず試してみたい方は, 列挙の下にある「基本的な使い方」とThor HP を読むのが手っ取り早いと思います). より詳しい情報は以下のサブページで読める.
On this page, you will find basic instructions on how to get started. Further information is available in the following subpages.
On this page, you will find basic instructions on how to get started. Further information is available in the following subpages.
- はじめに Getting Started -
Thorの基本のイントロダクション. タスク, パラメータ, オプションの説明とともに簡単な例がある.
Introduction to Thor conventions. Includes a simple example with explanations of tasks, parameters, and options. - メソッドオプション Method Options -
Thorタスクにオプションを定義するときのやり方について説明する.
Explains what you can do when defining options for Thor tasks. - 実行 Invocations -
Thorの実行依存性の機能を使って, 誤って同じタスクが何度も実行されないよう, どうやってThorのタスク同士を組み合わせて使うかについて示す.
Shows how you can have Thor tasks depend on other Thor tasks without accidentally invoking the same task more than once using Thor’s invocation-dependency features. - グループ Groups -
Thor::Group
は, 複数のタスクを順番に実行するのに便利だ.
Thor::Group is an easy way to run multiple tasks as a sequence. - アクション Actions -
Thor::Actions
は, ファイルシステムとのインタラクションや, コマンドラインでの対話的機能といった, 典型的なアクションをするThorタスクを, 簡単にするために役立つ.
Thor::Actions are helpers for your Thor tasks that make typical actions, like file system interaction or command line user dialogue, easier. - 名前空間 Namespaces -
独自のThorクラスを定義することもできる.
You can define your Thor classes under Namespaces - 実行ファイルを作る Making An Executable -
thor
コマンドなしに, Thorのタスクを直接実行する.
Run your Thor task directly, without thethor
command. - ジェネレータ Generators -
カスタムのジェネレータを定義するのにThorを使った一例 (Rails 3 のジェネレータとして知られる)
An example using Thor to define custom generators (aka Rails 3 generators).
基本的な使い方 Basic Usage
オプションもろもろをひとつのクラスに対応付ける. 単純に, 適切なアノテーションを与えたクラスをひとつ作り, もろもろのオプションを, 関数とパラメータ群に自動でマップさせる.
Map options to a class. Simply create a class with the appropriate annotations
and have options automatically map to functions and parameters.
Map options to a class. Simply create a class with the appropriate annotations
and have options automatically map to functions and parameters.
例:
class App < Thor # [1]
package_name "App" # [2]
map "-L" => :list # [3]
desc "install APP_NAME", "install one of the available apps" # [4]
method_options :force => :boolean, :alias => :string # [5]
def install(name)
user_alias = options[:alias]
if options.force?
# do something
end
# other code
end
desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
def list(search="")
# list everything
end
end
Thorはこのように自動でコマンド群をマップする:
Thor automatically maps commands as such:
Thor automatically maps commands as such:
thor app:install myname --force
これは以下のように変換される:
That gets converted to:
That gets converted to:
App.new.install("myname")
# with {'force' => true} as options hash
- クラスをオプション・マッパーへと変換するため,
Thor
クラスから継承する.
Inherit from Thor to turn a class into an option mapper. - Thorアプリに命名をし, コンソール/デバッグ出力に認識させる.
Allows a Thor application to be named and be recognized on console/debug output. - 非正規の識別子もろもろを, 特定のメソッドに追加でマップする. この例では
-L
を:list
へと変換する指定をしている.
Map additional non-valid identifiers to specific methods. In this case, convert -L to :list - その下にメソッドの説明を直接書く. 最初のパラメータは使用方法で, 2番めのパラメータは説明だ.
Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description. - 任意に追加のメソッドのオプションを与える (訳注: この例では boolean型の
--force
と string型の--alias
という2つのオプションを, まとめて定義している. ひとつずつ定義したい場合はmethod_option
(末尾にsなし) またはoption
を使う).
Provide any additional method options.
さらに理解を深めるには Further Reading
いろいろなユーザたちがどのようにThorを使っているか見てみるには, ‘require thor’ で Githubの検索 をするか Gisthubの検索 をしてみればよい (ただし, 見つけられた コードは Thorの正式な使い方であるという保証はない).
Thor offers many scripting possibilities beyond these examples. Be sure to read
through the documentation and specs to get a better understanding of the options available.
To see how users use Thor, you can search Github or search Gisthub for ‘require thor’. The code you find is user submitted content that has no warranty of correct usage of Thor.
through the documentation and specs to get a better understanding of the options available.
To see how users use Thor, you can search Github or search Gisthub for ‘require thor’. The code you find is user submitted content that has no warranty of correct usage of Thor.
#