美文网首页
Metaprograming Ruby -- C10 Activ

Metaprograming Ruby -- C10 Activ

作者: 我要走多远 | 来源:发表于2015-03-24 12:35 被阅读42次

    Summary

    1. ruby can include instance methods and extend class methods, but can't do those two things together.
      Rails just want do though this together(powerful language with powerful framework ...).
    2. at first, rails use included hook,
      when a class includes the instance methods, it extend class methods by the includes hook
      so rails do those two things together.
    3. but when a module includes a module, problem happens.
      the second level module extended the first level module,
      yeah, the first level's ClassMethod's methods have became the second level's class method.
      but, the second level module's ClassMethods' methods do not have the first level's ClassMethods' methods,
      so when include the second level module in a class, the class can not get the first level's ClassMethods' methods. Because the first level module's class methods do not in the second level module's ClassMethods module
    4. rails solve this by overwriting the apppend_features
      it flatten all nest included modules with right order.
      and let the class include all those included module in the right order.

    put include and extend together

    includes and extend

    included is a hook, when a class includes a module, this hook will be called
    def self.included(base)
    base.extend ClassMethods # ...
    end

    nested include

     Problem happens when BaseClass includes the FirstLevelModule, so the please read the comment in it and then read comment in FirstLevelModule's `included`
      module SecondLevelModule
        def self.included(base)
          base.extend ClassMethods
        end
    
        def second_level_instance_method; 'ok'; end
    
        module ClassMethods
          def second_level_class_method; 'ok'; end
        end
      end
    
      module FirstLevelModule
        def self.included(base)
          # called because the BaseClass me(`FirstLevelModule`)
          # I let the BaseClass extend all the methods in my ClassMethods module
          # but wait a minute, I include the SecondLevelModule,
          # and I have second_level_class_method as my class method
          # but it is not in my ClassMethods module,
          # so the BassClass dose not have second_level_class_method as its class method :(
          # include trick broken ...
          base.extend ClassMethods
        end
    
        def first_level_instance_method; 'ok'; end
    
        module ClassMethods
          def first_level_class_method; 'ok'; end
        end
    
        include SecondLevelModule
      end
    
      class BaseClass
        # the FirstLevelModule's included hook will be called
        include FirstLevelModule
      end
    

    append_features - solving module includes module problem

    the append_features is overwrote by rails

    goal: never include a concern in another concern,
    so just let the includer(class or module) 'includes' all concerns in the right order.

    it has two part

    1. a concern includes a concern,
      checked by base.instance_variable_defined?("@_dependencies")
      it add the included concern as a dependent and add it to its @_dependencies

    2. a module includes a concern
      def append_features(base)
      # recursive
      # no need include and extend
      return false if base < self
      @_dependencies.each { |dep| base.send(:include, dep) }

          # to include class method by call original append_features
          super
          # extend class methods
          base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
          base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
        end
      

    相关文章

      网友评论

          本文标题:Metaprograming Ruby -- C10 Activ

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