「Dart Advent Calendar 2014」 11日目は@zukkunが担当します。
Dartは、JavaScriptの代替として登場しましたが、独自のVMを持ち、コマンドラインからDartのプログラムを実行する環境が提供されています。
今回は、Dartでのコマンドラインツールを作る方法を、以下のページを参考にしながら紹介しようと思います。
Write Command-Line Apps | Dart: Structured web apps
動作確認環境はMac OS X 10.9.5です。(Dartは、Windows、Linuxでも使えます)
Dartをインストール
Dartがインストールされていなければ、まずDartをインストールします。
Mac環境では、Homebrewを使ってDartをインストールすることができます。
$ brew tap dart-lang/dart
$ brew install dart
はじめにbrew tapでリポジトリを追加する必要があるので注意です。
参考:Dart News & Updates: Dart launches support for Homebrew
インストールができたら、Dartがインストールされたか確認します。
$ dart --version
Dart VM version: 1.7.2 (Tue Oct 14 06:58:25 2014) on "macos_x64"
簡単なDartプログラムを書く
まず、簡単なDartのプログラムを書きます。
main() {
print('hello');
}
これを実行してみます。
$ dart hello.dart
hello
helloが出力されます。
これで一応コマンドラインのアプリケーションが作れました。
もう少しコマンドラインツールっぽくしてみましょう。
コマンドライン引数を受け取る
Dartでコマンドライン引数を受け取るには、main関数の引数にList<string>を型とした引数を加えます。
main(List<string> arguments) {
print('hello $arguments');
}
引数の内容をそのままhelloのあとに表示するようにしてみました。
試しに適当に引数を与えて実行してみます。
$ dart hello.dart foo bar 123
hello [foo, bar, 123]
コマンドライン引数がリストとしてそのまま文字列展開されて出力されました。
コマンドライン引数を解析する
自力でコマンドライン引数の内容を解析してもいいですが、複雑なものとなるとけっこう大変です。
そんなときは、このパッケージを使いましょう。
args 0.12.1 | Pub Package Manager
こちら、パッケージとして公開されていますが、Dart Team謹製の公式パッケージです。
パッケージをインストールするために、pubspec.yamlを書きます。
name: hello
dependencies:
args: any
依存パッケージにargsを追加しました。
pub getで依存パッケージを取得します。
$ pub get
Resolving dependencies... (2.5s)
+ args 0.12.1
+ collection 1.1.0
Downloading collection 1.1.0...
Changed 2 dependencies!
真偽値としてオプションを受け付ける
Dartプログラムに、コマンドライン引数の解析の処理を追加します。
import 'package:args/args.dart';
ArgResults argResults;
main(List<string> arguments) {
final parser = new ArgParser()
..addFlag('hoge', negatable: false, abbr: 'h');
argResults = parser.parse(arguments);
print('hello ${argResults['hoge']}');
}
ArgParserのaddFlagで「オプションを指定したか、していないか」の真偽値で引数を受け取ることができます。
negatableは、否定形の引数を受け付けるかを指定できます。(falseを指定しなければ、--no-hogeという指定を受け付ける)
abbrはAbbreviationの略で、「省略」を意味します。今回'h'としているので、-hという指定でも--hogeと同じ意味を持たせることが出来ます。
$ dart hello.dart --hoge
hello true
$ dart hello.dart
hello false
$ dart hello.dart -h
hello true
値付きのオプションを受け付ける
真偽値ではなく値付きでオプションを受け付ける場合は、addOptionを使います。
import 'package:args/args.dart';
ArgResults argResults;
main(List<string> arguments) {
final parser = new ArgParser()
..addFlag('hoge', negatable: false, abbr: 'h')
..addOption('foo', abbr: 'f');
argResults = parser.parse(arguments);
print('hello ${argResults['foo']}');
}
$ dart hello.dart --foo bar
hello bar
$ dart hello.dart
hello null
他にも、デフォルト値の指定や、バリデーションの機能など、盛りだくさんです。
また、GitやRailsなどで見る<プログラム名> <コマンド名> <パラメータ>のような「コマンド形式」でのコマンドライン引数の受け取りのためのaddCommandなどもあります。
コマンドラインツールをインストールする
作ったコマンドラインツールを実行するためにはdart hello.dartのように、dartコマンドの引数としてプログラムのファイル名を指定してあげる必要がありましたが、これをhelloという独立したコマンドとして実行できるように環境にインストールすることができます。
まず、先ほど作ったhello.dartを、pubspec.yamlがあるディレクトリから見てbin/hello.dartとしてファイルを移動させます。(binディレクトリ無ければ作ります)
そして、pubspec.yamlにexecutablesを追加し、その中にhelloを追加します。
name: hello
dependencies:
args: any
executables:
hello:
次にpub globalというコマンドを使用します。
参考:pub global | Dart: Structured web apps
通常は、pub.dartlang.orgに公開された実行可能なパッケージをインストールするときに使用しますが、先ほど作成したhello.dartをインストールしてみます。(pub global上では「インストール」ではなく「アクティベート」と呼んでいますが、便宜上インストールと書きます)
pub globalのあとにactivateを指定し、--source pathオプションをつけ、そのあとにpubspec.yamlが存在するパスを指定することで、ローカル環境にあるパッケージを指定してインストールできます。
$ cd <pubspec.yamlがあるパス>
$ pub global activate --source path .
Activated hello 0.0.0 at path "<pubspec.yamlがあるパス>".
Installed executable hello.
これでhelloというコマンドが使えるようになりました。
$ hello
hello null
$ hello --foo bar
hello bar
helloコマンドの実態は~/.pub-cache/bin/helloとして作られており、中身は以下のようになっています。
# !/usr/bin/env sh
# This file was created by pub v1.7.2.
# Package: hello
# Version: 0.0.0
# Executable: hello
# Script: hello
pub global run hello:hello "$@"
pub globalのアクティベートまわりやrunなどの仕様の説明については割愛します。
コマンドラインツールをアンインストールする
インストールしたコマンドラインツールをアンインストールする場合はpub global deactivateを使います。
$ pub global deactivate hello
Deactivated package hello 0.0.0 at path "<先ほどのpubspec.yamlがあったパス>".
これでhelloが使えなくなりました。
$ hello
zsh: command not found: hello
細かい機能や仕様の話など、まだまだ語り尽くせないものがありますので、機会があれば触って解説できたらと思います。
明日は…………担当者がいない?!どうする @laco0416 さん!
Twitterより引用
@zukkun「@laco0416 Dart Advent Calendarの明日の担当者いません!」
@laco0416「@zukkun 書いてどうぞ!」
明日は@zukkunさんです!俺だ!