開発備忘録 2018/10/19

Ruby の代入演算子 ||=

Ruby の実装でたまに見かけるこの記述について調べてみた。

user ||= fetch_user

上記の式は user が未定義だと fetch_user が呼び出されて user に代入され、そうでないなら user を返す。
何故こうなるのかが分からなかったが、どうやらこの式は以下のように展開されるらしい。

user || (user = fetch_user)

Ruby の場合 || は左辺が真なら右辺は評価しないという性質があるので、user が定義済みなら user を返し、そうでないなら fetch_user が呼び出され代入される、という仕組みになっていたようだ。

RSpec のモック化

Twitter からユーザーのツイートを取得するクライアントが実装されており、それを使ってユーザーのツイート一覧を表示する Controller があるとする。

class TweetsController < ApplicationController
  def index
    twitter_client = TwitterClient.new
    render json: { tweets: twitter_client.fetch_tweets }
  end
end

この Controller のテストを書くときに、ツイートを取得する部分 (twitter_client.fetch_tweets) をモック化する必要があるが、RSpec の場合はこう書く。

tweet_mock = %i[
  'こんにちは'
  'はじめまして'
]
allow(twitter_client).to receive(:fetch_tweets).and_return(tweet_mock)

これにより fetch_tweetstweet_mock を返すようになり、テストが書けるようになる。
ちなみに allowexpect と書くこともでき、両者の違いは allowfetch_tweets が呼びだされていなくてもエラーにはならないが、expect の方は fetch_tweets が呼び出されていないとエラーになる。

Ruby における Hash の定義方法

{'key' => 'value'}
=> {"key"=>"value"}

{:key => 'value'}
=> {:key=>"value"}

{key: 'value'}
=> {:key=>"value"}

最後の書き方は Ruby 1.9 以降の書き方ですが、いまはもうこの書き方が主流な感じがしますね。
最初と最後の書き方では key が文字列になるかシンボルになるかの違いがありますが、可能なら key はシンボルで定義した方がいいと思います。

Ruby のシンボルはただの数値 (:key なら 256348 という感じ) なので、文字列の生成と比べてコストが低いです。
またシンボルは何回呼び出してもひとつしか生成されない (皆んなが 1 つのオブジェクトを参照する) ので、そういった意味でもシンボルの方がパフォーマンスが高いです。

以上の理由から、hash を定義するときは key はなるべくシンボルで定義した方がいいですね。