[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

standard, pretty, and flexible meta-methods?

Greg Weeks

11/8/2007 7:58:00 PM

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.ruby-....

9 Answers

Phrogz

11/8/2007 8:06:00 PM

0

On Nov 8, 12:57 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
> 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?)


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://redcorundum.blogspot.com/2006/06/mixing-in-class-me...

Phrogz

11/8/2007 8:15:00 PM

0

On Nov 8, 12:57 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
> 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?)

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)

Gary Wright

11/8/2007 8:18:00 PM

0


On Nov 8, 2007, at 2:57 PM, Greg Weeks wrote:
> 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?)

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





Greg Weeks

11/8/2007 8:45:00 PM

0

Wow, what a rush of information, eg:

Gavin Kistner wrote:
> define_method( name ){

"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.ruby-....

Phrogz

11/8/2007 9:30:00 PM

0

On Nov 8, 1:44 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
> 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.

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



Phrogz

11/8/2007 9:39:00 PM

0

On Nov 8, 2:29 pm, Phrogz <phr...@mac.com> wrote:
> On Nov 8, 1:44 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
>
> > 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.
>
> It's what Rails and its component libraries mostly do. For example:

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.

Greg Weeks

11/8/2007 11:39:00 PM

0

Gavin Kistner wrote:
> 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

(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.ruby-....

Phrogz

11/8/2007 11:49:00 PM

0

On Nov 8, 4:39 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
> > class Person
> > include ActiveRecord::Validations
>
> (I assume that "include" above is a typo for "extend".)

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.

Greg Weeks

11/9/2007 6:32:00 AM

0

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.ruby-....