More newbie help with classes and methods please

I posted a question a week or so now which I got some great help with.
Here I am again I'm afraid! What I am now struggling with is how to add
help. What I want is if the user gets the input wrong three times, I'd
like to print to print

Press 'h' for help
h
You must enter your age as two digits. i.e if you are twenty five, type 25.

here is the original method:

···

-----------------------------------------------
def check_age
  print "Please enter your age: "
  age = gets.chomp
  target = 18..30
  valid = /^\d{2}/

  if valid.match(age)
    if target === age.to_i
      puts 'Have a nice holiday!'
    elsif age.to_i < 18
      puts 'Sorry, too young.'
    elsif age.to_i > 30
      puts 'Sorry, too old.'
    end
  else
    puts 'Incorrect input.'
    puts
    check_age # Try again
  end
end

check_age
gets
---------------------------------------------------

Should I create a class and add a 'show_help' method (putting the
'check_age' method in there as well)? If so, how/where do I call that
method? The method in the above code calls itself. I am a complete
programming newbie by the way.

Maybe we could expand this program to help other new programmers like
myself? The jukebox example in Pickaxe2 seems to fizzle out.

My suggestion would be to add that behavior right when you are getting
the user input. Add a check at the beggining, and keep it out if the
if statement.

Also, I would change the if/elsif statements to a case statement. The
case statement is perfect for what you are trying to do.

Dan

···

On 7/18/06, simonh <simonharrison@fastmail.co.uk> wrote:

I posted a question a week or so now which I got some great help with.
Here I am again I'm afraid! What I am now struggling with is how to add
help. What I want is if the user gets the input wrong three times, I'd
like to print to print

> Press 'h' for help
> h
> You must enter your age as two digits. i.e if you are twenty five, type 25.

here is the original method:
-----------------------------------------------
def check_age
  print "Please enter your age: "
  age = gets.chomp
  target = 18..30
  valid = /^\d{2}/

  if valid.match(age)
    if target === age.to_i
      puts 'Have a nice holiday!'
    elsif age.to_i < 18
      puts 'Sorry, too young.'
    elsif age.to_i > 30
      puts 'Sorry, too old.'
    end
  else
    puts 'Incorrect input.'
    puts
    check_age # Try again
  end
end

check_age
gets
---------------------------------------------------

Should I create a class and add a 'show_help' method (putting the
'check_age' method in there as well)? If so, how/where do I call that
method? The method in the above code calls itself. I am a complete
programming newbie by the way.

Maybe we could expand this program to help other new programmers like
myself? The jukebox example in Pickaxe2 seems to fizzle out.

A couple of things:

First, as Daniel already said, why not put the information right in the
loop? However, don't go recursive there, I'd do a loop instead:

age = 0
target_age = 30..65 # :wink:
while ! target === age
  print "Please enter your age: (as two digits): "
  result = gets
  age = result.chomp.to_i
  case age
  when age < 30
    puts 'Sorry, too young.'
  when age > 75
     puts 'Sorry, too old.'
  else
     puts 'Hava a nice holiday!'
     return age
  end
  puts "Remember, age must be entered as two digits, e.g. 35"
end

check_age

Thanks for replies. Just to point out, this code is not meant for
anything in particular, just an example to help me learn ruby. I wanted
to understand recursion better which I now do. Also to understand
ranges and if statements too. What I'm trying to do here is understand
how to branch inside a method.

What are the benefits of using case instead of if? I was going to look
at case a bit later on. The commented code below is what I've tried but
it does not work too well. if i type 21 its says 'have a nice holiday!'
then 'Incorrect Input' and prompts me again.

···

-----------------------------------------------------------------------
def check_age
  print "Please enter your age (or type 'h' for help): "
  age = gets.chomp
  target = 18..30
  valid = /^\d{2}/
# if age == 'h'
  # puts
   # puts "Example: if you are twenty five, type 25"
   # puts
   # check_age
  #end

  if valid.match(age)
    if target === age.to_i
      puts 'Have a nice holiday!'
    elsif age.to_i < 18
      puts 'Sorry, too young.'
    elsif age.to_i > 30
      puts 'Sorry, too old.'
    end
  else
    puts "Incorrect input."
    puts
    check_age # Try again
  end
