Beginner's tutorial and poor attempt at classes

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

gabe@dragffy.com

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

···

On Thu, 2 Aug 2007, Gabriel Dragffy wrote:

--
* 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)

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)

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:

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

gabe@dragffy.com

···

On 2 Aug 2007, at 15:18, dblack@rubypal.com wrote:

On Thu, 2 Aug 2007, Gabriel Dragffy wrote:

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

···

2007/8/2, dblack@rubypal.com <dblack@rubypal.com>:

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

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

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.

···

On 2 Aug 2007, at 15:18, dblack@rubypal.com wrote:

On Thu, 2 Aug 2007, Gabriel Dragffy wrote:

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)

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

···

On 2 Aug 2007, at 15:18, dblack@rubypal.com wrote:

Hi --

On Thu, 2 Aug 2007, Gabriel Dragffy wrote:

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)

Alle giovedì 2 agosto 2007, Gabriel Dragffy 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

Gabriel Dragffy 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:

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

···

On Sat, 4 Aug 2007, Gabriel Dragffy wrote:

On 2 Aug 2007, at 15:18, dblack@rubypal.com wrote:

Hi --

On Thu, 2 Aug 2007, Gabriel Dragffy wrote:

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

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.

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)

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

Regards,
Pit

···

2007/8/4, Gabriel Dragffy <gabe@dragffy.com>:

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?

Drew Olson wrote:

Gabriel Dragffy 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

···

--
Posted via http://www.ruby-forum.com/\.

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!

···

On 2 Aug 2007, at 15:53, Drew Olson wrote:

Gabriel Dragffy 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:

[...SNIP...]

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.

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

gabe@dragffy.com

···

On 3 Aug 2007, at 19:21, dblack@rubypal.com wrote:

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

ilan

···

On 2 Aug 2007, at 15:53, Drew Olson wrote:

--
Posted via http://www.ruby-forum.com/\.

Hi --

[...SNIP...]

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

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.

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 Ruby for Rails 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

···

On Sat, 4 Aug 2007, Gabriel Dragffy wrote:

On 3 Aug 2007, at 19:21, dblack@rubypal.com wrote:

--
* 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)

Gabriel Dragffy 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 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! :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

···

On 3 Aug 2007, at 15:49, Ilan Berci wrote:

On 2 Aug 2007, at 15:53, Drew Olson wrote: