よく使われているスタイルガイド
ロールモデルが重要なのだ。
-- アレックス・マーフィー巡査 / ロボコップ
Rubyディベロッパーとして、私は常にあることに悩まされてきました - Pythonディベロッパーは偉大なプログラミングスタイルガイド (PEP-8) を持っていますが、 我々には公式のコーディングスタイルやベストプラクティスを 一切持ち合わせていません。 そして、私はそれこそが問題であると確信しています。 また、Rubyが持っているような素晴らしいハッカーコミュニティは、 誰もが羨むようなドキュメントを作り出す力があるはずであるとも確信しています。
このガイドは、私達の社内製Rubyコーディングガイドから生まれました (著者は私)。 私がこのガイドを書くと決めたときは、一般のRubyコミュニティのメンバーに 興味を持ってもらえるだろうか、社内製のガイドはあまり必要とされていないのではないか と考えていました。 しかし、コミュニティ駆動の、コミュニティに認められた、 Rubyのための慣習、語法、スタイル規定は、 確実にRubyコミュニティに有益たりえるのではないでしょうか。
このガイドを発端に、私は世界中の優れたRubyコミュニティのメンバーから、 たくさんのフィードバックを受けています。 全ての提案、サポートに感謝します! お互いに、また全てのRubyディベロッパーにとって有益なリソースを、 一緒に作ることができています。
ところで、もしあなたがRailsが好きであれば、 こちらの補足も確認してみてください。 Ruby on Rails Style Guide.
このRuby style guideは、他のRubyプログラマーが保守できるコードを書くための ベストプラクティスを採用することをおすすめします。 実際の使われ方を反映したスタイルガイドは使われるようになり、 理想論にとどまり、それを採用することがリスクと感じる人々に拒絶されるような スタイルガイドは全く使われなくなります – たとえそれがどんなに素晴らしいものであっても。
このガイドは、関連するルールに基づいていくつかのセクションに分かれています。 ルールの後ろにその論理的根拠も付け加えるように努めています (自明であると判断したもの以外は)。
私はこれら全てのルールをどこからともなく考えついたわけではありません - これらのほとんどは、私のプロフェッショナルソフトウェアエンジニアとしての 豊富な経験と、Rubyコミュニティのメンバーからの意見や提案、 また、"Programming Ruby 1.9"や、 "The Ruby Programming Language"のような、 様々な高度で評価の高いRubyプログラミングリソースに基づいています。
特定のスタイルに関して、Rubyコミュニティ内での明らかな意見の一致を得ていない箇所もいくつかあります (文字列リテラルの引用記号、ハッシュリテラルの内側のスペース、複数行のメソッドチェーンのドットの位置、などなど)。 そのようなシナリオでは、どの有名なスタイルも許容されるので、 どれを選んで、一貫して用いるかはあなた次第です。
このスタイルガイドは、追加の慣習を定めたり、 Ruby自身の変化によって過去に定めたルールが時代遅れになるとともに進化してきました。
多くのプロジェクトは、それ自身のコーディングスタイルガイドを持っています (しばしばこのガイドを基に生成されています)。 結果としてルールの衝突が発生した場合は、 そのプロジェクトにおいては、プロジェクト固有のガイドを優先します。
PDFやHTMLのコピーはこのガイドを使って作成できます Transmuter。
RuboCopは、 このスタイルガイドに基づいたコード分析器です。
以下の言語の翻訳が利用可能です:
ほとんどすべての人が、彼ら自身のではないスタイルは 不快で合理的でないと確信している。 「彼ら自身の」を除けば、おそらく正しいのだが、、、 -- Jerry Coffin (on indentation)
ソースファイルのエンコーディングには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 }
演算子についてただひとつの例外は、指数演算子です:
# 悪い例
e = M * c ** 2
# 良い例
e = M * c**2
{
と }
は、構文の明確化のために有用です。
だから、文字列に式を埋め込む時と同様に、
ブロックやハッシュ構文に使われます。
ハッシュ構文には、2つのスタイルが許容できます。
# 良い例 - スペースを { の後と } の前に入れる
{ one: 1, two: 2 }
# 良い例 - スペースを { の後と } の前に入れない
{one: 1, two: 2}
1つ目の構文は、わずかながら少し読みやすいです(そして、ほぼ間違いなく一般的なRubyコミュニティで人気があります)。 2つ目の構文は、ブロックとハッシュを視覚的に差別化できるという点で有利です。 どちらでも片方を採用すれば、常に同じ構文を採用しましょう。
文字列に埋め込む構文も、2つのスタイルが許容できます:
# 良い例 - スペースを入れない
"string#{expr}"
# 良い例 - ほぼ間違いなくにこちらのほうが読みやすい
"string#{ expr }"
1つ目の式は、他の式よりも非常に人気があり、一般的にこちらを使うように進められる書き方です。 一方2つ目は、(間違いなく)少し読みやすいです。 ハッシュと同じように - 片方を採用すれば、常に同じ方を採用しましょう。
(
、 [
の後と、]
、 )
の前にはスペースは入れません。
[link]
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: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)
end
# 悪い例 (インデント2つで揃えています)
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
# 良い例
def send_mail(source)
Mailer.deliver(to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
# 良い例 (普通のインデントです)
def send_mail(source)
Mailer.deliver(
to: 'bob@example.com',
from: 'us@example.com',
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
あなたが使ってはならない理由を正確に知っていなければ、決して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
# 良い例
retuls =
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'
# obscure nil check
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
が好まれます。(もしくは||
構文を使いましょう)。
[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行のブロックではdo...end
より{...}
の方が好まれます。
複数行のブロックでは{...}
は避けましょう
(複数行のメソッドチェーンは常に醜いです)。
"制御構文"や"メソッド定義"では常にdo...end
を使いましょう
(例えばRakefilesや特定のDSLなど)
メソッドチェーンでのdo...end
は避けましょう。
[link]
names = ['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 { |name| name.upcase }
{...}
を用いた複数行のメソッドチェーンをOKと主張する人もいるかもしれないが、
自問してみてほしい - このコードは本当に読みやすいだろうか?
また、このブロックの本文は素早く展開できるだろうか?
単に他のブロックに引数を渡すだけのブロックリテラルを避けるため、
ブロック引数を明示することを検討しましょう。
ただしブロックがProc
に変換されることでのパフォーマンスに気をつけましょう。
[link]
require 'tempfile'
# 悪い例
def with_tmp_dir
Dir.mktmpdir do |tmp_dir|
Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments
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
は避けましょう (自身のアトリビュートへの書き込みでのみ必要です)。
[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
# both options and self.options are equivalent here
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が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
の条件判定で用いられており、
その外で用いられると混乱のもとになります。
[link]
# 悪い例
Array === something
(1..100) === 7
/something/ === some_string
# 良い例
something.is_a?(Array)
(1..100).include?(7)
some_string =~ /something/
Do not use eql?
when using ==
will do. The stricter comparison semantics
provided by eql?
are rarely needed in practice.
[link]
# 悪い例 - eql? は 文字列に対する == と同じです
"ruby".eql? some_str
# good
"ruby" == some_str
1.0.eql? x # eql? はFixnumとFloatの1を識別したいのであれば意味があります
Perlスタイルの($:
や$;
などのような)特別な変数の使用は避けましょう。
それらは極めて不可解で、
1行のスクリプト以外でそれらが使われるとやる気が削がれます。
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]
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
Proc.new
よりproc
を好みます。
[link]
# 悪い例
p = Proc.new { |n| puts n }
# 良い例
p = proc { |n| puts n }
ラムダや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'
引数が配列かどうかわからないが、それを配列として扱って処理したいとき、
配列のチェックを明示するより、[*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
ブーリアン値を扱わない限り、露骨なnil
でないかの検査は避けましょう。
[link]
# 悪い例
do_something if !something.nil?
do_something if something != nil
# 良い例
do_something if something
# 良い例 - ブーリアン値を扱うとき
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
を好みます。
これは厳しい要件ではありません;
もしエイリアスを用いるほうが可読性が上がるのであれば、
使うのもOKです。
それらの同韻のメソッドはSmalltalkから継承されており、
他の言語ではあまり一般的ではありません。
find_all
よりもselect
が推奨される理由は、
reject
と共に用いた時、その名前が極めて自己説明的だからです。
[link]
size
の代わりにcount
を用いてはいけません。
Array
以外のEnumerable
オブジェクトでは、
サイズを求めるためにコレクション全てをイテレートしてしまいます。
[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
を用いましょう。
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 SomeClass
...
end
class SomeXML
...
end
ファイル名にはsnake_case
を用いましょう。例えばhello_world.rb
のように。
[link]
ディレクトリ名にはsnake_case
を用いましょう。例えばlib/hello_world/hello_world.rb
のように。
[link]
1つのclass/module
につき、ちょうど1つのファイルを持つことを目指しましょう。
ファイル名はCamelCase
をsnake_case
に置き換えたclass/module
名を用いて命名しましょう。
[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]
余計なコメントは避けましょう。 [link]
# 悪い例
counter += 1 # Increments counter by one.
コメントは最新に保ちましょう。 古くなったコメントは、コメントがないより悪いです。 [link]
良いコードは良いジョークのようだ - なんの説明もいらない。
-- Russ Olsen
注釈は、通常関連するコードのすぐ上に書きましょう。 [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
# 定数定義はその次です
SOME_CONSTANT = 20
# その後ろはアトリビュートマクロです
attr_reader :name
# 他のマクロが続きます(もしあれば)
validates :name
# public class methods が次に来ます
def self.some_method
end
# public instance methods が続きます
def some_method
end
# protected and private methods は後ろの方にまとめます
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
は、適用するメソッド定義と同じインデントにしましょう。
可視性を定義する識別子以降のメソッドに適用されることを強調するため、
識別子の上下に空行を入れましょう。
[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
文脈上self
が静的に決定されるようなclass
のレキシカルスコープ内でメソッドのエイリアスを与える時はalias
を好みます。
そうすれば実行時やどのサブクラスないでも、それを明示的に行わない限り
あなたのエイリアスが変更されないことをユーザーに伝えることが出来ます。
[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]
begin
fail 'Oops'
rescue => error
raise if error.message != 'Oops'
end
2引数のfail/raise
では、RuntimeError
を明示しないようにしましょう。
[link]
# 悪い例
fail RuntimeError, 'message'
# 良い例 - デフォルトでRuntimeErrorが発生します
fail 'message'
例外インスタンスの代わりに、
例外クラスとメッセージが分かれているfail/raise
が好まれます。
[link]
# 悪い例
fail SomeException.new('message')
# `fail SomeException.new('message'), backtrace`とする書き方が存在しないことに注意しましょう。
# 良い例
fail SomeException, 'message'
# `fail SomeException, 'message', backtrace`の用法と一貫性があります
ensure
ブロックからreturn
してはいけません。
もしensure
から明示的に値を返したい場合は、
return
はどの例外発生よりも前に書いておき、
例外など発生していなかったかのように値を返しましょう。
事実上、例外は静かに捨てられます。
[link]
def foo
fail
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 Exception => e
# エラー処理
rescue StandardError => e
# 決して到達しないエラー処理
end
# 良い例
begin
# 処理
rescue StandardError => e
# エラー処理
rescue Exception => 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)
シンボルの配列が必要なときは%i
が好まれます
(Ruby 1.9との互換性の維持が必要で無ければ)。
このルールは要素が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 }
# 悪い例 - falseと判定される値が入っていた場合、望んだとお降りに動かないかもしれません
batman[:is_evil] || true # => true
# 良い例 - falseと判定される値が入っていても正しく動きます
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]
"#{ user.last_name }, #{ user.first_name }"
一貫した文字列リテラルの引用記号のスタイルを採用しましょう。 Rubyコミュニティには2つの有名なスタイル - デフォルトでシングルクォートを用いるもの (Option A)、 ダブルクォートを用いるもの (Option B) - があり、 どちらも良いと考えられています。 [link]
(Option A) 文字列挿入の必要がないときや、\t
や\n
`’`等の特別な文字がない場合は、
シングルクォーテーションが好まれます。
# 悪い例
name = "Bozhidar"
# 良い例
name = 'Bozhidar'
(Option B) 文字列中に"
を含んでいたり、エスケープ文字を抑えたいときでない限り、
ダブルクォーテーションが好まれます。
# 悪い例
name = 'Bozhidar'
# 良い例
name = "Bozhidar"
Rubyコミュニティの中では、ほぼ間違いなく 2つ目のスタイルの方が有名です。 しかしながら、このガイド内の文字列リテラル表記は、 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#<<
は、文字列インスタンスを直接書き換えるため、
String#+
よりも常に速いです、
String#+
はたくさんの新しいオブジェクトを作ってしまいます。
[link]
# 良く、そして速い例
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://")
url.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"
問題に突き当たった時、"そうだ、正規表現を使おう"と考えます。 そこには2つの問題があります。
-- Jamie Zawinski
単にプレーンテキストを文字列中から探すだけの時は、
正規表現を使ってはいけません: string['text']
を使いましょう。
[link]
単純化のため、文字列の添字に直接正規表現を渡しましょう。 [link]
match = string[/regexp/] # get content of matched regexp
first_group = string[/text(grp)/, 1] # get content of captured group
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]
挿入と"
双方が入る1行の文字列には、
%()
(%Q()
の短縮形)を使いましょう。
複数行の時はヒアドキュメントを好みます。
[link]
# 悪い例 (挿入の必要がありません)
%(<div class="text">Some text</div>)
# should be '<div class="text">Some text</div>'
# 悪い例 (ダブルクォートがありません)
%(This is #{quality} style)
# should be "This is #{quality} style"
# 悪い例 (複数行です)
%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# should be a heredoc.
# 良い例 (挿入が必要、ダブルクォートがある、そして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
のほうが、文字列挿入型よりも好ましいです。
__FILE__
と__LINE__
を渡しましょう:
[link]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]
ruby -w
で安全なコードを書きましょう。
[link]
オプショナルな変数としてのハッシュの使用を避けましょう。やりすぎてはいませんか?(オブジェクトの初期化はこのルールの例外です) [link]
コードのある行が10行を超えるメソッドは避けましょう。 理想を言えば、多くのメソッドは5行以内がよいです。 空行は行数には含めません。 [link]
3つや4つ以上引数を設定するのは避けましょう。 [link]
もし本当に"global"なメソッドが必要な場合は、 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)への金銭的な貢献は、 gittip経由で行うことができます。
簡単です! contribution guidelinesを読んでください!
この著作物は、Creative Commons Attribution 3.0 Unported License に従います。
コミュニティ駆動のスタイルガイドは、これを知らないコミュニティにはほとんど役に立ちません。 このガイドについてつぶやいたり、友達や同僚にシェアしてください。 全てのコメント、提案、オプションがこのガイドを少しだけでも良くしていきます。 そして、考えうるベストのガイドが欲しいですよね?
ありがとう
Bozhidar