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

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

関連記事


Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833

コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。
これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。
かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。
実は最近Go言語が好き。
仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