【问题标题】:ruby/rails: extending or including other modulesruby/rails:扩展或包含其他模块
【发布时间】:2015-04-18 23:09:41
【问题描述】:

我分离了我的模块,以便它们更易于阅读和搜索

lib
  features
    - running.rb
    - walking.rb
  features.rb

他们有

# lib/features/running.rb
module Features::Running
  extend ActiveSupport::Concern

  module ClassMethods
    def can_run
      ...
    end
  end
end

另一个是:

# lib/features/walking.rb
module Features::Walking
  extend ActiveSupport::Concern

  module ClassMethods
    def can_walk
      ...
    end
  end
end

有一天我可能会拥有很多这样的东西。

我的问题是当我想将它们添加到模型中时,我需要

# 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

我想知道是否有办法创建另一个模块并包含所有模块。比如:

# lib/features.rb
module Features
  extend ActiveSupport::Concern

  extend Features::Walking
  extend Features::Running
end

所以我只需要添加

# Sample model
class Man < ActiveRecord::Base
  # Include features modules
  include Features

  # Define what man can do
  can_walk
  can_run
end

或者我应该怎么做?

编辑 - 解决方案

我现在根据@Chris 解决方案得到了修复。我得到了这样的东西:

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

我的其他功能模块现在是:

# 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

编辑 - 更新解决方案

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

【问题讨论】:

    标签: ruby-on-rails ruby module


    【解决方案1】:

    你可以;您可能遇到的问题是ActiveSupport::Concern 自动将ClassMethods 中的方法扩展到目标类,而不是将多个ClassMethods 子模块合并为一个。不幸的是,由于 Ruby 的循环包含预防代码,这有点难以自动完成,但实际上您可以在没有 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
    

    这有点冗长,但您可以根据需要编写任意深度的片段,但必须小心始终包含父模块,然后将 ClassMethods 包含到相应的 ClassMethods 子模块中。

    【讨论】:

    • 每个模块上的空白def方法是做什么用的?
    • 现在我在应该写extend Stuff::ClassMethods的部分得到uninitialized constant Features::ClassMethods
    • 我想我让它工作了,但我已经改变了一点,并在开始时删除了空白方法。我将编辑我的帖子并在那里写下我的更改。
    • 空白方法只是为了表明它们已扩展到最终类。您的解决方案看起来应该可以工作,但您可以使其更简洁,例如 [Running, Walking].each {|mod| include mod },因为您已经在 Features 命名空间中。
    • 我应该删除Features::... 部分吗?
    猜你喜欢
    • 2016-02-24
    • 1970-01-01
    • 2017-08-28
    • 2015-09-24
    • 1970-01-01
    • 2011-06-10
    • 2013-07-07
    • 2017-07-13
    • 1970-01-01
    相关资源
    最近更新 更多