参考:include和extend的区别:html
http://www.javashuo.com/article/p-qfmslrbu-ed.htmlgit
传统的模块看起来像:github
module M def self.included(base) # base(一个类)扩展了一个模块"ClassMethods", base的类方法就包含了"ClassMethods"模块中的方法。 base.extend ClassMethods # base添加了一个:disabled方法。 base.class_eval do scope :disabled, -> { where(disabled: true) } end end module ClassMethods ... end end
使用ActiveSupport::Concern:app
require 'active_support/concern' module M # M扩展了模块Concern,能够使用Concern的方法。 extend ActiveSupport::Concern # 当M被一个类包括后,这个类就能够使用块内的方法了。 included do scope :disabled, -> { where(disabled: true) } end # 当M被一个类包括后,这个类的类方法就扩展了,👇的方法就做为类方法使用。 class_methods do ... end end
一个小的gem,为英文网站用户的注册名字添加了不少调用的方法。less
https://github.com/basecamp/name_of_person/tree/master/lib/name_of_person网站
1 . User类必须包括first_name, last_name2个属性,添加validates :first_name, :last_name, presence: trueui
2. 当实例化一个@user时,代码内部调用name= 方法为first_name, last_name属性分配值!spa
3. 以后经过@user.name.xxx就能够使用不一样的名和姓的组合。code
图2htm
图3:
首先是一个判断:
if @user.first_name NameOfPerson::PersonName.new(@user.first_name, @user.last_name) end
若是first_name存在,则新增一个PersonName对象,调用initialize方法
def initialize(first, last = nil) raise ArgumentError, "First name is required" unless first.present? @first, @last = first, last super full end
而后调用full这个方法,进行if判断
def full @full ||= last.present? ? "#{first} #{last}" : first end
分析:
若是@user.last_name存在(last.present?),则 把@user的两个name属性合并,并分配给@full对象。
最后返回一个PersonName对象实例, 内部包括@first, @full, 及@last(根据@user决定是否存在)
def name=(name) full_name = NameOfPerson::PersonName.full(name) self.first_name, self.last_name = full_name.try(:first), full_name.try(:last) end
首先:调用模块PersonName的类方法full。
def self.full(full_name) first, last = full_name.to_s.strip.split(/\s+/, 2) new(first, last) if first.present? end