assigning a method result to a variable in ruby - ruby

I'm sure it would be hard to find an easier question, but I'm a complete newbie. I have searched extensively and for some reason can't find the answer to this. Here's my code:
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
if x == "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
elsif x == "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
I'm just trying to get the returned result of the method into a variable so I can use it elsewhere....

Remember that calls like ctof temp just initiate a method and then, as you're not putting the result anywhere, discard it immediately.
To clean up this code let's organize it better:
# Temperature conversion method
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
# User input method
def temperature_prompt!
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
case (x)
when "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
when "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
end
Now you can make use of the fact that in Ruby things like if and case actually return values. In this case it's the value of the last thing to execute in each block, so that result isn't discarded, it's just passed along:
temp = temperature_prompt!
If you enter an invalid value you get the result of puts which is conveniently nil.
Here's something to consider: Ruby is very good at parsing arbitrary text if you can describe the patterns. Here's a simple input routine:
def temperature_prompt!
puts "Enter degrees (e.g. 8F, 2C)"
case (input = gets.chomp.downcase)
when /(\d+)f/
ftoc $1
when /(\d+)c/
ctof $1
else
puts "That does not compute."
end
end
You could add to those patterns to allow things like -2C and 3.4°F if you wanted.

Related

Can this be optimized without using a global variable?

I've recently begun learning ruby and I'm trying to avoid using global variables where possible. I wrote the below program which accepts user input and outputs math tables of the users choice (currently just +, * but to be expanded upon). I'm following suggestions from https://adriann.github.io/programming_problems.html to get me learning.
class User_input
.
# multiply
def User_input.mult1_to_12
by = (0..12).each do | range |
result = $choice_int * range
puts "#{$choice_int} x #{range} = #{result}"
end
end
# add
def User_input.add1_to_12
add = (0..12).each do | range |
result = $choice_int + range
puts "#{$choice_int} + #{range} = #{result}"
end
end
# accepts user input
puts "Please enter the tables you require (1-12): "
$choice_int = gets.to_i
puts "You have selected #{$choice_int}"
puts "Which tables do you require (+ - * /): "
choice_method = gets.chomp
puts "the method you have chosen is #{choice_method}"
if choice_method == "*"
User_input.mult1_to_12
elsif
choice_method == "+"
add1_to_12
end
end
You will note that I am currently using a global variable for $choice. Can someone with more experience suggest a more optimal solution. Please feel free to tear my code apart : ) Thanks.
Methods can accept parameters, for example:
# add numbers
def add(a,b)
a+b
end
puts add(1,2)
# will output 3
Here's a simple modification to your code using parameters:
class UserInput
# multiply
def self.mult1_to_12(choice_int)
(0..12).each do | range |
result = choice_int * range
puts "#{choice_int} x #{range} = #{result}"
end
end
# add
def self.add1_to_12(choice_int)
(0..12).each do | range |
result = choice_int + range
puts "#{choice_int} + #{range} = #{result}"
end
end
end
# accepts user input
puts "Please enter the tables you require (1-12): "
choice_int = gets.to_i
puts "You have selected #{choice_int}"
puts "Which tables do you require (+ - * /): "
choice_method = gets.chomp
puts "the method you have chosen is #{choice_method}"
if choice_method == "*"
UserInput.mult1_to_12(choice_int)
elsif choice_method == "+"
UserInput.add1_to_12(choice_int)
end
And here's a bit prettier solution that can also handle - and / (and a bunch of other operations provided by Ruby's Fixnum):
class UserInputProcessor
# define accessors to instance variables
attr_accessor :choice_int, :choice_method
def process
(0..12).map do |range|
if choice_method.eql?('/')
next if range.eql?(0) # need to skip X/0 to avoid division by zero
range = range.to_f # need to convert range to float to get float results
end
"#{choice_int} #{choice_method} #{range.to_i} = #{choice_int.send(choice_method, range)}"
end
end
end
handler = UserInputProcessor.new
print "Please enter the tables you require (1-12): "
handler.choice_int = gets.chomp.to_i
puts "You have selected #{handler.choice_int}"
print "Which tables do you require (+ - * /): "
handler.choice_method = gets.chomp
puts "the method you have chosen is #{handler.choice_method}"
puts "And here are the results:"
puts handler.process.join("\n")

Conversion to integer isn't executing?

i have this code :
#require_relative '../lib/hackex/net/typhoeus'
require_relative '../lib/hackex'
require 'rubygems'
require 'faker'
print "how many farms do you want : "
choice = gets.chomp
choice.to_i
check = choice.is_a?(Integer)
puts check
if choice > 250
puts "Error! you cannot make more than 250 farms at once"
elsif choice < 250
puts "Error! you have to make at least one farm..."
elsif choice.is_a?(Integer) == false
puts "Error, something went wrong !"
else
puts "making #{choice} acounts ! ! !"
cnt = 1
while choice>cnt
gen = Faker::Name.first_name + Faker::Name.last_name
path=("created1.txt")
email = gen+'#gmail.com'
password = Faker::Internet.password(8)
username = gen.to_s+'/>'
puts HackEx::Request.Do(http,HackEx::Request.CreateUser(username, email, password, facebook_id = nil))
cnt +=1
open(path, 'a') { |f|
f << "#{email};"
f << "#{password}"
f << "\n"
}
puts "Account created!"
puts "#{choice - cnt} accounts remaining!"
end
end
i am trying to determing if the choice is an integer... i did the .to_i on choice, but it returns false, meaning its not an integer, its a string, why isnt it switching ?
ps : i do not get any errors, and the rest of the code works fine, except for the if part
choice.to_i returns an integer, but does not change choice. If you want choice to be changed to the integral value of the old choice, you need to reassign it explicitly:
choice = choice.to_i
Quoting the doc of String::to_i, emphasis is mine
to_i(base=10) → integer
Returns the result of interpreting leading characters in str as an
integer base base (between 2 and 36).
So you have to assign the return to something, or itself:
choice = choice.to_i

Looking for help cleaning up code

This is for an assignment for a class. I want to create a register type application for a donut shop. The application should accept "l" to list flavors, "a" to add flavors, "d" to delete flavors, and "e" to exit. The prices should be listed in ascending order. When adding a flavor, it should ask first the flavor, then the price.
I have the application working. It uses Jekyll (what the class uses).
item = {}
item_asc = {}
puts "Welcome to d0nutz flavor menu"
input = ""
division_line = lambda {30.times {|x| print "="}}
while input != "e"
division_line.call
puts "\n(l)ist flavors\n(a)dd a flavor\n(d)elete a flavor\n(e)xit application"
division_line.call
print "\nYour choice: "
input = gets.chomp
case input
when "l"
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
when "a"
puts "Enter new flavor: "
flavor = gets.chomp
puts "Enter cost: "
cost = gets.chomp.to_i
item[flavor] = cost
item_asc = item.sort_by {|flavor,price| price}
input = ""
when "d"
puts "Enter a flavor to remove"
to_delete = gets.chomp
item.delete("#{to_delete}") {|x| puts "#{x} not found."}
item_asc = item.sort_by {|flavor,price| price}
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
input = ""
when "e"
else
puts "\nThat is not a recognised command"
end
end
However it's even uglier than what I have here. I appreciate any input. I am interested in seeing what I should have done for clean up purposes, and maybe adding classes/methods where they should be, and making this more Rubyesque.
I would change the code to the following. This is not refactor since it is not equivalent to your code. In particular, it is not inconsistent like your code is. For example, when it prompts, it does not sometimes change a line and sometimes not as in your code; My code never changes a line. My code also always prints the list after an operation, unlike your code, which does not do so particularly when an item is added. Also, unlike your code, it does not end a message sometimes with and sometimes without a period; Messages in my code never end with period.
def prompt s
print "#{s}: "
gets.chomp
end
def list_items
#items.each{|k, v| puts "Flavor: #{k} - Cost: $#{v}"}
end
def sort_items
#items = #items.sort_by{|flavor, price| price}.to_h
list_items
end
puts "Welcome to d0nutz flavor menu"
#items = {}
loop do
puts(
?= * 30,
"(l)ist flavors",
"(a)dd a flavor",
"(d)elete a flavor",
"(e)xit application",
?= * 30,
)
case prompt("Your choice")
when ?l
list_items
when ?a
#items[prompt("Enter new flavor")] = prompt("Enter cost").to_i
sort_items
when ?d
#items.delete(prompt("Enter a flavor to remove")){|k| puts "#{k} not found"}
sort_items
when ?e
break
else
puts "That is not a recognised command"
end
end

Variables not matching in if/else statement

