ruby-style-guideを読んだら知らないことがイロイロあって勉強になった

2年ぶりに業務でRubyを書きはじめたので、改めてruby-style-guideを読んだら知らなかったことがイロイロあったのでメモ。

2019/02/28当時の日本語版: 2bac495を読みました。

1. 本文のないクラスは1行のフォーマットを用いましょう。

# 悪い例
class FooError < StandardError
end

# 悪くない例
class FooError < StandardError; end

# 良い例
FooError = Class.new(StandardError)

「悪くない例」を書きがちだったので。

2. forは、どうしても使わなければいけない明確な理由が明言できる人以外は、使ってはいけません。 多くの場合は代わりにイテレータを使うべきです。 forはeachをつかって実装されています(だから、より遠回しです)が、 forは(eachと違い)新しいスコープを導入せず、 そのブロック内で定義された変数は、ブロックの外からも見えます。

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'

なんとなく、「Rubyでfor文は使わないものだ」という認識はあったし、実際for文は使ったことがなかったけど、なんで使わないのか、避けるべき理由は何なのかを意識していませんでした。

↑の例に書いてあるようにfor文内でつかった変数が、外に漏れ出てくるのはなんかのきっかけでハマりそうだし、やっぱりfor文は避けるべきなんだなと思いました。

3. あまりに暗号めいている String#% メソッドよりも sprintfformat を使いましょう。

# 悪い例
'%d %d' % [20, 10]
# => '20 10'

# 良い例
sprintf('%d %d', 20, 10)
# => '20 10'

# 良い例
sprintf('%<first>d %<second>d', first: 20, second: 10)
# => '20 10'

format('%d %d', 20, 10)
# => '20 10'

# 良い例
format('%<first>d %<second>d', first: 20, second: 10)
# => '20 10'

単純に String#% の存在を知らなかったです。 (推奨されてないし、あえてこれから使おうとは思わないですが)

4. 名前付きフォーマット文字列を使用する場合、 %{name} よりも %<name>s を使いましょう。 %<name>s は値の型に関する情報をエンコードするためです。

# 悪い例
format('Hello, %{name}', name: 'John')

# 良い例
format('Hello, %<name>s', name: 'John')

どっちの記法も知りませんでした。

5. あまりに暗号めいている Array#* メソッドよりも Array#join を使いましょう。

# 悪い例
%w[one two three] * ', '
# => 'one, two, three'

# 良い例
%w[one two three].join(', ')
# => 'one, two, three'

Array#* を知りませんでした。(使わないけど)

6. size の代わりに count を用いてはいけません。 Array 以外の Enumerable オブジェクトでは、 count を使うと要素数の計算のためにコレクション全体を走査してしまいます。

# 悪い例
some_hash.count

# 良い例
some_hash.size

これも知りませんでした。

標準ライブラリはこのルールに従うかもですが、ActiveRecord とか外部ライブラリだとまたルールが異なってきそうなので、結局のところdocumentなりソースなりをちゃんと読むべきな気がしました。

7. 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

Struct.new にブロックを渡せることを、知りませんでした。

こういうふうに使えそうですね。

Person = Struct.new(:first_name, :last_name) do
  def full_name
    "#{first_name} #{last_name}"
  end
end

p = Person.new('Hoge', 'Fuga')

p.full_name
#=> "Hoge Fuga"

ただ、メソッドを用意する必要があるような場合は Classを使うような気もするので、使いどころが多いかは分からないです。

8. 例外は fail より raise を使いましょう。

# 悪い例
fail SomeException, 'message'

# 良い例
raise SomeException, 'message'

「自分が例外を射出するときは failrescue などで補足した例外を再射出するときは raise」のような使い分けがあった気がしましたが、今は全部 raise で良いようでした。

9. きちんとインデントされた複数行の文字列には、Ruby 2.3 の、インデントされた ヒアドキュメントを使いましょう。

# 悪い例 - Powerpack の String#strip_margin を使用しています。
code = <<-RUBY.strip_margin('|')
  |def test
  |  some_method
  |  other_method
  |end
RUBY

# こちらも悪い例
code = <<-RUBY
def test
  some_method
  other_method
end
RUBY

# 良い例
code = <<~RUBY
  def test
    some_method
    other_method
  end
RUBY

<<~ で書くヒアドキュメントを知りませんでした。

10. キャプチャした結果を使う必要のないときは、キャプチャしないグループを用いましょう。

# 悪い例
/(first|second)/

# 良い例
/(?:first|second)/

これも単純に知らなかったシリーズ


まだまだ知らないことが多く、たまに読み返すと学びがあって良いなと思いました(小並感)