Rubyと筋肉とギターとわたし

エンジニア二年目の雑魚です。プログラミング・ギター・筋トレのことをメインにブログを書いていきます。

module完全に理解した

最近はRailsで業務アプリを開発しています。

どうもてぃです。

やっぱ、久々にやると色んな所で詰まりますね。

moduleで詰まって解決?したので、一旦まとめます。

環境

なにをしようとしたか

タスクで同じメソッドが合ったのでnamespaceが汚染されていました。

なので、処理部分をmoduleにして切り分けて呼びだそうとしたところ、今回のエラーに見まわれ2時間ほど溶かしてしまいました。

切り分けたmoduleは./lib/ext/配下に作成しました。 タスクのファイルでrequireする感じですね。

今回作ったmodule

こんな感じ。

タスクの方でincludeだけはしたくなかったので、moduleの特異メソッドとして作成しました。

module A
  def self.yeah
    puts 'yeah'
    ok
  end

  private

  def ok
    puts 'ok'
  end
end

なんら変哲のないmoduleです。

module内のメソッドだから、特異メソッドとして呼び出さないメソッド以外selfはつけてなかった。

こんな感じのmoduleをタスクの方で読み込んで、 A.year とすると

A.yeah

year
NameError: undefined local variable or method `ok' for A:Module

\(^o^)/

原因を探ってみた

moduleの特徴を改めて復習してみた。

  • インスタンスを生成できない
  • あるクラスのインスタンスメソッドとして取り込む
  • あるオブジェクトのメソッドとして取り込む
  • モジュール関数として使う
  • 名前空間を提供する
  • 定数やメソッドをまとめる etc...

いろんな記事を渡り歩いてリファレンスやrubydocも見てみたんですが、module内に複数メソッドを書いてる例がほとんどない。

なのでいろいろ検証してみました。

その1 クラスでネストしてみる

module A
  class B
    def self.yeah
      puts 'yeah'
      ok
    end

    private

    def ok
      puts 'ok'
    end
  end
end

A::B.yeah
yeah
NameError: undefined local variable or method `ok' for A::B:Class

はい、だめ。

その2 オブジェクトを生成してみる

module A
  class B
    def yeah
      puts 'yeah'
      ok
    end

    private

    def ok
      puts 'ok'
    end
  end
end

object = A::B.new
object.yeah

yeah
ok

うーん、いける。

そらそうか、普通だわ。

その3 全て特異メソッドにしてしまう

module A
  class << self
    def yeah
      puts 'yeah'
      ok
    end

    private

    def ok
      puts 'ok'
    end
  end
end

A.yeah
yeah
ok

お、いけた。

完全に理解した

とはいってないですが、なんとなくわかりました。

classでメソッドを定義した場合、インスタンスメソッドだから同じクラス内の別のメソッドからも呼び出せる。

けど、moduleの場合そもそも定義されたmethodはインスタンスメソッドじゃないです(一般的にmoduleメソッドとよばれる)。

そのため、

同じmodule内といえども、特異メソッドにしてないと呼び出すことが出来ない

ということですね。

完全に理解した。

最後に

もっとRubyを愛したいと思います。

間違ってたらコメントください。