私的Rubyのコーディングガイド
Cookpad・Shopify・GitHub・Airbnb・コミュニティ(bbatsov/rubocop)の各スタイルガイドを項目別にマージしたものです。
全般
private/protectedの可視性を迂回しないよう、sendよりpublic_sendを優先する。
# ❌
obj.send(:private_method)
# ✅
obj.public_send(:public_method)
インデントと改行
- インデントはスペース2つ。タブ文字は使わない。
- 改行コードは Unix 形式(LF)を使う。
;を使って複数の式を1行に書かない。1行1式を原則とする。
複数行の整形
- 複数行に展開する場合(メソッド呼び出し・ハッシュ・配列)、各要素・引数は必ず1要素1行にする。閉じ括弧は最後の要素の次の行に単独で置く。
# ❌
[value_1, value_2,
value_3]
# ✅
[
value_1,
value_2,
value_3,
]
デフォルト引数
デフォルト引数の = の前後にスペースを入れる。
# ❌
def foo(x=1, y=2); end
# ✅
def foo(x = 1, y = 2); end
命名規則
- シンボル・メソッド・変数・ファイル名・ディレクトリ名:
snake_case - クラス・モジュール:
CamelCase(HTTP・RFC・XML のような略語は大文字を維持) - その他の定数:
SCREAMING_SNAKE_CASE - ソースファイル1つにクラス・モジュール1つを定義し、ファイル名はクラス名を
snake_caseに変換したものにする。 - 真偽値を返すメソッドの名前は
?をつける - 破壊的メソッドには
!(bang)をつける - 使わないブロック引数・ローカル変数には
_プレフィックスをつけるか、_単独で使う。
文字列
- 文字列連結(
+)ではなく、文字列補間("#{...}")またはフォーマット(format())を使う。 - 補間の
#{}内部の前後にスペースを入れない。インスタンス変数・グローバル変数の補間は#{}で囲む。補間内の不要な.to_sは省略する。 gsubが使える場面でより特化したメソッドを優先する。- 複数行文字列にはヒアドキュメントを使い、Ruby 2.3+ では
<<~構文を使う。
配列
Array.newより配列リテラル[]を使う。- 複数行の配列リテラルは末尾の要素の後にもカンマを付ける(trailing comma)。
ハッシュ
Hash.newよりハッシュリテラル{}を使う。Symbol をキーにする場合は新記法{ key: value }を使う。- 複数行のハッシュリテラルでは、開き
{の後で改行し、各要素を1段インデント、閉じ}は独立した行に、末尾要素の後にもカンマを付ける。
# ✅
hash = {
first: 42,
second: 'foo',
}
- 存在が必須のキーには
Hash#fetchを使う。デフォルト値の設定にもHash#fetchを使い、||による falsy 誤判定を避ける。(場合による)
heroes = { batman: 'Bruce Wayne' }
# タイポしても nil が返りエラーに気づかない
heroes[:supermann] # => nil
# KeyError が即座に発生
heroes.fetch(:superman)
# デフォルト値の設定
config = { enabled: false }
# false が true に上書きされる
config[:enabled] || true # => true
config.fetch(:enabled, true) # => false
演算子と代入
and・or・notを使わない。常に&&・||・!を使う。- 三項演算子のネストは禁止。複数段になる場合は
if/elseを使う。 ||=を使って変数をデフォルト値で初期化してよい。ただし Boolean 変数への||=は使わない。- ミュータブルな定数オブジェクト(文字列・配列・ハッシュなど)には
freezeを呼ぶ。
# ✅
GREETING = 'Hello'.freeze
STATES = ['draft', 'open'].freeze
CONFIG = { timeout: 30 }.freeze
制御構造
- ifなどで代入演算をしない
- 複数行の
if/unlessにはthenを書かない。 - 1行ボディの場合は修飾子形式を使う。
if/unlessの条件を()で囲まない。 forループを避け、イテレータを使う。- ガード節(guard clause)を使い、無効データに対して早期 return する。また、ガード節後には必ず空行を入れる
メソッド定義と呼び出し
- パラメータがある場合は括弧を使い、ない場合は省略する。
returnが制御フローに必要でなければ省略する。selfが必要でなければ省略する。- キーワード引数をオプションハッシュより優先する。
# ❌
def create_user(options = {})
name = options[:name]
role = options[:role]
end
# ✅
def create_user(name:, role:)
# ...
end
TimeをDateTimeより優先する。ISO8601 形式の文字列にはTime.parseよりTime.iso8601を使う。
# ❌
DateTime.now
Time.parse('2025-01-01T00:00:00+09:00')
# ✅
Time.now
Time.iso8601('2025-01-01T00:00:00+09:00')
ブロック・Lambda・Proc
- 基本は
do...endを使う。メソッドチェーンをする場合や、戻り値を使う関数的なブロックには{...}を使う。1行で済む場合はdo..endを使わなず{...}を使う
クラスボディの定義順序
クラス・モジュール内の要素は次の順序で並べる。
include/extend/prepend- 定数
- クラス変数(
@@) - クラスメソッド(
class << selfブロック) attr_reader/attr_writer/attr_accessorinitialize- public インスタンスメソッド
protected/privateメソッド- ネストしたクラス・モジュール
- クラスメソッドを定義する際は
def self.methodよりclass << selfブロックを使い、クラスメソッドをまとめる。 - 単純なアクセサ・ミューテータには
attr_accessor・attr_reader・attr_writerを使う。attrは使わない。 - クラス変数(
@@)を避ける(継承での動作が直感に反するため)。 public・protected・privateはメソッド定義と同じインデントレベルで書き、上下に空行を入れる。aliasよりalias_methodを使う。
正規表現
- 文字列の単純な検索には正規表現よりプレーンテキスト検索を使う。
- キャプチャ結果を使わない場合は非キャプチャグループ
(?:...)を使う。 - Perl 由来のグローバル変数(
$1など)よりRegexp#matchの戻り値を使う。番号付きキャプチャより名前付きキャプチャ(?<name>...)を使う。 - 文字列全体の先頭・末尾にマッチさせる場合は
^/$より\A/\zを使う。