Beginner's tutorial and poor attempt at classes

  • Thread starter Gabriel Dragffy
  • Start date
G

Gabriel Dragffy

Hi all

I just started with Ruby (yesterday actually). Have been reading the
amazing Poignant Guide, and also a couple of other very basic
tutorials. From one of these I wrote an example class, now my
knowledge of Ruby has expanded a little I tried to rewrite the class
to be even better. I thought that the method "setme" would allow the
@numberShowing to be changed to any number between 1 and 6... but
obviously not...?


#/usr/bin/env ruby

class Die
def initialize
roll
end

def roll
@numberShowing = 1 + rand(6)
end
def showing
@numberShowing
end

def setme value
if value === 1..6
@numberShowing = value
else
puts "A dice has only six sides!"
end
end

end



Best regards


Gabriel Dragffy

(e-mail address removed)
 
D

dblack

Hi --

Hi all

I just started with Ruby (yesterday actually). Have been reading the amazing
Poignant Guide, and also a couple of other very basic tutorials. From one of
these I wrote an example class, now my knowledge of Ruby has expanded a
little I tried to rewrite the class to be even better. I thought that the
method "setme" would allow the @numberShowing to be changed to any number
between 1 and 6... but obviously not...?


#/usr/bin/env ruby

class Die
def initialize
roll
end

def roll
@numberShowing = 1 + rand(6)
end
def showing
@numberShowing
end

def setme value
if value === 1..6
@numberShowing = value
else
puts "A dice has only six sides!"
end
end

end

You've got the === backwards; you want:

if (1..6) === value

or

if (1..6).include?(value)

Here's a little rewrite, using a reader attribute to streamline the
retrieval of the die's number:

class Die
attr_reader :number

def initialize
roll
end

def roll
self.number = rand(6) + 1
end

def number=(value)
if (1..6).include?(value)
@number = value
else
puts "A die has only six sides!"
end
end
end

With this, you can do things like:

die = Die.new
puts die.number
die.roll
puts die.number
die.number = 20 # A die has only six sides!

You could also make the number= method private, to discourage (though
not entirely prevent, since private doesn't do that) people from
setting the number manually.


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 
G

Gabriel Dragffy

Hi --



You've got the === backwards; you want:

if (1..6) === value

or

if (1..6).include?(value)

Thank you very much, these work a treat! I've got to now ask the
inevitable question - why do they work? What difference does it make
which side the things being compared are? I'm sure I'll come across
the answer myself as I continue to get better with Ruby, but I'd be
glad of an explanation sooner :)

Here's a little rewrite, using a reader attribute to streamline the
retrieval of the die's number:

class Die
attr_reader :number

def initialize
roll
end

def roll
self.number = rand(6) + 1
end

def number=(value)
if (1..6).include?(value)
@number = value
else
puts "A die has only six sides!"
end
end
end

With this, you can do things like:

die = Die.new
puts die.number
die.roll
puts die.number
die.number = 20 # A die has only six sides!

You could also make the number= method private, to discourage (though
not entirely prevent, since private doesn't do that) people from
setting the number manually.

An interesting rewrite and no-doubt far superior. I still struggling
with trying to identify the differences between self.???, @, and @@.
As far as Python goes I'd say I understand most all of Python's ways
of dealing with classes, these Ruby ones.... are gonna take some
time! Thanks again for your fast and comprehensive reply, it's much
appreciated.

Gabriel Dragffy

(e-mail address removed)
 
S

Stefano Crocco

Alle gioved=EC 2 agosto 2007, Gabriel Dragffy ha scritto:
Thank you very much, these work a treat! I've got to now ask the =A0
inevitable question - why do they work? What difference does it make =A0
which side the things being compared are? I'm sure I'll come across =A0
the answer myself as I continue to get better with Ruby, but I'd be =A0
glad of an explanation sooner :)

When ruby sees an operator, for instance a + b, it calls the corresponding=
=20
method of the first operand, the one on the left, passing the second operan=
d=20
as argument. So, a + b becomes:

a.+(b)

So the line

value =3D=3D=3D (1..6)

becomes

value.=3D=3D=3D((1..6))

value is an integer, so its =3D=3D=3D method returns true if the other oper=
and is a=20
number with the same value (at least, I think it does, since I haven't been=
=20
able to find any documentation on it). Instead, the line

(1..6) =3D=3D=3D value

becomes

(1..6).=3D=3D=3D(value)

and the =3D=3D=3D method of class range returns true if its argument is an =
element=20
of the range itself.