end

check_age
gets

Hi --

A couple of things:

First, as Daniel already said, why not put the information right in the
loop? However, don't go recursive there, I'd do a loop instead:

age = 0
target_age = 30..65 # :wink:
while ! target === age

s/target/target_age/ Also, "until" is a nicer way to do while ! .

print "Please enter your age: (as two digits): "
result = gets
age = result.chomp.to_i

No need to chomp:

   age = gets.to_i

case age
when age < 30

Hang on.... Remember that a case statement works like this:

   case a
   when b

is equivalent to:

   if b === a

So what you've got is:

   if (age < 30) === age

which is going to be either:

   if true === age

or

   if false === age

Neither of those is ever true when age is an integer, so the test will
never succeed.

A simple if construct will work fine:

   if age < 30
     ...
   elsif age > 75
     ...
   else
     ...
   end

   puts 'Sorry, too young.'
when age > 75
    puts 'Sorry, too old.'
else
    puts 'Hava a nice holiday!'
    return age
end
puts "Remember, age must be entered as two digits, e.g. 35"
end

check_age

No such method :slight_smile:

David

···

On Wed, 19 Jul 2006, S Wayne wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

decided to have a go at using the case statement. Why won't this work?

···

-------------------------------------------------------------------------------------
def double_it
  print "Please enter a whole number (or type 'h' for help) : "
  num = gets.chomp
  case num
    when num == 'h'
      puts
      puts "A whole number is 45 for example, or 12564."
      puts
    when num.to_i > 1
      num * num
      print num.to_s
    when num.to_i <= 0
      puts "The number must be positive!"
  end
end
double_it
gets
--------------------------------------------------------------------------------------

Hi --

decided to have a go at using the case statement. Why won't this work?

-------------------------------------------------------------------------------------
def double_it
print "Please enter a whole number (or type 'h' for help) : "
num = gets.chomp
case num
   when num == 'h'
     puts
     puts "A whole number is 45 for example, or 12564."
     puts
   when num.to_i > 1
     num * num

What's that for?

     print num.to_s
   when num.to_i <= 0
     puts "The number must be positive!"
end
end
double_it
gets

Do you really mean to end with gets?

As for the case statement: have a look at my previous post in this
thread. The problem is that you're comparing:

    num

with the expression:

    num == 'h'

Then you're comparing it with the expression "num.to_i > 1", and so
on.

A case statement isn't a good fit here; I'd just use if/else/.../end.

David

···

On Wed, 19 Jul 2006, simonh wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

There are two forms of case block and you have sort of mixed them up. Either of the following defs of double_it will work. I think the first, using a case without a target, is probably what you want, but the second, a case with a target (compares target to pattern with ===), can be made to work, too.

Hope this helps.

def double_it
   print "Please enter a whole number (or type 'h' for help) : "
   num = gets.chomp
   case
     when num == 'h'
       puts "A whole number is 45 for example, or 12564."
       double_it
     when (n = num.to_i) > 1
       puts n * 2 # doubling not squaring
     else
       puts "Input must be positive number!"
       double_it
   end
end
double_it
print "Press any key to exit: "
STDIN.getc

def double_it
   print "Please enter a whole number (or type 'h' for help) : "
   num = gets.chomp
   case num
     when 'h'
       puts "A whole number is 45 for example, or 12564."
       double_it
     when /^[^-]\d+/
       puts num.to_i * 2 # doubling not squaring
     else
       puts "Input must be positive number!"
       double_it
   end
end
double_it
print "Press any key to exit: "
STDIN.getc

Regards, Morton

···

On Jul 19, 2006, at 5:05 AM, simonh wrote:

decided to have a go at using the case statement. Why won't this work?

-------------------------------------------------------------------------------------
def double_it
  print "Please enter a whole number (or type 'h' for help) : "
  num = gets.chomp
  case num
    when num == 'h'
      puts
      puts "A whole number is 45 for example, or 12564."
      puts
    when num.to_i > 1
      num * num
      print num.to_s
    when num.to_i <= 0
      puts "The number must be positive!"
  end
end
double_it
gets
--------------------------------------------------------------------------------------

