オライリーの「プログラミング言語 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のように動きますが、これは非推奨とのことです。 ↩