Another situation in which the order of the operands matters, is, for examp=
le,=20
when multiplying a string and a number:

'a' * 2 # this means 'a'.*(2)

returns the string 'aa', since the method * of class string returns a strin=
g=20
containing a number of copies of the receiver. On the other hand,=20

2 * 'a' # this means 2.*('a')

raises an exception, since the method * for a number only performs number=20
multiplication.

I hope this helps

Stefano
 
D

Drew Olson

Gabriel said:
I still struggling
with trying to identify the differences between self.???, @, and @@.

Gabriel -

I'll take a crack at trying to help you with these symbols.

@ - this designates an instance variable within an object. The value of
this variable differs between instances of the same class.

@@ - this is a class variable. The value of this variable is the same
between ALL instances of the same class.

self.* - this is used to declare class methods. You call these methods
directly on a class rather than using a instance of a class.

Below is a little irb session to demonstrate things a bit more:

irb(main):001:0> class Foo
irb(main):002:1> def initialize
irb(main):003:2> @inst = 0
irb(main):004:2> @@cls = 0
irb(main):005:2> end
irb(main):006:1> def increment_instance
irb(main):007:2> @inst += 1
irb(main):008:2> end
irb(main):009:1> def increment_class
irb(main):010:2> @@cls += 1
irb(main):011:2> end
irb(main):012:1> def print_stats
irb(main):013:2> puts "class var: #{@@cls}, instance var: #{@inst}"
irb(main):014:2> end
irb(main):015:1> def self.say_hello
irb(main):016:2> puts "Hello from a class method!"
irb(main):017:2> end
irb(main):018:1> end
=> nil
irb(main):019:0>
irb(main):020:0* one_foo = Foo.new
=> #<Foo:0x28d0f34 @inst=0>
irb(main):021:0> two_foo = Foo.new
=> #<Foo:0x28ced60 @inst=0>
irb(main):022:0>
irb(main):023:0* 2.times{ one_foo.increment_instance }
=> 2
irb(main):024:0> one_foo.increment_class
=> 1
irb(main):025:0>
irb(main):026:0* one_foo.print_stats
class var: 1, instance var: 2
=> nil
irb(main):027:0>
irb(main):028:0* two_foo.increment_instance
=> 1
irb(main):029:0> two_foo.increment_class
=> 2
irb(main):030:0>
irb(main):031:0* two_foo.print_stats
class var: 2, instance var: 1
=> nil
irb(main):032:0>
irb(main):033:0* Foo.say_hello
Hello from a class method!
=> nil

