參考: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