more newbie help with classes and methods please

S

simonh

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

Daniel Hollocher

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
 
S

S Wayne

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 # ;)
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
 
S

simonh

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
 
S

simonh

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

dblack

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 # ;)
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 :)


David

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
D

dblack

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

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
S

simonh

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,
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?

No such method :)


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

simonh

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

simonh

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
 
D

dblack

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

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
M

Morton Goldberg

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
 
D

dblack

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

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
M

Morton Goldberg

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
 
D

dblack

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... :) I'm glad to be reminded of it. Do you use
it when things get more deeply nested?


David

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
http://www.manning.com/black => RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) => me
 
P

Peña, Botp

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

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 :)
 
P

Peña, Botp

fr david:
# I'm not sure about its being more compact, unless you've got multiple
# conditions in one when. Compare:
#=20
# if a =3D=3D 1
# ...
# elsif a =3D=3D 2
# ...
# else
# ...
# end
#=20
# with:
#=20
# case
# when a =3D=3D 1
# ...
# when a =3D=3D 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... :) 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
 
D

dblack

---2049402039-1706185909-1153308072=:2285
Content-Type: MULTIPART/MIXED; BOUNDARY="-2049402039-1706185909-1153308072=:2285"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---2049402039-1706185909-1153308072=:2285
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Hi --

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

when i use it, i think more in "blocks". it's like "there's a case i'm ha=
ndling, and the conditions are...".
# In any, ummmm, case... :) 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 =3D 1

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

I imagine that would get some readability complaints... :) 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

--=20
http://www.rubypowerandlight.com =3D> Ruby/Rails training & consultancy
http://www.manning.com/black =3D> RUBY FOR RAILS (reviewed on
Slashdot, 7/12/2006!)
http://dablog.rubypal.com =3D> D[avid ]A[. ]B[lack's][ Web]log
(e-mail address removed) =3D> me
---2049402039-1706185909-1153308072=:2285--
---2049402039-1706185909-1153308072=:2285--
 
P

Peña, Botp

fr david:
# Here's another interesting usage (with target, but sort of in the
# non-targeted spirit):
#=20
# a =3D 1
#=20
# case false
# when a =3D=3D 1
# puts "a is not 1"
# when a =3D=3D 2
# puts "a is not 2"
# end
#=20
# I imagine that would get some readability complaints... :) 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 :) Not only do i get cross-eyed, i get my left-brain =
twisted w right. Though shall not combine targets with conditions :)

kind regards -botp
 
S

simonh

Very helpful reply Morton. Understand case a lot more now. One thing.
STDIN.getc
what exactly is STDIN? Does it belong to a class or is it a constant?
looking through ri I noticed that Kernel.getc is now obsolete. Any idea
why this is?

cheers
 

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

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,127
Latest member
CyberDefense
Top