2016年2月18日 星期四

Reading Rails - Concern 


major feature:
  1. auto extend ClassMethods and included InstanceMethods
  2. Dependency resolution

  • Included

Module defines the callback included which is called when a module is included into another class or module

if both two module are extend ActiveSupport::Concern, and both have included do 
module Named
  extendActiveSupport::Concern
  included do
     base.validates_presence_of:first_name,:last_name
  end#...
end

module Mailable
  extendActiveSupport::Concern
  include Named
  included do
     email_regexp =/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/base.validates_format_of:email,with:email_regexp
  end#...
end


Concern delays calling these blocks until your module is included in something that is not a Concern.

  • Class Methods

Calling include only mixes in the instance methods

If there is a ClassMethods module in a Concern, it will automatically extend whatever it is included in.
module Exclaimable
     def self.included(base)
          base.extend(ClassMethods)
     end
     module ClassMethods
          def shout!
               puts"Look out!"
          end
     end
end


  • How It Works

module ActiveSupport
  module Concern
    def self.extended(base)
      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.send :include, const_get("InstanceMethods") if const_defined?("InstanceMethods")
        base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
      end
    end

    def included(base = nil, &block)
      if base.nil?
        @_included_block = block
      else
        super
      end
    end
  end
end

Concern delays calling included blocks and mixing in ClassMethods by keeping track of modules in @_dependencies. When a Concern is included in another class, it triggers all the logic on that class.

While unpacking how Concern works, we also came across some other interesting things:
  • Module defines included and extended callbacks.
  • Ruby provides methods such as instance_method_get to access an object's internals.
  • Class methods are not mixed in with include.
  • include takes any number of arguments: include ModA, ModB, ModC.
  • Classes can be compared with equality operations: ClassA < ClassB.
  • By convention, anything starting with a capital letter is a constant.



沒有留言:

張貼留言