Skip to content

Latest commit

 

History

History
4541 lines (3604 loc) · 125 KB

README.ja.md

File metadata and controls

4541 lines (3604 loc) · 125 KB

はじめに

ロールモデルが重要なのだ。
-- アレックス・マーフィー巡査 / ロボコップ

Rubyディベロッパーとして、私は常にあることに悩まされてきました — Pythonにはプログラミングスタイルのすばらしい基準 (PEP-8) がある一方で、 Rubyにはコーディングスタイルやベストプラクティスに関する公式のガイドがこれまで存在してきませんでした。 私にはスタイルは重要なことだとしか思われないのにです。 Rubyが持っているような素晴らしいハッカーコミュニティは、 誰もが羨むようなドキュメントを作り出す力があるはずなのにです。

このガイドは、私達の社内製Rubyコーディング規約から生まれました (著者は)。 しかし仕事をするうちに、自分の仕事はRubyコミュニティの人たち全員に興味を持ってもらえるものではないかと思い始めました。 また、内製コーディング規約といったものをこの惑星はこれ以上必要としていないのではないかとの思いもありました。 そうではない、コミュニティ駆動の、コミュニティに認められた、 Rubyのための慣習、語法、スタイル規定は、 確実にRubyコミュニティに有益たりえると確信したのです。

このガイドを公開して以来、私は世界中の優れたRubyコミュニティのメンバーから、 たくさんのフィードバックを受けています。 全ての提案、サポートに感謝します! お互いに、また全てのRubyディベロッパーにとって有益なリソースを、 一緒に作ることができています。

また、もしあなたがRailsのことに興味があるなら、 こちらの補足も確認してみてください。 Ruby on Rails Style Guide.

The Ruby Style Guide

このRubyスタイルガイドでおすすめしているベストプラクティスは、実在のRubyプログラマが他の実在のRubyプログラマのために、メンテナンスしやすいコードを書いていくためのものです。 実社会での使われ方を反映したスタイルガイドは、実社会で使われるし、 たとえそれがどんなに素晴らしい理想であっても、 利用者が拒絶するようなスタイルに固執するスタイルガイドは結局全く使われなくなる危険性があります。

このガイドは、関連するルールごとにいくつかのセクションに分かれています。 ルールの後ろにその根拠も付け加えるように努めています (そのような根拠が省略されているときは、自明のものと判断したとお考えください)。

私はこれら全てのルールをどこからともなく考えついたわけではありません — これらのほとんどは、私の職業SEとしての長い経験と、 Rubyコミュニティのメンバーからの意見や提案、 また、"Programming Ruby"や、 "The Ruby Programming Language"のような、 様々な評価の高いRubyプログラミング関連資料に基づいています。

Rubyコミュニティ内でもスタイルについての統一見解が存在しないという領域もいくらか存在します (文字列リテラルの引用記号、ハッシュリテラルの内側のスペース、複数行のメソッドチェーンのドットの位置、などなど)。 そのようなシナリオでは、いずれの有力なスタイルも許容されるので、 どれを選んで、一貫して用いるかはあなた次第です。

新たな慣習が生まれたり、Ruby自身が変化することで慣習が時代遅れになったりしたことに従いながら、このガイドは時代とともに進化してきました。

多くのプロジェクトは、それ自身のコーディング規約を持っています (しばしばこのガイドを基に生成されています)。 ルールの衝突が発生した場合は、 そのプロジェクトにおいては、プロジェクト固有のガイドを優先してください。

このガイドのPDFやHTMLのコピーはPandocを使って生成できます。

RuboCopは、 このスタイルガイドに基づいたコード分析器です。

以下の言語の翻訳が利用可能です:

目次

レイアウト