I am creating a method that makes you solve random math problems. Code is below:
def subtraction()
puts "Your goal is to solve the math problem."
# Asks if user is ready
ready()
a = rand(0..5)
b = rand(0..5)
c = a - b
puts "what is #{a} - #{b}?"
prompt; next_move = gets.chomp
if next_move == c
puts "Lucky guess!"
water()
elsif next_move != c
puts "The answer was: #{c}"
dead("You suck at life")
else
dead("You didn't type anything")
end
end
I keep trying to run this and I keep getting the elsif option. Even though my variables match when I check with puts statements. I am not moving in the direction I want to. What am I doing wrong?
Change
next_move = gets.chomp
to
next_move = gets.chomp.to_i # gets.to_i will work also.
Kernel#gets will give you string, and you need to convert it to appropriate object as per your need, if your work is not with string object like this example. As per the line c = a - b, I am very much sure, you need to change your string object, that you are getting from stdin to an integer object. So you have to use String#to_i.

How to create a terminal calculator program in ruby?

So far I've got
puts "Enter a calculation: "
calc = gets.chomp
def add(a, b)
puts a + b
end
puts add(calc)
And now I'm ashamed to admit but I'm stumped, I've tried writing add methods etc... but I just can't seem to wrap my head around getting this to calculate and output the correct results.
To simplify this, how can I get the ability to add working?
I.E user enters calculation (2 integers), program adds the
calculation, program outputs results, program asks for another
calculation.
I think this kind of script is perfect for a case statement. Here's a first pass that works with binary operators:
#! /usr/bin/ruby
def calc
puts "Calculator 1.0 \nEnter 'q' to quit."
while true
print ">> "
str = gets.chomp.split(" ") # splits into array, rejects blanks
return if str[0] == 'q' # quit if first element is 'q'
operand1 = str[0].to_i
operand2 = str[2].to_i
operator = str[1].to_sym
case operator
when :+ then puts operand1 + operand2
when :- then puts operand1 - operand2
when :* then puts operand1 * operand2
when :/ then puts operand1 / operand2
when :% then puts operand1 % operand2
else
puts "invalid input"
end
end
end
if __FILE__ == $0 # if run as script, start calc: see http://j.mp/HOTGq8
calc
end
Then, at the command line:
$ ./calc.rb
Calculator 1.0
Enter 'q' to quit.
>> 55 / 5
11
>> 90 / 10
9
>> 5 * 3093
15465
Good luck!
These are great resources if you're just starting out: RubyMonk Codecademy
Just think of your problem one step at a time. You want the user to provide to integers. So start with a simple prompt, like you have already done:
puts "Enter your first value"
Now get the value from the user:
firstVal = gets.chomp
Now provide another prompt, and get a second value.
puts "Enter your second value"
secVal = gets.chomp
And output your results:
puts "#{firstVal} + #{secVal} = #{firstVal.to_i + secVal.to_i}"
Sometimes just writing it out plain and simple is the easiest first step. Now you can create an add function to do this more efficiently. Try it out, and see if you have any luck!
EDIT:
Also, I noticed your add function takes two parameters, but you are only passing it one.
In order to call a function with two parameters, you need two values to provide it with. For example:
x = 5
y = 2
def add(a, b)
return a + b
end
puts add(x, y)
I know this is a bit older post, but people do still find this answer and I want to add to what jkrmr said above.
The code jkrmr posted is great but does not handle floating point calculations and that was an easy fix so I added that functinoality. :-)
#! /usr/bin/ruby
def calc
puts "Calculator 1.1 \nEnter 'q' to quit."
while true
print ">> "
str = gets.chomp.split(" ") # splits into array, rejects blanks
return if str[0] == 'q' # quit if first element is 'q'
if str[0].include? "."
operand1 = str[0].to_f
else
operand1 = str[0].to_i
end
operator = str[1].to_sym
if str[2].include? "."
operand2 = str[2].to_f
else
operand2 = str[2].to_i
end
case operator
when :+ then puts operand1 + operand2
when :- then puts operand1 - operand2
when :* then puts operand1 * operand2
when :/ then puts operand1 / operand2
when :% then puts operand1 % operand2
else
puts "invalid input"
end
end
end
if __FILE__ == $0 # if run as script, start calc: see http://j.mp/HOTGq8
calc
end
Here's a quick little calculator I whipped up to help you get started:
#! /usr/bin/ruby
def add(a, b)
a + b
end
while(true) do
puts "Enter a calculation: "
# chomp off the \n at the end of the input
calc = gets.chomp
# quit if the user types exit
exit if calc.include?("exit")
# puts the result of the add function, taking input of calc "split" into two numbers
puts add(calc.split("").first.to_i, calc.split("").last.to_i)
# spacing
puts
end
To build on that. If you want to continue to recieve calculation requests you can put the process in a loop(among many solutions).
while true
puts 'Enter Val 1'
v1 = gets.chomp.to_i
puts 'Enter Val 2'
v2 = gets.chomp.to_i
puts "#{v1} + #{v2} = #{v1+v2} "
end

Resources