On Tue, 16 Aug 2005, Joe Van Dyk wrote:

> module JoeAccessors
>  class << self
>    def joe_accessor_method *args
>      args.each do |arg|
>        eval <<-src
>          def #{ arg }
>            @#{ arg }
>          end
>          def #{ arg }= value
>            @#{ arg } = value
>          end
>        src
>      end
>    end
>  end
> end
>
> class Joe
>  include JoeAccessors
>  joe_accessor_method :arg1, :arg2
> end
>
>> test.rb:21: undefined method `joe_accessor_method' for Joe:Class (NoMethodError)
>
> *bangs head against desk*

you're close - the issue is that including a module in another class/module
only inserts the __instance__ methods of the included module into the
class/module doing the reciever.  so, altough you've defined a class level
method correctly it doesn't make it into your new class.  there are a couple of
ways around that - you can do things like:

     module M
       def foo; 42; end
     end
     class C
       extend M
     end
     p C::foo #=> 42

but that only works if ALL the methods in M should be class methods - though
this is often the case where one is defining accessor type stuff in a module.
another approach is do define class level methods in the other class on the
fly and let the instance methods take care of themselves:

     module M
       def self::included other
         class << other
           def foo; 42; end
         end
       end
       def bar; 'forty-two'; end
     end
     class C
       include M
     end
     p C::foo #=> 42
     c = C::new
     p c.bar #=> 'forty-two'

what you can't do, however, is to define a class method in a module and then
somehow 'get it back' to inject it into the including class at runtime (well
you could but it'd be very ugly).  i've found this approach to be quite simple
and almost guaranteed to make sense to any developer that ever programmed an
object-oriented language instantly - even if they don't understand the
included method totally:

     harp:~ > cat b.rb
     module JoeAccessors

       module ClassMethods
         def joe_accessor_method *args
           args.each do |arg|
             module_eval <<-src
               def #{ arg }
                 @#{ arg }
               end
               def #{ arg }= value
                 @#{ arg } = value
               end
             src
           end
         end
       end

       module InstanceMethods
         # put em here
       end

       def self::included other
         other.extend ClassMethods
         other.module_eval{ include InstanceMethods }
       end
     end

     class Joe
       include JoeAccessors
       joe_accessor_method :arg1, :arg2
     end

     joe = Joe::new
     joe.arg1 = 42
     p joe.arg1



     harp:~ > ruby b.rb
     42

it's just a tiny bit clunky - but it makes it totally clear which methods are
which without any doccumentation or understanding of 'class << self' etc.

(note that you have to use 'module_eval' here.)

hth.

-a
-- 
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze.  --Nagarjuna
===============================================================================