ほとんどすべての人が、彼ら自身のものを除くすべてのスタイルが 醜くて、読むに耐えないと確信している。 「彼ら自身のものを除く」を除けば、おそらく正しいのだが… -- Jerry Coffin (インデントについて)

  • ソースファイルのエンコーディングにはUTF-8を用いましょう。 [link]

  • インデントには スペース 2つを用いましょう(別名ソフトタブ)。 ハードタブを用いてはいけません。 [link]

    # 悪い例 - 4つのスペース
    def some_method
        do_something
    end
    
    # 良い例
    def some_method
      do_something
    end
  • Unix-styleの改行にしましょう。 (*BSD/Solaris/Linux/macOS ユーザーはデフォルトで設定されています。 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
    class FooError < StandardError; end

    演算子について、いくつか例外があります。まずは、指数演算子です:

    # 悪い例
    e = M * c ** 2
    
    # 良い例
    e = M * c**2

    同様に、有理数のリテラル(rational literals)も例外です:

    # 悪い例
    o_scale = 1 / 48r
    
    # 良い例
    o_scale = 1/48r

    同様に、safe navigation operator(ぼっち演算子)も例外です:

    # 悪い例
    foo &. bar
    foo &.bar
    foo&. bar
    
    # 良い例
    foo&.bar
  • (, [の後ろ、], )の前にはスペースは入れません。 {の前後、}の前にはスペースが必要です。 [link]

    # 悪い例
    some( arg ).other
    [ 1, 2, 3 ].each{|e| puts e}
    
    # 良い例
    some(arg).other
    [1, 2, 3].each { |e| puts e }

    {} については多少の解説が必要でしょう。 ブロック、ハッシュリテラル、そして文字列埋め込み式にそれぞれ使われるからです。

    ハッシュリテラルでは、2つのスタイルが許容できます。 1つ目の書き方は、わずかながら少し読みやすいです(そして、Rubyコミュニティでより広く使われているのはこちらかもしれません)。 2つ目の書き方は、ブロックとハッシュを視覚的に差別化できるという点で有利です。 どちらでも片方を採用すれば、常に同じ方式を採用しましょう。

    # 良い例 - スペースを { の後と } の前に入れる
    { one: 1, two: 2 }
    
    # 良い例 - スペースを { の後と } の前に入れない
    {one: 1, two: 2}

    文字列埋め込み式では、中括弧の内側に空白を入れないでください。

    # 悪い例
    "From: #{ user.first_name }, #{ user.last_name }"
    
    # 良い例
    "From: #{user.first_name}, #{user.last_name}"
  • !の後にはスペースは入れません。 [link]

    # 悪い例
    ! something
    
    # 良い例
    !something
  • 範囲リテラルの内側にスペースは入れません。 [link]

    # 悪い例
    1 .. 3
    'a' ... 'z'
    
    # 良い例
    1..3
    'a'...'z'
  • whencaseと同じ深さに揃えましょう。 このスタイルは"The Ruby Programming Language"と"Programming Ruby"の双方で確立されたものです。 case及びswitchをインデントしないのは、 もともとこれらはブロックにならないという事実から来ています。 また、when及びelseキーワードはラベルです。 (C言語においては、これらはJMP命令のためのラベルにすぎません) [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]

    # 悪い例 - 空行が2つあります
    some_method
    
    
    some_method
    
    # 良い例
    some_method
    
    some_method
  • アクセス修飾子の前後には空行を用いましょう。 [link]

    # 悪い例
    class Foo
      attr_reader :foo
      def foo
        # do something...
      end
    end
    
    # 良い例
    class Foo
      attr_reader :foo
    
      def foo
        # do something...
      end
    end
  • メソッド、クラス、モジュール、ブロックの本文の前後には、空行を用いてはいけません。 [link]

    # 悪い例
    class Foo
    
      def foo
    
        begin
    
          do_something do
    
            something
    
          end
    
        rescue
    
          something
    
        end
    
      end
    
    end
    
    # 良い例
    class Foo
      def foo
        begin
          do_something do
            something
          end
        rescue
          something
        end
      end
    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
    
    # 悪い例 (インデントが倍)
    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 = %w[Spam Spam Spam Spam Spam Spam Spam Spam
      Baked beans Spam Spam Spam Spam Spam]
    
    # 良い例
    menu_item = %w[
      Spam Spam Spam Spam Spam Spam Spam Spam
      Baked beans Spam Spam Spam Spam Spam
    ]
    
    # 良い例
    menu_item =
      %w[Spam Spam Spam Spam Spam Spam Spam Spam
       Baked beans Spam Spam Spam Spam Spam]
  • 可読性のため、大きな数値にはアンダースコアをつけましょう。 [link]

    # 悪い例 - 0はいくつありますか?
    num = 1000000
    
    # 良い例 - 人の頭でもより簡単に解析できます
    num = 1_000_000
  • 数値リテラルのプレフィックスには、英小文字を使用しましょう。 8進数には0oを、16進数には0xを、2進数には0bを使用します。 10進数には0dを使用しません。 [link]

    # 悪い例
    num = 01234
    num = 0O1234
    num = 0X12AB
    num = 0B10101
    num = 0D1234
    num = 0d1234
    
    # good - プレフィックスと数字の分離が容易
    num = 0o1234
    num = 0x12AB
    num = 0b10101
    num = 1234
  • APIドキュメントを書くなら、YARDとその規約に従いましょう。 コメント行と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()
  • クラスメソッドを定義する目的で::を使ってはいけません。 [link]

    # 悪い例
    class Foo
      def self::some_method
      end
    end
    
    # 良い例
    class Foo
      def self.some_method
      end
    end
  • 引数があるとき、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
  • メソッド呼び出しの引数の周りに括弧を使用しましょう。 f((3 + 2) + 1)のようにメソッドの最初の引数が開き括弧で始まる場合は、 特に括弧を用いましょう。 [link]

    # 悪い例
    x = Math.sin y
    # 良い例
    x = Math.sin(y)
    
    # 悪い例
    array.delete e
    # 良い例
    array.delete(e)
    
    # 悪い例
    temperance = Person.new 'Temperance', 30
    # 良い例
    temperance = Person.new('Temperance', 30)

    以下の場合は常に括弧を省略します

    • 引数のないメソッド:

      # 悪い例
      Kernel.exit!()
      2.even?()
      fork()
      'test'.upcase()
      
      # 良い例
      Kernel.exit!
      2.even?
      fork
      'test'.upcase
    • 内部DSLに含まれるメソッド(例えばRake, Rails, RSpec):

      # 悪い例
      validates(:name, presence: true)
      # 良い例
      validates :name, presence: true
    • Rubyで「キーワード」と認識されているメソッド:

      class Person
        # 悪い例
        attr_reader(:name, :age)
        # 良い例
        attr_reader :name, :age
      
        # body omitted
      end

    以下の場合は括弧を省略することができます

    • Rubyで「キーワード」と認識されているが、宣言的ではないメソッド:

      # 良い例
      puts(temperance.age)
      system('ls')
      # こちらも良い例
      puts temperance.age
      system 'ls'
  • オプショナル引数は引数リストの最後に定義しましょう。 引数リストの先頭にオプショナル引数があるメソッドを呼んだ場合、 Rubyの挙動は予測不能です。 [link]

    # 悪い例
    def some_method(a = 1, b = 2, c, d)
      puts "#{a}, #{b}, #{c}, #{d}"
    end
    
    some_method('w', 'x') # => '1, 2, w, x'
    some_method('w', 'x', 'y') # => 'w, 2, x, y'
    some_method('w', 'x', 'y', 'z') # => 'w, x, y, z'
    
    # 良い例
    def some_method(c, d, a = 1, b = 2)
      puts "#{a}, #{b}, #{c}, #{d}"
    end
    
    some_method('w', 'x') # => '1, 2, w, x'
    some_method('w', 'x', 'y') # => 'y, 2, w, x'
    some_method('w', 'x', 'y', 'z') # => 'y, z, w, x'
  • メソッドにbooleanを渡す時にはキーワード引数を使いましょう。

    # 悪い例
    def some_method(bar = false)
      puts bar
    end
    
    # 悪い例 - キーワード引数が導入される以前によく見られたハックです
    def some_method(options = {})
      bar = options.fetch(:bar, false)
      puts bar
    end
    
    # 良い例
    def some_method(bar: false)
      puts bar
    end
    
    some_method            # => false
    some_method(bar: true) # => true
  • オプショナル引数のハッシュではなくキーワード引数を使いましょう。

    # 悪い例
    def some_method(options = {})
      bar = options.fetch(:bar, false)
      puts bar
    end
    
    # 良い例
    def some_method(bar: false)
      puts bar
    end
  • 変数を定義するために多重代入を使うのは避けましょう。 多重代入を使っていいのはメソッド戻り値を変数に代入する時、 splat演算子とともに使う時、 変数の値を相互に入れ替えたい時に限ります。 多重代入は代入をそれぞれ別に実施した場合と比べて可読性に劣ります。 [link]

    # 悪い例
    a, b, c, d = 'foo', 'bar', 'baz', 'foobar'
    
    # 良い例
    a = 'foo'
    b = 'bar'
    c = 'baz'
    d = 'foobar'
    
    # 良い例 - 変数の値の入れ替え
    # この用法は変数に入っている値を相互に入れ替えることができるので
    # 特例として認められます。
    a = 'foo'
    b = 'bar'
    
    a, b = b, a
    puts a # => 'bar'
    puts b # => 'foo'
    
    # 良い例 - メソッドの戻り値
    def multi_return
      [1, 2]
    end
    
    first, second = multi_return
    
    # 良い例 - splatとともに使う場合
    first, *list = [1, 2, 3, 4] # first => 1, list => [2, 3, 4]
    
    hello_array = *'Hello' # => ["Hello"]
    
    a = *(1..3) # => [1, 2, 3]
  • 多重代入においては不要なアンダースコア変数を後ろに並べないようにしましょう。 アンダースコア変数は名前が付いていたほうがコンテキストを明示できるので、 名前をつけておいたほうが良いでしょう。 アンダースコア変数は、その代入より左にスプラット変数が存在する場合には必要です。 その場合、スプラット変数はアンダースコア変数ではありません。 [link]

    # 悪い例
    foo = 'one,two,three,four,five'
    # 有用な情報を提供しない不要な代入です。
    first, second, _ = foo.split(',')
    first, _, _ = foo.split(',')
    first, *_ = foo.split(',')
    
    # 良い例
    foo = 'one,two,three,four,five'
    # このアンダースコア変数は、最後の要素を除いた全ての要素が必要で
    # あることを示すために必要です。
    *beginning, _ = foo.split(',')
    *beginning, something, _ = foo.split(',')
    
    a, = foo.split(',')
    a, b, = foo.split(',')
    # 未使用変数への代入は必須ではありませんが、この代入は有用な情報を
    # 提供します。
    first, _second = foo.split(',')
    first, _second, = foo.split(',')
    first, *_ending = foo.split(',')
  • forは、どうしても使わなければいけない明確な理由が明言できる人以外は、使ってはいけません。 多くの場合は代わりにイテレータを使うべきです。 foreachをつかって実装されています(だから、より遠回しです)が、 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
  • ifcaseが式で、値を返すという事実を活用しましょう。 [link]

    # 悪い例
    if condition
      result = x
    else
      result = y
    end
    
    # 良い例
    result =
      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]

    !!は値をbooleanに変換しますが、制御式の条件で明示的な変換は必要ありません。 あなたの意図を隠すだけです。 nilチェックをしたい場合、代わりにnil?を使用しましょう。

    # 悪い例
    x = 'test'
    # 難読なnil判定
    if !!x
      # body omitted
    end
    
    # 良い例
    x = 'test'
    if x
      # body omitted
    end
  • andorの使用は禁止です。可読性を良くするとしても、バグを埋め込む可能性が高いため使用に値しません。 boolean式では常に、代わりに&&||を使いましょう。 フロー制御ではifunlessを使いましょう。&&||も許容されますが、あまり明確ではありません。 [link]

    # 悪い例
    # boolean式
    ok = got_needed_arguments and arguments_are_valid
    
    # 制御構文
    document.save or raise("Failed to save document!")
    
    # 良い例
    # boolean式
    ok = got_needed_arguments && arguments_are_valid
    
    # 制御構文
    raise("Failed to save document!") unless document.save
    
    # ok
    # 制御構文
    document.save || raise("Failed to save document!")
  • 複数行にまたがる三項演算子?:は避けましょう; 代わりに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/while/until 修飾子をネストして利用しないようにしましょう。 可能であれば &&/|| を使いましょう。 [link]

    # 悪い例
    do_something if other_condition if some_condition
    
    # 良い例
    do_something if some_condition && other_condition
  • 否定形のときはifよりunlessを優先的に使いましょう。(もしくは||構文を使いましょう)。 [link]

    # 悪い例
    do_something if !some_condition
    
    # 悪い例
    do_something if not some_condition
    
    # 良い例
    do_something unless some_condition
    
    # もう1つの良い例
    some_condition || do_something
  • unlesselse付きで使ってはいけません。 肯定条件を先にして書き換えましょう。 [link]

    # 悪い例
    unless success?
      puts 'failure'
    else
      puts 'success'
    end
    
    # 良い例
    if success?
      puts 'success'
    else
      puts 'failure'
    end
  • 条件式の周囲を括弧で括らないようにしましょう。 [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/untilbegin/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
  • 暗黙のオプションハッシュの外側の括弧は省略しましょう。 [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
  • ブロック内で呼び出されるメソッドがただ1つである場合、簡略化されたproc呼び出しを用いましょう。 [link]

    # 悪い例
    names.map { |name| name.upcase }
    
    # 良い例
    names.map(&:upcase)
  • 1行のブロックではdo...endより{...}を使いましょう。 複数行のブロックでは{...}は避けましょう (複数行のメソッドチェーンは常に醜いです)。 制御構文(的な用法)やメソッド定義(的な用法)では常にdo...endを使いましょう (例えばRakefilesや特定のDSLなど) メソッドチェーンでのdo...endは避けましょう。 [link]

    names = %w[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(&:upcase)

    {...}を用いた複数行のメソッドチェーンをOKと主張する人もいるかもしれないが、 自問してみてほしい — そのコードは本当に読みやすいだろうか? また、そのブロックの中はメソッドに切り出すことはできないのか?

  • 単に他のブロックに引数を渡すだけのブロックリテラルを避けるため、 ブロック引数を明示することを検討しましょう。 ただしブロックがProcに変換されることでのパフォーマンスに気をつけましょう。 [link]

    require 'tempfile'
    
    # 悪い例
    def with_tmp_dir
      Dir.mktmpdir do |tmp_dir|
        Dir.chdir(tmp_dir) { |dir| yield dir }  # 引数を渡しているだけのブロック
      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は避けましょう (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
        # options と self.options はここでは等価
      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)
      # some code
    end
    
    # 良い例 (MRIはこれでも文句を言いますが、RuboCopでは問題ありません)
    if (v = array.grep(/foo/))
      do_something(v)
      # some code
    end
    
    # 良い例
    v = array.grep(/foo/)
    if v
      do_something(v)
      # some code
    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 = name ? name : 'Bozhidar'
    
    # 悪い例
    name = 'Bozhidar' unless name
    
    # 良い例 - 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等価演算子===の露骨な使用は避けましょう。 その名が示す通り、caseの条件判定で用いられており、 その外で用いられると混乱のもとになります。 [link]

    # 悪い例
    Array === something
    (1..100) === 7
    /something/ === some_string
    
    # 良い例
    something.is_a?(Array)
    (1..100).include?(7)
    some_string.match?(/something/)
  • ==で用が足りるならeql?は使わないようにしましょう。 eql?で実現されている、より厳密な等価性が必要になることは、実際には稀です。 [link]

    # 悪い例 - eql? は 文字列に対する == と同じです
    'ruby'.eql? some_str
    
    # good
    'ruby' == some_str
    1.0.eql? x # eql? はIntegerとFloatの1を識別したいのであれば意味があります
  • Perlスタイルの($:$;などのような)特別な変数の使用は避けましょう。 それらは極めて暗号的なので、ワンライナー以外での利用は推奨できません。 Englishライブラリから提供される人にやさしいエイリアスを用いましょう。 [link]

    # 悪い例
    $:.unshift File.dirname(__FILE__)
    
    # 良い例
    require 'English'
    $LOAD_PATH.unshift File.dirname(__FILE__)
  • メソッド名と開き括弧の間にスペースを入れてはいけません。 [link]

    # 悪い例
    f (3 + 2) + 1
    
    # 良い例
    f(3 + 2) + 1
  • Rubyインタープリタを走らせるときは、常に-wオプションを付けましょう。 これまでのルールのどれかを忘れてしまった時に警告を出してくれます! [link]

  • ネストしたメソッド定義は行ってはいけません - 代わりにラムダを用いましょう。 ネストしたメソッド定義は実際には外側のメソッドと同じスコープ(例えばclass)でメソッドを生成します。 そのうえ、そのようにネストしたメソッドは、そのメソッドを含んでいるメソッドが呼び出されるたびに再定義されるでしょう。 [link]

    # 悪い例
    def foo(x)
      def bar(y)
        # 本文略
      end
    
      bar(x)
    end
    
    # 良い例 - 前の例と同じですが、foo呼び出し時にのbar再定義がおこりません
    def bar(y)
      # 本文略
    end
    
    def foo(x)
      bar(x)
    end
    
    # こちらも良い例
    def foo(x)
      bar = ->(y) { ... }
      bar.call(x)
    end
  • 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
  • stabby lambdaを定義するときは、引数の周りの括弧は省略しないようにしましょう。 [link]

    # 悪い例
    l = ->x, y { something(x, y) }
    
    # 良い例
    l = ->(x, y) { something(x, y) }
  • stabby lambdaに引数がないときは、引数のための括弧は省略しましょう。 [link]

    # 悪い例
    l = ->() { something }
    
    # 良い例
    l = -> { something }
  • Proc.newよりprocを使いましょう。 [link]

    # 悪い例
    p = Proc.new { |n| puts n }
    
    # 良い例
    p = proc { |n| puts n }
  • lambdaや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)
      # some code
    end
    
    # 良い例
    result = hash.map { |_k, v| v + 1 }
    
    def something(x)
      _unused_var, used_var = something_else(x)
      # some code
    end
    
    # 良い例
    result = hash.map { |_, v| v + 1 }
    
    def something(x)
      _, used_var = something_else(x)
      # some code
    end
  • STDOUT/STDERR/STDINの代わりに$stdout/$stderr/$stdinを用いましょう。 STDOUT/STDERR/STDINは定数であり、 Rubyでの定数は、実際は再代入できます(つまりリダイレクトに使えます)が、 もし実行するとインタープリタからの警告が出ます。 [link]

  • $stderr.putsの代わりにwarnを用いましょう。 簡潔さや明快さもさることながら、 warnは必要であれば警告を抑制することができます (警告レベルを-W0を用いて0に設定することによって実現できます)。 [link]

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

    # 悪い例
    '%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'
  • 名前付きフォーマット文字列を使用する場合、%{name}よりも%<name>sを使いましょう。 %<name>sは値の型に関する情報をエンコードするためです。 [link]

    # 悪い例
    format('Hello, %{name}', name: 'John')
    
    # 良い例
    format('Hello, %<name>s', name: 'John')
  • あまりに暗号めいているArray#*メソッドよりもArray#joinを使いましょう。 [link]

    # 悪い例
    %w[one two three] * ', '
    # => 'one, two, three'
    
    # 良い例
    %w[one two three].join(', ')
    # => 'one, two, three'
  • 配列かどうかわからない変数を配列とみなして処理したいときは、 明示的にArrayかどうかチェックすることや[*var]よりも、Array()を使いましょう。 [link]

    # 悪い例
    paths = [paths] unless paths.is_a? Array
    paths.each { |path| do_something(path) }
    
    # 悪い例 (常に新しいArrayのインスタンスを生成します)
    [*paths].each { |path| do_something(path) }
    
    # 良い例 (そして少し読みやすいです)
    Array(paths).each { |path| do_something(path) }
  • ロジックを使って複雑な比較を行うよりも、 可能な限りRangeComparable#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
  • boolean値を扱わない限り、明示的なnilでないかの検査は避けましょう。 [link]

    # 悪い例
    do_something if !something.nil?
    do_something if something != nil
    
    # 良い例
    do_something if something
    
    # 良い例 - boolean値を扱うとき
    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[:foo])
        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よりmapdetectよりfindfind_allよりselect injectよりreducelengthよりsizeを使いましょう。 これは絶対のルールではないです。 別名のほうが可読性に優れているなら、 そちらを使っていただいて構いません。 韻を踏んでいるほうのメソッド名はSmalltalkから引き継いできたもので、 他のプログラミング言語でそこまで一般的ではないです。 find_allよりもselectが推奨されるのは、 rejectとの相性がよいことと、 メソッド名から挙動を推察することも容易だからです。 [link]

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

    # 悪い例
    some_hash.count
    
    # 良い例
    some_hash.size
  • mapflattenの組み合わせの代わりに、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を用いましょう。 何故なら、Enumerableをincludeしているクラスの側で、 より効率のよい実装が行われていることがあるからです。 最悪、クラスが特殊化を行っていない場合でも、Enumerableから継承される一般的な実装は、 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
      # some code
    end
    
    def SomeMethod
      # some code
    end
    
    # 良い例
    :some_symbol
    
    some_var = 5
    
    def some_method
      # some code
    end
  • シンボル、メソッド、および変数名において、文字と数字を分離しないようにしましょう。 [link]

    # 悪い例
    :some_sym_1
    
    some_var_1 = 1
    
    var_10  = 10
    
    def some_method_1
      # some code
    end
    
    # 良い例
    :some_sym1
    
    some_var1 = 1
    
    var10    = 10
    
    def some_method1
      # some code
    end
  • クラスやモジュールにはCamelCaseを用いましょう。(HTTP、RFC、XMLのような頭字語は大文字を保ちましょう)。 [link]

    # 悪い例
    class Someclass
      # some code
    end
    
    class Some_Class
      # some code
    end
    
    class SomeXml
      # some code
    end
    
    class XmlSomething
      # some code
    end
    
    # 良い例
    class SomeClass
      # some code
    end
    
    class SomeXML
      # some code
    end
    
    class XMLSomething
      # some code
    end
  • ファイル名にはsnake_caseを用いましょう。例えばhello_world.rbのように。 [link]

  • ディレクトリ名にはsnake_caseを用いましょう。例えばlib/hello_world/hello_world.rbのように。 [link]

  • ソースファイル1つにつきただ1つのクラス/モジュールだけが書かれている状態を目指しましょう。 そのファイルの名前はそのクラス/モジュールと同じ名前で、ただしキャメルケースをスネークケースに変換して用いましょう。 [link]

  • 他の定数はSCREAMING_SNAKE_CASEを用いましょう。 [link]

    # 悪い例
    SomeConst = 5
    
    # 良い例
    SOME_CONST = 5
  • 述語メソッド(boolean値が返るメソッド)は疑問符で終わりましょう。 (すなわちArray#empty?のように)。 boolean値を返さないメソッドは、疑問符で終わるべきではないです。 [link]

  • 述語メソッドに is doescanのような助動詞をつけるべきではありません。 これらの単語は冗長で、Rubyコアライブラリの述語メソッドのスタイル ( empty?include?など)と矛盾しています。 [link]

    # 悪い例
    class Person
      def is_tall?
        true
      end
    
      def can_play_basketball?
        false
      end
    
      def does_like_candy?
        true
      end
    end
    
    # 良い例
    class Person
      def tall?
        true
      end
    
      def basketball_player?
        false
      end
    
      def likes_candy?
        true
      end
    end
  • 危険 な可能性のあるメソッド (引数や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
  • 二項演算子や演算子風のメソッドを定義するときは、 演算子の「対称性」を明確にするために引数名はotherを用いましょう。 ここでいう対称性とは、演算子の両辺が典型的には同じ、 またはcoerce可能な型であるという意味です。 [link]

    • 対称性のある演算子や演算子風のメソッド(引数名をotherとすべきもの): +, -, *, /, %, **, ==, >, <, |, &, ^, eql?, equal?;
    • 対称性のない演算子(引数名をotherとすべきではない): <<, [] (コレクションとその要素の関係にある演算子), === (パターンやマッチの関係性);

    このルールは演算子の両辺が同じセマンティクスを持っている場合 のみ に用いることに注意しましょう。 典型的な例外としては、Ruby本体のArray#*(int)が挙げられます。

    # 良い例
    def +(other)
     # body omitted
    end
    
    # 悪い例
    def <<(other)
     @internal << other
    end
    
    # 良い例
    def <<(item)
     @internal << item
    end
    
    # 悪い例
    # Returns some string multiplied `other` times
    def *(other)
     # body omitted
    end
    
    # 良い例
    # Returns some string multiplied `num` times
    def *(num)
     # body omitted
    end

コメント

良く書けたコードは、それ自身が最良のドキュメントでもある。 コメントを書こうとしている時は、常に自問してほしい、 "このコメントが不要になるようにコードを改善できるだろうか?" コードを改善した上で、ドキュメントでさらに明快にするのだ。 -- Steve McConnell

  • 自己説明的なコードを書いて、このセクションの残りのパートは無視しましょう。本当に! [link]

  • コメントは英語で書きましょう。 [link]

  • 最初の#とコメントの間にスペースを1つ入れましょう。 [link]

  • 1語より長いコメントは頭語を大文字化してピリオドを打ちましょう。 文と文の間にはスペースを一つだけ入れましょう。 [link]

  • 過剰なコメントは避けましょう。 [link]

    # 悪い例
    counter += 1 # カウンターをインクリメント
  • コメントは最新に保ちましょう。 古くなったコメントは、コメントがないより悪いです。 [link]

良いコードは良いジョークのようだ - なんの説明もいらない。
— プログラマの格言 Russ Olsen

  • 悪いコードを説明するコメントは避けましょう。 自己説明的なコードへのリファクタリングを行いましょう (「やるかやらないか — "やってみる"はなしだ。」 Yoda)。 [link]

注釈

  • 注釈は、通常関連するコードのすぐ上に書きましょう。 [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]

マジックコメント

  • マジックコメントは、全てのコメントとコードよりも上に置きましょう(Shebangは例外で、それに関しては次の項目を参照のこと)。 [link]

    # 悪い例
    # Some documentation about Person
    
    # frozen_string_literal: true
    class Person
    end
    
    # 良い例
    # frozen_string_literal: true
    
    # Some documentation about Person
    class Person
    end
  • ファイルにShebangが存在する場合は、マジックコメントはその下に置きましょう。 [link]

    # 悪い例
    # frozen_string_literal: true
    #!/usr/bin/env ruby
    
    App.parse(ARGV)
    
    # 良い例
    #!/usr/bin/env ruby
    # frozen_string_literal: true
    
    App.parse(ARGV)
  • マジックコメントが複数必要な場合、一つのマジックコメントは一つの行に置きましょう。 [link]

    # 悪い例
    # -*- frozen_string_literal: true; encoding: ascii-8bit -*-
    
    # 良い例
    # frozen_string_literal: true
    # encoding: ascii-8bit
  • マジックコメントは、コードやドキュメントから空行で区切りましょう。 [link]

    # 悪い例
    # frozen_string_literal: true
    # Some documentation for Person
    class Person
      # Some code
    end
    
    # 良い例
    # frozen_string_literal: true
    
    # Some documentation for Person
    class Person
      # Some code
    end

クラスとモジュール

  • クラス定義の構造には一貫性をもたせましょう。 [link]

    class Person
      # extendとincludeを最初に書きます。
      extend SomeModule
      include AnotherModule
    
      # 内部クラス
      CustomError = Class.new(StandardError)
    
      # 次に定数
      SOME_CONSTANT = 20
    
      # 次にattribute系マクロ
      attr_reader :name
    
      # (あれば) それ以外のマクロ
      validates :name
    
      # publicクラスメソッドが続きます
      def self.some_method
      end
    
      # initializationはクラスメソッドと他のpublicメソッドの間に
      def initialize
      end
    
      # 他のpublicメソッドが続きます
      def some_method
      end
    
      # protectedとprivateのメソッドは最後のあたりにグループ化します
      protected
    
      def some_protected_method
      end
    
      private
    
      def some_private_method
      end
    end
  • 複数のミックスインは、別々の行に分割しましょう。 [link]

    # 悪い例
    class Person
      include Foo, Bar
    end
    
    # 良い例
    class Person
      # 複数のミックスインは分割された文にします
      include Foo
      include Bar
    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
  • 名前空間の中にクラスやモジュールを定義したり再定義したりする場合、 その名前空間を明示的にネストして記述しましょう。 Rubyのレキシカルスコープ は定義された場所のモジュールのネスティングに依存しているため、 名前解決演算子を用いてしまうと、定数参照が意図しない振る舞いをすることがあります。 [link]

    module Utilities
      class Queue
      end
    end
    
    # 悪い例
    class Utilities::Store
      Module.nesting # => [Utilities::Store]
    
      def initialize
        # nestingにUtilitiesを含まないため、
        # この参照はトップレベルの ::Queueを参照します。
        @queue = Queue.new
      end
    end
    
    # 良い例
    module Utilities
      class WaitingList
        Module.nesting # => [Utilities::WaitingList, Utilities]
    
        def initialize
          @queue = Queue.new # Utilities::Queue を参照します
        end
      end
    end
  • クラスメソッドしかないクラスよりモジュールを使いましょう。 クラスはインスタンスを生成することに意味がある時にのみ使われるべきです。 [link]

    # 悪い例
    class SomeClass
      def self.some_method
        # body omitted
      end
    
      def self.some_other_method
        # body omitted
      end
    end
    
    # 良い例
    module SomeModule
      module_function
    
      def some_method
        # body omitted
      end
    
      def some_other_method
        # body omitted
      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
  • クラス階層の設計を行うときは、 リスコフの置換原則. に従いましょう。 [link]

  • あなたのクラスを可能な限り SOLID に保ちましょう。 [link]

  • ドメインオブジェクトのクラスにおいては常に適切な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
  • アクセサやミューテータの場合、メソッド名の前にget_set_をつけないようにしましょう。 アクセサ(リーダ)にはアトリビュートの名前を、ミューテータ(ライタ)にはattr_name= を使用するのはRubyの規約です。 [link]

    # 悪い例
    class Person
      def get_name
        "#{@first_name} #{@last_name}"
      end
    
      def set_name(name)
        @first_name, @last_name = name.split(' ')
      end
    end
    
    # 良い例
    class Person
      def name
        "#{@first_name} #{@last_name}"
      end
    
      def name=(name)
        @first_name, @last_name = name.split(' ')
      end
    end
  • attrの使用は避けましょう。代わりにattr_readerattr_accessorを使いましょう。 [link]

    # 悪い例 - 1つのアクセサしか作れません(Ruby 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
  • 継承よりダック・タイピングを使いましょう。 [link]

    # 悪い例
    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つのクラス変数を共有してしまいます。 クラス変数よりもクラスのインスタンス変数のほうを使うべきです。

  • 意図した使い方に沿って、可視性(privateprotected)を設定しましょう。 全てをpublic(デフォルトの設定)のままにしないようにしましょう。 結局私達は今 Ruby を書いているのだから。 Python ではなく。 [link]

  • publicprotectedprivateは、適用するメソッド定義と同じインデントにしましょう。 そして、以降のすべてのメソッド定義に適用されることを強調するために、 それらの修飾子の前1行と後1行に空行を入れましょう。 [link]

    class SomeClass
      def public_method
        # some code
      end
    
      private
    
      def private_method
        # some code
      end
    
      def another_private_method
        # some code
      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
  • メソッドの別名をつける時はaliasを使いましょう。 クラスのレキシカルスコープの中ではselfと同じように名前解決されます。 またユーザーにとっても、実行時やサブクラス側で明示的にエイリアスを変更しなければ、 変更されないことが読み取りやすいです。 [link]

    class Westerner
      def first_name
        @names.first
      end
    
      alias given_name first_name
    end

    aliasdefと同じく予約語なので、シンボルや文字列よりも名前そのものを使いましょう。 言い換えると、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
  • クラス(またはモジュール)メソッドが他のメソッドを呼び出す際は、 selfまたは自分自身のクラス名の後に.を続けて使用しないようにしましょう。 これは、「サービスクラス」やそれと類似の、クラスがあたかも関数であるかのように 扱われるコンセプトの場合でよく見られます。 この規則は、そのようなクラスで反復的なボイラープレートを減らす傾向があります。 [link]

    class TestClass
      # 悪い例 -- クラスのリネームやメソッドの移動の際に余分な手間がかかります
      def self.call(param1, param2)
        TestClass.new(param1).call(param2)
      end
    
      # 悪い例 -- 必要以上に冗長です
      def self.call(param1, param2)
        self.new(param1).call(param2)
      end
    
      # 良い例
      def self.call(param1, param2)
        new(param1).call(param2)
      end
    
      # ...other methods...
    end

例外

  • 例外はfailよりraiseを使いましょう。 [link]

    # 悪い例
    fail SomeException, 'message'
    
    # 良い例
    raise SomeException, 'message'
  • 2引数のraiseでは、RuntimeErrorを明示しないようにしましょう。 [link]

    # 悪い例
    raise RuntimeError, 'message'
    
    # 良い例 - デフォルトでRuntimeErrorが発生します
    raise 'message'
  • raiseの引数としては例外クラスのインスタンスよりも、 例外クラスとメッセージをそれぞれの引数で渡す方を使いましょう。 [link]

    # 悪い例
    raise SomeException.new('message')
    # `raise SomeException.new('message'), backtrace`とする書き方が存在しないことに注意しましょう。
    
    # 良い例
    raise SomeException, 'message'
    # `raise SomeException, 'message', backtrace`の用法と一貫性があります
  • ensureブロックからreturnしてはいけません。 もしensureの中から明示的に値を返した場合は、 returnはどの例外発生よりも優先されて、 例外など発生していなかったかのように値を返してしまいます。 事実上、例外は静かに捨てられます。 [link]

    # 悪い例
    def foo
      raise
    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
  • Exceptionrescueするのは避けましょう。 これは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 StandardError => e
      # エラー処理
    rescue IOError => e
      # 決して到達しないエラー処理
    end
    
    # 良い例
    begin
      # 処理
    rescue IOError => e
      # エラー処理
    rescue StandardError => 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 = []
    arr = Array.new(10)
    hash = {}
    hash = Hash.new(0)
  • 単語(空でなく、スペースを含まない文字列)の配列を生成する時は %wリテラルを使いましょう。 このルールは配列の要素が2つ以上の場合に限ります。 [link]

    # 悪い例
    STATES = ['draft', 'open', 'closed']
    
    # 良い例
    STATES = %w[draft open closed]
  • シンボルの配列が必要な時 (かつRuby 1.9との互換性を維持しなくていい時)は %iリテラルを使いましょう。 このルールは配列の要素が2つ以上の場合に限ります。 [link]

    # 悪い例
    STATES = [:draft, :open, :closed]
    
    # 良い例
    STATES = %i[draft open closed]
  • ArrayHashリテラルの最後の要素の後ろの,は避けましょう。 複数行にわかれていない時は特に避けましょう。 [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]よりfirstlastを使いましょう。 [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?を用いましょう。 [link]

    # 悪い例
    hash.has_key?(:test)
    hash.has_value?(value)
    
    # 良い例
    hash.key?(:test)
    hash.value?(value)
  • Hash#keys.each の代わりに Hash#each_key を、 Hsah#values.each の代わりに Hash#each_value を用いましょう。 [link]

    # 悪い例
    hash.keys.each { |k| p k }
    hash.values.each { |v| p v }
    hash.each { |k, _v| p k }
    hash.each { |_k, v| p v }
    
    # 良い例
    hash.each_key { |k| p k }
    hash.each_value { |v| p v }
  • 存在すべきキーを扱う時は、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 }
    
    # 悪い例 - たんに||演算子を使ってしまうと偽値が入っていた時に望まない結果になります
    batman[:is_evil] || true # => true
    
    # 良い例 - fetchなら偽値でも正しく動きます
    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

数値

  • 整数型の型をチェックする為に、Integerを使用して下さい。 Fixnumはプラットフォームに依存するため、32ビットマシンと64ビットマシンで異なる結果が返されます。 [link]

    timestamp = Time.now.to_i
    
    # 悪い例
    timestamp.is_a? Fixnum
    timestamp.is_a? Bignum
    
    # 良い例
    timestamp.is_a? Integer
  • 乱数を生成する場合は、整数とオフセットの代わりに範囲リテラルを使用しましょう。 意図が明確であるためです。サイコロの役割をシミュレートすることを想像してください: [link]

    # 悪い例
    rand(6) + 1
    
    # 良い例
    rand(1..6)

文字列

  • 文字列連結の代わりに文字列挿入や文字列整形を使いましょう。 [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)
  • 文字列リテラルの引用符は一貫したスタイルで使いましょう。 Rubyコミュニティでは、 デフォルトでシングルクォートを用いるもの (Option A)、 ダブルクォートを用いるもの (Option B) の二つのよく使われるスタイルがあって、 どちらも良いと考えられています。 [link]

    • (Option A) 文字列挿入の必要がないときや、\t\n`’`等の特別な文字がない場合は、 シングルクォーテーションを使いましょう。

      # 悪い例
      name = "Bozhidar"
      
      name = 'De\'Andre'
      
      # 良い例
      name = 'Bozhidar'
      
      name = "De'Andre"
    • (Option B) 文字列中に"を含んでいたり、エスケープ文字を抑えたいときでない限り、 ダブルクォーテーションを使いましょう。

      # 悪い例
      name = 'Bozhidar'
      
      sarcasm = "I \"like\" it."
      
      # 良い例
      name = "Bozhidar"
      
      sarcasm = 'I "like" it.'

    このガイド内の文字列リテラル表記は、 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#+よりも常に速いです。 [link]

    # 悪い例
    html = ''
    html += '<h1>Page title</h1>'
    
    paragraphs.each do |paragraph|
      html += "<p>#{paragraph}</p>"
    end
    
    # 良く、そして速い例
    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://')
    str.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"
  • きちんとインデントされた複数行の文字列には、Ruby 2.3 の、インデントされた ヒアドキュメントを使いましょう。 [link]

    # 悪い例 - 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
  • ヒアドキュメントのデリミタは説明的な名前にしましょう。 デリミタはヒアドキュメントの内容に関して追加の情報になりますし、 エディタによっては適切なデリミタを使うことでヒアドキュメント内のコードをハイライトしてくれるかもしれません。 [link]

    # 悪い例
    code = <<~END
      def foo
        bar
      end
    END
    
    # 良い例
    code = <<~RUBY
      def foo
        bar
      end
    RUBY
    
    # 良い例
    code = <<~SUMMARY
      著名なSF作家アーサー C. クラークの短編を独創的に解釈したこの作品では、
      巨大な黒色の構造物が過去、そして未来とのつながりを指し示す。
    SUMMARY

日時

  • 現在のシステム時間を読み出すには、Time.newよりもTime.nowを使いましょう。 [link]

  • 改暦を考慮する必要がある場合を除いて、DateTimeを使用しないようにしましょう。 もし必要な場合は、start引数を明示的に指定して意図を明示して下さい。 [link]

    # 悪い例 - DateTimeを現在の時刻の為に使用
    DateTime.now
    
    # 良い例 - Timeを現在の時刻の為に使用
    Time.now
    
    # 悪い例 - DateTimeを現代の日の為に使用
    DateTime.iso8601('2016-06-29')
    
    # 良い例 - Dateを現代の日の為に使用
    Date.iso8601('2016-06-29')
    
    # 良い例 - DateTimeを`start`と共に過去の日付の為に使用
    DateTime.iso8601('1751-04-23', Date::ENGLAND)

正規表現

なにか問題に突き当たった時、「わかった、正規表現を使えばいいんだ」と思う人がいますね。 その時、元の問題のほかにもう一つ問題が加わっているんです。
-- Jamie Zawinski

  • 単に文字列中から文字列を探すだけの時は、 正規表現を使ってはいけません: string['text']を使いましょう。 [link]

  • 文字列の添字に直接正規表現を渡すことで、文字列の構築をシンプルにできます。 [link]

    match = string[/regexp/]             # マッチした内容が得られる
    first_group = string[/text(grp)/, 1] # キャプチャグループの内容が得られる
    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
    # some code
    process Regexp.last_match(1)
    
    # 良い例
    /(?<meaningful_var>regexp)/ =~ string
    # some code
    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]

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

パーセントリテラル

  • 文字列挿入と"文字の双方が入る1行の文字列には、 %()(%Q()の短縮形)を使いましょう。 複数行の時はヒアドキュメントを使いましょう。 [link]

    # 悪い例 (挿入の必要がありません)
    %(<div class="text">Some text</div>)
    # '<div class="text">Some text</div>' であるべき
    
    # 悪い例 (ダブルクォートがありません)
    %(This is #{quality} style)
    # "This is #{quality} style" であるべき
    
    # 悪い例 (複数行です)
    %(<div>\n<span class="big">#{exclamation}</span>\n</div>)
    # ヒアドキュメントであるべき
    
    # 良い例 (挿入が必要、ダブルクォートがある、そして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]

  • さまざまな種類のパーセントリテラルに最も適した括弧を使用します。 [link]

    • 文字列リテラル(%q, %Q)には()を使用しましょう。
    • 配列リテラル(%w, %i, %W, %I)には、標準の配列リテラルに 合わせて[]を使用しましょう。
    • 正規表現リテラル(%r)には、{}を使用しましょう。 正規表現の中に括弧が現れることが多いためです。 {が最も一般的でない為、%rの区切り文字には最適です。
    • その他のリテラル(例えば %s, %x)には()を使用しましょう。
    # 悪い例
    %q{"Test's king!", John said.}
    
    # 良い例
    %q("Test's king!", John said.)
    
    # 悪い例
    %w(one two three)
    %i(one two three)
    
    # 良い例
    %w[one two three]
    %i[one two three]
    
    # 悪い例
    %r((\w+)-(\d+))
    %r{\w{1,2}\d{2,5}}
    
    # 良い例
    %r{(\w+)-(\d+)}
    %r|\w{1,2}\d{2,5}|

メタプログラミング

  • 不要なメタプログラミングは避けましょう。 [link]

  • ライブラリを作成する時にコアクラスを汚染するのはやめましょう。 (モンキーパッチを当ててはいけません)。 [link]

  • ブロック渡しのclass_evalのほうが、文字列挿入型よりも好ましいです。 [link]

    class_eval 'def use_relative_model_naming?; true; end', __FILE__, __LINE__
    • 文字列挿入型を使う時は、バックトレースが働くように、常に__FILE____LINE__を渡しましょう:

      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]

    # OrganizationというActiveModelがあって、Activatableをincludeしている
    module Activatable
      extend ActiveSupport::Concern
    
      included do
        before_create :create_token
      end
    
      private
    
      def reset_token
        # some code
      end
    
      def create_token
        # some code
      end
    
      def activate!
        # some code
      end
    end
    
    class Organization < ActiveRecord::Base
      include Activatable
    end
    
    linux_organization = Organization.find(...)
    # 悪い例 - 可視性を無視している
    linux_organization.send(:reset_token)
    # 良い例 - 例外があがる
    linux_organization.public_send(:reset_token)
  • sendは他の既存のメソッドと衝突するかもしれないので、__send__を使いましょう。 [link]

    require 'socket'
    
    u1 = UDPSocket.new
    u1.bind('127.0.0.1', 4913)
    u2 = UDPSocket.new
    u2.connect('127.0.0.1', 4913)
    # レシーバーオブジェクトにメッセージが送信されない
    # かわりに、UDPソケット経由でメッセージが送信されてしまう
    u2.send :sleep, 0
    # こちらならたしかにレシーバーオブジェクトにメッセージが送信される
    u2.__send__ ...

雑則

  • ruby -wで実行しても何も警告されないコードを書きましょう。 [link]

  • オプショナルな変数としてのハッシュの使用を避けましょう。そのメソッドはあまりにたくさんのことをやろうとしていませんか?(オブジェクトの初期化はこのルールの例外です) [link]

  • コードのある行が10行を超えるメソッドは避けましょう。 理想を言えば、多くのメソッドは5行以内がよいです。 空行は行数には含めません。 [link]

  • 3つや4つ以上引数を設定するのは避けましょう。 [link]

  • もし本当にグローバルなメソッドが必要な場合は、 Kernelに定義し、privateに設定しましょう。 [link]

  • グローバル変数の代わりに、モジュールのインスタンス変数を使用しましょう。 [link]

    # 悪い例
    $foo_bar = 1
    
    # 良い例
    module Foo
      class << self
        attr_accessor :bar
      end
    end
    
    Foo.bar = 1
  • 複雑なコマンドラインオプションをパースするためにOptionParserを使いましょう。 また、些細なオプションにはruby -sを使いましょう。 [link]

  • 破壊的変更をしなくても済むなら、できるだけ関数的プログラミング手法を使いましょう。 [link]

    a = []; [1, 2, 3].each { |i| a << i * 2 }   # 悪い例
    a = [1, 2, 3].map { |i| i * 2 }             # 良い例
    
    a = {}; [1, 2, 3].each { |i| a[i] = i * 17 }                # 悪い例
    a = [1, 2, 3].reduce({}) { |h, i| h[i] = i * 17; h }        # 良い例
    a = [1, 2, 3].each_with_object({}) { |i, h| h[i] = i * 17 } # 良い例
  • それがメソッドの目的でない限り、引数に破壊的変更をするのはやめましょう。 [link]

  • 3段階を超えるブロックのネストは避けましょう。 [link]

  • 一貫性を保ちましょう。理想を言えば、このガイドラインに沿いましょう。 [link]

  • 常識を用いましょう。 [link]

ツール

ここでは、このガイドに反するコードを自動的にチェックするのを支援するツールをいくつか紹介します。

RuboCop

RuboCopは、このガイドに基づいた Rubyコードスタイルチェッカーです。 RuboCopはすでにこのガイドの重要な部分をカバーしており、 MRI 1.9、MRI 2.0 双方をサポートし、Emacs向けのよいプラグインがあります。

RubyMine

RubyMine のコードインスペクションは、このガイドに 部分的に基づいています

Contributing

このガイドはまだ未完成です — いくつかのルールは例がなく、 いくつかのルールの例はじゅうぶんにクリアにルールを説明できていません。 そのようなルールの改善はRubyコミュニティを助ける素晴らしい(そしてシンプルな)手段です!

これらの課題はやがて解決されると思いたいです — ただ現状にご留意ください。

このガイドに書いてあることには変更不能なものはありません。 Rubyのコードスタイルに興味のある全ての人と共に取り組むことで、 究極的には、全てのRubyコミュニティにとって有益なリソースを作ることができればと思っています。

改善のために、遠慮せずチケットを立てたりプルリクエストを送ったりしてください。 あなたの手助けに予め感謝します!

また、このプロジェクト(とRuboCop)への金銭的な貢献は、 Patreon経由で行うことができます。

貢献するには

簡単です! contribution guidelinesを読んでください!

ライセンス

Creative Commons License この著作物は、Creative Commons Attribution 3.0 Unported License に従います。

広めましょう

コミュニティ駆動のスタイルガイドは、これを知らないコミュニティにはほとんど役に立ちません。 このガイドについてつぶやいたり、友達や同僚にシェアしてください。 全てのコメント、提案、オプションがこのガイドを少しだけでも良くしていきます。 そして、考えうるベストのガイドが欲しいですよね?

ありがとう
Bozhidar