Modules, instance methods and class methods

V

Vincent Fourmond

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
 
D

dblack

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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
T

Trans

Hi--

Vincent said:
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
 
V

Vincent Fourmond

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
 
D

dblack

Hi --

Hello !


Thanks !


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 | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
T

Trans

Hi --



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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top