Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rubyスタイルガイドを読む: クラスとモジュール(1)構造

こんにちは、hachi8833です。Rubyスタイルガイドを読むシリーズ、今回の「クラスとモジュール編」は2回に分けてお送りします。

クラスとモジュール(1)構造

5-01【統一】クラス定義は以下の構造で統一する

Use a consistent structure in your class definitions.

クラス内要素の記述順序を示しています。

class Person
  # extendとincludeは他の要素より先に書く
  extend SomeModule
  include AnotherModule

  # インナークラス定義は最初に書く
  CustomError = Class.new(StandardError)

  # 定数はその次に書く
  SOME_CONSTANT = 20

  # 属性マクロはその次に書く
  attr_reader :name

  # その他のマクロがあればここに書く
  validates :name

  # publicなクラスメソッドはその次にインライン形式で書く(class << selfでもよい: 後述)
  def self.some_method
  end

  # 初期化メソッドはクラスメソッドと他のインスタンスメソッドの間に書く
  def initialize
  end

  # publicなインスタンスメソッドはその後に書く
  def some_method
  end

  # protectedメソッドやprivateメソッドは末尾にまとめる
  protected

  def some_protected_method
  end

  private

  def some_private_method
  end
end

インナークラス定義は本スタイルガイド冒頭でもFooError = Class.new(StandardError)のようなスタイルが推奨されていますね。

また、「# publicなクラスメソッドはその次にインライン形式で書く」についてはclass << selfでの定義も認められます。このスタイルは次回分で登場します。

  # Also possible and convenient when you
  # have to define many class methods.
  class << self
    def first_method
      # body omitted
    end

    def second_method_etc
      # body omitted
    end
  end

5-02【統一】mixinが複数ある場合は別々に書く

Split multiple mixins into separate statements.

# 不可
class Person
  include Foo, Bar # 複数のmixinが1行で書かれている
end

# 良好
class Person
  include Foo      # mixinは1行ずつ分けて書く
  include Bar
end

mixinを1行ずつ書くことでGitの差分が見やすくなり、mixinの順序変更も行いやすいなどのメリットがあるという指摘をkazzさんからいただきました。

5-03【統一】1つのファイル内で、複数行の大きなクラスを別のクラス内で直接ネストしない

Don't nest multi-line classes within classes. Try to have such nested classes each in their own file in a folder named like the containing class.

そのような場合は、たとえば親のクラス名を持つフォルダを作成し、子のクラスごとに別ファイルを作ってその中に置くようにしてほしいとあります。常にそうできるとも限りませんが、ファイルの適切な分割を促進するためのスタイルだと思います。

# 不可

# 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

5-04【統一】クラスメソッドしか持たないクラスは、モジュールに書き換えるのが望ましい

「クラスはインスタンスを生成するために使う」のが適切であるという考え方ですね。

Prefer modules to classes with only class methods. Classes should be used only when it makes sense to create instances out of them.

# 不可
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

5-05【統一】extend selfmodule_functionに書き換えるのが望ましい

モジュールのインスタンスメソッドをクラスメソッドにする場合は例のmodule_functionが望ましいということですね。

Favor the use of module_function over extend self when you want to turn a module's instance methods into class methods.

# 不可
module Utilities
  extend self      # 推奨されない

  def parse_something(string)
    # 何かする
  end

  def other_utility_method(number, string)
    # 何か他のことをする
  end
end

# 良好
module Utilities
  module_function  # おすすめ

  def parse_something(string)
    # 何かする
  end

  def other_utility_method(number, string)
    # 何か他のことをする
  end
end

後半はクラス設計関連の記述が多いので次回にいたします。ご期待ください。

関連記事



CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。