Welcome to ruby! (it's wayyyy better than python :)
 
D

Drew Olson

Drew said:
Gabriel -

I'll take a crack at trying to help you with these symbols.

Whoops! I should not be resetting the class variable inside initialize!
It doesn't effect the output of the previous example, though:

class Foo

@@cls = 0

def initialize
@inst = 0
end
def increment_instance
@inst += 1
end
def increment_class
@@cls += 1
end
def print_stats
puts "class var: #{@@cls}, instance var: #{@inst}"
end
def self.say_hello
puts "Hello from a class method!"
end
end
 
G

Gabriel Dragffy

Gabriel -

I'll take a crack at trying to help you with these symbols.

@ - this designates an instance variable within an object. The
value of
this variable differs between instances of the same class.

@@ - this is a class variable. The value of this variable is the same
between ALL instances of the same class.

self.* - this is used to declare class methods. You call these methods
directly on a class rather than using a instance of a class.

Below is a little irb session to demonstrate things a bit more:

irb(main):001:0> class Foo
irb(main):002:1> def initialize
irb(main):003:2> @inst = 0
irb(main):004:2> @@cls = 0
irb(main):005:2> end
irb(main):006:1> def increment_instance
irb(main):007:2> @inst += 1
irb(main):008:2> end
irb(main):009:1> def increment_class
irb(main):010:2> @@cls += 1
irb(main):011:2> end
irb(main):012:1> def print_stats
irb(main):013:2> puts "class var: #{@@cls}, instance var: #
{@inst}"
irb(main):014:2> end
irb(main):015:1> def self.say_hello
irb(main):016:2> puts "Hello from a class method!"
irb(main):017:2> end
irb(main):018:1> end
=> nil
irb(main):019:0>
irb(main):020:0* one_foo = Foo.new
=> #<Foo:0x28d0f34 @inst=0>
irb(main):021:0> two_foo = Foo.new
=> #<Foo:0x28ced60 @inst=0>
irb(main):022:0>
irb(main):023:0* 2.times{ one_foo.increment_instance }
=> 2
irb(main):024:0> one_foo.increment_class
=> 1
irb(main):025:0>
irb(main):026:0* one_foo.print_stats
class var: 1, instance var: 2
=> nil
irb(main):027:0>
irb(main):028:0* two_foo.increment_instance
=> 1
irb(main):029:0> two_foo.increment_class
=> 2
irb(main):030:0>
irb(main):031:0* two_foo.print_stats
class var: 2, instance var: 1
=> nil
irb(main):032:0>
irb(main):033:0* Foo.say_hello
Hello from a class method!
=> nil

Welcome to ruby! (it's wayyyy better than python :)



WOW! What a reply! This has got to be the single best thing for Ruby
- the peeps on this mailing list are awesome!! Very dry, unwelcoming,
and sometimes rude on the Python list - doesn't apply to everyone on
there, some peeps are dashing, but the majority...

Anyway. That example does make it somewhat clearer, thank you. I
think that all in all I do understand what these things are and what
they do, however, because I haven't come across them before I just
feel a little unsure when to use them, or even when it's best to use
them.

Oh one other thing I am liking more about ruby than python is the
different approaches taken by the languages. I'm starting to have
warm feelings for Ruby because it's more... human. I can write the
code using blocks, on one line, or whatever I deem best for that
particular item. I thought the compulsory white space in Python was
good, but it makes coding very 'rigid'. Well anyway, enough about
this Python vs Ruby thing, I obviously don't need to harp on about it
to the people on this list - you've already settled in the newfoundland!

I'm looking forward to the version of Ruby that gives you a .rbc :)
then things will be even faster!
 
I

Ilan Berci

Gabriel said:
On 2 Aug 2007, at 15:53, Drew Olson wrote:
Oh one other thing I am liking more about ruby than python is the
different approaches taken by the languages. I'm starting to have
warm feelings for Ruby because it's more... human. I can write the
code using blocks, on one line, or whatever I deem best for that
particular item. I thought the compulsory white space in Python was
good, but it makes coding very 'rigid'. Well anyway, enough about
this Python vs Ruby thing, I obviously don't need to harp on about it
to the people on this list - you've already settled in the newfoundland!

I'm looking forward to the version of Ruby that gives you a .rbc :)
then things will be even faster!


Gabriel Dragffy,

Welcome to the board, If I can make one suggestion, it would be to
refrain from direct comparisons to other languages as it invites flames
and trolls and may detract from your experience here on this forum.

Glad you came here however and this forum was one of the primary reasons
I fell in love with the language. Although it has been suggested that
many in the ruby upper echelon no longer post here, I have noticed that
many amazing developers have stepped up and have taken their place, so
of course I leech off of them every chance I get! :)

ilan
 
R

Robert Klemme

2007/8/2 said:
def number=(value)
if (1..6).include?(value)
@number = value
else
puts "A die has only six sides!"
end
end
end

Interesting that you do it that way. In the light of exception
handling, I would rather have done

def number=(v)
raise ArgumentError, "not a valid dice value: #{v}" unless (1..6).include? v
@number = v
end

Apparently everybody has different approaches. :)

Kind regards

robert
 
G

Gabriel Dragffy

Hi --



You've got the === backwards; you want:

if (1..6) === value

or

if (1..6).include?(value)

Here's a little rewrite, using a reader attribute to streamline the
retrieval of the die's number:

class Die
attr_reader :number

def initialize
roll
end

def roll
self.number = rand(6) + 1
end


Have been rereading your example. Just wanted to ask why in the code
just above did you use "self.number" which you changed from @number?

def number=(value)
if (1..6).include?(value)
@number = value
else
puts "A die has only six sides!"
end
end
end

and then here "@number" is used.. finding this a little confusing.
Thanks again, for all your help.
 
G

Gabriel Dragffy

Gabriel Dragffy,

Welcome to the board, If I can make one suggestion, it would be to
refrain from direct comparisons to other languages as it invites
flames
and trolls and may detract from your experience here on this forum.

Glad you came here however and this forum was one of the primary
reasons
I fell in love with the language. Although it has been suggested that
many in the ruby upper echelon no longer post here, I have noticed
that
many amazing developers have stepped up and have taken their place, so
of course I leech off of them every chance I get! :)

ilan

Thank you for your suggestion, Ilan, I'll certainly be more careful
in the future. I hope that I can learn a lot and have a good
experience from this community, and later start to give back and help
others when I'm more knowledgeable.

