Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Quick module include question.

Reply
Thread Tools

Quick module include question.

 
 
Chris Eskow
Guest
Posts: n/a
 
      10-09-2005
------=_Part_18429_13903458.1128823698427
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

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=3Dnil
val =3D=3D nil ? @#{att} : @#{att} =3D 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 #=3D> "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?

Chris

------=_Part_18429_13903458.1128823698427--


 
Reply With Quote
 
 
 
 
Christophe Grandsire
Guest
Posts: n/a
 
      10-09-2005
En r=E9ponse =E0 Chris Eskow :
> Hi, I'm semi-new to Ruby and I have a question.
>=20
> I have a class, World, that basically looks like this:
>=20
> class World
>=20
> # 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=3Dnil
> val =3D=3D nil ? @#{att} : @#{att} =3D val
> end
> }
> end
> end
>=20
> # Now I can define some attributes.
> att :title, :author
>=20


This looks a lot like the traits library. You might want to look at it.

>=20
> 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:
>=20
> class World
> include Attributes
> att :title, :author
> end
>=20
> class Thing
> include Attributes
> att :name, :desc
> end
>=20
> 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?
>=20


What you need is the att method to become a class method rather than an=20
instance method, so that you can use it like one uses attr_accessor. To=20
do that, simply use "extend" instead of "include":
class World
extend Attributes
att :title, :author
end

Another way that uses metaclasses indeed is to include your module in=20
the metaclass of the class:
class OtherWorld
class <<self
include Attributes
end
att :title, :author
end

I'm not aware of any difference between those two ways.
--=20
Christophe Grandsire.

http://rainbow.conlang.free.fr

You need a straight mind to invent a twisted conlang.


 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      10-09-2005
Chris Eskow <(E-Mail Removed)> 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

=> #<Object:0x10192dc8>
>> class<<o
>> 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<<self;self;end
>> a.each {|at| cl.send(:attr_accessor,at)}
>> end
>> end

=> nil
>> o=Object.new

=> #<Object:0x10164808>
>> 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

=> <OpenStruct>
>> o.name="bar"

=> "bar"
>> o.name

=> "bar"


Kind regards

robert


 
Reply With Quote
 
Chris Eskow
Guest
Posts: n/a
 
      10-10-2005
------=_Part_27645_15304138.1128911235631
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

To Christophe Grandsire:

I tried both suggestions but I still can't get them to work. Could you
elaborate futher?

To Robert Klemme:

I know about attr_*, but this is a bit different: instead of using
"attr=3Dval" to set an attribute, this uses "attr val" (val being an
argument). I'd rather do it this way because the seemingly miniscule
improvement in looks gets a lot nicer looking in the particular instance
that I'm using it in:

world do
title "A Title"
author "An Author"
end

world is a method that creates a World object and instance_evals the block.
Now, if I were to just use "attr_accessor :title, :author", I would have to
do this:

world do
@title =3D "A Title"
@author =3D "An Author"
end

That's a lot uglier and a bit more obtrusive. If you haven't guessed
already, I'm making a text adventure. I'd like the story-definition DSL to
look as clean as possible. Yes, I know about the recent Ruby Quiz entry, bu=
t
I'm trying not to look at the solutions' code too much or else I'd be
tempted to copy...

Chris

------=_Part_27645_15304138.1128911235631--


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Why does Module#include exclude the module's metaclass? John Mair Ruby 8 10-07-2010 12:29 PM
include module in module Ittay Dror Ruby 2 12-08-2008 12:03 PM
How to exec a module method when "include Module" from a Class ? IƱaki Baz Castillo Ruby 3 05-02-2008 09:37 AM
/* #include <someyhing.h> */ => include it or do not include it?That is the question .... Andreas Bogenberger C Programming 3 02-22-2008 10:53 AM
include Module in another Module Brian Buckley Ruby 3 02-20-2007 05:32 AM



Advertisments