diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7d42365851b86a018d70481280d620561ff6ee81
--- /dev/null
+++ b/activesupport/lib/active_support/concern.rb
@@ -0,0 +1,134 @@
+module ActiveSupport
+ # A typical module looks like this:
+ #
+ # module M
+ # def self.included(base)
+ # base.extend ClassMethods
+ # base.class_eval do
+ # scope :disabled, -> { where(disabled: true) }
+ # end
+ # end
+ #
+ # module ClassMethods
+ # ...
+ # end
+ # end
+ #
+ # By using ActiveSupport::Concern 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
+ # 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 base
+ # is the +Bar+ module, not the +Host+ class. With ActiveSupport::Concern,
+ # module dependencies are properly resolved:
+ #
+ # require 'active_support/concern'
+ #
+ # module Foo
+ # extend ActiveSupport::Concern
+ # included do
+ # def self.method_injected_by_foo
+ # ...
+ # 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
+ class MultipleIncludedBlocks < StandardError #:nodoc:
+ def initialize
+ super "Cannot define multiple 'included' blocks for a Concern"
+ end
+ end
+
+ def self.extended(base) #:nodoc:
+ 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.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
+ end
+ end
+
+ def included(base = nil, &block)
+ if base.nil?
+ raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
+
+ @_included_block = block
+ else
+ super
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..32ac8f4655baf7e523ad8ccc7fbf3228b9807133
--- /dev/null
+++ b/activesupport/test/concern_test.rb
@@ -0,0 +1,98 @@
+require 'abstract_unit'
+require 'active_support/concern'
+
+class ConcernTest < ActiveSupport::TestCase
+ module Baz
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def baz
+ "baz"
+ end
+
+ def included_ran=(value)
+ @@included_ran = value
+ end
+
+ def included_ran
+ @@included_ran
+ end
+ end
+
+ included do
+ self.included_ran = true
+ end
+
+ def baz
+ "baz"
+ end
+ end
+
+ module Bar
+ extend ActiveSupport::Concern
+
+ include Baz
+
+ def bar
+ "bar"
+ end
+
+ def baz
+ "bar+" + super
+ end
+ end
+
+ module Foo
+ extend ActiveSupport::Concern
+
+ include Bar, Baz
+ end
+
+ def setup
+ @klass = Class.new
+ end
+
+ def test_module_is_included_normally
+ @klass.send(:include, Baz)
+ assert_equal "baz", @klass.new.baz
+ assert @klass.included_modules.include?(ConcernTest::Baz)
+ end
+
+ def test_class_methods_are_extended
+ @klass.send(:include, Baz)
+ assert_equal "baz", @klass.baz
+ assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; self.included_modules; end)[0]
+ end
+
+ def test_included_block_is_ran
+ @klass.send(:include, Baz)
+ assert_equal true, @klass.included_ran
+ end
+
+ def test_modules_dependencies_are_met
+ @klass.send(:include, Bar)
+ assert_equal "bar", @klass.new.bar
+ assert_equal "bar+baz", @klass.new.baz
+ assert_equal "baz", @klass.baz
+ assert @klass.included_modules.include?(ConcernTest::Bar)
+ end
+
+ def test_dependencies_with_multiple_modules
+ @klass.send(:include, Foo)
+ assert_equal [ConcernTest::Foo, ConcernTest::Bar, ConcernTest::Baz], @klass.included_modules[0..2]
+ end
+
+ def test_raise_on_multiple_included_calls
+ assert_raises(ActiveSupport::Concern::MultipleIncludedBlocks) do
+ Module.new do
+ extend ActiveSupport::Concern
+
+ included do
+ end
+
+ included do
+ end
+ end
+ end
+ end
+end
\ No newline at end of file