ロールモデルが重要なのだ。
-- アレックス・マーフィー巡査 / ロボコップ
Rubyディベロッパーとして、私は常にあることに悩まされてきました - Pythonにはプログラミングスタイルのすばらしい基準 (PEP-8) がある一方で、 Rubyにはコーディングスタイルやベストプラクティスに関する公式のガイドがこれまで存在してきませんでした。 私にはスタイルは重要なことだとしか思われないのにです。 Rubyが持っているような素晴らしいハッカーコミュニティは、 誰もが羨むようなドキュメントを作り出す力があるはずなのにです。
このガイドは、私達の社内製Rubyコーディング規約から生まれました (著者は私)。 しかし仕事をするうちに、自分の仕事はRubyコミュニティの人たち全員に興味を持ってもらえるものではないかと思い始めました。 また、内製コーディング規約といったものをこの惑星はこれ以上必要としていないのではないかとの思いもありました。 そうではない、コミュニティ駆動の、コミュニティに認められた、 Rubyのための慣習、語法、スタイル規定は、 確実にRubyコミュニティに有益たりえると確信したのです。
このガイドを公開して以来、私は世界中の優れたRubyコミュニティのメンバーから、 たくさんのフィードバックを受けています。 全ての提案、サポートに感謝します! お互いに、また全てのRubyディベロッパーにとって有益なリソースを、 一緒に作ることができています。
また、もしあなたがRailsのことに興味があるなら、 こちらの補足も確認してみてください。 Ruby on Rails Style Guide.
このRubyスタイルガイドでおすすめしているベストプラクティスは、実在のRubyプログラマが他の実在のRubyプログラマのために、メンテナンスしやすいコードを書いていくためのものです。 実社会での使われ方を反映したスタイルガイドは、実社会で使われるし、 たとえそれがどんなに素晴らしい理想であっても、 利用者が拒絶するようなスタイルに固執するスタイルガイドは結局全く使われなくなる危険性があります。
このガイドは、関連するルールごとにいくつかのセクションに分かれています。 ルールの後ろにその根拠も付け加えるように努めています (そのような根拠が省略されているときは、自明のものと判断したとお考えください)。
私はこれら全てのルールをどこからともなく考えついたわけではありません - これらのほとんどは、私の職業SEとしての長い経験と、 Rubyコミュニティのメンバーからの意見や提案、 また、"Programming Ruby"や、 "The Ruby Programming Language"のような、 様々な評価の高いRubyプログラミング関連資料に基づいています。
Rubyコミュニティ内でもスタイルについての統一見解が存在しないという領域もいくらか存在します (文字列リテラルの引用記号、ハッシュリテラルの内側のスペース、複数行のメソッドチェーンのドットの位置、などなど)。 そのようなシナリオでは、いずれの有力なスタイルも許容されるので、 どれを選んで、一貫して用いるかはあなた次第です。
新たな慣習が生まれたり、Ruby自身が変化することで慣習が時代遅れになったりしたことに従いながら、このガイドは時代とともに進化してきました。
多くのプロジェクトは、それ自身のコーディング規約を持っています (しばしばこのガイドを基に生成されています)。 ルールの衝突が発生した場合は、 そのプロジェクトにおいては、プロジェクト固有のガイドを優先してください。
このガイドのPDFやHTMLのコピーはTransmuterを使って生成できます。
RuboCopは、 このスタイルガイドに基づいたコード分析器です。
以下の言語の翻訳が利用可能です:
ほとんどすべての人が、彼ら自身のものを除くすべてのスタイルが 醜くて、読むに耐えないと確信している。 「彼ら自身のものを除く」を除けば、おそらく正しいのだが… -- Jerry Coffin (インデントについて)
-
ソースファイルのエンコーディングには
UTF-8
を用いましょう。 [link] -
インデントには スペース 2つを用いましょう(別名ソフトタブ)。 ハードタブを用いてはいけません。 [link]
# 悪い例 - 4つのスペース def some_method do_something end # 良い例 def some_method do_something end
-
Unix-styleの改行にしましょう。 (*BSD/Solaris/Linux/OS X ユーザーはデフォルトで設定されています。 Windows ユーザーは特に注意が必要です。) [link]
-
もしGitを使っていれば、プロジェクトにWindowsの改行が紛れ込まないように、以下の設定を追加したほうがよいかもしれません:
$ git config --global core.autocrlf true
-
-
命令文や式の区切りに
;
を用いてはいけません。 当然、1行につき式1つにしましょう。 [link]# 悪い例 puts 'foobar'; # 余分なセミコロンです puts 'foo'; puts 'bar' # 2つの式が1行にあります # 良い例 puts 'foobar' puts 'foo' puts 'bar' puts 'foo', 'bar' # putsの場合はこれも可です
-
本文のないクラスは1行のフォーマットを用いましょう。 [link]
# 悪い例 class FooError < StandardError end # 悪くない例 class FooError < StandardError; end # 良い例 FooError = Class.new(StandardError)
-
1行のメソッドは避けましょう。 この用法は実際にはよく見かけるものではあるのですが、 構文に奇妙な点があるため、使用は望ましくないです。 仮に使うとしても、 1行メソッドに含めるのは多くとも式1つまでにすべきです。 [link]
# 悪い例 def too_much; something; something_else; end # 悪くない例 - 最初の ; は必要です def no_braces_method; body end # 悪くない例 - 2つ目の ; は任意です def no_braces_method; body; end # 悪くない例 - 文法上は正しいです、ただし; がない記述は少し読みづらいです def some_method() body end # 良い例 def some_method body end
本文が空のメソッドはこのルールの例外です。
# 良い例 def no_op; end
-
演算子の前後、コンマ、コロン、セミコロンの後ろ、
{
の前後、}
の前にはスペースを入れましょう。 スペースはRubyのインタープリタには(ほとんどの場合)重要ではありませんが、 スペースの適切な使用は、読みやすいコードを書くための鍵です。 [link]sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts 'Hi' [1, 2, 3].each { |e| puts e } class FooError < StandardError; end
演算子についてただひとつの例外は、指数演算子です:
# 悪い例 e = M * c ** 2 # 良い例 e = M * c**2
{
と}
については多少の解説が必要でしょう。 ブロック、ハッシュリテラル、そして文字列埋め込み式にそれぞれ使われるからです。 ハッシュリテラルでは、2つのスタイルが許容できます。# 良い例 - スペースを { の後と } の前に入れる { one: 1, two: 2 } # 良い例 - スペースを { の後と } の前に入れない {one: 1, two: 2}
1つ目の書き方は、わずかながら少し読みやすいです(そして、Rubyコミュニティでより広く使われているのはこちらかもしれません)。 2つ目の書き方は、ブロックとハッシュを視覚的に差別化できるという点で有利です。 どちらでも片方を採用すれば、常に同じ方式を採用しましょう。
-
(
、[
の後と、]
、)
の前にはスペースは入れません。 [link]# 悪い例 some( arg ).other [ 1, 2, 3 ].size # 良い例 some(arg).other [1, 2, 3].size
-
!
の後にはスペースは入れません。 [link]# 悪い例 ! something # 良い例 !something
-
範囲リテラルの内側にスペースは入れません。 [link]
# 悪い例 1 .. 3 'a' ... 'z' # 良い例 1..3 'a'...'z'
-
when
はcase
と同じ深さに揃えましょう。 このスタイルは"The Ruby Programming Language"、"Programming Ruby" 双方で確立されたものです。 [link]# 悪い例 case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end # 良い例 case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end
-
条件式を変数に代入するときは、 条件分岐のインデントは普段と同じ基準で揃えましょう。 [link]
# 悪い例 - かなり複雑です kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end result = if some_cond calc_something else calc_something_else end # 良い例 - 何が行われているか明らかです kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end result = if some_cond calc_something else calc_something_else end # 良い例 (少しだけ幅の効率がよいです) kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end result = if some_cond calc_something else calc_something_else end
-
メソッド定義式の間には空行をいれ、 メソッド同士は論理的なかたまりに分けましょう。 [link]
def some_method data = initialize(options) data.manipulate! data.result end def some_method result end
-
メソッド呼び出しの最後の引数の後ろのコンマは避けましょう。 引数が複数行にわかれていない時は、特に避けましょう。 [link]
# 悪い例 - 簡単に引数を移動・追加・削除できますが、それでもお奨めできません some_method( size, count, color, ) # 悪い例 some_method(size, count, color, ) # 良い例 some_method(size, count, color)
-
メソッドの引数に初期値を割り当てるとき、
=
演算子の周りにはスペースを入れましょう。 [link]# 悪い例 def some_method(arg1=:default, arg2=nil, arg3=[]) # do something... end # 良い例 def some_method(arg1 = :default, arg2 = nil, arg3 = []) # do something... end
いくつかのRuby本は最初のスタイルを提案していますが、 2つ目の方が、実用的により優れています (そして、おそらくこちらのほうが読みやすいでしょう)。
-
\
を用いた行の継続は可能であれば避けましょう。 可能であればというのは、つまり、文字列連結以外のすべての場合でです。 [link]# 悪い例 result = 1 - \ 2 # 良い例 (しかしそれでも地獄のように醜い) result = 1 \ - 2 long_string = 'First part of the long string' \ ' and second part of the long string'
-
一貫した複数行のメソッドチェーンのスタイルを採用しましょう。 Rubyコミュニティには2つのよく使われるスタイル - 先頭に
.
を付けるもの (Option A)、 末尾に.
を付けるもの (Option B) - があり、 どちらも良いと考えられています。 [link]-
(Option A) メソッドチェーンを次の行へつなげる時は、
.
は次の行に置きましょう。# 悪い例 - 2行目を理解するのに1行目を調べなければなりません one.two.three. four # 良い例 - 2行目で何が行われているかすぐに理解できます one.two.three .four
-
(Option B) メソッドチェーンを次の行につなげる時は、 式が続くことを示すように最初の行に
.
を置きましょう。# 悪い例 - メソッドチェーンが続いているかを知るには、次の行を読む必要があります one.two.three .four # 良い例 - 最初の行を越えて式が続くか一目瞭然です one.two.three. four
双方のスタイルのメリットに関する議論はこちら で見ることができます。
-
-
メソッド呼び出しが複数行に及ぶときは、引数は揃えましょう。 1行の長さの制約のために、引数を揃えるのに適していない時は、 最初の引数以降をインデント1つ分で揃えるスタイルも許容できます。 [link]
# 初期状態 (1行がとても長いです) def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 悪い例 (インデントが倍) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 良い例 def send_mail(source) Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text) end # 良い例 (普通のインデントです) def send_mail(source) Mailer.deliver( to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text ) end
-
複数行に及ぶ配列は、要素を揃えましょう。 [link]
# 悪い例 - インデント1つです menu_item = ["Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Baked beans", "Spam", "Spam", "Spam", "Spam", "Spam"] # 良い例 menu_item = [ "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Baked beans", "Spam", "Spam", "Spam", "Spam", "Spam" ] # 良い例 menu_item = ["Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Spam", "Baked beans", "Spam", "Spam", "Spam", "Spam", "Spam"]
-
可読性のため、大きな数値にはアンダースコアをつけましょう。 [link]
# 悪い例 - 0はいくつありますか? num = 1000000 # 良い例 - 人の頭でもより簡単に解析できます num = 1_000_000
-
APIドキュメントを書くなら、RDocとその規約に従いましょう。 コメント行と
def
の間に空行を入れてはいけません。 [link] -
1行は80字までにしましょう。 [link]
-
行末のスペースは避けましょう。 [link]
-
ファイルの終端には改行を入れましょう。 [link]
-
ブロックコメントは使ってはいけません。 前にスペースが入ると機能しませんし、 通常のコメントと違い、簡単に見分けが付きません。 [link]
# 悪い例 == begin comment line another comment line == end # 良い例 # comment line # another comment line
-
::
は、定数(クラスやモジュールも含みます)や コンストラクタ(例えばArray()
やNokogiri::HTML()
)を参照するときにのみ使いましょう。 通常のメソッド呼び出しでは::
の使用は避けましょう。 [link]# 悪い例 SomeClass::some_method some_object::some_method # 良い例 SomeClass.some_method some_object.some_method SomeModule::SomeClass::SOME_CONST SomeModule::SomeClass()
-
引数があるとき、
def
は括弧と共に使いましょう。 引数がない場合は括弧は除きましょう。 [link]# 悪い例 def some_method() # 本文省略 end # 良い例 def some_method # 本文省略 end # 悪い例 def some_method_with_parameters param1, param2 # 本文省略 end # 良い例 def some_method_with_parameters(param1, param2) # 本文省略 end
-
オプショナル引数は引数リストの最後に定義しましょう。 引数リストの先頭にオプショナル引数があるメソッドを呼んだ場合、 Rubyの挙動は予測不能です。 [link]
# 悪い例 def some_method(a = 1, b = 2, c, d) puts "#{a}, #{b}, #{c}, #{d}" end some_method('w', 'x') # => '1, 2, w, x' some_method('w', 'x', 'y') # => 'w, 2, x, y' some_method('w', 'x', 'y', 'z') # => 'w, x, y, z' # 良い例 def some_method(c, d, a = 1, b = 2) puts "#{a}, #{b}, #{c}, #{d}" end some_method('w', 'x') # => 'w, x, 1, 2' some_method('w', 'x', 'y') # => 'w, x, y, 2' some_method('w', 'x', 'y', 'z') # => 'w, x, y, z'
-
変数を定義するために多重代入を使うのは避けましょう。 多重代入を使っていいのはメソッド戻り値を変数に代入する時、 splat演算子とともに使う時、 変数の値を相互に入れ替えたい時に限ります。 多重代入は代入をそれぞれ別に実施した場合と比べて可読性に劣ります。 [link]
# 悪い例 a, b, c, d = 'foo', 'bar', 'baz', 'foobar' # 良い例 a = 'foo' b = 'bar' c = 'baz' d = 'foobar' # 良い例 - 変数の値の入れ替え # この用法は変数に入っている値を相互に入れ替えることができるので # 特例として認められます。 a = 'foo' b = 'bar' a, b = b, a puts a # => 'bar' puts b # => 'foo' # 良い例 - メソッドの戻り値 def multi_return [1, 2] end first, second = multi_return # 良い例 - splatとともに使う場合 first, *list = [1, 2, 3, 4] hello_array = *'Hello' a = *(1..3)
-
多重代入においては不要なアンダースコア変数を後ろに並べないようにしましょう。 アンダースコア変数は左辺にsplat変数を定義するときには必要です。 その場合、splat変数はアンダースコアではありえないです。 [link]
# 悪い例 a, b, _ = *foo a, _, _ = *foo a, *_ = *foo # 良い例 *a, _ = *foo *a, b, _ = *foo a, = *foo a, b, = *foo a, _b = *foo a, _b, = *foo
-
for
は、どうしても使わなければいけない明確な理由が明言できる人以外は、使ってはいけません。 多くの場合は代わりにイテレータを使うべきです。for
はeach
をつかって実装されています(だから、より遠回しです)が、for
は(each
と違い)新しいスコープを導入せず、 そのブロック内で定義された変数は、ブロックの外からも見えます。 [link]arr = [1, 2, 3] # 悪い例 for elem in arr do puts elem end # elemはループの外からも参照できることに注意しましょう elem # => 3 # 良い例 arr.each { |elem| puts elem } # elemはeachブロックの外からは参照できません elem # => NameError: undefined local variable or method `elem'
-
then
は複数行にまたがるif/unless
では使ってはいけません。 [link]# 悪い例 if some_condition then # 本文省略 end # 良い例 if some_condition # 本文省略 end
-
複数行にまたがる
if/unless
では、条件式は常にif/unless
と同じ行に置きましょう。 [link]# 悪い例 if some_condition do_something do_something_else end # 良い例 if some_condition do_something do_something_else end
-
三項演算子(
?:
)をif/then/else/end
構文よりも優先的に使いましょう。 そちらの方がより一般的だし、あきらかに簡潔です。 [link]# 悪い例 result = if some_condition then something else something_else end # 良い例 result = some_condition ? something : something_else
-
三項演算子の1つの分岐には1つだけ式を入れましょう。 つまり、三項演算子はネストしてはいけません。 そのようなケースでは
if/else
の方がよいです。 [link]# 悪い例 some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # 良い例 if some_condition nested_condition ? nested_something : nested_something_else else something_else end
-
if x; ...
を使ってはいけません。代わりに三項演算子を使いましょう。 [link]# 悪い例 result = if some_condition; something else something_else end # 良い例 result = some_condition ? something : something_else
-
if
やcase
が式で、値を返すという事実を活用しましょう。 [link]# 悪い例 if condition result = x else result = y end # 良い例 result = if condition x else y end
-
1行の
case
文ではwhen x then ...
を使いましょう。 代わりの表現であるwhen x: ...
は、Ruby 1.9で廃止されました。 [link] -
when x; ...
を使ってはいけません。前のルールを見てください。 [link] -
not
の代わりに!
を使いましょう。 [link]# 悪い例 - 演算子優先順位のため、()が必要になります x = (not something) # 良い例 x = !something
-
!!
は避けましょう。 [link]# 悪い例 x = 'test' # 難読なnil判定 if !!x # body omitted end x = false # 二重否定はbooleanとして役に立ちません !!x # => false # 良い例 x = 'test' unless x.nil? # body omitted end
-
and
とor
の使用は禁止です。使うべき理由がないです。 常に、代わりに&&
と||
を使いましょう。 [link]# 悪い例 # boolean式 if some_condition and some_other_condition do_something end # 制御構文 document.saved? or document.save! # 良い例 # boolean式 if some_condition && some_other_condition do_something end # 制御構文 document.saved? || document.save!
-
複数行にまたがる三項演算子
?:
は避けましょう; 代わりにif/unless
を使いましょう。 [link] -
本文が1行のときは、
if/unless
修飾子を優先的に使いましょう。 他の良い代替案としては&&/||
を使った制御構文があります。 [link]# 悪い例 if some_condition do_something end # 良い例 do_something if some_condition # もう1つの良い例 some_condition && do_something
-
複数行に渡るような些細とは言えない規模のブロックに
if/unless
修飾子を用いるのは避けましょう。 [link]# 悪い例 10.times do # 複数行のbody省略 end if some_condition # 良い例 if some_condition 10.times do # 複数行のbody省略 end end
-
if/unless/while/until
修飾子をネストして利用しないようにしましょう。 可能であれば&&/||
を使いましょう。 [link]# 悪い例 do_something if other_condition if some_condition # 良い例 do_something if some_condition && other_condition
-
否定形のときは
if
よりunless
を優先的に使いましょう。(もしくは||
構文を使いましょう)。 [link]# 悪い例 do_something if !some_condition # 悪い例 do_something if not some_condition # 良い例 do_something unless some_condition # もう1つの良い例 some_condition || do_something
-
unless
をelse
付きで使ってはいけません。 肯定条件を先にして書き換えましょう。 [link]# 悪い例 unless success? puts 'failure' else puts 'success' end # 良い例 if success? puts 'success' else puts 'failure' end
-
if/unless/while/until
の条件式の周囲を括弧で括らないようにしましょう。 [link]# 悪い例 if (x > 10) # body omitted end # 良い例 if x > 10 # body omitted end
留意しなければならないのは、このルールには例外(条件式中の安全な代入)があるということです。
-
複数行の
while/until
では、while/until condition do
を使ってはいけません。 [link]# 悪い例 while x > 5 do # 本文省略 end until x > 5 do # 本文省略 end # 良い例 while x > 5 # 本文省略 end until x > 5 # 本文省略 end
-
本文が1行のときは、
while/until
修飾子を利用しましょう。 [link]# 悪い例 while some_condition do_something end # 良い例 do_something while some_condition
-
否定形のときは、
while
よりもuntil
を使いましょう。 [link]# 悪い例 do_something while !some_condition # 良い例 do_something until some_condition
-
無限ループが必要な時は、
while/until
の代わりにKernel#loop
を用いましょう。 [link]# 悪い例 while true do_something end until false do_something end loop do do_something end
-
後判定ループの場合、
begin/end/until
やbegin/end/while
より、break
付きのKernel#loop
を使いましょう。 [link]# 悪い例 begin puts val val += 1 end while val < 0 # 良い例 loop do puts val val += 1 break unless val < 0 end
-
内部DSL(例えばRake、Rails、RSpec)や、 Rubyで「キーワード」と認識されているメソッド(例えば
attr_reader
やputs
)や、 アトリビュートにアクセスするメソッドでは、 引数の周りの括弧を省略しましょう。 それ以外のすべてのメソッドでは、メソッド呼び出しの時に括弧を付けましょう。 [link]class Person attr_reader :name, :age # 省略 end temperance = Person.new('Temperance', 30) temperance.name puts temperance.age x = Math.sin(y) array.delete(e) bowling.score.should == 0
-
暗黙のオプションハッシュの外側の括弧は省略しましょう。 [link]
# 悪い例 user.set({ name: 'John', age: 45, permissions: { read: true } }) # 良い例 user.set(name: 'John', age: 45, permissions: { read: true })
-
内部DSLの一部として使われるメソッドの引数では、外側の括弧類は省略しましょう [link]
class Person < ActiveRecord::Base # 悪い例 validates(:name, { presence: true, length: { within: 1..10 } }) # 良い例 validates :name, presence: true, length: { within: 1..10 } end
-
引数のないメソッド呼び出しの括弧は省略しましょう。 [link]
# 悪い例 Kernel.exit!() 2.even?() fork() 'test'.upcase() # 良い例 Kernel.exit! 2.even? fork 'test'.upcase
-
ブロック内で呼び出されるメソッドがただ1つである場合、簡略化されたproc呼び出しを用いましょう。 [link]
# 悪い例 names.map { |name| name.upcase } # 良い例 names.map(&:upcase)
-
1行のブロックでは
do...end
より{...}
を使いましょう。 複数行のブロックでは{...}
は避けましょう (複数行のメソッドチェーンは常に醜いです)。 制御構文(的な用法)やメソッド定義(的な用法)では常にdo...end
を使いましょう (例えばRakefilesや特定のDSLなど) メソッドチェーンでのdo...end
は避けましょう。 [link]names = %w(Bozhidar Steve Sarah) # 悪い例 names.each do |name| puts name end # 良い例 names.each { |name| puts name } # 悪い例 names.select do |name| name.start_with?('S') end.map { |name| name.upcase } # 良い例 names.select { |name| name.start_with?('S') }.map(&:upcase)
{...}
を用いた複数行のメソッドチェーンをOKと主張する人もいるかもしれないが、 自問してみてほしい - そのコードは本当に読みやすいだろうか? また、そのブロックの中はメソッドに切り出すことはできないのか? -
単に他のブロックに引数を渡すだけのブロックリテラルを避けるため、 ブロック引数を明示することを検討しましょう。 ただしブロックが
Proc
に変換されることでのパフォーマンスに気をつけましょう。 [link]require 'tempfile' # 悪い例 def with_tmp_dir Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir) { |dir| yield dir } # 引数を渡しているだけのブロック end end # 良い例 def with_tmp_dir(&block) Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir, &block) end end with_tmp_dir do |dir| puts "dir is accessible as parameter and pwd is set: #{dir}" end
-
制御構文上不要な
return
は避けましょう。 [link]# 悪い例 def some_method(some_arr) return some_arr.size end # 良い例 def some_method(some_arr) some_arr.size end
-
不要な
self
は避けましょう (self
のアクセサへの書き込みでのみ必要です)。 [link]# 悪い例 def ready? if self.last_reviewed_at > self.last_updated_at self.worker.update(self.content, self.options) self.status = :in_progress end self.status == :verified end # 良い例 def ready? if last_reviewed_at > last_updated_at worker.update(content, options) self.status = :in_progress end status == :verified end
-
当然の帰結として、ローカル変数でメソッドをシャドウイングするのは、 それらが等価なものでない限り避けましょう。 [link]
class Foo attr_accessor :options # ok def initialize(options) self.options = options # options と self.options はここでは等価 end # 悪い例 def do_something(options = {}) unless options[:when] == :later output(self.options[:message]) end end # 良い例 def do_something(params = {}) unless params[:when] == :later output(options[:message]) end end end
-
代入部分を括弧で囲まずに、
=
の返り値を条件式に用いてはいけません。 これは、Rubyistの中では 条件式内での安全な代入 としてとても有名です。 [link]# 悪い例 (+ 警告が出ます) if v = array.grep(/foo/) do_something(v) ... end # 良い例 (MRIはこれでも文句を言いますが、RuboCopでは問題ありません) if (v = array.grep(/foo/)) do_something(v) ... end # 良い例 v = array.grep(/foo/) if v do_something(v) ... end
-
利用できるときには省略された自己代入演算子を用いましょう。 [link]
# 悪い例 x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # 良い例 x += y x *= y x **= y x /= y x ||= y x &&= y
-
変数がまだ初期化されていないときにだけ初期化したいのであれば、
||=
を使いましょう。 [link]# 悪い例 name = name ? name : 'Bozhidar' # 悪い例 name = 'Bozhidar' unless name # 良い例 - nameがnilかfalseの場合のみ、Bozhidarで初期化します name ||= 'Bozhidar'
-
boolean変数には
||=
を用いてはいけません (現在の値がfalse
であったときに何が起こるか考えてみましょう)。 [link]# 悪い例 - たとえenabledがfalseでもtrueが入ります enabled ||= true # 良い例 enabled = true if enabled.nil?
-
値が入っているかわからない変数の前処理のは
&&=
を用いましょう。&&=
を使えば変数が存在するときのみ値を変更するので、 存在確認に用いている不要なif
を除去できます。 [link]# 悪い例 if something something = something.downcase end # 悪い例 something = something ? something.downcase : nil # ok something = something.downcase if something # 良い例 something = something && something.downcase # より良い例 something &&= something.downcase
-
case等価演算子
===
の露骨な使用は避けましょう。 その名が示す通り、case
の条件判定で用いられており、 その外で用いられると混乱のもとになります。 [link]# 悪い例 Array === something (1..100) === 7 /something/ === some_string # 良い例 something.is_a?(Array) (1..100).include?(7) some_string =~ /something/
-
==
で用が足りるならeql?
は使わないようにしましょう。eq?
で実現されている、より厳密な等価性が必要になることは、実際には稀です。 [link]# 悪い例 - eql? は 文字列に対する == と同じです 'ruby'.eql? some_str # good 'ruby' == some_str 1.0.eql? x # eql? はFixnumとFloatの1を識別したいのであれば意味があります
-
Perlスタイルの(
$:
や$;
などのような)特別な変数の使用は避けましょう。 それらは極めて暗号的なので、ワンライナー以外での利用は推奨できません。English
ライブラリから提供される人にやさしいエイリアスを用いましょう。 [link]# 悪い例 $:.unshift File.dirname(__FILE__) # 良い例 require 'English' $LOAD_PATH.unshift File.dirname(__FILE__)
-
メソッド名と開き括弧の間にスペースを入れてはいけません。 [link]
# 悪い例 f (3 + 2) + 1 # 良い例 f(3 + 2) + 1
-
メソッドの最初の引数が開き括弧で始まるならば、 常にメソッド呼び出しに括弧を用いましょう。 例えば次のように書きます
f((3 + 2) + 1)
。 [link] -
Rubyインタープリタを走らせるときは、常に
-w
オプションを付けましょう。 これまでのルールのどれかを忘れてしまった時に警告を出してくれます! [link] -
ネストしたメソッド定義は行ってはいけません - 代わりにラムダを用いましょう。 ネストしたメソッド定義は実際には外側のメソッドと同じスコープ(例えばclass)でメソッドを生成します。 そのうえ、そのようにネストしたメソッドは、そのメソッドを含んでいるメソッドがが呼び出されるたびに再定義されるでしょう。 [link]
# 悪い例 def foo(x) def bar(y) # 本文略 end bar(x) end # 良い例 - 前の例と同じですが、foo呼び出し時にのbar再定義がおこりません def bar(y) # 本文略 end def foo(x) bar(x) end # こちらも良い例 def foo(x) bar = ->(y) { ... } bar.call(x) end
-
1行の本文を持つラムダには新しいリテラルを持ちましょう。
lambda
は複数行にまたがるときに使いましょう。 [link]# 悪い例 l = lambda { |a, b| a + b } l.call(1, 2) # 正しい例、ですがギクシャクしています l = ->(a, b) do tmp = a * 7 tmp * b / 50 end # 良い例 l = ->(a, b) { a + b } l.call(1, 2) l = lambda do |a, b| tmp = a * 7 tmp * b / 50 end
-
stabby lambdaを定義するときは、引数の周りの括弧は省略しないようにしましょう。 [link]
# 悪い例 l = ->x, y { something(x, y) } # 良い例 l = ->(x, y) { something(x, y) }
-
stabby lambdaに引数がないときは、引数のための括弧は省略しましょう。 [link]
# 悪い例 l = ->() { something } # 良い例 l = -> { something }
-
Proc.new
よりproc
を使いましょう。 [link]# 悪い例 p = Proc.new { |n| puts n } # 良い例 p = proc { |n| puts n }
-
lambdaやprocの呼び出しには
proc[]
やproc.()
よりproc.call()
を使いましょう。 [link]# 悪い例 - 列挙型のアクセスに似ているように見えます l = ->(v) { puts v } l[1] # こちらも悪い例 - 珍しい構文です l = ->(v) { puts v } l.(1) # 良い例 l = ->(v) { puts v } l.call(1)
-
使わないブロック引数やローカル変数の先頭には
_
を付けましょう。 単に_
を用いるのも許容されます (少し説明不足ではありますが)。 この記法を使うことで、 RubyインタープリタやRubocopのような対応しているツールでは 変数を使っていないという警告を抑制できます。 [link]# 悪い例 result = hash.map { |k, v| v + 1 } def something(x) unused_var, used_var = something_else(x) end # 良い例 result = hash.map { |_, v| v + 1 } def something(x) _, used_var = something_else(x) end
-
STDOUT/STDERR/STDIN
の代わりに$stdout/$stderr/$stdin
を用いましょう。STDOUT/STDERR/STDIN
は定数であり、 Rubyでの定数は、実際は再代入できます(つまりリダイレクトに使えます)が、 もし実行するとインタープリタからの警告が出ます。 [link] -
$stderr.puts
の代わりにwarn
を用いましょう。 簡潔さや明快さもさることながら、warn
は必要であれば警告を抑制することができます (警告レベルを-W0
を用いて0に設定することによって実現できます)。 [link] -
あまりに暗号めいている
String#%
メソッドよりもsprintf
やformat
を使いましょう。 [link]# 悪い例 '%d %d' % [20, 10] # => '20 10' # 良い例 sprintf('%d %d', 20, 10) # => '20 10' # 良い例 sprintf('%{first} %{second}', first: 20, second: 10) # => '20 10' format('%d %d', 20, 10) # => '20 10' # 良い例 format('%{first} %{second}', first: 20, second: 10) # => '20 10'
-
あまりに暗号めいている
Array#*
メソッドよりもArray#join
を使いましょう。 [link]# 悪い例 %w(one two three) * ', ' # => 'one, two, three' # 良い例 %w(one two three).join(', ') # => 'one, two, three'
-
配列かどうかわからない変数を配列とみなして処理したいときは、 明示的に
Array
かどうかチェックするよりも、[*var]
やArray()
を使いましょう。 [link]# 悪い例 paths = [paths] unless paths.is_a? Array paths.each { |path| do_something(path) } # 良い例 [*paths].each { |path| do_something(path) } # 良い例 (そして少し読みやすいです) Array(paths).each { |path| do_something(path) }
-
ロジックを使って複雑な比較を行うよりも、 可能な限り
Range
やComparable#between?
を用いましょう。 [link]# 悪い例 do_something if x >= 1000 && x <= 2000 # 良い例 do_something if (1000..2000).include?(x) # 良い例 do_something if x.between?(1000, 2000)
-
==
を明示した比較よりも判定メソッドを用いましょう。 数値の比較はOKです。 [link]# 悪い例 if x % 2 == 0 end if x % 2 == 1 end if x == nil end # 良い例 if x.even? end if x.odd? end if x.nil? end if x.zero? end if x == 0 end
-
boolean値を扱わない限り、明示的な
nil
でないかの検査は避けましょう。 [link]# 悪い例 do_something if !something.nil? do_something if something != nil # 良い例 do_something if something # 良い例 - boolean値を扱うとき def value_set? !@some_boolean.nil? end
-
BEGIN
ブロックの使用は避けましょう。 [link] -
END
ブロックを使ってはいけません。代わりにKernel#at_exit
を使いましょう。 [link]# 悪い例 END { puts 'Goodbye!' } # 良い例 at_exit { puts 'Goodbye!' }
-
フリップフロップの使用は避けましょう。 [link]
-
制御構文で条件式のネストは避けましょう。 [link]
不正なデータを弾きたいときはガード節を使いましょう。 ガード節とは、できるだけ素早く関数から抜けられるようにと 関数の先頭に置かれている条件文のことです。
# 悪い例 def compute_thing(thing) if thing[:foo] update_with_bar(thing) if thing[:foo][:bar] partial_compute(thing) else re_compute(thing) end end end # 良い例 def compute_thing(thing) return unless thing[:foo] update_with_bar(thing[:foo]) return re_compute(thing) unless thing[:foo][:bar] partial_compute(thing) end
ループ内では条件判定ブロックよりも
next
を使いましょう。# 悪い例 [0, 1, 2, 3].each do |item| if item > 1 puts item end end # 良い例 [0, 1, 2, 3].each do |item| next unless item > 1 puts item end
-
collect
よりmap
、detect
よりfind
、find_all
よりselect
inject
よりreduce
、length
よりsize
を使いましょう。 これは絶対のルールではないです。 別名のほうが可読性に優れているなら、 そちらを使っていただいて構いません。 韻を踏んでいるほうのメソッド名はSmalltalkから引き継いできたもので、 他のプログラミング言語でそこまで一般的ではないです。find_all
よりもselect
が推奨されるのは、reject
との相性がよいことと、 メソッド名から挙動を推察することも容易だからです。 [link] -
size
の代わりにcount
を用いてはいけません。Array
以外のEnumerable
オブジェクトでは、count
を使うと要素数の計算のためにコレクション全体を走査してしまいます。 [link]# 悪い例 some_hash.count # 良い例 some_hash.size
-
map
とflatten
の組み合わせの代わりに、flat_map
を用いましょう。 これは深さが2以上の配列には適用できません。 すなわち、users.first.songs == ['a', ['b','c']]
のときは、flat_map
よりmap + flatten
を用いましょう。flatten
は配列を全て平坦にするのに対し、flat_map
は配列を1次元だけ平坦にします。 [link]# 悪い例 all_songs = users.map(&:songs).flatten.uniq # 良い例 all_songs = users.flat_map(&:songs).uniq
-
reverse.each
の代わりにreverse_each
を用いましょう。 何故なら、Enumerable
をincludeしているクラスの側で、 より効率のよい実装が行われていることがあるからです。 最悪、クラスが特殊化を行っていない場合でも、Enumerable
から継承される一般的な実装は、reverse.each
を用いた場合と同じ効率です。 [link]# 悪い例 array.reverse.each { ... } # 良い例 array.reverse_each { ... }
プログラミングで真に困難な領域は、キャッシュの無効化と命名にしかない。
-- Phil Karlton
-
識別子は英語で名づけましょう。 [link]
# 悪い例 - 識別子がnon-asciiな文字列です заплата = 1_000 # 悪い例 - (キリル文字の代わりに)ラテン文字で書かれてはいますが、識別子がブルガリア語です zaplata = 1_000 # 良い例 salary = 1_000
-
シンボル、メソッド、変数には
snake_case
を用いましょう。 [link]# 悪い例 :'some symbol' :SomeSymbol :someSymbol someVar = 5 def someMethod ... end def SomeMethod ... end # 良い例 :some_symbol def some_method ... end
-
クラスやモジュールには
CamelCase
を用いましょう。(HTTP、RFC、XMLのような頭字語は大文字を保ちましょう)。 [link]# 悪い例 class Someclass ... end class Some_Class ... end class SomeXml ... end class XmlSomething ... end # 良い例 class SomeClass ... end class SomeXML ... end class XMLSomething ... end
-
ファイル名には
snake_case
を用いましょう。例えばhello_world.rb
のように。 [link] -
ディレクトリ名には
snake_case
を用いましょう。例えばlib/hello_world/hello_world.rb
のように。 [link] -
ソースファイル1つにつきただ1つのクラス/モジュールだけが書かれている状態を目指しましょう。 そのファイルの名前はそのクラス/モジュールと同じ名前で、ただしキャメルケースをスネークケースに変換して用いましょう。 [link]
-
他の定数は
SCREAMING_SNAKE_CASE
を用いましょう。 [link]# 悪い例 SomeConst = 5 # 良い例 SOME_CONST = 5
-
述語メソッド(boolean値が返るメソッド)は疑問符で終わりましょう。 (すなわち
Array#empty?
のように)。 boolean値を返さないメソッドは、疑問符で終わるべきではないです。 [link] -
危険 な可能性のあるメソッド (引数や
self
を変更するようなメソッドや、exit!
(exit
と違ってファイナライザが走らない)のようなもの) は、その安全なバージョンがある場合には、 危険 であることを明示する意味で感嘆符で終わりましょう。 [link]# 悪い例 - 対応する「安全」なメソッドが存在しません class Person def update! end end # 良い例 class Person def update end end # 良い例 class Person def update! end def update end end
-
危険な(感嘆符付き)メソッドがあるときは、対応する安全な(感嘆符なし)メソッドを定義できないか検討しましょう。 [link]
class Array def flatten_once! res = [] each do |e| [*e].each { |f| res << f } end replace(res) end def flatten_once dup.flatten_once! end end
-
短いブロックと共に
reduce
を使うとき、引数は|a, e|
と名づけましょう。 (accumulator, element). [link] -
二項演算子を定義するとき、引数名は
other
を用いましょう (<<
と[]
は意味が違ってくるので、このルールの例外です)。 [link]def +(other) # body omitted end
良く書けたコードは、それ自身が最良のドキュメントでもある。 コメントを書こうとしている時は、常に自問してほしい、 "このコメントが不要になるようにコードを改善できるだろうか?" コードを改善した上で、ドキュメントでさらに明快にするのだ。 -- Steve McConnell
-
自己説明的なコードを書いて、このセクションの残りのパートは無視しましょう。本当に! [link]
-
コメントは英語で書きましょう。 [link]
-
最初の
#
とコメントの間にスペースを1つ入れましょう。 [link] -
1語より長いコメントは頭語を大文字化してピリオドを打ちましょう。 文と文の間にはスペースを一つだけ入れましょう。 [link]
-
過剰なコメントは避けましょう。 [link]
# 悪い例 counter += 1 # カウンターをインクリメント
-
コメントは最新に保ちましょう。 古くなったコメントは、コメントがないより悪いです。 [link]
良いコードは良いジョークのようだ - なんの説明もいらない。
-- Russ Olsen
- 悪いコードを説明するコメントは避けましょう。 自己説明的なコードへのリファクタリングを行いましょう (やるかやらないか - "やってみる"はなしだ。 --Yoda)。 [link]
-
注釈は、通常関連するコードのすぐ上に書きましょう。 [link]
-
注釈のキーワードの後ろは
:
を続けましょう。 その後ろに問題点を書きましょう。 [link] -
もし問題点の記述に複数行かかる場合は、 後続の行は
#
の後ろにスペース3つでインデントしましょう。 (通常の1つに加え、インデント目的に2つ) [link]def bar # FIXME: This has crashed occasionally since v3.2.1. It may # be related to the BarBazUtil upgrade. baz(:quux) end
-
もし問題が明らかで、説明すると冗長になる時は、 問題のある行の末尾に、本文なしの注釈だけ付けましょう。 この用法は例外であり、ルールではありません。 [link]
def bar sleep 100 # OPTIMIZE end
-
あとで追加されるべき、今はない特徴や機能の注釈には
TODO
を使いましょう。 [link] -
直す必要がある壊れたコードの注釈には
FIXME
を使いましょう。 [link] -
パフォーマンスに問題を及ぼすかもしれない遅い、または非効率なコードの注釈には
OPTIMIZE
を使いましょう。 [link] -
疑問の残るコードの書き方でコードの臭いを感じた箇所の注釈には
HACK
を使いましょう。 [link] -
意図したとおりに動くか確認する必要がある箇所の注釈には
REVIEW
を使いましょう。 例:REVIEW: Are we sure this is how the client does X currently?
[link] -
適切に感じるのであれば、他の独自のキーワードを用いても構いませんが、 それらのキーワードは
README
やそれに類するものに書いておきましょう。 [link]
-
クラス定義の構造には一貫性をもたせましょう。 [link]
class Person # extendとincludeを最初に書きます。 extend SomeModule include AnotherModule # 内部クラス CustomErrorKlass = Class.new(StandardError) # 次に定数 SOME_CONSTANT = 20 # 次にattribute系マクロ attr_reader :name # (あれば) それ以外のマクロ validates :name # publicクラスメソッドが続きます def self.some_method end # initializationはクラスメソッドと他のpublicメソッドの間に def initialize end # 他のpublicメソッドが続きます def some_method end # protectedとprivateのメソッドは最後のあたりにグループ化します protected def some_protected_method end private def some_private_method end end
-
クラスの中に複数行あるようなクラスをネストしてはいけません。 それぞれのクラスごとにファイルに分けて、 外側のクラスの名前のついたフォルダに含めるようにしましょう。 [link]
# 悪い例 # foo.rb class Foo class Bar # 中に30メソッド end class Car # 中に20メソッド end # 中に30メソッド end # 良い例 # foo.rb class Foo # 中に30メソッド end # foo/bar.rb class Foo class Bar # 中に30メソッド end end # foo/car.rb class Foo class Car # 中に20メソッド end end
-
クラスメソッドしかないクラスよりモジュールを使いましょう。 クラスはインスタンスを生成することに意味がある時にのみ使われるべきです。 [link]
# 悪い例 class SomeClass def self.some_method # body omitted end def self.some_other_method end end # 良い例 module SomeModule module_function def some_method # body omitted end def some_other_method end end
-
モジュールのインスタンスメソッドをクラスメソッドにしたいときは、
extend self
よりもmodule_function
を使いましょう。 [link]# 悪い例 module Utilities extend self def parse_something(string) # do stuff here end def other_utility_method(number, string) # do some more stuff end end # 良い例 module Utilities module_function def parse_something(string) # do stuff here end def other_utility_method(number, string) # do some more stuff end end
-
ドメインオブジェクトのクラスにおいては常に適切な
to_s
メソッドを提供しましょう。 [link]class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def to_s "#{@first_name} #{@last_name}" end end
-
単純なアクセサやミューテータの定義には、
attr
群を用いましょう。 [link]# 悪い例 class Person def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def first_name @first_name end def last_name @last_name end end # 良い例 class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end
-
attr
の使用は避けましょう。代わりにattr_reader
やattr_accessor
を使いましょう。 [link]# 悪い例 - 1つのアクセサしか作れません(1.9で廃止されました) attr :something, true attr :one, :two, :three # attr_readerと同じです # 良い例 attr_accessor :something attr_reader :one, :two, :three
-
Struct.new
の使用を考えましょう、 それは、単純なアクセサ、コンストラクタや比較演算子を定義してくれます。 [link]# 良い例 class Person attr_accessor :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end # より良い例 Person = Struct.new(:first_name, :last_name) do end
-
Struct.new
で初期化されたインスタンスを拡張してはいけません。 それは余分なクラスレベルをもたらし、 複数回require
された時に、奇妙なエラーの原因にもなります。 [link]# 悪い例 class Person < Struct.new(:first_name, :last_name) end # 良い例 Person = Struct.new(:first_name, :last_name)
-
あるクラスのインスタンス生成する追加の方法を提供したいときは、 ファクトリメソッドの追加を検討しましょう。 [link]
class Person def self.create(options_hash) # body omitted end end
-
# 悪い例 class Animal # abstract method def speak end end # 継承 class Duck < Animal def speak puts 'Quack! Quack' end end # 継承 class Dog < Animal def speak puts 'Bau! Bau!' end end # 良い例 class Duck def speak puts 'Quack! Quack' end end class Dog def speak puts 'Bau! Bau!' end end
-
継承での振る舞いが"扱いづらい"ので、クラス変数(
@@
)の使用は避けましょう。 [link]class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print 'child'
このように、ひとつのクラス階層に属するすべてのクラスは、 1つのクラス変数を共有してしまいます。 クラス変数よりもクラスのインスタンス変数のほうを使うべきです。
-
意図した使い方に沿って、可視性(
private
、protected
)を設定しましょう。 全てをpublic
(デフォルトの設定)のままにしないようにしましょう。 結局私達は今 Ruby を書いているのだから。 Python ではなく。 [link] -
public
、protected
、private
は、適用するメソッド定義と同じインデントにしましょう。 そして、以降のすべてのメソッド定義に適用されることを強調するために、 それらの修飾子の前1行と後1行に空行を入れましょう。 [link]class SomeClass def public_method # ... end private def private_method # ... end def another_private_method # ... end end
-
クラスメソッドを定義するときは
def self.method
を用いましょう。 クラス名を繰り返さないので、簡単にリファクタリングできるようになります。 [link]class TestClass # 悪い例 def TestClass.some_method # body omitted end # 良い例 def self.some_other_method # body omitted end # たくさんのクラスメソッドを定義しなければならない時 # この書き方も便利です。 class << self def first_method # body omitted end def second_method_etc # body omitted end end end
-
メソッドの別名をつける時は
alias
を使いましょう。 クラスのレキシカルスコープの中ではself
と同じように名前解決されます。 またユーザーにとっても、実行時やサブクラス側で明示的にエイリアスを変更しなければ、 変更されないことが読み取りやすいです。 [link]class Westerner def first_name @names.first end alias given_name first_name end
alias
はdef
と同じく予約語なので、シンボルや文字列よりも名前そのものを使いましょう。 言い換えると、alias :foo :bar
ではなく、alias foo bar
と書きましょう。また、Rubyがエイリアスや継承をどのように扱うか注意しましょう。
alias
はそれが定義された地点で解決されたメソッドを参照します。 動的には解決されません。class Fugitive < Westerner def first_name 'Nobody' end end
この例では、
Fugitive#given_name
は、Fugitive#first_name
ではなく、オリジナルのWesterner#first_name
を呼び出します。Fugitive#given_name
もオーバーライドしたい時は、継承したクラスでも 再定義しなければなりません。class Fugitive < Westerner def first_name 'Nobody' end alias given_name first_name end
-
モジュールやクラス、実行時のシングルトンクラス等では、
alias
の挙動が予期できないので、 エイリアス定義には常にalias_method
を用いましょう。 [link]module Mononymous def self.included(other) other.class_eval { alias_method :full_name, :given_name } end end class Sting < Westerner include Mononymous end
-
例外は
fail
よりraise
を使いましょう。 [link]# 悪い例 fail SomeException, 'message' # 良い例 raise SomeException, 'message'
-
2引数の
raise
では、RuntimeError
を明示しないようにしましょう。 [link]# 悪い例 raise RuntimeError, 'message' # 良い例 - デフォルトでRuntimeErrorが発生します raise 'message'
-
raise
の引数としては例外クラスのインスタンスよりも、 例外クラスとメッセージをそれぞれの引数で渡す方を使いましょう。 [link]# 悪い例 raise SomeException.new('message') # `raise SomeException.new('message'), backtrace`とする書き方が存在しないことに注意しましょう。 # 良い例 raise SomeException, 'message' # `raise SomeException, 'message', backtrace`の用法と一貫性があります
-
ensure
ブロックからreturn
してはいけません。 もしensure
の中から明示的に値を返した場合は、return
はどの例外発生よりも優先されて、 例外など発生していなかったかのように値を返してしまいます。 事実上、例外は静かに捨てられます。 [link]def foo raise ensure return 'very bad idea' end
-
可能な場所では、 暗黙のbeginブロック を用いましょう。 [link]
# 悪い例 def foo begin # main logic goes here rescue # failure handling goes here end end # 良い例 def foo # main logic goes here rescue # failure handling goes here end
-
不確実性のあるメソッド(Avdi Grimmによって作られた言葉です) を用いて
begin
の蔓延を和らげましょう。 [link]# 悪い例 begin something_that_might_fail rescue IOError # handle IOError end begin something_else_that_might_fail rescue IOError # handle IOError end # 良い例 def with_io_error_handling yield rescue IOError # handle IOError end with_io_error_handling { something_that_might_fail } with_io_error_handling { something_else_that_might_fail }
-
例外をもみ消してはいけません。 [link]
# 悪い例 begin # an exception occurs here rescue SomeError # the rescue clause does absolutely nothing end # 悪い例 do_something rescue nil
-
rescue
を修飾子として利用するのは避けましょう。 [link]# 悪い例 - StandardErrorとそれを継承した全てのクラスをキャッチしてしまいます read_file rescue handle_error($!) # 良い例 - Errno::ENOENTとそれを継承したクラスのみをキャッチします def foo read_file rescue Errno::ENOENT => ex handle_error(ex) end
-
制御フローに例外を使っては行けません。 [link]
# 悪い例 begin n / d rescue ZeroDivisionError puts 'Cannot divide by 0!' end # 良い例 if d.zero? puts 'Cannot divide by 0!' else n / d end
-
Exception
をrescue
するのは避けましょう。 これはexit
のシグナルも捕捉するため、プロセスを殺すのにkill -9
が必要になります。 [link]# 悪い例 begin # calls to exit and kill signals will be caught (except kill -9) exit rescue Exception puts "you didn't really want to exit, right?" # exception handling end # 良い例 begin # a blind rescue rescues from StandardError, not Exception as many # programmers assume. rescue => e # exception handling end # こちらも良い例 begin # an exception occurs here rescue StandardError => e # exception handling end
-
より詳細な例外を
rescue
チェーンの上に配置しましょう。 そうでなければ、決してrescue
されません。 [link]# 悪い例 begin # 処理 rescue StandardError => e # エラー処理 rescue IOError => e # 決して到達しないエラー処理 end # 良い例 begin # 処理 rescue IOError => e # エラー処理 rescue StandardError => e # エラー処理 end
-
プログラム内で確保した外部リソースは、
ensure
で開放しましょう [link]f = File.open('testfile') begin # .. process rescue # .. handle error ensure f.close if f end
-
自動的にリソースを開放してくれる機能を含むメソッドを利用可能な時は、そちらを使いましょう。 [link]
# 悪い例 - 明示的にファイルディスクリプタを閉じる必要が有ります f = File.open('testfile') # ... f.close # 良い例 - ファイルディスクリプタは自動的に閉じられます File.open('testfile') do |f| # ... end
-
新しい例外クラスを導入するより、基本ライブラリの例外クラスを使いましょう [link]
-
配列やハッシュを生成する時はリテラル記法を使いましょう。 (コンストラクタに引数を渡す場合を除けば、ということですが) [link]
# 悪い例 arr = Array.new hash = Hash.new # 良い例 arr = [] hash = {}
-
単語(空でなく、スペースを含まない文字列)の配列を生成する時は
%w
リテラルを使いましょう。 このルールは配列の要素が2つ以上の場合に限ります。 [link]# 悪い例 STATES = ['draft', 'open', 'closed'] # 良い例 STATES = %w(draft open closed)
-
シンボルの配列が必要な時 (かつRuby 1.9との互換性を維持しなくていい時)は
%i
リテラルを使いましょう。 このルールは配列の要素が2つ以上の場合に限ります。 [link]# 悪い例 STATES = [:draft, :open, :closed] # 良い例 STATES = %i(draft open closed)
-
Array
やHash
リテラルの最後の要素の後ろの,
は避けましょう。 複数行にわかれていない時は特に避けましょう。 [link]# 悪い例 - 簡単に要素を移動・追加・削除できますが、それでもお奨めできません VALUES = [ 1001, 2020, 3333, ] # 悪い例 VALUES = [1001, 2020, 3333, ] # 良い例 VALUES = [1001, 2020, 3333]
-
配列に大きな隙間を作るのは避けましょう。 [link]
arr = [] arr[100] = 1 # now you have an array with lots of nils
-
配列の最初や最後にアクセスしたいときは、
[0]
や[-1]
よりfirst
やlast
を使いましょう。 [link] -
要素が一意のものを扱うときは、
Array
の代わりにSet
を用いましょう。Set
は要素に重複と順序がないようなコレクションの実装です。 これはArray
の直感的な二項演算子と、Hash
の速さが合わさっています。 [link] -
ハッシュのキーには文字列よりシンボルが好まれます。 [link]
# 悪い例 hash = { 'one' => 1, 'two' => 2, 'three' => 3 } # 良い例 hash = { one: 1, two: 2, three: 3 }
-
変更のできるオブジェクトをハッシュのキーに使うのは避けましょう。 [link]
-
ハッシュのキーがシンボルの時は、Ruby 1.9のハッシュリテラル記法を用いましょう。 [link]
# 悪い例 hash = { :one => 1, :two => 2, :three => 3 } # 良い例 hash = { one: 1, two: 2, three: 3 }
-
Ruby 1.9のハッシュ記法とロケット記法を同じハッシュリテラル内で混在させてはいけません。 シンボルでないキーがある場合は、ロケット記法を使いましょう。 [link]
# 悪い例 { a: 1, 'b' => 2 } # 良い例 { :a => 1, 'b' => 2 }
-
Hash#has_key?
よりHash#key?
を、Hash#has_value?
よりHash#value?
を用いましょう。 ここ でMatzが述べているように、長い記法は廃止が検討されています。 [link]# 悪い例 hash.has_key?(:test) hash.has_value?(value) # 良い例 hash.key?(:test) hash.value?(value)
-
存在すべきキーを扱う時は、
Hash#fetch
を用いましょう。 [link]heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' } # 悪い例 - もし誤りがあってもすぐに気づくことができないかもしれません heroes[:batman] # => 'Bruce Wayne' heroes[:supermann] # => nil # 良い例 - fetchはKeyErrorを投げるので、問題が明らかになります heroes.fetch(:supermann)
-
Hash#fetch
のデフォルト値を使い、自力でロジックを書かないようにしましょう。 [link]batman = { name: 'Bruce Wayne', is_evil: false } # 悪い例 - たんに||演算子を使ってしまうと偽値が入っていた時に望まない結果になります batman[:is_evil] || true # => true # 良い例 - fetchなら偽値でも正しく動きます batman.fetch(:is_evil, true) # => false
-
Hash#fetch
のデフォルト値は評価するべき式に副作用があったり実行コストが高いときはうまくいかないので、代わりにブロックを使いましょう。 [link]batman = { name: 'Bruce Wayne' } # 悪い例 - デフォルト値が使われると、先に評価してしまいます # だから、もし複数回呼ばれると、プログラムが遅くなります batman.fetch(:powers, get_batman_powers) # get_batman_powers は高コストな呼び出し # 良い例 - ブロックは後から評価されます。だから、KeyErrorが評価の引き金になります batman.fetch(:powers) { get_batman_powers }
-
ハッシュから連続して複数の値が必要になる時は、
Hash#values_at
を用いましょう。 [link]# 悪い例 email = data['email'] username = data['nickname'] # 良い例 email, username = data.values_at('email', 'nickname')
-
Ruby 1.9以降、ハッシュは順序付けられるということを信頼しましょう。 [link]
-
コレクションを走査している時に変更を加えてはいけません。 [link]
-
コレクションにアクセスするとき、
[n]
の代替のリーダーメソッドが提供されている場合に 直接[n]
経由でアクセスすることは避けましょう。nil
に対して[]
を呼ぶことを避けることが出来ます。 [link]# 悪い例 Regexp.last_match[1] # 良い例 Regexp.last_match(1)
-
コレクションに対するアクセサを提供するとき、 コレクション内の要素にアクセスする前に、
nil
でアクセスするのを防ぐための代替のアクセス方法を提供しましょう。 [link]# 悪い例 def awesome_things @awesome_things end # 良い例 def awesome_things(index = nil) if index && @awesome_things @awesome_things[index] else @awesome_things end end
-
文字列連結の代わりに文字列挿入や文字列整形を使いましょう。 [link]
# 悪い例 email_with_name = user.name + ' <' + user.email + '>' # 良い例 email_with_name = "#{user.name} <#{user.email}>" # 良い例 email_with_name = format('%s <%s>', user.name, user.email)
-
文字列挿入時には、括弧の内部にスペースを入れるべきではありません。 [link]
# 悪い例 "From: #{ user.first_name }, #{ user.last_name }" # 良い例 "From: #{user.first_name}, #{user.last_name}"
-
文字列リテラルの引用符は一貫したスタイルで使いましょう。 Rubyコミュニティでは、 デフォルトでシングルクォートを用いるもの (Option A)、 ダブルクォートを用いるもの (Option B) の二つのよく使われるスタイルがあって、 どちらも良いと考えられています。 [link]
-
(Option A) 文字列挿入の必要がないときや、
\t
や\n
`’`等の特別な文字がない場合は、 シングルクォーテーションを使いましょう。# 悪い例 name = "Bozhidar" # 良い例 name = 'Bozhidar'
-
(Option B) 文字列中に
"
を含んでいたり、エスケープ文字を抑えたいときでない限り、 ダブルクォーテーションを使いましょう。# 悪い例 name = 'Bozhidar' # 良い例 name = "Bozhidar"
このガイド内の文字列リテラル表記は、 1つ目のスタイルを採用しています。
-
-
文字リテラル構文
?x
を用いてはいけません。 Ruby 1.9以降、この表記法を必要とする場面はないはずです -?x
は'x'
(1文字の文字列)と解釈されるからです。 [link]# 悪い例 char = ?c # 良い例 char = 'c'
-
文字列の中の挿入されるインスタンス変数やグローバル変数の周りの
{}
は省略してはいけません。 [link]class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end # 悪い例 - 有効ですが不格好です def to_s "#@first_name #@last_name" end # 良い例 def to_s "#{@first_name} #{@last_name}" end end $global = 0 # 悪い例 puts "$global = #$global" # 良い例 puts "$global = #{$global}"
-
文字列に挿入するときに
Object#to_s
を使ってはいけません。 自動的に呼び出されます。 [link]# 悪い例 message = "This is the #{result.to_s}." # 良い例 message = "This is the #{result}."
-
大きなデータの塊を作る必要があるときは、
String#+
の使用は避けましょう。 代わりに、String#<<
を使いましょう。 文字列連結は、文字列インスタンスを直接書き換えるため、 たくさんの新しいオブジェクトを作ってしまうString#+
よりも常に速いです。 [link]# 悪い例 html = '' html += '<h1>Page title</h1>' paragraphs.each do |paragraph| html += "<p>#{paragraph}</p>" end # 良く、そして速い例 html = '' html << '<h1>Page title</h1>' paragraphs.each do |paragraph| html << "<p>#{paragraph}</p>" end
-
利用するケースにより特化した速い代替手段がある場合、
String#gsub
は使わないようにしましょう。 [link]url = 'http://example.com' str = 'lisp-case-rules' # 悪い例 url.gsub('http://', 'https://') str.gsub('-', '_') # 良い例 url.sub('http://', 'https://') str.tr('-', '_')
-
複数行のヒアドキュメントを用いるときは、 先頭のスペースも保持してしまうということを頭に入れておかなければなりません。 過剰なスペースを取り除くためのマージンを採用するのはよい習慣です。 [link]
code = <<-END.gsub(/^\s+\|/, '') |def test | some_method | other_method |end END # => "def test\n some_method\n other_method\nend\n"
なにか問題に突き当たった時、「わかった、正規表現を使えばいいんだ」と思う人がいますね。 その時、元の問題のほかにもう一つ問題が加わっているんです。
-- Jamie Zawinski
-
単に文字列中から文字列を探すだけの時は、 正規表現を使ってはいけません:
string['text']
を使いましょう。 [link] -
文字列の添字に直接正規表現を渡すことで、文字列の構築をシンプルにできます。 [link]
match = string[/regexp/] # マッチした内容が得られる first_group = string[/text(grp)/, 1] # キャプチャグループの内容が得られる string[/text (grp)/, 1] = 'replace' # string => 'text replace'
-
キャプチャした結果を使う必要のないときは、キャプチャしないグループを用いましょう。 [link]
# 悪い例 /(first|second)/ # 良い例 /(?:first|second)/
-
最後に正規表現にマッチした値を示すPerlレガシーの暗号的な変数を用いてはいけません (
$1
、$2
など)。 代わりにRegexp.last_match(n)
を用いましょう。 [link]/(regexp)/ =~ string ... # 悪い例 process $1 # 良い例 process Regexp.last_match(1)
-
どの値が入っているか追うのが困難になるので、 グループ番号を使うのは避けましょう。 代わりにグループに名前をつけましょう。 [link]
# 悪い例 /(regexp)/ =~ string ... process Regexp.last_match(1) # 良い例 /(?<meaningful_var>regexp)/ =~ string ... process meaningful_var
-
文字クラスの中では、特別な意味を持つ文字が少ないので注意が必要です:
^
、-
、\
、]
のみが特別な意味を持つので、.
や括弧を[]
の中でエスケープしてはいけません。 [link] -
^
や$
は、文字列の先頭や末尾ではなく、 行頭や行末にマッチするので注意が必要です。 もし文字列全体の先頭末尾にマッチさせたいときは、\A
、\z
を使いましょう (\n?\z
と等価である\Z
と混同しないようにしましょう)。 [link]string = "some injection\nusername" string[/^username$/] # matches string[/\Ausername\z/] # don't match
-
複雑な正規表現には
x
識別子を用いましょう。 これを用いることで、より読みやすくなり、 便利なコメントを使えるようになります。 スペースが無視されることに注意しましょう。 [link]regexp = / start # some text \s # white space char (group) # first group (?:alt1|alt2) # some alternation end /x
-
sub
/gsub
での複雑な置換は、ブロックやハッシュを用いることで実現できます。 [link]words = 'foo bar' words.sub(/f/, 'f' => 'F') # => 'Foo bar' words.gsub(/\w+/) { |word| word.capitalize } # => 'Foo Bar'
-
文字列挿入と
"
文字の双方が入る1行の文字列には、%()
(%Q()
の短縮形)を使いましょう。 複数行の時はヒアドキュメントを使いましょう。 [link]# 悪い例 (挿入の必要がありません) %(<div class="text">Some text</div>) # '<div class="text">Some text</div>' であるべき # 悪い例 (ダブルクォートがありません) %(This is #{quality} style) # "This is #{quality} style" であるべき # 悪い例 (複数行です) %(<div>\n<span class="big">#{exclamation}</span>\n</div>) # ヒアドキュメントであるべき # 良い例 (挿入が必要、ダブルクォートがある、そして1行です) %(<tr><td class="name">#{name}</td>)
-
文字列に
'
と"
双方が含まれない限り、%q
の使用は避けましょう。 通常の文字列リテラルのほうがより読みやすいので、 エスケープが大量に必要出ない限りは、そちらを使いましょう。 [link]# 悪い例 name = %q(Bruce Wayne) time = %q(8 o'clock) question = %q("What did you say?") # 良い例 name = 'Bruce Wayne' time = "8 o'clock" question = '"What did you say?"'
-
'/'が1つ 以上の 正規表現に限り、
%r
を使いましょう。 [link]# 悪い例 %r{\s+} # 良い例 %r{^/(.*)$} %r{^/blog/2011/(.*)$}
-
呼び出すコマンドにバッククォートが含まれる(かなり起こりえないが)ことがない限り、
%x
の使用は避けましょう。 [link]# 悪い例 date = %x(date) # 良い例 date = `date` echo = %x(echo `date`)
-
%s
の使用は避けましょう。 Rubyコミュニティは、スペース含むシンボルをを作る時は:"文字列"
がよいと決めたようです。 [link] -
パーセントリテラルの区切り文字は、
%r
を除いて()
が好まれます。 正規表現の中では、括弧は色々なシーンで使われるので、 正規表現の内容によっては、より使われる機会の少ない{
のほうが 良い選択となることがあるかもしれません。 [link]# 悪い例 %w[one two three] %q{"Test's king!", John said.} # 良い例 %w(one two three) %q("Test's king!", John said.)
-
不要なメタプログラミングは避けましょう。 [link]
-
ライブラリを作成する時にコアクラスを汚染するのはやめましょう。 (モンキーパッチを当ててはいけません)。 [link]
-
ブロック渡しの
class_eval
のほうが、文字列挿入型よりも好ましいです。 [link]class_eval 'def use_relative_model_naming?; true; end', __FILE__, __LINE__
-
文字列挿入型を使う時は、バックトレースが働くように、常に
__FILE__
と__LINE__
を渡しましょう:class_eval 'def use_relative_model_naming?; true; end', __FILE__, __LINE__
-
define_method
の方が、class_eval{ def ... }
よりも好ましいです。
-
-
文字列挿入型の
class_eval
(または他のeval
)を用いる時は、 挿入されたときのコードをコメントに追加しましょう(Railsで使われているプラクティス)。 [link]# from activesupport/lib/active_support/core_ext/string/output_safety.rb UNSAFE_STRING_METHODS.each do |unsafe_method| if 'String'.respond_to?(unsafe_method) class_eval <<-EOT, __FILE__, __LINE__ + 1 def #{unsafe_method}(*params, &block) # def capitalize(*params, &block) to_str.#{unsafe_method}(*params, &block) # to_str.capitalize(*params, &block) end # end def #{unsafe_method}!(*params) # def capitalize!(*params) @dirty = true # @dirty = true super # super end # end EOT end end
-
method_missing
を用いたメタプログラミングは避けましょう。 何故なら、バックトレースがよくわからなくなるし、#methods
のリストの中に出てこず、 ミススペルしたメソッド呼び出しも無言で動いてしまいます、 例えばnukes.launch_state = false
のようにです。 代わりに、移譲、プロキシ、またはdefine_method
を使いましょう。 もしmethod_missing
を使わなければならない時は: [link]respond_to_missing?
も実装されているか確かめましょう- 既知の接頭辞、
find_by_*
のようなものだけを捕捉しましょう -- 可能な限りアサートさせましょう - 最後に
super
を呼び出しましょう - アサートする、特別でないメソッドに移譲しましょう:
# 悪い例 def method_missing?(meth, *params, &block) if /^find_by_(?<prop>.*)/ =~ meth # ... lots of code to do a find_by else super end end # 良い例 def method_missing?(meth, *args, &block) if /^find_by_(?<prop>.*)/ =~ meth find_by(prop, *args, &block) else super end end # というか、最も良い選択は、発見できる全てのアトリビュートにdefine_methodすることです
-
private
/protected
制約を回避しないために、send
よりもpublic_send
を使いましょう。 [link]# OrganizationというActiveModelがあって、Activatableをincludeしている module Activatable extend ActiveSupport::Concern included do before_create :create_token end private def reset_token ... end def create_token ... end def activate! ... end end class Organization < ActiveRecord::Base include Activatable end linux_organization = Organization.find(...) # 悪い例 - 可視性を無視している linux_organization.send(:reset_token) # 良い例 - 例外があがる linux_organization.public_send(:reset_token)
-
send
は他の既存のメソッドと衝突するかもしれないので、__send__
を使いましょう。 [link]require 'socket' u1 = UDPSocket.new u1.bind('127.0.0.1', 4913) u2 = UDPSocket.new u2.connect('127.0.0.1', 4913) # レシーバーオブジェクトにメッセージが送信されない # かわりに、UDPソケット経由でメッセージが送信されてしまう u2.send :sleep, 0 # こちらならたしかにレシーバーオブジェクトにメッセージが送信される u2.__send__ ...
-
ruby -w
で実行しても何も警告されないコードを書きましょう。 [link] -
オプショナルな変数としてのハッシュの使用を避けましょう。そのメソッドはあまりにたくさんのことをやろうとしていませんか?(オブジェクトの初期化はこのルールの例外です) [link]
-
コードのある行が10行を超えるメソッドは避けましょう。 理想を言えば、多くのメソッドは5行以内がよいです。 空行は行数には含めません。 [link]
-
3つや4つ以上引数を設定するのは避けましょう。 [link]
-
もし本当にグローバルなメソッドが必要な場合は、 Kernelに定義し、privateに設定しましょう。 [link]
-
グローバル変数の代わりに、モジュールのインスタンス変数を使用しましょう。 [link]
# 悪い例 $foo_bar = 1 # 良い例 module Foo class << self attr_accessor :bar end end Foo.bar = 1
-
複雑なコマンドラインオプションをパースするために
OptionParser
を使いましょう。 また、些細なオプションにはruby -s
を使いましょう。 [link] -
現在のシステム時間を読み出すには、
Time.new
よりもTime.now
を使いましょう。 [link] -
破壊的変更をしなくても済むなら、できるだけ関数的プログラミング手法を使いましょう。 [link]
-
それがメソッドの目的でない限り、引数に破壊的変更をするのはやめましょう。 [link]
-
3段階を超えるブロックのネストは避けましょう。 [link]
-
一貫性を保ちましょう。理想を言えば、このガイドラインに沿いましょう。 [link]
-
常識を用いましょう。 [link]
ここでは、このガイドに反するコードを自動的にチェックするのを支援するツールをいくつか紹介します。
RuboCopは、このガイドに基づいた Rubyコードスタイルチェッカーです。 Rubocopはすでにこのガイドの重要な部分をカバーしており、 MRI 1.9、MRI 2.0 双方をサポートし、Emacs向けのよいプラグインがあります。
RubyMine のコードインスペクションは、このガイドに 部分的に基づいています。
このガイドはまだ未完成です - いくつかのルールは例がなく、 いくつかのルールの例はじゅうぶんにクリアにルールを説明できていません。 そのようなルールの改善はRubyコミュニティを助ける素晴らしい(そしてシンプルな)手段です!
これらの課題はやがて解決されると思いたいです - ただ現状にご留意ください。
このガイドに書いてあることには変更不能なものはありません。 Rubyのコードスタイルに興味のある全ての人と共に取り組むことで、 究極的には、全てのRubyコミュニティにとって有益なリソースを作ることができればと思っています。
改善のために、遠慮せずチケットを立てたりプルリクエストを送ったりしてください。 あなたの手助けに予め感謝します!
また、このプロジェクト(とRubocop)への金銭的な貢献は、 Gratipay経由で行うことができます。
簡単です! contribution guidelinesを読んでください!
この著作物は、Creative Commons Attribution 3.0 Unported License に従います。
コミュニティ駆動のスタイルガイドは、これを知らないコミュニティにはほとんど役に立ちません。 このガイドについてつぶやいたり、友達や同僚にシェアしてください。 全てのコメント、提案、オプションがこのガイドを少しだけでも良くしていきます。 そして、考えうるベストのガイドが欲しいですよね?
ありがとう
Bozhidar