On 3/23/07, Yukihiro Matsumoto <matz / ruby-lang.org> wrote:

> I am not sure what class_extension or extension does.  Do they return
> class/module themselves?

You don't remember? It was your idea! Great, now I feel about this
('') small. I've been telling everyone I work with that
class_extension was being considered for inclusion into 1.9/2.0 b/c
that's what you indicated in the ruby-talk thread where this code came
into existence.

Well, I don't mean to blame. Lord, knows I forget things all the time.
So here's a complete reminder:

  ruby-talk:196402

It's a long thread however. In sum the resulting code (and
explanation) of what class_extension does follows.

Concerning #extension, yes it returns a special module used to achieve
the same ends.

T.


---

class Module

  alias_method :append_features_without_class_extension, :append_features

  # = class_extension
  #
  # Normally when including modules, class/module methods are not
  # extended. To achieve this behavior requires some clever
  # Ruby Karate. Instead class_extension provides an easy to use
  # and clean solution. Simply place the extending class methods
  # in a block of the special module method #class_extension.
  #
  #   module Mix
  #     def inst_meth
  #       puts 'inst_meth'
  #     end
  #
  #     class_extension do
  #       def class_meth
  #         "Class Method!"
  #       end
  #     end
  #   end
  #
  #   class X
  #     include Mix
  #   end
  #
  #   X.class_meth  #=> "Class Method!"
  #

  def class_extension(&block)
    @class_extension ||= Module.new do
      def self.append_features(mod)
        append_features_without_class_extension(mod)
      end
    end
    @class_extension.module_eval(&block) if block_given?
    @class_extension
  end

  private :class_extension

  def append_features(mod)
    append_features_without_class_extension(mod)
    mod.extend(class_extension)
    if mod.instance_of? Module
      mod.__send__(:class_extension).__send__(:include, class_extension)
    end
  end

end

class Class
  undef_method :class_extension
end



#  _____         _
# |_   _|__  ___| |_
#   | |/ _ \/ __| __|
#   | |  __/\__ \ |_
#   |_|\___||___/\__|
#

=begin test

  require 'test/unit'

  class TC_ClassMethods < Test::Unit::TestCase

    # fixture

    module N
      class_extension do
        def n ; 43 ; end
        def s ; self ; end
      end
      extend class_extension
    end

    class X
      include N
      def n ; 11 ; end
    end

    module K
      include N
      class_extension do
        def n ; super + 1 ; end
      end
    end

    class Z
      include K
    end

    # tests

    def test_01
      assert_equal( 43, N.n )
      assert_equal(  N,  N.s )
    end
    def test_02
      assert_equal( 43, X.n )
      assert_equal(  X, X.s )
    end
    def test_03
      assert_equal( 11, X.new.n )
    end
    def test_04
      assert_equal( 43, K.n )  #notic the difference!
      assert_equal(  K, K.s )
    end
    def test_05
      assert_equal( 44, Z.n )
      assert_equal(  Z, Z.s )
    end

  end

=end