GitHubによるコーディングスタイルガイドのうちRuby編の翻訳です。原文はこちらにあります。
HTML編もありますので、こちらもあわせてどうぞ。
#Ruby
このスタイルガイドの多くはhttps://github.com/bbatsov/ruby-style-guideから来ています。GitHub従業員は、社内で受理されたコーディングパターンやスタイルがあれば、pull requestを出してフィードバックを要求してください。
コーディングスタイル
- スペース2つをインデントとするソフト・タブを使うこと。
- 1行の長さは80文字以下にすること。
- 行末の空白スペースを残さないこと。
- ファイルの最終行には空行を入れること。
- 演算子・カンマ・コロンやセミコロンのあとや
{
と}
の前後にはスペースを入れること。
sum = 1 + 2
a, b = 1, 2
1 > 2 ? true : false; puts "Hi"
[1, 2, 3].each { |e| puts e }
-
(
や[
、)
や]
の前後にはスペースを入れないこと。
some(arg).other
[1, 2, 3].length
-
!
の後にスペースを入れないこと。
!array.include?(element)
-
when
はcase
と同じインデントの深さにすること。
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
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
-
def
の間や、メソッド内のロジックの段落の間に改行を入れること。
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
ドキュメンテーション
出来るかぎりTomDocを使うこと。
# Public: Duplicate some text an arbitrary number of times.
#
# text - The String to be duplicated.
# count - The Integer number of times to duplicate the text.
#
# Examples
#
# multiplex("Tom", 4)
# # => "TomTomTomTom"
#
# Returns the duplicated String.
def multiplex(text, count)
text * count
end
シンタックス
-
def
に引数がつく場合は括弧を使うこと。メソッドが引数を受け取らない場合は、括弧は省くこと。
def some_method
# method body
end
def some_method_with_arguments(arg1, arg2)
# method body
end
- 完全にそうすべき理由がないかぎり、
for
は使わないこと。多くの場合、代わりにイテレーションをすることの方が適切である。for
はeach
から少し違った形で実装されているので、結果的に遠回りをしてしまうことになる。つまり、for
はeach
と違って新しいスコープを用意しないので、ブロック内で定義された変数は外から参照できてしまう。
arr = [1, 2, 3]
# bad
for elem in arr do
puts elem
end
# good
arr.each { |elem| puts elem }
- 複数行にわたる
if/unless
にはthen
を使わないこと。
# bad
if some_condition then
# condition body
end
# good
if some_condition
# condition body
end
- 分岐条件が細かすぎるとき以外は、三項演算子
?:
の使用は控えること。ただし、if/then/else/end
構文を1行の条件式にする目的には三項演算子?:
を使うこと。
# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
- 三項演算子による条件分岐ではそれぞれ1つの式を使うこと。つまり、三項演算子はネストしないこと。そういった場合は
if/else
構文の方が好ましい。
# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
# good
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
-
and
やor
といったキーワードは禁止とする。とくにそうする価値がないから。常に&&
と||
を使うこと。 -
複数行にわたる三項演算子
?:
は避け、代わりにif/else
を使うこと。 -
条件の中身が1行の場合は、
if/unless
を1行で書くこと。
# bad
if some_condition
do_something
end
# good
do_something if some_condition
-
unless
とelse
は一緒に使わないこと。こういったものは、肯定文が先にくるように書き直すこと。
# bad
unless success?
puts "failure"
else
puts "success"
end
# good
if success?
puts "success"
else
puts "failure"
end
-
if/unless/while
による条件式には括弧を使わないこと。
# bad
if (x > 10)
# condition body
end
# good
if x > 10
# condition body
end
- 1行で書ける場合は
do...end
よりも{...}
を使うこと。また、複数行にわたるブロックでは{...}
を使わないこと(チェーンが複数行になると見難くなる)。フロー制御やメソッド定義においてはdo...end
を使うこと(Rakefileや特定のDSLなど)。チェーンで書くときはdo...end
を使わないこと。
names = ["Bozhirdar", "steve", "Sarah"]
# good
names.each { |name| puts name }
# bad
names.each do |name|
puts name
end
# good
names.select { |name| name.start_with?("S") }.map { |name| name.upcase }
# bad
names.select do |name|
name.start_with?("S")
end.map { |name| name.upcase }
複数行にわたるコードで{...}
を使うことは特に見た目上問題はないという意見もあるかもしれないが、本当にリーダブルであるか?このブロックはいい感じの他のメソッドに切り分けることはできないか?を自問するべきである。
- 不要な箇所での
return
は使わないこと。
# bad
def some_method(some_arr)
return some_arr.size
end
# good
def some_method(some_arr)
some_arr.size
end
- パラメータ引数に代入するときは、
=
演算子の前後にスペースを入れること。
# bad
def some_method(arg1=:default, arg2=nil, arg3=[])
# do something...
end
# good
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
# do something...
end
-
=
演算子(代入)の返り値は使っても良い。
# bad
if (v = array.grep(/foo/)) ...
# good
if v = array.grep(/foo/) ...
# 正しい順序になっていればこれも可
if (v = next_value) == "hello" ...
- 変数を初期化するときには
||=
を自由に使って良い。
# set name to Bozhidar, only if it's nil or false
name ||= "Bozhidar"
- ブール値を初期化する際には
||=
を使わないこと。(変数の現在の値がfalse
だったときのことを考えてみれば分かる)
# bad - would set enabled to true even if it was false
enabled ||= true
# good
enabled = true if enabled.nil?
-
$0-9
や$
といったような、Perlスタイルな特殊変数を使わないこと。こういった変数は謎を増やすので、ワンライナーのスクリプト以外では使用を控えること。$PROGRAM_NAME
といったような長いバージョンの方が望ましい。 -
メソッドの名前と括弧の間にはスペースを入れないこと。
# bad
f (3 + 2) + 1
# good
f(3 + 2) + 1
-
メソッドの1つめの引数が括弧開きから始まる場合、メソッドを使うときには括弧を使うこと。例:
f((3 + 2) + 1)
-
ブロック内の未使用の引数には
_
を使うこと。
# bad
result = hash.map { |k, v| v + 1 }
# good
result = hash.map { |_, v| v + 1 }
- 型チェックにおいては、
===
を使わないこと。===
はRubyにおけるcase
などの実装サポートなので、可換とは限らない。たとえば、String === "hi"
はtrueであるが"hi" === String
はfalseになる。代わりに、必要なときはis_a?
やkind_of?
を使うこと。
リファクタリングのほうがなお良い。明示的に型チェックを行うコードは、詳しく検討してみるべきである。
命名
- メソッド名や変数名にはスネークケース(
snake_case
)を使うこと。 - クラス名やモジュール名にはキャメルケース(
CamelCase
)を使うこと。(HTTP、RFC、XMLなどの頭字語は大文字のままで良い) - そのほかの定数はすべて大文字(
SCREAMING_CAMEL_CASE
)を使うこと。 - 推定を行うメソッド(返り値がブール値であるメソッド)には、最後にクエスチョンマークをつけること(例:
Array#empty?
) - 危険な挙動をともなう可能性のあるメソッド(例:
self
や引数を書き換えるもの、exit!
など)には、最後にエクスクラメーションマークをつけること。バングメソッド(エクスクラメーションマークがついたメソッド)は、エクスクラメーションマークがついていないメソッドがある場合のみ作ること。より詳しく見る
クラス
- 継承に関連して変わった挙動をすることがあるので、クラス変数
@@
は使わないこと。
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 # => "child"と出力される
上を見るとわかるように、クラスにおけるヒエラルキーでは1つのクラス変数を共有してしまう。クラス変数よりも、インスタンス変数のほうが好ましい。
- リファクタリングや変更に強くするために、シングルトンメソッドには
def self.method
を使うこと。
class TestClass
# bad
def TestClass.some_method
# method body
end
# good
def self.some_other_method
# method body
end
- 必要なとき(アクセサや属性のエイリアスの設定)以外は
class << self
を使わないこと。
class TestClass
# bad
class << self
def first_method
# method body
end
def second_method
# method body
end
end
# good
class << self
attr_accessor :per_page
alias_method :nwo, :find_by_name_with_owner
end
def self.first_method
# method body
end
def self.second_method
# method body
end
end
-
public
、protected
やprivate
は、メソッド定義と同じインデントの深さにすること。また、それぞれの上には空行を入れること。
class SomeClass
def public_method
# ...
end
private
def private_method
# ...
end
end
- 内部的なクラス/インスタンスメソッドのやりとりにおいて、変数に隠れたメソッドを特定する以外には、明示的に
self
をレシーバとしないこと。
class SomeClass
attr_accessor :message
def greeting(name)
message = "Hi #{name}" # Rubyではattribute writeではなくローカル変数
self.message = message
end
end
例外
- フロー制御のために例外を使わないこと。
# bad
begin
n / d
rescue ZeroDevisionError
puts "Cannot devide by 0!"
end
# good
if d.zero?
puts "Cannot devide by 0!"
else
n / d
end
-
Exception
クラスとして例外を拾わないこと。
# bad
begin
# ここで例外が発生する
rescue
# 例外処理
end
# これもダメ
begin
# ここで例外が発生する
rescue Exception
# 例外処理
end
コレクション
- 文字列の配列が必要なときは、配列リテラルよりも
%w
が好ましい。
# bad
STATES = ["draft", "open", "closed"]
# good
STATES = %w(draft open closed)
-
ユニークな要素を扱うときは、
Array
ではなくSet
を使うこと。Set
は非順序で重複のないコレクションとして持つ。これはArray
の直感的な操作性や機能と、Hash
の参照速度のどちらもあわせ持つ。 -
ハッシュのキーには文字列ではなくシンボルを使うこと。
# bad
hash = { "one" => 1, "two" => 2, "three" => 3 }
# good
hash = { :one => 1, :two => 2, :three => 3 }
文字列
- 文字列は、結合するよりも文字列内で展開するほうが好ましい。
# bad
email_with_name = user.name + " <" + user.email + ">"
# good
email_with_name = "#{user.name} <#{user.email}>"
- 文字列にはダブルクオテーションを使うこと。文字列内展開やエスケープ記号は区切り記号が変わろうと動作し、また文字列リテラルにおいては
'
よりも"
の方がはるかに一般的である。
# bad
name = 'Bozhidar'
# good
name = "Bozhidar"
- 大きなデータのかたまりを作るときには、
String#+
の使用は避けること。代わりにString#<<
を使うこと。文字列の結合は文字列インスタンスを適切に変異させ、また文字列オブジェクトをたくさん生成するString#+
よりも速い。
# good and also fast
html = ""
html << "<h1>Page title</h1>"
paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end
正規表現
-
$1-9
は何を内包しているかが把握しづらいため使わないこと。代わりに名前のついたグループを使うこと。
# bad
/(regexp)/ =~ string
...
process $1
# good
/(?<meaningful_var>regexp>)/ =~ string
...
process meaningful_var
-
^
と$
は行の始まりと終わりと示すものであり、文字列の始めと終わりを指さないことに注意する。文字列全体とのマッチを行うには、\A
と\z
を使うこと。
string = "some injection\nusername"
string[/^username$/] # マッチする
string[/\Ausername\z/] # マッチしない
- 複雑な正規表現では、
x
オプション使うこと。これにより、可読性が向上し、コメントをつけることができる。ただし、スペースが無視されることに注意する。
regexp = %r{
start # テキスト
\s # スペースと文字
(group) # 最初のグループ
(?:alt1|alt2) # 代替要素
end
}x
パーセント(%)リテラル
-
%w
は自由に使ってよい。
STATES = %w(draft open closed)
- 文字列の式展開やダブルクオテーションの埋め込みを必要とする文字列には、
%()
を使うこと。複数行にわたる場合は、ヒアドキュメントの方が好ましい。
# bad (式展開がない)
%(<div class="text">Some text</div>)
# ok
"<div class=\"text\">Some text</div>"
# bad (ダブルクオテーションがない)
%(This is #{quality} style)
# ok
"This is #{quality} style"
# bad (複数行)
%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# ヒアドキュメントが望ましい
# good (式展開やクオテーションがあり1行である)
%(<tr><td class="name">#{name}</td>)
- 1つ以上の
/
とマッチさせるときのみ%r
を使うこと。
# bad
%r(\s+)
# これもダメ
%r(^/(.*)$)
# 修正後: /^\/(.*)$/
# good
%r(^/blog/2011/(.*)$)
ハッシュ
ハッシュリテラルには、1.9で導入されたJSONスタイルのシンタックスではなく、ハッシュロケットを使うこと。
# bad
user = {
login: "defunkt",
name: "Chris Wanstrath"
}
# bad
user = {
login: "defunkt",
name: "Chris Wanstrath",
"followers-count" => 52390235
}
# good
user = {
:login => "defunkt",
:name => "Chris Wanstrath",
"followers-count" => 52390235
}
キーワード引数
キーワード引数の使用は推奨されているものの、メソッドの引数がともすれば不明瞭になるような場合には必須ではない。また、pre-2.0 ruby以降では、「擬似引数としてのハッシュ」よりもキーワード引数の方が望ましい。
これの代わりには
def remove_member(user, skip_membership_check=false)
# ...
end
# メソッド定義以外の場所: ここでのtrueとはどういう意味だろうか?
remove_member(user, true)
もっと明示的になるよう、こうするべきである。
def remove_member(user, skip_membership_check: false)
# ...
end
# Elsewhere, now with more clarity:
remove_member user, skip_membership_check: true
上記の何よりも
自らのに従うこと。