Regards

Gabriel
 
D

dblack

Hi --

Have been rereading your example. Just wanted to ask why in the code just
above did you use "self.number" which you changed from @number?



and then here "@number" is used.. finding this a little confusing. Thanks
again, for all your help.

The number= method does some data checking, and if all is well it sets
@number. I don't want to set @number directly, because the checking
won't happen. I guess rand(6) + 1 is pretty safe, but still, since my
setter method does more than just set @number, it's "polite" to go
through that method instead of just setting @number.


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 
G

Gabriel Dragffy

On 3 Aug 2007, at 19:21, (e-mail address removed) wrote:
[...SNIP...]

The number= method does some data checking, and if all is well it sets
@number. I don't want to set @number directly, because the checking
won't happen. I guess rand(6) + 1 is pretty safe, but still, since my
setter method does more than just set @number, it's "polite" to go
through that method instead of just setting @number.


Hi David

Thank you for your quick reply and help. I have to confess I'm being
quite dumb about this, I still don't understand 100% why one should
use self.number.... but I think that's something that I need to work
on and all will become clear as I become more familiar with Ruby as a
whole. I've bought on Amazon a book called Beginning Ruby, dunno if
it's any good, but I should received it tomorrow (fingers crossed!)
so I can study it over the weekend.

My full time job is a web programmer, I've got a couple of large
projects coming up, and because my boss is cool I can use any
language/framework I like. Naturally I've chosen Rails.... I hope to
get my Ruby up to speed for this, and I'll be needing a good RoR
book. I see that you yourself have authored some books. That's
awesome! Do you think your rails books would fit my needs? Also, is
there anywhere I can view several pages from it?


Best regards


Gabriel Dragffy

(e-mail address removed)
 
D

dblack

Hi --

On 3 Aug 2007, at 19:21, (e-mail address removed) wrote:
[...SNIP...]

The number= method does some data checking, and if all is well it sets
@number. I don't want to set @number directly, because the checking
won't happen. I guess rand(6) + 1 is pretty safe, but still, since my
setter method does more than just set @number, it's "polite" to go
through that method instead of just setting @number.


Hi David

Thank you for your quick reply and help. I have to confess I'm being quite
dumb about this, I still don't understand 100% why one should use
self.number.... but I think that's something that I need to work on and all
will become clear as I become more familiar with Ruby as a whole. I've bought
on Amazon a book called Beginning Ruby, dunno if it's any good, but I should
received it tomorrow (fingers crossed!) so I can study it over the weekend.

It's really just so the data filtering and checking will happen.
Here's another example -- a Person class where every new Person object
gets a name, and the name is stored in uppercase:

class Person
attr_reader :name

def initialize(name)
self.name = name.chomp
end

def name=(name)
@name = name.upcase
end
end

print "Name: "
name = gets
p = Person.new(name)

puts "Your name has been recorded as #{p.name}."

I could write initialize like this:

@name = name.chomp

But then I'd be bypassing the upcasing of the name. So by calling the
method, even from within other methods in the class, I'm respecting
the filtering that I've put in place.

Meanwhile, attr_reader :name gives me an automatic "reader" method.
Unlike the writer method (name=) I'm using the default, which will
just return the current value of the instance variable @name.
My full time job is a web programmer, I've got a couple of large projects
coming up, and because my boss is cool I can use any language/framework I
like. Naturally I've chosen Rails.... I hope to get my Ruby up to speed for
this, and I'll be needing a good RoR book. I see that you yourself have
authored some books. That's awesome! Do you think your rails books would fit
my needs? Also, is there anywhere I can view several pages from it?

At http://www.manning.com/black there are some sample chapters. I
think you'd get a lot out of the book, but I'll abstain and let the
chapters speak for themselves :)


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 
G

Gabriel Dragffy

Hi --



You've got the === backwards; you want:

if (1..6) === value

or

if (1..6).include?(value)


and I just discovered yet another way of getting to the same place!!
if value.between?(1, 6)

IMO the prettiest code to read, but which one *should* be used, or is
it all OK so long as it works?

Regards

Gabe
 
P

Pit Capitain

2007/8/4 said:
and I just discovered yet another way of getting to the same place!!
if value.between?(1, 6)

IMO the prettiest code to read, but which one *should* be used, or is
it all OK so long as it works?

Gabe, your version should be more efficient, because it doesn't create
a new Range object. So go for it!

Regards,
Pit
 

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

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,318
Members
47,998
Latest member
GretaCjy4

Latest Threads

Top