はじめに
調べ物をしている際に、using Module.new {}
というコードを見たのでどういう処理をするんだろうと思い調べてみた備忘録です。
そもそも無名モジュールってなに?
無名モジュールは、その名の通り名前のついていないモジュールのことです。Module.new
で作成したモジュールは無名モジュールとなるらしいです。
もちろん無名なので、includeなどで指定することが出来ませんので他のファイルから呼び出すこともできません、多分...。Mix-inすることできますね...(@scivolaありがとうございます)
mod = Module.new {
def self.anonymous
puts "anonymous module"
end
}
mod.name
# => nil
mod.anonymous
# => anonymous module
MyClass = Class.new do
include mod
end
MyClass.ancestors
# => [MyClass, #<Module:0x000001fb1163dc48>, Object, Kernel, BasicObject]
わざわざ無名で作成してるので、名前をつけたくなることがあるかは分かりませんが...
変数を参照することで名前を与えることができます。
mod = Module.new {
def self.named
puts "Named"
end
}
Foo = mod
mod.name
# => Foo
Foo.named
# => Named
また、無名モジュールを返すメソッドを作成しincludeすることも可能です。
def anonymous_module(val)
Module.new {
define_method "#{val}" do
puts "#{val}"
end
}
end
class MyClass
include anonymous_module('hey')
end
MyClass.new.hey
# => hey
どのような時に使うのか?
タイトルから脱線していますが、そもそもusing Module.new
はどのようにしようするのか?
クラス拡張をして他のファイルには影響を与えたくないときや、sendで外部から呼ばれたくないし、他のファイルでは使わないけどメソッドでまとめておきたい時に使用するらしいです。
例えば、String#reverseを書き換えたいけど、このファイルのみでしか使わないんだよなーってときに
using Module.new {
refine String do
def reverse
"xxxx#{super}xxxx"
end
end
}
puts "abc".reverse
# => xxxxcbaxxxx
これで、String#reverseを書き換えることが出来ました。
ですが、先程のファイルを別ファイルに読込んでも拡張したString#reverseは使用することは出来ません。
require './anonymous'
puts "abc".reverse
# => cba
んー他に使い方があるのかな...何かわかれば追記していきます。