webエンジニアの日常

RubyやPython, JSなど、IT関連の記事を書いています

Rubyをもう一歩進んで勉強する3章(Perl風機能の排除)

第3章はRubyに残っているPerl風機能を排除(できるだけ使わないようにしよう)です。

Rubyは様々な言語から影響を受けながら作られた言語です。

影響を受けた言語の一つとしてPerlがあります。

僕はPerlを触ったことがなく、初めてRubyを触ったのも2系になってからなので(Perl風機能がだんだんと減っている?)実はこの章はあまりピンときませんでした。

Rubyの暗号名多Perl風機能を避けよう

Perl風機能とは何か次の例で示します

スポンサーリンク

def extract_error(message)
  if message =~ /^ERROR:\$s+(.+)/
    $1
  else
    "no error"
  end
end

この中に2か所Perl風機能が含まれています。

一つ目は、=~演算子です。

これは右の正規表現にマッチした文字列内の位置を返します。マッチする部分が無ければnilを返します。

nilはRubyでは偽になるので、マッチする部分が無ければ"no error"が返り値になりますね。

もう一つは、Perlではグローバル変数として使われる?$1変数です。

ですが、実際は$1はグローバル変数ではなく、メソッド内でのみ値を持つ特殊グローバル変数となっています。

すなわち、一度値が入っても、メソッドを抜けるとnilに戻ってしまいます。

例外的な動きをする変数があるとややこしいですよね。僕は「?」となります。というかなってました。

そこで、文字列のマッチや、マッチした文字列を見たいときは、String#matchメソッドを使いましょう

def extract_error(message)
  if m = message.match(/^ERROR:\s+(.+)$/)
    m[1]
  else
    "no error"
  end
end

ずいぶんと分かりやすく、Rubyらしくなりました。

=~演算子は僕もしょっちゅう使っているので、これからはこちらにしたいです。

$1はローカル変数でしたが、Rubyには$:、$;, $/などの暗号のようなグローバル変数がありますが、もっと意味の分かりやすい名前(例えば、$LOAD_PATHは$:の別名)の方を使うべきです。

これらの別名はEnglishライブラリをロードすることで使えます。

また、直接暗号のようなグローバル変数を使わなくても、暗黙のうちに使っている場合もあります。

while readline
  print if ~ /^ERROR:/
end

この処理の意味が分かるでしょうか?僕は全然わかりませんでした。

それも、そのはず、この処理の中では表に出てこない$_というグローバル変数を動かしているからです。

まず、Kernel#readlineメソッドは標準入力を$_へ代入します

次に、~演算子は、右の正規表現に$_の中身をマッチさせます。

もしERRORにマッチしなければnilが返るのでprintメソッドを実行しません。マッチしたとき、引数なしのprintメソッドを実行します。

最後にKernel#printメソッドは引数なしの場合、$_変数を標準出力へ表示します。

このように、Rubyに残っている暗号のようなPerl風機能を使うと読みにくくなり、メンテナンス性も下がります。Rubyにはこれらの機能を避ける方法がよういされているので、そちらを使うようにしましょう。

Effective Ruby

Effective Ruby

たのしいRuby 第5版

たのしいRuby 第5版

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング