Newbie: It works, how can I make it better?

I wrote this little prog giving the user two choices.

I would really appreciate any advice on how I can improve anything about
this program (structure, layout, etc)

Many thanks!

Code:

···

-----
# Name: 2choices-jb.rb
# Date: December 2006
# Author: Jason Bornhoft
# Email: jbornhoft@gmail.com

puts ""
puts "Conversion Program"
puts "------------------\n"

puts "Would you like to convert:"
puts "1. F to C"
puts "2. C to F"
puts"Enter your choice now: "
choice = gets.chomp.to_i

if choice == 1
  puts "Enter a temperature in F:"
  fahr = gets.chomp.to_f
  cent = ( (fahr - 32) / 1.8 )
  puts fahr.to_s + " F is " + cent.round.to_s + " C."

elsif choice == 2
  puts "Enter a temperature in C:"
  cent = gets.chomp.to_f
  fahr = ( (cent * 1.8) + 32 )
  puts cent.to_s + " C is " + fahr.round.to_s + " F."
else
  puts "That is a not a valid choice. Good bye!"
end

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

One mini-advice would be that there is no need for

puts ""

puts alone should be enough.

If you want, you can design a mini class for this.

Normally, especially in other languages, this is
overkill for simple programs :wink:
But in ruby its nice and easy enough. And maybe practise for you.

···

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

Jay Bornhoft wrote:

I wrote this little prog giving the user two choices.

I would really appreciate any advice on how I can improve anything about
this program (structure, layout, etc)

Many thanks!

Code:
-----
# Name: 2choices-jb.rb
# Date: December 2006
# Author: Jason Bornhoft
# Email: jbornhoft@gmail.com

puts ""
puts "Conversion Program"
puts "------------------\n"

puts "Would you like to convert:"
puts "1. F to C"
puts "2. C to F"
puts"Enter your choice now: "
choice = gets.chomp.to_i

if choice == 1
  puts "Enter a temperature in F:"
  fahr = gets.chomp.to_f
  cent = ( (fahr - 32) / 1.8 )
  puts fahr.to_s + " F is " + cent.round.to_s + " C."

elsif choice == 2
  puts "Enter a temperature in C:"
  cent = gets.chomp.to_f
  fahr = ( (cent * 1.8) + 32 )
  puts cent.to_s + " C is " + fahr.round.to_s + " F."
else
  puts "That is a not a valid choice. Good bye!"
end

print "
Conversion Program

···

------------------
Would you like to convert:
1. F to C
2. C to F
Enter your choice now: "

case gets.to_i
  when 1
    print "Enter a temperature in F: "
    fahr = gets.to_f
    cent = ( (fahr - 32) / 1.8 )
    puts fahr.to_s + " F is " + cent.round.to_s + " C."

  when 2
    print "Enter a temperature in C: "
    cent = gets.to_f
    fahr = ( (cent * 1.8) + 32 )
    puts "#{ cent } C is #{ fahr.round } F."

  else
    puts "That is a not a valid choice. Good bye!"
end

--- A more interesting way. -----

print "
Conversion Program
------------------
Would you like to convert:
1. F to C
2. C to F
Enter your choice now: "

def convert( from, to, func )
  print "Enter a temperature in #{from}: "
  temp = gets.to_f
  puts "#{temp} #{from} is #{func[temp].round} #{to}."
end

case gets.to_i
  when 1
    convert( "F", "C", proc{|f| (f - 32) / 1.8 } )
  when 2
    convert( "C", "F", proc{|f| f * 1.8 + 32 } )
  else
    puts "That is a not a valid choice. Good bye!"
end

puts ""
puts "Conversion Program"
puts "------------------\n"

puts "Would you like to convert:"
puts "1. F to C"
puts "2. C to F"
puts"Enter your choice now: "
choice = gets.chomp.to_i

if choice == 1
  puts "Enter a temperature in F:"
  fahr = gets.chomp.to_f
  cent = ( (fahr - 32) / 1.8 )
  puts fahr.to_s + " F is " + cent.round.to_s + " C."

elsif choice == 2
  puts "Enter a temperature in C:"
  cent = gets.chomp.to_f
  fahr = ( (cent * 1.8) + 32 )
  puts cent.to_s + " C is " + fahr.round.to_s + " F."
else
  puts "That is a not a valid choice. Good bye!"
end

I'm using Ruby, but I'll take a stab at it (learn from my mistakes).

Well, I started off OK (using classes for temp conversion) and then things got ugly (probably putting too much in the manager class).

At any rate, here it is. (aka, here's how not to do it. :wink:

#! /usr/bin/env ruby

class TemperatureConverter
   attr_reader :from_unit, :to_unit, :conversion

   def initialize( from_unit='', to_unit='', conversion=proc {|x| x } )
     @from_unit = from_unit
     @to_unit = to_unit
     @conversion = conversion
   end

   def convert( arg )
     @conversion.call( arg )
   end
end

class FahrenheitToCelsiusConverter < TemperatureConverter
   def initialize
     super( 'F', 'C', proc {|f| (f - 32.0) / 1.8 } )
   end
end

class CelsiusToFahrenheitConverter < TemperatureConverter
   def initialize
     super( 'C', 'F', proc {|c| (c * 1.8) + 32 } )
   end
end

class TemperatureConversionManager
   attr_reader :prompt
   def initialize( *converters )
     @converters = converters
     @prompt = <<END_OF_PROMPT

Conversion Program

···

------------------
Would you like to convert:
END_OF_PROMPT

     index = 0
     @prompt += @converters.map do |converter|
       "#{index += 1}. #{converter.from_unit} to #{converter.to_unit}"
     end.join( "\n" )
     @prompt += "\nEnter your choice now: "
   end

   def run
     print prompt
     user_choice = choose_converter - 1
     if user_choice < 0 or user_choice >= @converters.size
       puts "That is not a valid choice. Goodbye."
     else
       prompt_and_display_conversion( @converters[ user_choice ] )
     end
   end

   def choose_converter
     gets.chomp.to_i
   end

   def get_temperature
     gets.chomp.to_f
   end

   def temperature_prompt( converter )
     "Please enter temperature in #{converter.from_unit}: "
   end

   def prompt_and_display_conversion( converter )
     print temperature_prompt( converter )
     user_input = get_temperature
     converted_temp = converter.convert( user_input )
     puts <<END_OF_RESULTS
#{user_input} #{converter.from_unit} is #{converted_temp} #{converter.to_unit}
END_OF_RESULTS
   end
end

TemperatureConversionManager.new(
   FahrenheitToCelsiusConverter.new,
   CelsiusToFahrenheitConverter.new
).run

Corrections / advice / criticisms are welcome.
(I think that I prefer the original version.)

Richard

Since you're doing a single conversion only, you could as well use command line arguments. I have also added automatic detection of the conversion direction with Fahrenheit being the default input value using regular expressions. You could use that technique in an interactive version as well thus improving usability (because you do have to enter one value only vs. two values).

Sample execution

$ ruby cf.rb 10c "10 f" 20

Temperature conversion

+10.0C is -12.2F
+10.0F is +50.0C
+20.0F is +68.0C

Kind regards

  robert

puts <<HEAD

Temperature conversion

HEAD

ARGV.each do |val|
   case val
     when /^(\d+)(?:\s*f)?$/i
       celsius = $1.to_f
       printf "%+3.1fF is %+3.1fC\n", celsius, (celsius * 1.8) + 32
     when /^(\d+)\s*c$/i
       fahrenheit = $1.to_f
       printf "%+3.1fC is %+3.1fF\n", fahrenheit, (fahrenheit - 32) / 1.8
     else
       $stderr.puts "ERROR: could not convert '#{val}'"
   end
end

···

On 30.12.2006 21:02, Jay Bornhoft wrote:

I wrote this little prog giving the user two choices.

I would really appreciate any advice on how I can improve anything about
this program (structure, layout, etc)

else
  puts "That is a not a valid choice. Good bye!"
end

Thank you all for your guidance... and now I have another question...
If instead of ending the program for an invalid choice...

How do I loop back to the beginning of the program to let them make a
valid choice?

Thx, J

···

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

William James wrote:

def convert( from, to, func )
  print "Enter a temperature in #{from}: "
  temp = gets.to_f
  puts "#{temp} #{from} is #{func[temp].round} #{to}."
end

case gets.to_i
  when 1
    convert( "F", "C", proc{|f| (f - 32) / 1.8 } )
  when 2
    convert( "C", "F", proc{|f| f * 1.8 + 32 } )
  else
    puts "That is a not a valid choice. Good bye!"
end

Err... why not make it a block?

def convert( from, to )
   print "Enter a temperature in #{from}: "
   temp = gets.to_f
   puts "#{temp} #{from} is #{yield(temp).round} #{to}."
end

case gets.to_i
   when 1
     convert( "F", "C") {|f| (f - 32) / 1.8 }
   when 2
     convert( "C", "F") {|f| f * 1.8 + 32 }
   else
     puts "That is a not a valid choice. Good bye!"
end

Also, check out http://highline.rubyforge.org/ for your prompting needs.

Devin

puts ""
puts "Conversion Program"
puts "------------------\n"

puts "Would you like to convert:"
puts "1. F to C"
puts "2. C to F"
puts"Enter your choice now: "
choice = gets.chomp.to_i

if choice == 1
  puts "Enter a temperature in F:"
  fahr = gets.chomp.to_f
  cent = ( (fahr - 32) / 1.8 )
  puts fahr.to_s + " F is " + cent.round.to_s + " C."

elsif choice == 2
  puts "Enter a temperature in C:"
  cent = gets.chomp.to_f
  fahr = ( (cent * 1.8) + 32 )
  puts cent.to_s + " C is " + fahr.round.to_s + " F."
else
  puts "That is a not a valid choice. Good bye!"
end

I'm using Ruby, but I'll take a stab at it (learn from my mistakes).

Well, I started off OK (using classes for temp conversion) and then things got ugly (probably putting too much in the manager class).

At any rate, here it is. (aka, here's how not to do it. :wink:

#! /usr/bin/env ruby

class TemperatureConverter
  attr_reader :from_unit, :to_unit, :conversion

  def initialize( from_unit='', to_unit='', conversion=proc {|x| x } )
    @from_unit = from_unit
    @to_unit = to_unit
    @conversion = conversion
  end

  def convert( arg )
    @conversion.call( arg )
  end
end

class FahrenheitToCelsiusConverter < TemperatureConverter
  def initialize
    super( 'F', 'C', proc {|f| (f - 32.0) / 1.8 } )
  end
end

class CelsiusToFahrenheitConverter < TemperatureConverter
  def initialize
    super( 'C', 'F', proc {|c| (c * 1.8) + 32 } )
  end
end

class TemperatureConversionManager
  attr_reader :prompt
  def initialize( *converters )
    @converters = converters
    @prompt = <<END_OF_PROMPT

Conversion Program
------------------
Would you like to convert:
END_OF_PROMPT

    index = 0
    @prompt += @converters.map do |converter|
      "#{index += 1}. #{converter.from_unit} to #{converter.to_unit}"
    end.join( "\n" )
    @prompt += "\nEnter your choice now: "
  end

  def run
    print prompt
    user_choice = choose_converter - 1
    if user_choice < 0 or user_choice >= @converters.size
      puts "That is not a valid choice. Goodbye."
    else
      prompt_and_display_conversion( @converters[ user_choice ] )
    end
  end

  def choose_converter
    gets.chomp.to_i
  end

  def get_temperature
    gets.chomp.to_f
  end

  def temperature_prompt( converter )
    "Please enter temperature in #{converter.from_unit}: "
  end

  def prompt_and_display_conversion( converter )
    print temperature_prompt( converter )
    user_input = get_temperature
    converted_temp = converter.convert( user_input )
    puts <<END_OF_RESULTS
#{user_input} #{converter.from_unit} is #{converted_temp} #{converter.to_unit}
END_OF_RESULTS
  end
end

TemperatureConversionManager.new(
  FahrenheitToCelsiusConverter.new,
  CelsiusToFahrenheitConverter.new
).run

Corrections / advice / criticisms are welcome.
(I think that I prefer the original version.)

Richard

s/^I'm using Ruby/I'm new to using Ruby/

Sorry.

Not according to units:

$ units
2438 units, 71 prefixes, 32 nonlinear units

You have: tempC(10)
You want: tempF
        50
You have: tempF(10)
You want: tempC
        -12.222222
You have: tempF(20)
You want: tempC
        -6.6666667

I think you may have your formulae backwards.

-jonathan

···

On Sun, 31 Dec 2006 14:57:34 +0100 Robert Klemme <shortcutter@googlemail.com> wrote:

Temperature conversion

+10.0C is -12.2F
+10.0F is +50.0C
+20.0F is +68.0C

Jay Bornhoft wrote:

> else
> puts "That is a not a valid choice. Good bye!"
> end

Thank you all for your guidance... and now I have another question...
If instead of ending the program for an invalid choice...

How do I loop back to the beginning of the program to let them make a
valid choice?

Thx, J

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

Seems to me the easiest way to go back would be to use just what you
said - a loop. A while loop would probably suffice, perhaps something
like the following:

while (line = gets) != "quit"
  case line
  # set of where statements
end

rwtnorton@charter.net wrote:

Corrections / advice / criticisms are welcome.
(I think that I prefer the original version.)

Me too. I like your heredoc usage, but overall it's too much gold
plating, looks like java to me. I would feel the pain of the next guy
to maintain this. All the meat would have to be recompressed into one
paragraph.
-R

Devin Mullins wrote:

Err... why not make it a block?

Why did you write "Err..."? Writing is a different process from
speaking. Making inarticulate noises when speaking provides
time to marshal one's thoughts. Imitating this when writing
is simply sarcastic, rude, and insolent---but you probably
knew that already.

A newbie may find +yield+ harder to understand than +proc+.

Devin Mullins wrote:

> Err... why not make it a block?

Why did you write "Err..."? Writing is a different process from
speaking. Making inarticulate noises when speaking provides
time to marshal one's thoughts. Imitating this when writing
is simply sarcastic, rude, and insolent---but you probably
knew that already.

Jesus. And I thought **I** needed to get laid.

A newbie may find +yield+ harder to understand than +proc+.

Well, that is quite possible.

···

On 12/30/06, William James <w_a_x_man@yahoo.com> wrote:

--
Giles Bowkett
http://www.gilesgoatboy.org

http://gilesgoatboy.blogspot.com

William James wrote:

Devin Mullins wrote:

Err... why not make it a block?

Why did you write "Err..."? Writing is a different process from
speaking. Making inarticulate noises when speaking provides
time to marshal one's thoughts. Imitating this when writing
is simply sarcastic, rude, and insolent---but you probably
knew that already.

No, I didn't know that, and I wouldn't be offended if you "Err"ed me. I deliberately write in a vocal style. I find it more fun. Funner.

(Well, in this case, let's assume "Err..." means "Maybe I'm missing the obvious here, but..." Happy?)

Devin