Thanks David. Great book by the way. Easier for a beginner than
pickaxe. Ever considered writing a 'Ruby Projects' book. Start with
some simple program ideas and build them up to something useful?
Demonstrating all the syntax/conventions of Ruby. I'm happy to put down
a deposit!

Anyway,

> case age
> when age < 30

Hang on.... Remember that a case statement works like this:

   case a
   when b

is equivalent to:

   if b === a

So what you've got is:

   if (age < 30) === age

which is going to be either:

   if true === age

or

   if false === age

Neither of those is ever true when age is an integer, so the test will
never succeed.

I don't quite understand I'm afraid. I have a variable I want to check
a number of conditions against. Can't i do this with the case
expression? Further explanation would be greatly appreciated.

A simple if construct will work fine:

   if age < 30
     ...
   elsif age > 75
     ...
   else
     ...
   end

Thats what I thought! What is the main advantage of case over if? Or
when would you be more likely to use one than the other?

> puts 'Sorry, too young.'
> when age > 75
> puts 'Sorry, too old.'
> else
> puts 'Hava a nice holiday!'
> return age
> end
> puts "Remember, age must be entered as two digits, e.g. 35"
> end
>
> check_age

No such method :slight_smile:

I tried wrapping that code in a method and got an error. The main thing
I am trying to understand is where to put the code to print out help.

Hi --

There are two forms of case block and you have sort of mixed them up. Either of the following defs of double_it will work. I think the first, using a case without a target, is probably what you want, but the second, a case with a target (compares target to pattern with ===), can be made to work, too.

That's a more thorough answer than mine, since I didn't think of the
non-targeted case. But I realize that I never think of it, because
I'm not clear on what its advantages are over a bunch of ifs. I guess
with multiple things you can do:

   case
   when a == 1, a == 2

etc.

David

···

On Wed, 19 Jul 2006, Morton Goldberg wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

I end with gets because I'm on Windows which usually shuts the window
immediately unless gets is there.

I view case without a target as a fancy, more compact, and (IMHO) more readable if-elsif-else block. Because it is more compact and more readable, I prefer it to if-elsif-else and tend to favor it. I may be influenced by some years of doing Common Lisp programming -- I was quite fond of cond.

Regards, Morton

···

On Jul 19, 2006, at 6:42 AM, dblack@wobblini.net wrote:

Hi --

On Wed, 19 Jul 2006, Morton Goldberg wrote:

There are two forms of case block and you have sort of mixed them up. Either of the following defs of double_it will work. I think the first, using a case without a target, is probably what you want, but the second, a case with a target (compares target to pattern with ===), can be made to work, too.

That's a more thorough answer than mine, since I didn't think of the
non-targeted case. But I realize that I never think of it, because
I'm not clear on what its advantages are over a bunch of ifs. I guess
with multiple things you can do:

  case
  when a == 1, a == 2

etc.

David

would this be an example of using case:

case favourite_colour
when white
  print 'white'
when blue
  print 'blue'
when orange
  print 'orange'
end

instead of

var = favourite_colour
if white
print 'white'
elsif blue
print 'blue'
...
end

Hi --

I view case without a target as a fancy, more compact, and (IMHO) more readable if-elsif-else block. Because it is more compact and more readable, I prefer it to if-elsif-else and tend to favor it. I may be influenced by some years of doing Common Lisp programming -- I was quite fond of cond.

I'm not sure about its being more compact, unless you've got multiple
conditions in one when. Compare:

   if a == 1
     ...
   elsif a == 2
     ...
   else
     ...
   end

with:

   case
   when a == 1
     ...
   when a == 2
     ...
   else
     ...
   end

In any, ummmm, case... :slight_smile: I'm glad to be reminded of it. Do you use
it when things get more deeply nested?

David

···

On Wed, 19 Jul 2006, Morton Goldberg wrote:

On Jul 19, 2006, at 6:42 AM, dblack@wobblini.net wrote:

Hi --

On Wed, 19 Jul 2006, Morton Goldberg wrote:

There are two forms of case block and you have sort of mixed them up. Either of the following defs of double_it will work. I think the first, using a case without a target, is probably what you want, but the second, a case with a target (compares target to pattern with ===), can be made to work, too.

