思い出話とか

こんにちは、近ごろ寒くてハーパンからジーパンに衣替えした @takano32 です。

さて、久しぶりに Ruby について何か書くような気がするこの頃ですが、ふと昔の事を思い出していました。

いまでは Ruby on Rails とかでインターネットを賑わせている言語となりましたが、バージョン 1.2 くらいのときはオブジェクト指向できれいなプログラミングができるし UNIX とも仲良しな言語として使われていました。Perl のように $ ではじまる省略された記法で文字列処理もできるし、 class を定義して、なんだか簡単にきれいなオブジェクト指向のプログラミングもできます、みたいな感じ。Java とかは static public void main とか面倒だからいらない。

その後にキラーアプリとして RWiki とか tDiary がでてきて、なんかこう「あの、はてなダイアリーみたいなの自分でホストするには Ruby という言語が必要なんだってね」っていう時代があったりなかったりしましたね。だいたいこのくらいの頃からですかね、 Hyper NIKKI System の数が減少傾向に入っていったのは。まあそれはいいか。

それで、最初の RubyKaigi 的な何か1は Ruby についての英語のドキュメントとか少ない頃に開かれていて、なんというか、会場に行ってみると半数くらいが「メーリングリストで名前をみた」って感じのメンバーで、いま思えば単なるオフ会でしたね。あれ。
ちなみに、そのころのプレゼンでよくあった内容としては「いかにして Ruby で仕事をするか」「上司を説得して Ruby を導入する方法」みたいな、そんな内容でした。お前らには想像できないだろう〜、ハッハッハッ。すみません、調子にのりました。

その後は Rails が 1.2 くらいがリリースされた頃から有名になって、ドーン、バシーン、ガシャーン!有名!!!って感じです。雑ですね。はい。

Ruby が Perl の次を狙っていたころの話

Ruby が Perl のようなプログラミングもできるってところの話を掘り下げようと思います。

では、 Perl とは何だったのか。という話ですよね。
Perl は真珠の Pearl という名前で作ろうとしたところ、すでに UNIX には pearl コマンドがあったから、 perl となった、という話を聞いています。
んじゃあ、なんで真珠なの?というと、Perl のコンセプトのひとつにシェルスクリプトよりも扱いやすいスクリプト言語、というのがあったんですね。
Shell つまり 貝 よりも使いやすい、ということで真珠、ってわけです。

シェルスクリプトはどんなだったの?っていうと UNIX のコマンドを関数のように組み合わせて使いながら目的を果たしていく、みたいな言語だったわけです。
そのシェルスクリプトの中でも特に便利だったのが sed, awk, grep とかだったりするわけです。そういった経緯で Perl には sed, awk, grep らができるような文字列処理についてはサポートされており、それらの強力な機能が内包されているわけなのでした。

そういった感じの時代に Perl でちょいちょい CGI とか書かれるよねぇ、みたいなころですかね。
真珠が6月の誕生石であって、ルビーが7月の誕生石って感じでなんか Ruby っていう名前いいよね、みたいな感じのルビィができたわけです。たぶん。そのころのことよく知らないけど、どこかで読みました。

なんかあんまり歴史のことあってるか分からないので、詳しくはRubyist Magazineのヤツを読んで下さい。

Ruby > Perl > sed

ということはですね、Ruby を sed のように使う事もできるんですよ。
みなさん、sed 使ってますか?使ってますよね。うん、使ってる。「sedは日暮れて」を読んで使いまくったものです。
しかしですね。ホールドスペースとかちゃんと使えてますか?

使えてないでしょう!そんなんじゃダメです!はい、わたしもあんまり使いません。

まあ、何が言いたいかというと、 sed で前後の行で関連性をもたせた置換とかをするのにはコツが必要でありまして、老いてくると思い出せないんですよ、これが。

それなら Ruby が Perl の機能を内包していて、Perl が sed の機能を内包しているんなら Ruby で書けばいいじゃない、というのが今回の話です。あ、ここの文章というか、この節のタイトルはマサカリ投げられそう。ウッ。でも、気にしない。

コマンドライン引数を使いこなせ

-Ke だと *.rb の文字コードを EUC-JP として解釈するぜ!

じゃなくて。

