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 –

On Wed, 27 Sep 2006, Vincent F. wrote:

end
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

Hi–

Vincent F. wrote:

def desc

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 !

    return @desc

(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 F. wrote:

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

[email protected] wrote:

module Base

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.