That's a more thorough answer than mine, since I didn't think of the
non-targeted case. But I realize that I never think of it, because
I'm not clear on what its advantages are over a bunch of ifs. I guess
with multiple things you can do:

case
when a == 1, a == 2

etc.

David

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

fr morton:
# I view case without a target as a fancy, more compact, and (IMHO)
# more readable if-elsif-else block. Because it is more compact and
# more readable, I prefer it to if-elsif-else and tend to favor it. I
# may be influenced by some years of doing Common Lisp

me, too. if i ever need an elsif, i'd go then for the case block. i never did liked the "elsif" keyword (reminds me too of *nix scripts w if-fi blocks :). but that is just me :slight_smile:

Hi --

would this be an example of using case:

case favourite_colour
when white

Assuming that:

   white === favourite_colour

returned a useful value.

print 'white'
when blue
print 'blue'
when orange
print 'orange'
end

instead of

var = favourite_colour
if white
print 'white'
elsif blue
print 'blue'
...
end

In the second example you're not testing var; you're just testing
the values white and blue. So it's hard to compare it to the case
statement.

A case statement is basically a wrapper for a bunch of "if" tests --
but the wrapper has very specific behavior: it runs the === method on
each term in succession, with the cased object as the argument:

   case a
   when b # if b === a
     ...
   when c,d # if (c === a) || (d === a)

etc.

When you're doing a comparison that doesn't have a === equivalent,
you'll generally need a plain "if".

David

···

On Wed, 19 Jul 2006, simonh wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

fr david:
# I'm not sure about its being more compact, unless you've got multiple
# conditions in one when. Compare:

···

#
# if a == 1
# ...
# elsif a == 2
# ...
# else
# ...
# end
#
# with:
#
# case
# when a == 1
# ...
# when a == 2
# ...
# else
# ...
# end

when i use it, i think more in "blocks". it's like "there's a case i'm handling, and the conditions are...".

# In any, ummmm, case... :slight_smile: I'm glad to be reminded of it. Do you use
# it when things get more deeply nested?

i combine it w if-else (no elsif)

kind regards -botp

I try (not always successfully) to avoid deeply nested constructs. When I can't escape nesting, rather than directly nesting, I favor writing something like:

def case_A
   case
   when ...
   end
end

def case_B
   case
   when ...
   end
end

case
when condition_A then case_A
when condition_B then case_B
end

Regards, Morton

···

On Jul 19, 2006, at 7:06 AM, dblack@wobblini.net wrote:

In any, ummmm, case... :slight_smile: I'm glad to be reminded of it. Do you use
it when things get more deeply nested?

Hi --

fr david:
# I'm not sure about its being more compact, unless you've got multiple
# conditions in one when. Compare:
#
# if a == 1
# ...
# elsif a == 2
# ...
# else
# ...
# end
#
# with:
#
# case
# when a == 1
# ...
# when a == 2
# ...
# else
# ...
# end

when i use it, i think more in "blocks". it's like "there's a case i'm handling, and the conditions are...".

# In any, ummmm, case... :slight_smile: I'm glad to be reminded of it. Do you use
# it when things get more deeply nested?

i combine it w if-else (no elsif)

Here's another interesting usage (with target, but sort of in the
non-targeted spirit):

a = 1

case false
when a == 1
   puts "a is not 1"
when a == 2
   puts "a is not 2"
end

I imagine that would get some readability complaints... :slight_smile: But I
kind of like it because once you get "false" in your head it's easier
to follow, possibly, than a lot of unless/! stuff.

David

···

On Wed, 19 Jul 2006, Peña, Botp wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

fr david:
# Here's another interesting usage (with target, but sort of in the
# non-targeted spirit):

···

#
# a = 1
#
# case false
# when a == 1
# puts "a is not 1"
# when a == 2
# puts "a is not 2"
# end
#
# I imagine that would get some readability complaints... :slight_smile: But I
# kind of like it because once you get "false" in your head it's easier
# to follow, possibly, than a lot of unless/! stuff.

lol.

you are weird :slight_smile: Not only do i get cross-eyed, i get my left-brain twisted w right. Though shall not combine targets with conditions :slight_smile:

kind regards -botp