From: Robert Klemme Date: 2005-10-09T18:21:50+09:00 Subject: Re: Quick module include question. Chris Eskow wrote: > Hi, I'm semi-new to Ruby and I have a question. > > I have a class, World, that basically looks like this: > > class World > > # Convenience method that takes one or more symbols and defines an > # accessor+mutator method for each one. > def self.att *atts > atts.each do |att| > class_eval %{ > def #{att} val=nil > val == nil ? @#{att} : @#{att} = val > end > } > end > end > > # Now I can define some attributes. > att :title, :author > > # Other methods here... > > end > > ..which allows me to do things like this: > > world.title "My Title" > world.title #=> "My Title" > > The att method creates an instance method that sets an attribute if > an argument is given, or returns it if no arguments are given. This > is nice and all, but now I want to use this att method with another > class. Since it's very short I could just copy and paste it, but I'd > rather use a module, Attributes, that I could include into any class: > > class World > include Attributes > att :title, :author > end > > class Thing > include Attributes > att :name, :desc > end > > I'm having trouble getting it to work, however. I have a feeling I > have to use metaclasses or something, but I'm not quite sure how I'm > suppose to do that. Everything I tried resulted in "undefined method > `att'" errors. Any thoughts? You're basically reimplementing attr_accessor, attr_reader, attr_writer and attr. These come predefined and you can even use them on an instance level: >> o=Object.new => # >> class<> attr_accessor :name >> end => nil >> o.name="foo" => "foo" >> o.name => "foo" Of course you can wrap that in an instance method: >> class Object >> def att(*a) >> cl=class<> a.each {|at| cl.send(:attr_accessor,at)} >> end >> end => nil >> o=Object.new => # >> o.att :name => [:name] >> o.name="foo" => "foo" >> o.name => "foo" Also note that if you use OpenStruct you don't even need to define attributes - you can just use them. >> require 'ostruct' => true >> o=OpenStruct.new => >> o.name="bar" => "bar" >> o.name => "bar" Kind regards robert