Ruby Class question


#1

Hi all,

I am really starting to get into ruby and I am currently reading the
PickAxe book and the Agile Rails book, but there is one part of classes
that I don’t understand and I can’t seem to find any reference to it.

Here is a basic class as defined in the Pickaxe book:

1: class Song
2: attr_writer :duration
3: end

My question is, what is the whole statement on line #2? I know what it
does, it creates a attribute-setting method for the “duration” variable,
but what I don’t understand is how it does it. When does that line of
code get executed?

I am used to doing classes in C++ and PHP where the only thing outside
methods and inside a class are class variable declarations. Is this a
way to make variable declarations with a method?

This seems to be a very common construct in Ruby and I want to
understand what it is and how to use it correctly. Thanks

Peer


#2

Peer A. wrote:

3: end
This seems to be a very common construct in Ruby and I want to
understand what it is and how to use it correctly. Thanks

In Ruby, objects interact with other objects my sending messages.
Messages usually (but not always) map to methods; methods in turn can
manipulate instance variables.

Instance variables (the @foo things) are private, but if you want to
create the appearance that an object has public properties, you can
create methods that match the instance variables:

def foo
@foo
end

def foo=( val )
@foo=val
end

This is such a common convention that Ruby has a method that writes
these methods for you:

attr_accessor :foo

This take symbol :foo and uses it to create the pair of methods that
reference an instance variable of the same name.

Note that you can always create such methods by hand, and the names need
not match the internal variables; such properties are just methods
calls:

Create the appearance of a “public property” called ‘foo’

def foo
@bar
end

def foo=( val )
@bar=val
end

And you can add whatever code you like to these methods.

A few things to note:

Ruby methods usually return the value of the last expression evaluated,
but methods that end with ‘=’ do not follow this; they return the value
passed to the method.

When you use attr_accessor, attr_reader, or attr_writer to create these
methods, RDoc will list them as attributes, not as methods; they will
not appear in the list of methods in the class’s RDoc.

(If you create the exact same methods by hand, though, RDoc treats them
as methods.)

James B.

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - The Journal By & For Rubyists
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys
http://www.30secondrule.com - Building Better Tools


#3

Peer A. wrote:

3: end

My question is, what is the whole statement on line #2? I know what it
does, it creates a attribute-setting method for the “duration” variable,
but what I don’t understand is how it does it. When does that line of
code get executed?

James already answered the question pretty well, I just want to address
the “when does that line get executed?” question.
It is executed when the class is ‘parsed’. For example:

irb(main):001:0> class A
irb(main):002:1> puts “Hello!”
irb(main):003:1> end
Hello!
=> nil

Notice that “Hello!” appears immediately after I define the class and it
gets parsed. So the attr_writer() method (it is really just a method,
not special syntax) is executed while your class is being defined and
adds a method to your class for you. You can execute any ol’ code you
wanted within the class definition, as shown above.

Also, the attr* methods DO NOT declare any variables. They only create
methods to access those variables.

irb(main):001:0> class A
irb(main):002:1> attr_reader :something
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> #<A:0x40223968>
irb(main):005:0> a.instance_variables
=> []
irb(main):006:0> a.methods.sort
=> ["==", “===”, “=~”, “id”, “send”, “class”, “clone”,
“display”, “dup”, “eql?”, “equal?”, “extend”, “freeze”, “frozen?”,
“hash”, “id”, “inspect”, “instance_eval”, “instance_of?”,
“instance_variable_get”, “instance_variable_set”, “instance_variables”,
“is_a?”, “kind_of?”, “method”, “methods”, “nil?”, “object_id”,
“private_methods”, “protected_methods”, “public_methods”, “respond_to?”,
“send”, “singleton_methods”, “something”, “taint”, “tainted?”, “to_a”,
“to_s”, “type”, “untaint”]

Notice the method called “something” which was defined by attr_reader
:something.

Hope that helps.

-Justin


#4

Peer A. wrote:

… I did not
realize that the code within the class definition gets executed, rather
than just defined. Neat!

Yes, it’s actually very neat – you can put almost anything in there:

class Foo
if condition? then
def bar(arg1, arg2)

end
end

 [:foo, :bar, :baz].each do |name|
   define_method(name){ puts name.inspect }
 end

end

Cheers,
Daniel


#5

Peer A. wrote:

Hello!
=> nil

Thanks for the explanations. This is what I was looking for. I did not
realize that the code within the class definition gets executed, rather
than just defined. Neat!

It’s a subtle point, though.

For example, there have been threads here on some issues that arise when
you do not control the order in which files are loaded.

You may see this idiom a lot, too:

if FILE == $0

Some code …

end

This checks to see if the file has been loaded directly, rather than
being included in another file. It is a way to wrap stuff (such as unit
tests or command line interaction) that should not execute if the
source file is being used by as part of a larger application


James B.

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - The Journal By & For Rubyists
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.30secondrule.com - Building Better Tools


#6

Justin C. wrote:

James already answered the question pretty well, I just want to address
the “when does that line get executed?” question.
It is executed when the class is ‘parsed’. For example:

irb(main):001:0> class A
irb(main):002:1> puts “Hello!”
irb(main):003:1> end
Hello!
=> nil

Thanks for the explanations. This is what I was looking for. I did not
realize that the code within the class definition gets executed, rather
than just defined. Neat!

Thanks again,

Peer