Beginner's tutorial and poor attempt at classes


#1

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

removed_email_address@domain.invalid


#2

Hi –

On Thu, 2 Aug 2007, Gabriel D. wrote:

#/usr/bin/env ruby
@numberShowing
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


#3

On 2 Aug 2007, at 15:18, removed_email_address@domain.invalid wrote:

class to be even better. I thought that the method “setme” would

else
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 :slight_smile:

end
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 D.

removed_email_address@domain.invalid


#4

Alle giovedì 2 agosto 2007, Gabriel D. ha scritto:

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 :slight_smile:

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

a.+(b)

So the line

value === (1…6)

becomes

value.===((1…6))

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

(1…6) === value

becomes

(1…6).===(value)

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

Another situation in which the order of the operands matters, is, for
example,
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
string
containing a number of copies of the receiver. On the other hand,

2 * ‘a’ # this means 2.*(‘a’)

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

I hope this helps

Stefano


#5

Gabriel D. wrote:

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 :slight_smile:


#6

Drew O. wrote:

Gabriel D. wrote:

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.

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


#7

On 2 Aug 2007, at 15:53, Drew O. wrote:

this variable differs between instances of the same class.
irb(main):002:1> def initialize
irb(main):013:2> puts "class var: #{@@cls}, instance var: #
irb(main):021:0> two_foo = Foo.new
irb(main):027:0>
Hello from a class method!
=> nil

Welcome to ruby! (it’s wayyyy better than python :slight_smile:

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 :slight_smile:
then things will be even faster!


#8

Gabriel D. wrote:

On 2 Aug 2007, at 15:53, Drew O. 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 :slight_smile:
then things will be even faster!

Gabriel D.,

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! :slight_smile:

ilan


#9

2007/8/2, removed_email_address@domain.invalid removed_email_address@domain.invalid:

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. :slight_smile:

Kind regards

robert


#10

On 3 Aug 2007, at 15:49, Ilan B. wrote:

good, but it makes coding very ‘rigid’. Well anyway, enough about
Welcome to the board, If I can make one suggestion, it would be to
of course I leech off of them every chance I get! :slight_smile:

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


#11

Hi –

On Sat, 4 Aug 2007, Gabriel D. wrote:

amazing Poignant Guide, and also a couple of other very basic tutorials.
roll
if value === 1…6
if (1…6) === value

above did you use “self.number” which you changed from @number?

end

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


#12

On 2 Aug 2007, at 15:18, removed_email_address@domain.invalid wrote:

class to be even better. I thought that the method “setme” would

else
or
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.


#13

On 3 Aug 2007, at 19:21, removed_email_address@domain.invalid wrote:
[…SNIP…]

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.

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

removed_email_address@domain.invalid


#14

Hi –

On Sat, 4 Aug 2007, Gabriel D. wrote:

end
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 :slight_smile:

David


#15

On 2 Aug 2007, at 15:18, removed_email_address@domain.invalid wrote:

class to be even better. I thought that the method “setme” would

else
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


#16

2007/8/4, Gabriel D. removed_email_address@domain.invalid:

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