standard, pretty, and flexible meta-methods?

standard, pretty, and flexible meta-methods?

Post by Greg Week » Sat, 10 Nov 2007 04:57:34


The following code makes the meta-method "def_foo" available to any
class that inherits from Definer:

class Definer
def Definer.def_foo
def foo
17
end
end
end
# A TEST:
class User < Definer
def_foo
end
puts User.new.foo # prints 17

Is there a way to make meta-methods like "def_foo" available in class
definitions without using inheritance? Is there a standard way? Is it
pretty? (Or is it perhaps pointless?)
--
Posted via http://www.yqcomputer.com/
 
 
 

standard, pretty, and flexible meta-methods?

Post by Phrog » Sat, 10 Nov 2007 05:05:53


module Def1
def make_method( name )
define_method( name ){
"Hello from #{name}"
}
end
end

class Foo
extend Def1
end
Foo.make_method( 'jimmy' )
p Foo.new.jimmy
#=> "Hello from jimmy"


Note the use of 'extend' instead of 'include'.

Some people like this idiom:
http://www.yqcomputer.com/

 
 
 

standard, pretty, and flexible meta-methods?

Post by Phrog » Sat, 10 Nov 2007 05:15:18


In addition to using modules to mix in methods to only specific
classes, I should point out that you can define methods in the Module
class to have them available to every class and module you create. (Or
you can define them in the Class class to have them available only to
classes but not modules.)

class Module
def make_method( name )
define_method( name ){
"Hello from #{name}"
}
end
end

class Foo; end

Foo.make_method( 'jimmy' )
p Foo.new.jimmy
#=> "Hello from jimmy"

module Whee; end
class Foo
include Whee
end
Whee.make_method( 'junk' )

p Foo.new.junk
#=> "Hello from junk"

class Class
def classes_only!
"Classes are awesome. Modules suck!"
end
end

p Foo.classes_only!
#=> "Classes are awesome. Modules suck!"

p Whee.classes_only!
#=> undefined method `classes_only!' for Whee:Module (NoMethodError)
 
 
 

standard, pretty, and flexible meta-methods?

Post by Gary Wrigh » Sat, 10 Nov 2007 05:18:00


1) Put your method definition in a module:

module M
def my_class_method
# do something
end
end

2) extend your class object with your module

class A
extend M
end

3) use your methods from M

class A
my_class_method
end

Of course you can combine 2 and 3:

class A
extend M
my_class_method
end
 
 
 

standard, pretty, and flexible meta-methods?

Post by Greg Week » Sat, 10 Nov 2007 05:44:51

Wow, what a rush of information, eg:



"define_method" is what I was missing.

I'm still curious about the most common practice, if there is one,
specifically about creating little "mini-languages" that can be used
inside class definitions. (Yes, I'm wondering about Rails.) My example
with explicit class methods now smells pretty bad to me, for example.
Could modules (using "define_method" and other magic) "extended" into
class objects be considered the norm? This is a more vague question,
but I'm putting it out FWIW.

Anyway, thanks to all for the info so far.

--
Posted via http://www.yqcomputer.com/
 
 
 

standard, pretty, and flexible meta-methods?

Post by Phrog » Sat, 10 Nov 2007 06:29:42


It's what Rails and its component libraries mostly do. For example:

module ActiveRecord
module Associations
def self.included(base)
base.extend(ClassMethods)
end
...
module ClassMethods
def has_many(association_id, options = {}, &extension)
...
end
end
end
end

ActiveRecord::Base.class_eval do
...
include ActiveRecord::Associations
...
end


And that's how you get the has_many method:
class Person < ActiveRecord::Base
has_many :cats
end
 
 
 

standard, pretty, and flexible meta-methods?

Post by Phrog » Sat, 10 Nov 2007 06:38:41


Actually, I would like to change my answer:

The various Rails libraries generally define class methods as
'instance' methods in modules and extend classes with those modules to
add the class methods to various classes.

However, as you've no doubt seen in rails, most of the end user
functionality of the framework is achieved by subclassing (as with my
example based on ActiveRecord). The Rails programmer does not write:

class Person
include ActiveRecord::Validations
include ActiveRecord::Locking::Optimistic
include ActiveRecord::Locking::Pessimistic
include ActiveRecord::Callbacks
include ActiveRecord::Observing
include ActiveRecord::Timestamp
include ActiveRecord::Associations
include ActiveRecord::Aggregations
include ActiveRecord::Transactions
include ActiveRecord::Reflection
include ActiveRecord::Acts::Tree
include ActiveRecord::Acts::List
include ActiveRecord::Acts::NestedSet
include ActiveRecord::Calculations
include ActiveRecord::XmlSerialization
include ActiveRecord::AttributeMethods

# phew! time to actually code stuff up
end

So perhaps you don't care *how* the class methods were placed in the
parent class.

I would say:

* Define the class methods in the class itself if you only need them
for that class.

* Define the class methods in a common parent class if a strict
hierarchy suits your needs.

* Define the class methods in a module if you want to be able to pick
and choose which sets of class methods to bring into a particular
class.
 
 
 

standard, pretty, and flexible meta-methods?

Post by Greg Week » Sat, 10 Nov 2007 08:39:20


(I assume that "include" above is a typo for "extend".)

Thanks again. I don't know why I was obsessed with this issue, but it
is a relief to resolve it. (The "However ..." part was obvious, but you
couldn't know that without reading my mind.)

BTW, I just got a hold of "The Ruby Way" a couple minutes ago. The very
first words inside it are: "Among other things, this book excels at
explaining metaprogramming, one of the most interesting aspects of Ruby.
Many of the early ideas for Rails were inspired by the first edition,
especially what is now chapter 11..." -- David Heinemeier Hansson,
Creator of Ruby on Rails.

So, combine that with your responses, and I'm about as assuaged
as a curious person can be.

--
Posted via http://www.yqcomputer.com/
 
 
 

standard, pretty, and flexible meta-methods?

Post by Phrog » Sat, 10 Nov 2007 08:49:16


Nope, only because (as seen in my earlier post)
ActiveRecord::Validations has a hook method that detects when it has
been included in something else, and automagically calls 'extend's
that something else with the methods in the
ActiveRecord::Validations::ClassMethods module.
 
 
 

standard, pretty, and flexible meta-methods?

Post by Greg Week » Sat, 10 Nov 2007 15:32:25

Regarding:

module Associations
def self.included(base)
base.extend(ClassMethods)
end
...
module ClassMethods
def has_many(association_id, options = {}, &extension)
...
end
end
end

Sorry about my initial haste. I see now. Lessons learned (I hope):

- I must expect to see classy operations in instance method code.
- "define_method"
- the above "included" trick

Plus, of course, the concepts of A) extending a class object and B)
opening up Module.

Thanks again.

--
Posted via http://www.yqcomputer.com/