I separated my modules so they are easier to read and search like
lib
features
- running.rb
- walking.rb
features.rb
And they have
# lib/features/running.rb
module Features::Running
extend ActiveSupport::Concern
module ClassMethods
def can_run
...
end
end
end
and the other is:
# lib/features/walking.rb
module Features::Walking
extend ActiveSupport::Concern
module ClassMethods
def can_walk
...
end
end
end
And I might have a lot of this someday.
My problem is when I want to add them in a model, I'd need to
# Sample model
class Man < ActiveRecord::Base
# Include features modules
include Features::Walking
include Features::Running
# Define what man can do
can_walk
can_run
end
I was wondering if there is a way to create another module and include all of them. Something like:
# lib/features.rb
module Features
extend ActiveSupport::Concern
extend Features::Walking
extend Features::Running
end
So I'd only need to add
# Sample model
class Man < ActiveRecord::Base
# Include features modules
include Features
# Define what man can do
can_walk
can_run
end
Or how should I go about this?
Edit - solution
I got the fix now based on @Chris solution. I got something like this:
module Features
FEATURES = %w(running walking)
# include Features::Running
FEATURES.each do |feature|
send :include, "Features::#{feature.camelize}".constantize
end
module ClassMethods
# include Features::Running::ClassMethods
FEATURES.each do |feature|
send :include, "Features::#{feature.camelize}::ClassMethods".constantize
end
end
def self.included(base)
base.send :extend, ClassMethods
end
end
and my other feature modules are now:
# lib/features/running.rb
module Features::Running
module ClassMethods
def can_run
...
end
end
end
# lib/features/walking.rb
module Features::Walking
module ClassMethods
def can_walk
...
end
end
end
Edit - updated solution
module Features
FEATURES = [Running, Walking]
# include Features::Running
FEATURES.each do |feature|
send :include, feature
end
module ClassMethods
# include Features::Running::ClassMethods
FEATURES.each do |feature|
send :include, feature::ClassMethods
end
end
def self.included(base)
base.send :extend, ClassMethods
end
end
You can; the issue you're likely running into is that ActiveSupport::Concern
automagically extends the methods in ClassMethods
onto the target class, rather than combining multiple ClassMethods
sub-modules into one. This is unfortunately a little hard to do automatically because of Ruby's cyclical include prevention code, but you can actually do it all manually without AS::Concern.
module Foo
def foo
end
module ClassMethods
def cfoo
end
end
end
module Baz
def baz
end
module ClassMethods
def cbaz
end
end
end
module Bar
include Baz
def bar
end
module ClassMethods
include Baz::ClassMethods
def cbar
end
end
end
module Stuff
include Foo
include Bar
module ClassMethods
include Foo::ClassMethods
include Bar::ClassMethods
end
end
class Final
include Stuff
extend Stuff::ClassMethods
end
This is a little more verbose, but you can compose pieces as deep as you want, though you have to be careful to always include the parent module and then include ClassMethods onto the corresponding ClassMethods submodule.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.