# Modularizing class methods

**URL:** <https://www.ruby-forum.com/t/modularizing-class-methods/61820>\
**Category:** Ruby\
**Created:** [May 28, 2006, 3:42am UTC](https://www.ruby-forum.com/t/modularizing-class-methods/61820 "2006-05-28T03:42:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 28, 2006, 3:42am UTC](https://www.ruby-forum.com/t/modularizing-class-methods/61820/1 "2006-05-28T03:42:13Z")

</div>

Suppose you have a base class that defines some class methods, and that  
these class methods are intended to be used in the derived classes to  
(for example) add fields at incrementally increasing offsets in some  
storage. Maybe you want to define named accessors for positions in an  
array or string. Or maybe you are generating code to access fields in a  
C struct. The point is that these class methods must be called in  
sequence as the class is being defined, because some index is being  
updated (as a class variable perhaps), or a because a C struct def is  
being built up.

The problem is: how can you define such fields in a _module_ so that you  
can include the module in one of your derived classes, and have these  
fields use the correct offset in the context of the class they are being  
added to (which is not known at the time the module is defined)?

In other words you want to write code like this:

module NameFields  
field :first, :last, :middle  
end

module AddressFields  
field :street, :city, :state, :zip  
end

class Person \< ArrayWithNamedFields  
include NameFields  
include AddressFields  
end

per = Person.new  
per.first = “Fred”  
per.last = “Flintstone”  
per.city = “Bedrock”

This doesn’t work, not just because #field is undefined in NameFields  
and AddressFields, but because if you did define it, it would use the  
wrong array indexes when called in the module. The #field method should  
only be called on the class that the field is being added to.

This statement of the problem is more wordy and confusing than the  
solution. It’s probably not original, but it’s very simple, and a nice  
example of meta-meta-programming that I happened to need right now. So  
here it is. Maybe someone can think of a better name.

module ModuleMethodSaver  
def method\_missing(meth, \*args, &block)  
@saved ||= []  
@saved \<\< [meth, args, block]  
end

def included(m)  
if @saved  
@saved.each do |meth, args, block|  
m.send(meth, \*args, &block)  
end  
end  
end  
end

# First, a simple example:

module M  
extend ModuleMethodSaver

foo 1,2,3  
bar “zap”  
end

class Base  
def self.foo(\*args)  
puts “#{self}.foo with #{args.inspect}”  
end

def self.bar(\*args)  
puts “#{self}.bar with #{args.inspect}”  
end  
end

class C \< Base  
include M  
# output:  
# ==\> C.foo with [1, 2, 3]  
# ==\> C.bar with [“zap”]  
end

# The next example shows how ModuleMethodSaver can be used with a

# fixed-offset storage system, in this case based on Array. It could

# also be used with String (or BitStruct) or with CShadow (from

# cgenerator).

class ArrayWithNamedFields \< Array  
def self.field(\*names)  
names.each do |name|  
pos = @pos ||= 0  
define\_method name do ||  
self[pos]  
end  
define\_method “#{name}=” do |v|  
self[pos] = v  
end  
@pos += 1  
end  
end  
end

module NameFields  
extend ModuleMethodSaver  
field :first, :last, :middle  
end

module AddressFields  
extend ModuleMethodSaver  
field :street, :city, :state, :zip  
end

class Person \< ArrayWithNamedFields  
include NameFields  
include AddressFields  
end

per = Person.new  
per.first = “Fred”  
per.last = “Flintstone”  
per.city = “Bedrock”  
p per # ==\> [“Fred”, “Flintstone”, nil, nil, “Bedrock”]

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 28, 2006, 4:36am UTC](https://www.ruby-forum.com/t/modularizing-class-methods/61820/2 "2006-05-28T04:36:38Z")

</div>

Interesting approach. It’s a little bit of a misnomer mind you, becasue  
you have taken over the include processes such that you are not  
actually including module definitions, but rather are defining code in  
the base class itself. In other words, while your class will report  
ancestors of NameFields and AddressFields, there are actually no  
methods defined in those modules.

I have seen another common way of doing this:

module NameFields  
def included( base )  
base.class\_eval %{  
field :first, :last, :middle  
}  
end  
end

This works too, of course, though I think your technique is more clever  
and worth additional study. Nonetheless there is still the fact in  
either case of being real module inclusion. Maybe it would be better  
not to use the include mechinism. Ie. just create a different module  
method to do the work. You could still go about it the same way, but  
just use a different method other than #include.

Here is an example of what I came up with some time ago.

class Module

def package( name, &block )  
@ **package** ||= {}  
return @ **package** unless block\_given?  
@ **package** [name.to\_sym] = block  
end

def provide\_features( base, \*selection )  
selection.each do |s|  
base.class\_eval( &@ **package** [s.to\_sym] )  
end  
end

def use( package, \*selection )  
if String === package or Symbol === package  
package = constant(package)  
end  
package.provide\_features( self, \*selection )  
end

end

# \_\_\_\_\_ \_

# |\_ _|_\_ \_\__| |_

# | |/ \_ / \_\_| \_\_|

# | | _/\_ \ |_

# |_|\_ **||** _/\_\_|

# 

require ‘test/unit’

class TCModule \< Test::Unit::TestCase

```
module MyPackages
  package :foo do
    def foo
      "yes"
    end
  end
end

class Y
  use MyPackages, :foo
end

def test_package
  y = Y.new
  assert_equal( "yes", y.foo )
end

```

end

Though it may need some tweaking to work for your usecase, I suspect  
something like this woud do the job nicely.

In any case I’m gogin to give your code some more thought. Please let  
us know if you improve upon it.

T.

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e19b73/32.png) [@Joel\_VanderWerf](https://www.ruby-forum.com/u/Joel_VanderWerf)\
**Post date:** [May 28, 2006, 4:54am UTC](https://www.ruby-forum.com/t/modularizing-class-methods/61820/3 "2006-05-28T04:54:53Z")

</div>

removed\_email\_address@domain.invalid wrote:

> Interesting approach. It’s a little bit of a misnomer mind you, becasue  
> you have taken over the include processes such that you are not  
> actually including module definitions, but rather are defining code in  
> the base class itself. In other words, while your class will report  
> ancestors of NameFields and AddressFields, there are actually no  
> methods defined in those modules.

True, but the parallel with the following is just so appealing, that I  
thought #include was the best mechanism to use:

module NameFields  
attr\_accessor :first, :last, :middle  
end

module AddressFields  
attr\_accessor :street, :city, :state, :zip  
end

class Person  
include NameFields  
include AddressFields  
end

(The above depends on the fact that attrs are stored by name, and not  
incrementally allocated in some linear store.)

Anyway, you _might_ want to put some definitions in the modules, and  
have them propagate to the class via include, like this (in the context  
of my example from the previous post):

module AddressFields  
extend ModuleMethodSaver  
field :street, :city, :state, :zip  
def postal\_address  
[street, city, “#{state} #{zip}”].join("\n")  
end  
end

Using include is the most natural way to do this.

> I have seen another common way of doing this:
> 
> module NameFields  
> def included( base )  
> base.class\_eval %{  
> field :first, :last, :middle  
> }  
> end  
> end

Yep, same effect, but a little harder to write naturally. Also, you  
cannot copy and paste from the class def to the module def, as you can  
with ModuleMethodSaver:

class Person \< ArrayWithNamedFields  
field :first, :last, :middle  
end

is the same as

module NameFields  
extend ModuleMethodSaver  
field :first, :last, :middle  
end

class Person \< ArrayWithNamedFields  
include NameFields  
end

So it makes refactoring easier. (Well, ok, you still have to type the  
“extend” line. But that’s easier to remember than the def included(…  
stuff.)

Thanks for the comments!
