Quick module include question.

C

Chris Eskow

------=_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--
 
C

Christophe Grandsire

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

Robert Klemme

Chris Eskow said:
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:
=> "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
=> # said:
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.
=> "bar"


Kind regards

robert
 
C

Chris Eskow

------=_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--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top