Hi--

Vincent Fourmond wrote:
> Hello !
>
>   I have a rather tortured architecture where several classes should
> share code for some class methods and for some instance methods. To fix
> the ideas, I need that some class I define have:
>
> def ThisClass.desc
>   return @desc
> end
>
> def desc
>   return self.class.desc
> end
>
>   To do that, I define two modules
>
> module BaseInclude
>   def desc
>     return self.class.desc
>   end
> end
>
> module BaseExtend
>   def desc
>     return @desc
>   end
> end
>
>   and I include them with
>
> class ThisClass
>   include BaseInclude
>   extend BaseExtend
> end
>
>   That works perfectly fine. My question, then, is : is there a simpler
> way ? I can't afford to have a shared ancestor for these classes.
>
>   Thanks !

Not too long ago this was discussed with a length with Matz. The result
was #class_extension.

 module Base
    def desc
      return self.class.desc
    end

    class_extension do
      def desc
        return @desc
      end
    end
  end

  class ThisClass
     include Base
  end

An excellent pure Ruby implementation of this was developed by Daniel
Schierbeck, It can be found it the Facets project
(facets.rubyforge.org). To use: require 'facet/module/class_extension'.
For convenience the code follows.

It remains to be seen if Matz ultimately goes with this approach in
Ruby 2.0. But as of yet I guess one could say it the most "official"
technique available. (Not to say that others are prefectly valid of
course)

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_methods 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