Standard, pretty, and flexible meta-methods?

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-forum.com/.

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-methods.html

···

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?)

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

···

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?)

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)

···

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?)

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-forum.com/\.

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

···

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.

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.

···

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:

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-forum.com/\.

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.

···

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

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-forum.com/.