今回は ruby --help のこの部分です。

  -Fpattern       split() pattern for autosplit (-a)
  -i[extension]   edit ARGV files in place (make backup if extension supplied)
  -Idirectory     specify $LOAD_PATH directory (may be used more than once)
  -l              enable line ending processing
  -n              assume 'while gets(); ... end' loop around your script
  -p              assume loop like -n but print line also like sed

ここを使いこなすとよい感じにできます。

sed のように使う Ruby

まあ、なんかコマンドライン引数を説明していくより見てもらった方がはやそう。

そのまま

$ echo hoge | sed -ne 'p'

$ echo hoge | ruby -lne 'print $_'

これです。

もちろん、 -p を使って

$ echo hoge | ruby -pe ''

とかでもいいです。

置換

$ echo hoge | sed -ne 's/o/a/p'

$ echo hoge | ruby -lne 'print $_.sub("o", "a")'

なんかcut(1) みたいなことしたければ String のメソッドが使えるので String#split とかしてもいいし、コマンドライン引数の -F とかを使ってもよい。

Regex も使い放題だし、名前付きキャプチャとかも使えるわけだから、かなり複雑なところまで耐えられる。耐えられなかったら次の節を読むといい。

複数行とか

shebang!2#! ruby -ln とか書いて Array に << していって、好きなところを好きなように使えばホールドスペースのことを忘れても平気です。shebang を使うのは卑怯なんじゃ…って気もしますけど、ホールドスペースを使うくらいのものになったら #! sed -f ですよね。許してよ。

複数ファイルの置換

sed の -i オプションみたいなのが Ruby でも -i で使えるのでそれで、find -print0 とか xargs -0みたいなの組み合わせて上書きしてやればいい。

なんで Ruby 2.4 のタグがついてるの?

あんた、いいところに気づいたね。

sed みたいに短く書けるのは -n の効果がデカい。

  -n              assume 'while gets(); ... end' loop around your script

そのままに表示する

echo hoge | ruby -lne 'print $_'

というワンライナーは -n を使わないとこうなる。

echo hoge | ruby -le 'while gets; print $_; end'

長い。でも、それはそれで便利な事があって、 awk で言うところの BEGIN とか END みたいなのが書けたりするわけよ。

このときに gets がでてくるわけだけど、じつは Ruby 2.4 から新しく chomp flag が渡せるようになっている。

chomp flag

なんか説明するの面倒なので感じろ。

-n オプションの改行の扱い

p で改行がどうなってるのか見てみる。

$ echo hoge | ruby -ne 'p $_'
"hoge\n"

gets の改行の扱い

$ echo hoge | ruby -le 'while gets; p $_; end'
"hoge\n"

モロに捕まえてる。ラインフィード。君を。

gets + chomp flag

chomp flag を使うと

$ echo hoge | ruby -le 'while gets(chomp: true); p $_; end'
"hoge"

こうなる。

さようなら ARGF.read.each_line{ |line| line = line.chomp ... よ。
うそです。便利なので ARGF とか DATA も友だちでいてください。

本当に Ruby 2.4 からなの?

この機能は

$ ruby -v
ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin16]

には入ってる。

けど

$ ruby -v
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16]

とかだと

$ echo hoge | ruby -le 'while gets(chomp: true); p $_; end'
-e:1:in `gets': no implicit conversion of Hash into Integer (TypeError)
    from -e:1:in `gets'
    from -e:1:in `<main>'

ギャフン。

chomp flag は Ruby 2.4 からの新機能のひとつ。なので、これを紹介したことによって Ruby2.4 タグがこの記事に付いていてもおかしくないわけ!おかしくないの!!!

終わりに

世の中の変人たちの間ではシェル芸というものが流行っているらしいので Ruby も仲間に入れてあげて下さい。

あと、あんまり調べずに書いたので、きちんと知りたいひとは自分で調べて下さい。寒い。眠い。


  1. いちおう、わたくし、このあいだの京都の RubyKaigi は SORABITO株式会社からのサポートがあって行く事ができまして、RubyKaigiとかRuby会議みたいな名前の日本で開かれている何かは皆勤賞です。 

  2. +x なファイルの先頭に書くと便利な #! ではじまるアレ