💨
クラスメソッドを利用して動的に指定したインスタンスメソッドを追加する方法
クラスXのfooメソッドをコール時に指定のattributeを渡すことで、動的にattribute付きのbarメソッドを各インスタンスに定義する。
継承クラスごとにfooメソッドのコール有無および名前の切り替えが可能。
class X
def self.foo(attribute)
include InstanceMethods.new(attribute)
end
class InstanceMethods < Module
def initialize(attribute)
define_method(:"bar_#{attribute}") do
puts "bar_#{attribute}"
end
end
end
end
class Xfoo < X
foo :attribute
end
xfoo = Xfoo.new
xfoo.bar_attribute
#=> bar_attribute
railsのhas_secure_password
で利用されており、has_secure_password :bar
でattributeを引数にして動的にインスタンスメソッドが定義されている。
def has_secure_password(attribute = :password, validations: true)
# Load bcrypt gem only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework)
# being dependent on a binary library.
begin
require "bcrypt"
rescue LoadError
warn "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install."
raise
end
include InstanceMethodsOnActivation.new(attribute)
補足
単なるインスタンスメソッドの追加はmoduleをincludeすればよい。
class X
def self.foo
include InstanceMethods
end
module InstanceMethods
def bar
puts "bar"
end
end
end
class Xfoo < X
foo
end
xfoo = Xfoo.new
xfoo.bar
# => bar
Discussion