diff options
Diffstat (limited to 'activesupport/lib/active_support/concern.rb')
-rw-r--r-- | activesupport/lib/active_support/concern.rb | 140 |
1 files changed, 105 insertions, 35 deletions
diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb index 2d87e8d0e5..81fb859334 100644 --- a/activesupport/lib/active_support/concern.rb +++ b/activesupport/lib/active_support/concern.rb @@ -1,39 +1,109 @@ -# A typical module looks like this -# -# module M -# def self.included(base) -# base.send(:extend, ClassMethods) -# base.send(:include, InstanceMethods) -# scope :foo, :conditions => { :created_at => nil } -# end -# -# module ClassMethods -# def cm; puts 'I am a class method'; end -# end -# -# module InstanceMethods -# def im; puts 'I am an instance method'; end -# end -# end -# -# By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as: -# -# module M -# extend ActiveSupport::Concern -# -# included do -# scope :foo, :conditions => { :created_at => nil } -# end -# -# module ClassMethods -# def cm; puts 'I am a class method'; end -# end -# -# module InstanceMethods -# def im; puts 'I am an instance method'; end -# end -# end module ActiveSupport + # A typical module looks like this: + # + # module M + # def self.included(base) + # base.extend ClassMethods + # base.send(:include, InstanceMethods) + # scope :disabled, where(:disabled => true) + # end + # + # module ClassMethods + # ... + # end + # + # module InstanceMethods + # ... + # end + # end + # + # By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as: + # + # require 'active_support/concern' + # + # module M + # extend ActiveSupport::Concern + # + # included do + # scope :disabled, where(:disabled => true) + # end + # + # module ClassMethods + # ... + # end + # + # module InstanceMethods + # ... + # end + # end + # + # Moreover, it gracefully handles module dependencies. Given a +Foo+ module and a +Bar+ + # module which depends on the former, we would typically write the following: + # + # 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 # We need to include this dependency for Bar + # include Bar # Bar is the module that Host really needs + # end + # + # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We could try to hide + # these from +Host+ directly including +Foo+ in +Bar+: + # + # module Bar + # include Foo + # def self.included(base) + # base.method_injected_by_foo + # end + # end + # + # class Host + # include Bar + # end + # + # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt> is the +Bar+ module, + # not the +Host+ class. With <tt>ActiveSupport::Concern</tt>, module dependencies are properly resolved: + # + # require 'active_support/concern' + # + # module Foo + # extend ActiveSupport::Concern + # included do + # class_eval do + # def self.method_injected_by_foo + # ... + # end + # end + # end + # end + # + # module Bar + # extend ActiveSupport::Concern + # include Foo + # + # included do + # self.method_injected_by_foo + # end + # end + # + # class Host + # include Bar # works, Bar takes care now of its dependencies + # end + # module Concern def self.extended(base) base.instance_variable_set("@_dependencies", []) |