Modules, instance methods and class methods

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 !

  Vince

Hi --

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.

Personally, I like your approach: you've grouped methods according to
plan, and then carried out the plan. There are more elaborate ways,
but this seems to work for you, and it's very clear.

Just to point you to a couple of possible variations:

You could make the module that's destined for the extend operation a
nested module inside the other. In fact, you'll sometimes see this:

   module Something
     def a_method
     end

     module ClassMethods
       def some_class_level_method
       end
     end
   end

followed by:

   class MyClass
     include Something
     extend Something::ClassMethods
   end

(And you can even hook the extend operation into the include operation
by defining an appropriate self.included hook method in Something, so
that you don't have to have a separate extend call.)

I use the name "ClassMethods" advisedly: it's a popular choice. It
has the disadvantage of being inaccurate, in the sense that the
methods inside it are instance methods. But as long as they're
destined to be class methods (which, after all, are really instance
methods of the singleton class of a class!), it might be a reasonable
name.

David

···

On Wed, 27 Sep 2006, Vincent Fourmond wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

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

Hello !

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.

  Thanks !

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)

  That would be cool if the syntax could be somewhat lighter: it somehow
doesn't look right to me to have the code within a block. But that's
just aesthetics... And that would be for ruby 2.0, if I understand right.

  Cheers !

  Vince

Hi --

···

On Wed, 27 Sep 2006, Vincent Fourmond wrote:

Hello !

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.

Thanks !

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)

That would be cool if the syntax could be somewhat lighter: it somehow
doesn't look right to me to have the code within a block. But that's
just aesthetics... And that would be for ruby 2.0, if I understand right.

I agree; it seems odd to resort to a block when generally the
inclusion/extension mechanism involves modules. Also, the terminology
is a bit narrow; it should really be 'includer_extension' or
something, since modules can be included by modules as well as
classes.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

dblack@wobblini.net wrote:

Hi --

>
> Hello !
>
>> 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.
>
> Thanks !
>
>> 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)
>
> That would be cool if the syntax could be somewhat lighter: it somehow
> doesn't look right to me to have the code within a block. But that's
> just aesthetics... And that would be for ruby 2.0, if I understand right.

I agree; it seems odd to resort to a block when generally the
inclusion/extension mechanism involves modules.

Yea. I get the same vibe. There's no precedence for it so it doesn't
seem very Rubyish. But at the very least I'm happy to have something
that works well. Also it doesn't require any changes under the hood so
I imagine it'll just be part of the standard library, nor core. Ideally
though I still tend to favor an alternate to #include, eg
#include_with_class_extension, or something (though that name is way
too long). But a solution like that does require some changes to Ruby
itself --it's not possible to implement in plain Ruby.

Also, the terminology
is a bit narrow; it should really be 'includer_extension' or
something, since modules can be included by modules as well as
classes.

I think "class" is referring to the singleton, which is a class in
etither case.

T.

···

On Wed, 27 Sep 2006, Vincent Fourmond wrote: