読者です 読者をやめる 読者になる 読者になる

Memento memo.

Today I Learned.

Ruby Style Guide読んだ && 一部抜粋

github.com

普段はRubocopのおかげで概ねStyle準拠できているはず、と思ってたのですが、 改めてStyle Guideを読むと知見がたくさんありました。

以下、個人的に把握できてなかった箇所を抜粋しつつ、今後意識していきます。

andとorの使用は禁止

使うべき理由がないです。 常に、代わりに&&と||を使いましょう。

メソッドチェーンでのdo...endは避ける

# 悪い例
names.select do |name|
  name.start_with?('S')
end.map { |name| name.upcase }

# 良い例
names.select { |name| name.start_with?('S') }.map(&:upcase)

do...end.map やりたくなる場面がたまにあるんですが、我慢します。

代入部分を括弧で囲まずに、=の返り値を条件式に用いてはいけない

# 悪い例 (+ 警告が出ます)
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

変数がまだ初期化されていないときにだけ初期化したいのであれば、||=を使う

# 悪い例
name = name ? name : 'Bozhidar'

# 悪い例
name = 'Bozhidar' unless name

# 良い例 - nameがnilかfalseの場合のみ、Bozhidarで初期化します
name ||= 'Bozhidar'

値が入っているかわからない変数の前処理のは&&=を用いる

# 悪い例
if something
  something = something.downcase
end

# 悪い例
something = something ? something.downcase : nil

# ok
something = something.downcase if something

# 良い例
something = something && something.downcase

# より良い例
something &&= something.downcase

Proc.newよりprocを使う

# 悪い例
p = Proc.new { |n| puts n }

# 良い例
p = proc { |n| puts n }

STDOUT/STDERR/STDINの代わりに$stdout/$stderr/$stdinを用いる

STDOUT/STDERR/STDINは定数であり、 Rubyでの定数は、実際は再代入できます(つまりリダイレクトに使えます)が、 もし実行するとインタープリタからの警告が出ます。

ロジックを使って複雑な比較を行うよりも、 可能な限りRangeやComparable#between?を用いる

# 悪い例
do_something if x >= 1000 && x <= 2000

# 良い例
do_something if (1000..2000).include?(x)

# 良い例
do_something if x.between?(1000, 2000)

collectよりmap、detectよりfind、find_allよりselect injectよりreduce、lengthよりsizeを使う

これは絶対のルールではないです。 別名のほうが可読性に優れているなら、 そちらを使っていただいて構いません。 韻を踏んでいるほうのメソッド名はSmalltalkから引き継いできたもので、 他のプログラミング言語でそこまで一般的ではないです。 find_allよりもselectが推奨されるのは、 rejectとの相性がよいことと、 メソッド名から挙動を推察することも容易だからです。

シンボル、メソッド、変数にはsnake_caseを用いましょう。

シンボルはcamelCaseでも怒られない気がしたんですが、こちらもsnake_caseが良いみたいです。

危険 な可能性のあるメソッド (引数やselfを変更するようなメソッドや、 exit!(exitと違ってファイナライザが走らない)のようなもの) は、その安全なバージョンがある場合には、 危険 であることを明示する意味で感嘆符で終わる

# 悪い例 - 対応する「安全」なメソッドが存在しません
class Person
  def update!
  end
end

# 良い例
class Person
  def update
  end
end

# 良い例
class Person
  def update!
  end

  def update
  end
end

対応する安全なメソッドが存在しない場合は ! 付けない方が正しいみたいですね。副作用が大きいメソッドは ! つけるようにしてたんですが、Style Guilde的には微妙みたいです。

コメント

  • パフォーマンスに問題を及ぼすかもしれない遅い、または非効率なコードの注釈にはOPTIMIZEを使いましょう。
  • 疑問の残るコードの書き方でコードの臭いを感じた箇所の注釈にはHACKを使いましょう。
  • 意図したとおりに動くか確認する必要がある箇所の注釈にはREVIEWを使いましょう。

ハッシュから連続して複数の値が必要になる時は、Hash#values_atを用いる

# 悪い例
email = data['email']
username = data['nickname']

# 良い例
email, username = data.values_at('email', 'nickname')

利用するケースにより特化した速い代替手段がある場合、String#gsubは使わないようにする

url = 'http://example.com'
str = 'lisp-case-rules'

# 悪い例
url.gsub('http://', 'https://')
str.gsub('-', '_')

# 良い例
url.sub('http://', 'https://')
str.tr('-', '_')

文字列の添字に直接正規表現を渡すことで、文字列の構築をシンプルにできる

match = string[/regexp/]             # マッチした内容が得られる
first_group = string[/text(grp)/, 1] # キャプチャグループの内容が得られる
string[/text (grp)/, 1] = 'replace'  # string => 'text replace'

sub/gsubでの複雑な置換は、ブロックやハッシュを用いることで実現できる

words = 'foo bar'
words.sub(/f/, 'f' => 'F') # => 'Foo bar'
words.gsub(/\w+/) { |word| word.capitalize } # => 'Foo Bar'