ぶていのログでぶログ

思い出したが吉日

rfコマンドv1.4.0をリリースした

rfコマンドを普段遣いしていて気になったところをちょくちょく直していて、先程v1.4.0をリリースした。 前回ブログを書いたときはv1.1.0だったので3つほどバージョンアップした。

github.com github.com github.com

以下では、このバージョンアップによる変更点を紹介する。

組み込みメソッドのmatchにブロックを渡せるようにした

組み込みメソッドのmatchはRegexp#matchを内部的に呼び出している。 Regexp#matchはブロックを取れるのに対して、組み込みのmatchメソッドはブロックを渡せなかったので修正した。 この変更で何が嬉しいかというと、例えばfooが含まれる行の2番目のフィールドを出力するということができるようになった。

# v1.4.0未満ではifを使う必要があった
$ echo 'foo bar' | rtx exec rf@1.1.0 -- rf -q 'puts _2 if _ =~ /foo/'
bar

# v1.4.0ではmatchでかける
$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf 'match /foo/ { $F[1] }'
bar

# awkで書くとしたら
$ echo 'foo bar' | awk '/foo/{print $2}'

なお、ブロック外であれば $F[1]_2とかけるのだが、_2が本来のブロックの引数の2番目を意味してしまいnilになってしまうので$F[1]とかく必要がある。 ここはもう少しうまい感じにしたいなぁ。

組み込み関数のmatch/match?のエイリアスとしてm/m?を追加した

matchにブロックを渡せるようになり便利になったので短縮できるように m メソッドをエイリアスで作成した。 前項の例をmに置き換えるとだいぶタイプ数少なくフィルタできるようになったのでは?っと思っている。

$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf 'm /foo/{ $F[1] }'
bar

matchのエイリアスも作ったのでmatch?のエイリアスも作った。

$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf 'm? /foo/'
bar

ただ、これはRegexpだけにしても同じ挙動になるのでm?は不要である。

$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf '/foo/'
bar

それならmatch?とm?は不要では?って思うかもしれないが、複雑な処理を書きたいときにタイプ数が減る・・・ハズ。

# m?を使えばタイプ数は減りそうだが可読性が低くなる。だけど、ワンライナーだから気にしない!
$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf -q 'puts _2 if m? /foo/'
bar

textフィルタでRegexpでマッチした部分を色付けするようにした

grepコマンドのようにマッチした部分をANSIエスケープコードで色付けするようにした。 なお色付けしないオプションは今のところないので、困ったら実装する。

textフィルタに置いて配列を自動でjoinするようにした

配列を出力しようとするとRubyのオブジェクトをto_sした文字列が出力されていた。 これは扱いづらいので、空白()でjoinして出力するようにした。

$ echo 'foo bar' | rtx exec rf@1.1.0 -- rf '$F'
["foo", "bar"]

$ echo 'foo bar' | rtx exec rf@1.4.0 -- rf '$F'
foo bar

Object#to_jsonをpretty printするようにした

JSONフィルタではデフォルトで出力がpretty printされるようになっている。

$ echo '{"foo":"bar"}' | rf -j '_'
{
  "foo":"bar"
}

しかし、Object#to_jsonを使うとpretty printされていなかった。 使用するメソッドによって出力が変わるのは混乱しそうなので統一した。

$ echo '{"foo":"bar"}' | rtx exec rf@1.1.0 -- rf -j 'puts _.to_json'
{"foo":"bar"}

$ echo '{"foo":"bar"}' | rtx exec rf@1.4.0 -- rf -j 'puts _.to_json'
{
  "foo":"bar"
}

YAMLフィルタに--no-docオプションを追加した

mrubyのto_yamlでは*1行頭にドキュメントセパレータ(---)がついてしまう。 これがあると不都合な場合があるので、ドキュメントセパレータを出力しないオプションを追加した。 なお、デフォルトでドキュメントセパレータを出力しないようにしていて、出力したい場合は--docをつける必要がある。

$ echo 'foo' | rtx exec rf@1.4.0 -- rf -y '_'
foo

$ echo 'foo' | rtx exec rf@1.4.0 -- rf -y --doc '_'
--- foo

入力を一括で読み込む-Aオプションを追加した

通常各フィルタにおいては1行/1オブジェクトごとにイテレーションされるが、それを一括で読み込むオプションを追加した。 ユースケースが限られるが、例えばJSONをYAMLに変換したり、今はできないが文字コードを変換したりすることができる。

# input.jsonをYAMLに変換して出力
$ rf -jA '_.to_yaml' input.json

# 今はできないがUTF-8なテキストをSJISに変換するという場面
$ rf -A '_.encode("SJIS")' input.txt

この記事を書いていて思いついたのだがSHA1などのハッシュを取るみたいなこともできるか?

-fオプションでプログラムファイルを外部から読み込めるようにした

今のrfで長いプログラムを書くことはないだろうけど、実装が楽だったので-fオプションを追加した

$ echo '/foo/' > example.rf
$ echo 'foo' | rtx exec rf@1.4.0 -- rf -f example.rf
foo

バージョン情報の出力内容を増やした

バージョン番号を出していただけでそっけなかったので、mrubyエンジンのバージョンも出すようにした。 mrubyを使っている感↑↑

$ echo '{"foo":"bar"}' | rtx exec rf@1.1.0 -- rf -v
1.1.0

$ echo '{"foo":"bar"}' | rtx exec rf@1.4.0 -- rf -v
rf 1.4.0 (mruby 3.2.0)

rfコマンドを日常的に使っている

各アップデート内容はrfコマンドを日常使いしていて、これができたらいいのに!という体験から実装している。 だいぶ指も慣れてきて、grepのかわりにrfを使えるくらいにはなった。 単純なgrepくらいならrfに置き換えてもタイプ数がわからないのがよい。

$ echo foo | grep foo
$ echo foo | rf /foo/

とはいえ、awkやsedの置き換えがまだシュッとできないのでどんどん機能を追加していきたい。

*1:CRubyも?というかlibyamlの実装かも