オライリーの「プログラミング言語 Ruby」に改めてめを通していたのですが、知らない書き方があちこちに出てきました。実用できる機会はそう多くないかと思いますが、せっかくなのでまとめてみることにします。
リテラル編
「?+1文字」のリテラル
- 代替可能性…☆☆☆☆☆
- 実用性…☆★★★★
p ?あ # => "あ"
ここにもあるように、「?+1文字(エスケープも可)」というものが、「1文字を表す文字列リテラル」となります。コードゴルフのような特殊な場面ではまだ使うこともありますが、実用プログラムを書く上ではふつうに'あ'と書いたほうが圧倒的にわかりやすいので、出番はほぼ皆無です。
正規表現リテラルへのエンコード指定オプション
- 代替可能性…☆☆★★★
- 実用性…☆★★★★
/[あいう]/u
正規表現リテラルの後には、iを付けて大文字小文字を無視させるなど、修飾子をつけることができます。
そして、n、s、e、uを付けると、それぞれ正規表現のエンコードがASCII-8BIT、シフトJIS、EUC、UTF-8になります。
Ruby 2.0以降、ソースエンコーディングのデフォルトがUTF-8になったこと、そして多様なエンコードを扱うにしても通常は出入りで変換して、プログラム内では1通りのエンコードとすることなどを考え合わせれば、実用する場面はほぼ来ないでしょう。
制御構造編
BEGIN、END
- 代替可能性…☆☆★★★
- 実用性…☆★★★★
puts 'ふつうのコード1'
BEGIN { puts 'プログラム起動時に実行' }
puts 'ふつうのコード2'
END { puts 'プログラム終了時に実行' }
puts 'ふつうのコード3'
例外処理用のbegin...endとはまったく別物で、BEGINはプログラム開始時に実行するコード、ENDは終了時に実行するコードをブロックで渡します。
AWK、Perlから受け継いだ由緒正しい機能なのですが、書き捨てのスクリプトを越えるような規模のコードでは、出番はないと言っていいでしょう(なお、ENDをメソッド内に書くと警告されますが、同様なat_exitカーネルメソッドがあります)。
redo、retry
- 代替可能性…☆★★★★
- 実用性…☆☆☆★★
一般的なループ制御のbreakやnextと違って、redoはループ条件を評価せずに中身を実行する、retryは例外処理で同じことをやり直す、というものです。
通信エラーをrescueしたときにretryをかけたことはありますが、どちらもそこまで汎用はしないものだと思います。
if...then
- 代替可能性…☆☆☆☆★
- 実用性…☆★★★★
if cond then
some_method
some_method2
end
ifの条件の後にthenと書くことができますが、複数行の場合はまったく意味がありません。
1行で書く場合はthenを条件と本体の区切りにできますが、そもそも1行で書けるなら後置ifなり三項演算子なりを使うのが適当でしょう。
後置while
- 代替可能性…☆☆☆★★
- 実用性…☆★★★★
後置のifやunlessはふつうに使いますし、後置rescueというのもたまに便利な場面はありますが、1行で済む規模のwhileというのがなかなかないので、使用例もちょっと思いつけないです1。
フリップフロップ
- 代替可能性…☆☆★★★
- 実用性…☆☆☆★★
詳しい記事があるので詳細は譲りますが、..や...を条件式に使うと、同じ式のはずなのに状態によって評価が変わる、という挙動になります。
ワンライナーでは便利だと思いますが、好き嫌いが分かれる機能かなと思いました。
例外処理のelse
- 代替可能性…☆☆☆★★
- 実用性…☆★★★★
def some_method
# 省略
rescue SomeException
# 省略
else
# 省略
end
例外処理のrescueと並んでelseを書くと、「例外が何も発生せずにrescue直前にたどり着いた」ときに実行されるコードとなります。実際のところは、rescue直前に書くのと比べて、「else節内では、すぐ上のrescueへ飛ぶことがない」というだけが違いとなります。…正直、使い所がわかりません。
クラス宣言でrescue
- 代替可能性…☆★★★★
- 実用性…☆☆★★★
class SomeClass
attr_reader :some_attribute
rescue SomeException
# 略
end
例外処理のrescueはbegin、あるいはメソッド定義のdefに付随させる、という印象があるかと思いますが、Rubyではクラス宣言も実行文だということもあって、classやmoduleに付随する形でrescueやensureなどを書くことができます。
…とはいえ、通常クラス宣言内でバリバリコードを実行することは行いませんし、このタイミングで例外に対応しなければならないクラス自体、ほぼ存在しないと思います(外部ライブラリの参照、などで必要になるのかな?)。
変数・定数編
Object::Object::Object
- 代替可能性…☆☆☆☆☆
- 実用性…☆★★★★
p Object::Object::Object # => Object
Rubyにはグローバルな関数は存在しないのと同様、定数も厳密には「グローバル」になっておらず、Object配下となります。そのため、Object::ObjectもObjectですし、何度重ねてもObjectです。
実際上は、Object::Hogeとしなくても::Hogeで同じ定数を取れるわけですし、(ネタとして以外の)有用な用途はほぼなさそうです。
グローバル変数のalias
- 代替可能性…☆★★★★
- 実用性…☆☆☆★★
$foo = 1
alias $bar $foo
$bar = 3
p $foo # => 3
メソッドの別名をaliasで書くかalias_methodで書くかがよく議論となりますが、aliasはグローバル変数に対して行うことも可能です。
しかも、上の例を見れば分かる通り、その時の値のコピーではなく、真のエイリアスとなっています(組み込みの特殊変数のaliasを作成した場合も、機能まで有効となります)。
もっとも、グローバル変数自体、そこまで多用すべきものでもないので、これの出番も限られそうです。
メソッド・ブロック編
クラスメソッドの呼び方
- 代替可能性…☆☆☆☆☆
- 実用性…☆★★★★
p Math::sqrt(4) # => 2.0
クラスメソッドといえども、Rubyでは「クラスインスタンスのメソッド」なので、Class.methodの形で呼ぶのが普通です。Class::methodとも書けるとのことですが、こう書く意味もないし定数と間違えるのでやめたほうがいいでしょう。
ブロックパラメーターでローカル変数を確保
- 代替可能性…☆☆☆★★
- 実用性…☆☆☆★★
x = 3
arr.each { |item; x| x = 5 }
p x # => 3
ブロックの作成時にブロックパラメーターの後へセミコロンで区切って変数名をつなげることで、ブロックにローカルな変数とすることができます。
もっとも、変数名が外側と衝突しないようにすればそれで済む、とも言えますが。
番外編
Enumerable#map/#collect
- 代替可能性…☆☆☆☆☆
- 実用性…☆☆☆☆☆
この2つは全く同一の動作をするメソッドですが、どちらを使うかはある種宗教戦争みたいな面があるとのことです。自分自身はmapしか使ったことがない気もします。
-
begin...endにwhileを後置した場合、他言語のdo-whileのように動きますが、これは非推奨とのことです。 ↩