Perl Monger が Ruby に入門してつまづいたことのまとめ

初心者向けです。
過去6年間ぐらい、仕事で主に Perl を書いていた筆者が、ここ約1ヶ月と少しの間で Ruby を勉強し直して、ハマったことや「あれっ？」となったことをまとめておきます。

それ以前の Ruby 経験というと、Ruby 1.8 〜 1.9 ぐらいの頃に Rails で Web アプリケーションを作っていたこともありました、というぐらいです。[^1]

[^1]: ちなみに、2016/4/9 現在は[『初めてのRuby』](http://amzn.to/1VetpEG)を読み終えて、[『パーフェクトRuby』](http://amzn.to/1oKG6cv)と[『Rails3レシピブック 190の技』](http://amzn.to/1SVW3qO)を読んでいる途中です。

## 前提
（この辺りはハマったことというか、Ruby 初心者向け。）

- Ruby は基本データ型を持たない。すべてがオブジェクト(特定クラスのインスタンス)
  - 数値や文字列などのリテラルは特別な書き方ができるが、実体は `Fixnum` や `String` クラスのインスタンス
- `+` や `==`, `[]` など、他言語では演算子とされるものが Ruby ではメソッドとして実装されていたりする[^2]

[^2]: コメントを参考に。また、正確には[リファレンスマニュアル](http://docs.ruby-lang.org/ja/2.3.0/doc/)を参照のこと。

## つまづいたこと

### リテラル
- シンボルと文字列の違い
  - `stash[‘foo’]` と `stash[:foo]` は異なる
    - Rails の ActiveSupport では同一になるように拡張されているようだ

参考:
> 「ActiveSupportによる既存Rubyクラスの拡張は人間をダメにするんじゃないか」 - [ActiveSupportのHash拡張であるslice, exceptがびっくりするぐらい便利 - Qiita] (http://qiita.com/mah_lab/items/ed10bae99105ea2fd8bd)

### 真偽値
- 偽判定されるのは `false` と `nil` だけ
  - Perl では空文字列や `0` も偽

### 演算子(のように見えるメソッド):
- `++`, `--` はない

参考:

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/key_amb">@key_amb</a> Matzさんによる回答をご覧ください<a href="https://t.co/9x3up3x3Ef">https://t.co/9x3up3x3Ef</a></p>&mdash; YSR@ゆきちさんを応援し隊 (@YSRKEN) <a href="https://twitter.com/YSRKEN/status/687990212761391104">2016年1月15日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

### 配列と範囲
- 配列(Array)と範囲(Range)は違う
  - `(1..3)` と `[1..3]` は違う。後者には `1..3` という Range オブジェクトの要素が1個しか入ってない。 `(1..3).to_a` すれば `[1, 2, 3]` になる。

参考:

- [rubyで連番の配列作ろうとして気づいたアホな思いこみ - みんなのちからになりたい](http://ginzanomama.hatenablog.com/entry/2013/04/15/164701)

### 暗黙の型変換
- たまにやってくれることもあるけど、Perlと同じ挙動を期待してはいけない。

```ruby
#!ruby
5 + "1"        #=> TypeError
"foo" + 5      #=> TypeError
"foo" << 5     #=> "foo\u0005"
5 + "1".to_i   #=> 6
"foo" + 5.to_s #=> "foo5"
```

```perl
#!perl
5 + "1"   #=> 6
"foo" + 5 #=> 5 ※警告は出る
"foo" . 5 #=> "foo5"
```

### 変数の局所性
- perl は `sub { ... }` の中でも外側のスコープのレキシカル変数に対して読み書きできる
- ruby の `def ... end` はローカル変数を局所化する

### 多値
- `a, b, c` みたいなの
- Perl からの類推だと、ただの配列なのかなと思ってしまったが、別物っぽい。
  - 使う構文が決まっている。今のところ、代入か、多値を `return` するか、関数で引数を受け渡しするケースかと思う。
- 特に、多重代入については、[『初めてのRuby』](http://amzn.to/1VetpEG)において「誰もが完全な仕様を把握してないのではないか」とさえ噂される Ruby の魔境の1つ」という記述があった。

### クラス変数
継承先でも共有される。
サブクラスで変更されると、親クラスや他のサブクラスも影響を受ける。

参考:
- [これはMUST！ActiveSupport の Class#class_attribute を使おう！ - Qiita](http://qiita.com/cuzic/items/ffd115f1e17458020b1b)

### '===' 演算子によるクラス判定

Ruby でオブジェクト同士が等価的かどうか判定するメソッドは `==` と `===` があり、case 構文内では後者が使われている。
大雑把な理解としては、 `===` の方がフレキシブルな使い方ができる。

例えばオブジェクトがどのクラスに属しているか、 case 構文で判定するサンプルコードは以下のような感じ(NG 例と OK 例を載せている):

```ruby
# NG
case x.class
when String
  p "x is String"
when Hash
  p "x is Hash"
end

# OK
case x # ここが違う
when String
  p "x is String"
when Hash
  p "x is Hash"
end
```

ちなみに、 `x === String` と `String === x` の結果は異なる。
これは、 `===` がメソッドであり、左辺がレシーバであることを考えれば理解できる。

参考:

- [ruby - caseで変数のクラスを比較しようとすると上手く行かない - スタック・オーバーフロー](http://ja.stackoverflow.com/questions/4596/case%E3%81%A7%E5%A4%89%E6%95%B0%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E6%AF%94%E8%BC%83%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%99%E3%82%8B%E3%81%A8%E4%B8%8A%E6%89%8B%E3%81%8F%E8%A1%8C%E3%81%8B%E3%81%AA%E3%81%84)

### その他
- クラスインスタンス変数というものがある
- Ruby 1.9 で `{ foo: 1 }` みたいな書き方ができるようになった。昔は `{ :foo => 1 }` だけだった。

参考:

-  [【まとめ】インスタンス変数、クラス変数、クラスインスタンス変数 - Qiita](http://qiita.com/mogulla3/items/cd4d6e188c34c6819709)

## 結びに

今のところ、こんなところです。
もうだいぶ慣れてきたかな、と思っていますが、また何か驚くようなことがあれば書き足すかもしれません。

以上です。

## 脚注