知ってもあまり役に立たないRubyの記法n選

[オライリーの「プログラミング言語 Ruby」](https://www.oreilly.co.jp/books/9784873113944/)に改めてめを通していたのですが、知らない書き方があちこちに出てきました。実用できる機会はそう多くないかと思いますが、せっかくなのでまとめてみることにします。

# リテラル編
## 「?＋1文字」のリテラル
* 代替可能性…☆☆☆☆☆
* 実用性…☆★★★★

```rb
p ?あ # => "あ"
```

[ここ](https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#string)にもあるように、「?＋1文字（エスケープも可）」というものが、「1文字を表す文字列リテラル」となります。コードゴルフのような特殊な場面ではまだ使うこともありますが、実用プログラムを書く上ではふつうに`'あ'`と書いたほうが圧倒的にわかりやすいので、出番はほぼ皆無です。

## 正規表現リテラルへのエンコード指定オプション
* 代替可能性…☆☆★★★
* 実用性…☆★★★★

```rb
/[あいう]/u
```

[正規表現リテラル](https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#regexp)の後には、`i`を付けて大文字小文字を無視させるなど、修飾子をつけることができます。

そして、`n`、`s`、`e`、`u`を付けると、それぞれ正規表現のエンコードがASCII-8BIT、シフトJIS、EUC、UTF-8になります。

Ruby 2.0以降、ソースエンコーディングのデフォルトがUTF-8になったこと、そして多様なエンコードを扱うにしても通常は出入りで変換して、プログラム内では1通りのエンコードとすることなどを考え合わせれば、実用する場面はほぼ来ないでしょう。

# 制御構造編
## BEGIN、END
* 代替可能性…☆☆★★★
* 実用性…☆★★★★

```rb
puts 'ふつうのコード1'

BEGIN { puts 'プログラム起動時に実行' }

puts 'ふつうのコード2'

END { puts 'プログラム終了時に実行' }

puts 'ふつうのコード3'
```

例外処理用の`begin`...`end`とはまったく別物で、`BEGIN`はプログラム開始時に実行するコード、`END`は終了時に実行するコードをブロックで渡します。

AWK、Perlから受け継いだ由緒正しい機能なのですが、書き捨てのスクリプトを越えるような規模のコードでは、出番はないと言っていいでしょう（なお、`END`をメソッド内に書くと警告されますが、同様な[`at_exit`カーネルメソッド](https://docs.ruby-lang.org/ja/latest/method/Kernel/m/at_exit.html)があります）。

## `redo`、`retry`
* 代替可能性…☆★★★★
* 実用性…☆☆☆★★

一般的なループ制御の`break`や`next`と違って、`redo`は**ループ条件を評価せずに**中身を実行する、`retry`は例外処理で同じことをやり直す、というものです。

通信エラーを`rescue`したときに`retry`をかけたことはありますが、どちらもそこまで汎用はしないものだと思います。

## `if`...`then`
* 代替可能性…☆☆☆☆★
* 実用性…☆★★★★

```rb
if cond then
  some_method
  some_method2
end
```

`if`の条件の後に`then`と書くことができますが、複数行の場合はまったく意味がありません。

1行で書く場合は`then`を条件と本体の区切りにできますが、そもそも1行で書けるなら後置`if`なり三項演算子なりを使うのが適当でしょう。

## 後置`while`
* 代替可能性…☆☆☆★★
* 実用性…☆★★★★

後置の`if`や`unless`はふつうに使いますし、後置`rescue`というのもたまに便利な場面はありますが、1行で済む規模の`while`というのがなかなかないので、使用例もちょっと思いつけないです[^1]。

## フリップフロップ
* 代替可能性…☆☆★★★
* 実用性…☆☆☆★★


[詳しい記事がある](http://qiita.com/Ping/items/acb7fbb9aa141c2c46df)ので詳細は譲りますが、`..`や`...`を条件式に使うと、同じ式のはずなのに状態によって評価が変わる、という挙動になります。

ワンライナーでは便利だと思いますが、好き嫌いが分かれる機能かなと思いました。

## 例外処理の`else`
* 代替可能性…☆☆☆★★
* 実用性…☆★★★★

```rb
def some_method
  # 省略
rescue SomeException
  # 省略
else
  # 省略
end
```

例外処理の`rescue`と並んで`else`を書くと、「例外が何も発生せずに`rescue`直前にたどり着いた」ときに実行されるコードとなります。実際のところは、`rescue`直前に書くのと比べて、「`else`節内では、すぐ上の`rescue`へ飛ぶことがない」というだけが違いとなります。…正直、使い所がわかりません。

## クラス宣言で`rescue`
* 代替可能性…☆★★★★
* 実用性…☆☆★★★

```rb
class SomeClass
  attr_reader :some_attribute
rescue SomeException
  # 略
end
```

例外処理の`rescue`は`begin`、あるいはメソッド定義の`def`に付随させる、という印象があるかと思いますが、Rubyでは[クラス宣言も実行文](http://qiita.com/jkr_2255/items/a188b51c2fad4ef1578c)だということもあって、`class`や`module`に付随する形で`rescue`や`ensure`などを書くことができます。

…とはいえ、通常クラス宣言内でバリバリコードを実行することは行いませんし、このタイミングで例外に対応しなければならないクラス自体、ほぼ存在しないと思います（外部ライブラリの参照、などで必要になるのかな？）。

# 変数・定数編
## `Object::Object::Object`
* 代替可能性…☆☆☆☆☆
* 実用性…☆★★★★

```rb
p Object::Object::Object # => Object
```

Rubyにはグローバルな関数は存在しないのと同様、定数も厳密には「グローバル」になっておらず、`Object`配下となります。そのため、`Object::Object`も`Object`ですし、何度重ねても`Object`です。

実際上は、`Object::Hoge`としなくても`::Hoge`で同じ定数を取れるわけですし、（ネタとして以外の）有用な用途はほぼなさそうです。

## グローバル変数の`alias`
* 代替可能性…☆★★★★
* 実用性…☆☆☆★★

```rb
$foo = 1
alias $bar $foo
$bar = 3
p $foo # => 3
```

メソッドの別名を`alias`で書くか`alias_method`で書くかがよく議論となりますが、`alias`はグローバル変数に対して行うことも可能です。

しかも、上の例を見れば分かる通り、その時の値のコピーではなく、真のエイリアスとなっています（組み込みの特殊変数の`alias`を作成した場合も、機能まで有効となります）。

もっとも、グローバル変数自体、そこまで多用すべきものでもないので、これの出番も限られそうです。

# メソッド・ブロック編
## クラスメソッドの呼び方
* 代替可能性…☆☆☆☆☆
* 実用性…☆★★★★

```rb
p Math::sqrt(4) # => 2.0
```

クラスメソッドといえども、Rubyでは「クラスインスタンスのメソッド」なので、`Class.method`の形で呼ぶのが普通です。`Class::method`とも書けるとのことですが、こう書く意味もないし定数と間違えるのでやめたほうがいいでしょう。

## ブロックパラメーターでローカル変数を確保
* 代替可能性…☆☆☆★★
* 実用性…☆☆☆★★

```rb
x = 3
arr.each { |item; x| x = 5 }
p x # => 3
```

ブロックの作成時にブロックパラメーターの後へセミコロンで区切って変数名をつなげることで、ブロックにローカルな変数とすることができます。

もっとも、変数名が外側と衝突しないようにすればそれで済む、とも言えますが。

# 番外編
## `Enumerable#map`/`#collect`
* 代替可能性…☆☆☆☆☆
* 実用性…☆☆☆☆☆

この2つは全く同一の動作をするメソッドですが、どちらを使うかはある種[宗教戦争みたいな面がある](http://magazine.rubyist.net/?0038-MapAndCollect)とのことです。自分自身は`map`しか使ったことがない気もします。


[^1]: `begin`...`end`に`while`を後置した場合、他言語のdo-whileのように動きますが、これは非推奨とのことです。