美文网首页Ruby & Rails
利用ActiveSupport::Concern来组织你需要in

利用ActiveSupport::Concern来组织你需要in

作者: 我天真无邪 | 来源:发表于2016-01-07 16:50 被阅读290次

    • 下面用到了 module 的 hook方法 included
    • 下面也可以看出来一个module是怎么被引入到一个类里面的 (include extend require)

    来看一个 typical 的 module

    module M
      def self.included(base)
        base.extend ClassMethods
        base.class_eval do 
          scope :disabled, -> { where(disabled: true) }
        end
      end
      
      module ClassMethods
        
      end
    end
    

    然后是一个 active_support/concern

    require 'active_support/concern'
    
    module M
      extend ActiveSupport::Concern
      
      included do 
        scope :disabled, -> { where(disabled: true) }
      end
      
      class_methods do 
        
      end
    end
    
    

    然后就是 module 的依赖了 Bar依赖于Foo

    module Foo
      def self.included(base)
        base.class_eval do 
          def self.method_injected_by_foo
          
          end
        end
      end
    end
    
    module Bar
      def self.included(base)
        base.method_injected_by_foo
      end
    end
    
    class Host
      include Foo
      include Bar
    end
    

    使用 ActiveSupport::Concern 之后 依赖就是可以是单独的

    module Foo
      extend ActiveSupport::Concern
      included do 
        def self.method_injected_by_foo
        end
      end
    end
    
    module Bar
      extend ActiveSupport::Concern
      include Foo
      
      included do
        self.method_injected_by_foo
      end
    end
    
    class Host
      include Bar
    end
    

    有了上面的这些背景知识 。很多时候一些工具类可以如是扩展

    #源码 其实挺精彩的 append_features 也很好的说明了 extend 和 include的区别
    
    module ActiveSupport
      module Concern
        class MultipleIncludedBlocks < StandardError #:nodoc:
          def initialize
            super "Cannot define multiple 'included' blocks for a Concern"
          end
        end
    
        def self.extended(base) #:nodoc:
          base.instance_variable_set(:@_dependencies, [])
        end
    
        def append_features(base)
          if base.instance_variable_defined?(:@_dependencies)
            base.instance_variable_get(:@_dependencies) << self
            return false
          else
            return false if base < self
            @_dependencies.each { |dep| base.send(:include, dep) }
            super
            base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
            base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
          end
        end
    
        def included(base = nil, &block)
          if base.nil?
            raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
    
            @_included_block = block
          else
            super
          end
        end
    
        def class_methods(&class_methods_module_definition)
          mod = const_defined?(:ClassMethods, false) ?
            const_get(:ClassMethods) :
            const_set(:ClassMethods, Module.new)
    
          mod.module_eval(&class_methods_module_definition)
        end
      end
    end
    
    

    相关文章

      网友评论

        本文标题:利用ActiveSupport::Concern来组织你需要in

        本文链接:https://www.haomeiwen.com/subject/tqufkttx.html