Rubyのselfとmodule_functionの違いがよく分からないので色々試してみた

※この記事は https://kunosu.qrunch.io/entries/QmFLXo16Vx9DyWrL に移動しました。

## 経緯

『[オブジェクト指向設計実践ガイド](https://www.amazon.co.jp/dp/B01L8SEVYI/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』を読んで、
オブジェクトを生成するためのモジュール(=ファクトリー)を実際に書いてみました。
しかし、`モジュール名.メソッド名`の形で呼び出すにはメソッドを外部に公開する必要があり、
その方法が調べると2つありました。

1. メソッドの宣言時、メソッド名に`self`を追加する
2. `module_function :メソッド名`をモジュールに追加する

本では`self`をつけていたのでそちらで書きましたが、
上記2つの違いについては分からなかったのでコードを実行して調べてみました。

この記事で書いたソースコードは下記の [Gist](https://gist.github.com) で公開しています。
https://gist.github.com/kunosu/7d51967d1a79815aadf0f32dadb50d69

## 実験用のモジュール

以下のようなモジュールに対して、普通に呼び出す、`include`, `extend` したクラスに対してメソッドを呼び出してみます。
Rubyは ver 2.5です。

```ruby:Test_module.rb
module Test_module
	def normal_method
		# __method__ は実行中のメソッド名を文字列で返す
		puts "called #{__method__}"
	end

	def self.self_method
		puts "called #{__method__}"
	end

	def module_function_method
		puts "called #{__method__}"
	end
	module_function :module_function_method
end
```

## 試してみた結果

呼び出し方法                  | なし | self | module_function
-----------------------------|:----:|:----:|:---------------:
Test_module.メソッド名        | ×   | ○    | ○

```ruby:Test_module.rb
Test_module.normal_method
# => NoMethodError

Test_module.self_method
# => called self_method

Test_module.module_function_method
# => called module_function_method
```

### モジュールをクラスに `include` した場合

呼び出し方法                  | なし | self | module_function
-----------------------------|:----:|:----:|:---------------:
Test_class.メソッド名         | ×   | ×    | ×
obj.メソッド名                | ○   | ×    | ×
obj.メソッドを呼び出すメソッド  | ○   | ×    | ○

```ruby:Test_class_include.rb
require_relative "Test_module.rb"

class Test_class
	include Test_module

	def caller_normal_method
		normal_method
	end

	def caller_self_method
		self_method
	end

	def caller_module_function_method
		module_function_method
	end
end

Test_class.normal_method
# => NoMethodError

Test_class.self_method
# => NoMethodError

Test_class.module_function_method
# => NoMethodError

test_class = Test_class.new

test_class.normal_method
# => called normal_method

test_class.self_method
# => NoMethodError

test_class.module_function_method
# => NoMethodError

test_class.caller_normal_method
# => called normal_method

test_class.caller_self_method
# => NameError

test_class.caller_module_function_method
# => called module_function_method
```

### モジュールをクラスに `extend` した場合

呼び出し方法                  | なし | self | module_function
-----------------------------|:----:|:----:|:---------------:
Test_class.メソッド名         | ○   | ×    | ×
obj.メソッド名                | ×   | ×    | ×
obj.メソッドを呼び出すメソッド  | ×   | ×    | ×

```ruby:Test_class_extend.rb
require_relative "Test_module.rb"

class Test_class
	extend Test_module
	
	def caller_normal_method
		normal_method
	end

	def caller_self_method
		self_method
	end

	def caller_module_function_method
		module_function_method
	end
end

Test_class.normal_method
# => called normal_method

Test_class.self_method
# => NoMethodError

Test_class.module_function_method
# => NoMethodError

test_class = Test_class.new

test_class.normal_method
# => NoMethodError

test_class.self_method
# => NoMethodError

test_class.module_function_method
# => NoMethodError

test_class.caller_normal_method
# => NameError

test_class.caller_self_method
# => NoMethodError

test_class.caller_module_function_method
# => NoMethodError
```

## 試してみた結果からの `self` と `module_function` の使い分け

※試してみた結果から得たものであり、**こう使うのが正しいという訳ではありません。**

- モジュールだけで使う場合はどちらでもいい
	- 書くのが楽なので `self` を使う
	- ファクトリーなど
- `クラス名.メソッド名` の形で呼び出す場合は、メソッドに何も指定せず、`extend` して使う
	- 特異メソッドとして使う
- `obj.メソッド名` の形で呼び出す場合は、メソッドに何も指定しない
- `obj.メソッドを呼び出すメソッド` の形で呼び出す場合は、次のどちらかで `extend` して使う
	- メソッドに何も指定しない
	- `module_function` を使う

...結論としては、基本的には`self`を使えばいいのかな？