rubocopを使うに当たって把握しておく
- 知らなかったこと/よさ気なところをメモ
ソース
レイアウト
{の前後、}の前にはスペース
[1, 2, 3].each { |e| puts e }
メソッドの引数に初期値を割り当てるとき、 =演算子の周りにはスペース
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
- ")"の置き場に悩むことがあったので、このようにする
# 良い例 (普通のインデントです) def send_mail(source) Mailer.deliver( to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text ) end
可読性のため、大きな数値にはアンダースコア
num = 1_000_000
構文
複数行にまたがるif/unlessでは、条件式は常にif/unlessと同じ行に
- 悪い例をやりがち
# 悪い例 if some_condition do_something do_something_else end # 良い例 if some_condition do_something do_something_else end
1行のcase文ではwhen x then ...を使う
- ";" でやりがちだけど、英文的にはthenの方がしっくりくるのかしら
case x when 100; p "100" # NG when 200 then p "200" # OK end
andとorの使用は禁止
- andを使いがち
代入部分を()で囲まずに、=の返り値を条件式に用いてはいけません
if (v = array.grep(/foo/)) do_something(v) ... end
- そもそも条件式内で代入するなよ的な気持ちが...
値が入っているかわからない変数の前処理のは&&=。 &&=を使えば変数が存在するときのみ値を変更するので、 存在確認に用いている不要なifを除去できる
- 知らなかった...
if something # NG something = something.downcase end something = something ? something.downcase : nil # NG something = something.downcase if something # OK something = something && something.downcase # OK something &&= something.downcase # More better
Perlスタイルの($:や$;などのような)特別な変数の使用は避ける。 Englishライブラリを使う
- こんなのあるのか! → library English (Ruby 2.2.0)
1行の本文を持つラムダには新しいリテラルを使う。 lambdaは複数行にまたがるときのみ
l = ->(a, b) { a + b }
Proc.newよりproc
p = proc { |n| puts n }
使わないブロック引数やローカル変数の先頭にはを付ける。 単にを用いてもOK
- rubocopなどで使用されていない変数エラーを回避できる
result = hash.map { |_, v| v + 1 } def something(x) _, used_var = something_else(x) end
複雑な比較ロジックの代わりに、 可能な限りRangeやComparable#between?を使う
- わすれがち
do_something if x >= 1000 && x <= 2000 # 悪い例 do_something if (1000..2000).include?(x) # 良い例 do_something if x.between?(1000, 2000) # 良い例
ループ内では条件判定ブロックよりもnext
- 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
mapとflattenの組み合わせの代わりに、flat_map
- 深さが2以上の配列には適用できないので注意
- flat_map知らなかった...
reverse.eachの代わりにreverse_each
- reverse_each知らなかった...
注釈
- TODO : あとで追加されるべき、今はない機能や関数
- FIXME : 直す必要がある
- OPTIMIZE* : パフォーマンスに問題を及ぼすような、遅い、または非効率な
- HACK : 疑わしくリファクタリングで除去すべきコード
- REVIEW : 意図したとおりに動くか確認する必要がある箇所
- 例: REVIEW: Are we sure this is how the client does X currently?
クラス
- クラスメソッドしかないクラスはモジュールであることが好まれます
- モジュールのインスタンスメソッドをクラスメソッドにしたいときは、 extend selfより もmodule_functionが好まれます。
Struct.newの使用を考えましょう、 それは、単純なアクセサ、コンストラクタや比較演算子を定義してくれます
# 良い例 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
- truct.newで初期化されたインスタンスを拡張してはいけません。 それは余分なクラスレベルをもたらし、 複数回requireされた時に、奇妙なエラーの原因にもなります
- 継承での振る舞いが"扱いづらい"ので、クラス変数(@@)の使用は避けましょう
例外
例外発生にはfail。 raiseは例外をキャッチして、再度発生させるときにのみ
不確実性のあるメソッド(Avdi Grimmによって作られた言葉です) を用いてbeginの蔓延を和らげる
# 悪い例 begin something_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 }
- これ便利そう!!
Collections
- シンボルの配列が必要なときは%iが好まれます
- 要素が一意のものを扱うときは、Arrayの代わりにSet
- Hash#has_key?よりHash#key?を、 Hash#has_value?よりHash#value?。Matzが述べているように、長い記法は廃止が検討されています
コレクションに対するアクセサを提供するとき、 コレクション内の要素にアクセスする前に、 nilでアクセスするのを防ぐための代替のアクセス方法を提供しましょう
# 悪い例 def awesome_things @awesome_things end # 良い例 def awesome_things(index = nil) if index && @awesome_things @awesome_things[index] else @awesome_things end end
正規表現
速い代替手段がある場合、String#gsubは使わない
- subやtrで代替する
捕捉した結果を使う必要のないとき、捕捉しないグループを用いる
/(first|second)/ # 悪い例 /(?:first|second)/ # 良い例
Perlレガシーの暗号的な変数は使わない
Regexp.last_match(1) /(?<meaningful_var>regexp)/ =~ string puts meaningful_var
複雑な正規表現にはx識別子を用いる
- スペースが無視されることに注意
regexp = / start # some text \s # white space char (group) # first group (?:alt1|alt2) # some alternation end /x