Reputation: 18871
I am using Ruby 1.9.2 and the Ruby on Rails v3.2.2 gem. After my previous question on how to “nest” the inclusion of modules when using the Ruby on Rails ActiveSupport::Concern feature, I would like to understand where I should state methods added to a class by including "nested" modules in order to make these instance methods of that class. That is, I have the following:
class MyClass < ActiveRecord::Base
include MyModuleA
end
module MyModuleA
extend ActiveSupport::Concern
included do
include MyModuleB
end
end
module MyModuleB
extend ActiveSupport::Concern
included do
# def my_method
# ...
# end
end
# def my_method
# ...
# end
end
Should I state def my_method ... end
in the "body" / "context" / "scope" of MyModuleB
or I should state that in the included do ... end
block? What is the difference and what I should expect from that?
Upvotes: 2
Views: 1272
Reputation: 62638
Methods in modules that get mixed into a class become instance methods on that class. While putting them in the included
block would likely work, there's no need to do it. This, by extension, works with modules, since you can include ModuleB
in ModuleA
and all its instance methods become instance methods on ModuleA
, and once ModuleA
is included on class Foo
, all its instance methods (including those mixed in from B
) become instance methods on Foo.
A "traditional" mix-in looks like this:
module Mixin
def self.included(klass)
klass.send :extend, ClassMethods
klass.some_class_method
end
module ClassMethods
def some_class_method
puts "I am a class method on #{self.inspect}"
end
end
def some_instance_method
puts "I am an instance method on #{self.inspect}"
end
end
class Foo
include Mixin
end
Foo.new.some_instance_method
# Output:
# I am a class method on Foo
# I am an instance method on #<Foo:0x00000002b337e0>
ActiveSupport::Concern just pretties this up a bit by automatically including a module named ClassMethods
and by running the included
block in the context of the including class, so the equivalent is:
module Mixin
extend ActiveSupport::Concern
included do
some_class_method
end
module ClassMethods
def some_class_method
puts "I am a class method on #{self.inspect}"
end
end
def some_instance_method
puts "I am an instance method on #{self.inspect}"
end
end
class Foo
include Mixin
end
Foo.new.some_instance_method
# Output:
# I am a class method on Foo
# I am an instance method on #<Foo:0x000000034d7cd8>
Upvotes: 5