How to solve ruby string [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm new to ruby, and I'm trying to make a simple calculator in which a user types in a simple problem (such as addition or subtraction) and the answer is returned. The problem is when the user types in a question, the question itself is being returned instead of the answer to that question.
puts "How many Questions?"
questions = gets.chomp.to_i
questions.times do |problem|
puts "question: "
problem = gets.chomp
puts "answer: #{problem}"
end

Inside your loop, instead of:
problem = gets.chomp
puts "answer: #{problem}"
Try this:
problem = gets.chomp
solved_problem = eval(problem)
puts "answer : #{solved_problem}"
eval will take care of interpreting your string as a Ruby instruction. But it's very messy, because anyone could write any Ruby program in your input and eval will make it run, so it's not safe at all.
If you only want to take care of simple operations, you can use a regex first to check if the input string looks like what you want:
problem_is_ok = (problem =~ /^\d+ *[+-] *\d+$/)
This will be true if the string starts with a number, followed by 0 to many spaces, followed by either a + or - sign, followed by 0 or more spaces, followed by another number and nothing else. Then you raise an error if this is not true.
Your loop now look like this:
questions.times do |problem|
puts "question: "
problem = gets.chomp
problem_is_ok = (problem =~ /^\d+ *[+-] *\d+$/)
if problem_is_ok
puts "answer: #{eval(problem)}"
else
#I raise an error, but you might aswell just print it instead for your simple program
raise ArgumentError("Can't compute this")
end
end

Add and subtract can be simple ruby definitions
We pass in 5 and 1
The lower portion of the code is the clear user interface implementation
when we loop we do it 3 times
It outputs 3 options for the user to select from
We read in with chomp, standard in, the keyboard, chooses 1, 2, or 3
If elsif statements conditionally select for each case
Using string interpolation we render the variables a and b into a new string,
and run their respective methods (add or subtract)
Converting that methods integer output to a string, and concatenate it.
Outputting that to the users screen
The 3rd option does no calculation,
instead it prints to users screen a simple string
our else condition catches the case when people don't enter one of the choices of 1, 2 or 3
It tells you to correct your choice to the options provided
Hope this helps
#!/usr/bin/env ruby
questions = 3
a, b = 5, 1
def add(a,b)
a + b
end
def subtract(a,b)
a - b
end
questions.times do |questions|
puts "Please choose:
1. add
2. subtract
3. exit"
questions = gets.chomp
if questions == '1'
puts "#{a} + #{b} = " + add(a,b).to_s
elsif questions == '2'
puts "#{a} - #{b} = " + subtract(a,b).to_s
elsif questions == '3'
puts 'exiting, goodbye.'
exit
else
p 'please choose again'
end
end

Related

Ruby, `puts` doesn't print anything [duplicate]

This question already has answers here:
Why does Ruby's 'gets' includes the closing newline?
(5 answers)
Closed 2 years ago.
I'm new to writing in Ruby and I have this assignment for my Programming Languages class where I have to implement Mergesort into Ruby such that the user can enter an array of their own choice of numbers and end with a -1. I thought I had everything written in correctly, there are no bugs being reported, but the program doesn't print anything out.
Here's the important part of the code:
puts "Please enter as many numbers as you would like followed by -1"
Many_Numbers = Array.new
x_1 = '-1'
while gets != x_1
Many_Numbers.push gets
end
sorted = merge_sort(Many_Numbers)
puts "SORTED CORRECTLY: #{sorted == Many_Numbers.sort}\n\n#{Many_Numbers}\n\n#{sorted}"
Like I said, nothing is printed out, not even what is provided in the puts methods, so I have nothing to present for an error. What am I doing wrong, here?
EDIT:
I edited the code after I had an idea to improve this part of the code but I still got nothing.
This is what I changed
puts "Please enter as many numbers as you would like followed by -1"
Many_Numbers = Array.new
input = gets
while input != -1
case response
when input != -1
Many_Numbers.push(input)
when input == -1
end
end
You have a couple of problems with your input code.
gets returns all the user input, which includes the newline. So, your loop condition is comparing "-1" to "-1\n" and hence will never end. Calling .chomp on the input will fix that.
You are calling gets twice for each valid number -- once in the loop condition and once when you actually push a value into your array. This causes the loss of one of every two entries. Using a loop do construct with a break condition can fix that problem.
END_OF_LIST = '-1'
puts "Please enter as many numbers as you would like followed by -1"
Many_Numbers = Array.new
loop do
val = gets.chomp
break if val == END_LIST
Many_Numbers.push val
end
The good news is your merge sort method appears to be working once you sort out your input woes.

Ruby Loop Countdown method not Counting down [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to define a method that countdowns 10 to 0 and at the end returns HAPPY NEW YEARS! however i don't want i"am doing wrong?
def countdown(number)
while number > 0
puts "#{number} SECONDS(S)!"
number -= 1
end
"HAPPY NEW YEAR!"
end
A quick Google search revealed that you are apparently trying to solve https://learn.co/lessons/countdown-to-midnight (you really should have included that link)
Your code is not passing the spec, because it contains an additional S:
puts "#{number} SECONDS(S)!"
# ^
It has to be:
puts "#{number} SECOND(S)!"
def countdown(number)
while number > 0
puts "#{number} SECONDS(S)!"
number -= 1
end
puts "HAPPY NEW YEAR!"
end
I added a puts on the last line of your code. You method is counting down to 0 seconds, but the last line only return the string "HAPPY NEW YEAR!", and does not print it to the screen. Or if you need to return the string and print it on the screen, you can do p "HAPPY NEW YEAR!"

Checking if content of an array is all integers [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm working on a sorting code. I would like to check if my array contains non integers. Here is my code:
array = Array.new
puts "Please enter your 3 digits."
3.times do
str = gets.chomp.to_i
array.push str.to_i
end
if array.is_a?(Numeric) == false
puts "Error, only use Integers please!"
else
print "Here are your sorted numbers: #{array.sort}"
end
You clearly can't gets.chomp.to_i (or the equivalent, gets.to_i), because that will only return integers. You therefore need to see if the string represents a number before adding it to the array.
You can do that with a regular expression or confirm that Kernel::Integer does not raise an exception (and catch it if it does).
A regular expression that would work is simply:
str =~ /^-?\d+$/
after
str = gets.chomp.strip
To use Kernel::Integer:
def integer?(str)
begin
Integer(str)
rescue ArgumentError
return false
end
str.to_i
end
For example,
integer?("-33") #=> -33
integer?("-x33") #=> false
integer?(" 33 ") #=> 33
integer?("33\n") #=> 33
The last two examples show that you can drop chomp.strip from gets.chomp.strip when using this approach.
If you wish to allow integers or floats, change the regular expression to:
/^-?\d+\.?\d*$/
or check to see that Kernel::Float raises an exception:
def float?(str)
begin
Float(str)
rescue ArgumentError
return false
end
str.to_f
end
float?("-33.4") #=> -33.4
float?("-33") #=> -33.0
float?("x33.4") #=> false
float?(" 33.4\n") #=> 33.4
With the code you have above your array is guaranteed to contain integers since you are converting your input to Integers using to_i:
array.push str.to_i
You are in fact doing it twice. When you read the string from STDIN and when you push it onto the array.
You need to check to see if the input is a string before you call to_i.
3.times do
str = gets.chomp
# code to verify if str is numeric.
array.push str
end
There are lots of ways to implement that code depending on what your requirements are. Integers only could be done like this:
unless str =~ /^\d+$/
puts "Error, only use Integers please!"
exit
end
The above would work for any positive integers, but not negative. It would also fail if you allowed decimals. But it gives you an idea. Search "ruby check if string is a number" and you'll find a lot more info.
Also note that the above fails as soon as it finds a non integer instead of waiting till after.

Learn Ruby the Hard Way #41 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Hi I`m learning from LRtHW and I got stuck....
I have program like this:
require 'open-uri'
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
"class ### < ###\nend" => "Make a class named ### that is-a ###.",
"class ###\n\tdef initialize(###)\n\tend\nend" => "class ### has-a initialize that takes ### parameters.",
"class ###\n\tdef ***(###)\n\tend\nend" =>"class ### has-a function named *** that takes ### parameters.",
"*** = ###.new()" => "Set *** to an instance of class ###.",
"***.***(###)" => "From *** get the *** function, and call it with parameters ###.",
"***.*** = '***'" => "From *** get the *** attribute and set it to '***'."
}
PHRASE_FIRST = ARGV[0] == "english"
open(WORD_URL) do |f|
f.each_line {|word| WORDS.push(word.chomp)}
end
def craft_names(rand_words, snippet, pattern, caps=false)
names = snippet.scan(pattern).map do
word = rand_words.pop()
caps ? word.capitalize : word
end
return names * 2
end
def craft_params(rand_words,snippet,pattern)
names = (0...snippet.scan(pattern).length).map do
param_count = rand(3) + 1
params = (0...param_count).map {|x| rand_words.pop()}
params.join(', ')
end
return names * 2
end
def convert(snippet, phrase)
rand_words = WORDS.sort_by {rand}
class_names = craft_names(rand_words, snippet, /###/, caps=true)
other_names = craft_names(rand_words, snippet,/\*\*\*/)
param_names = craft_params(rand_words, snippet, /###/)
results = []
for sentence in [snippet, phrase]
#fake class name, also copies sentence
result = sentence.gsub(/###/) {|x| class_names.pop}
#fake other names
result.gsub!(/\*\*\*/) {|x| other_names.pop}
#fake parameter list
result.gsub!(/###/) {|x| param_names.pop}
results.push(result)
end
return results
end
# keep going until they hit CTRL-D
loop do
snippets = PHRASES.keys().sort_by { rand }
for snippet in snippets
phrase = PHRASES[snippet]
question, answer = convert(snippet, phrase)
if PHRASE_FIRST
question, answer = answer, question
end
print question, "\n\n> "
odp = gets.chomp
if odp == "exit"
exit(0)
end
#exit(0) unless STDIN.gets
puts "\nANSWER: %s\n\n" % answer
end
end
I understand most of this code, but I have a problem with:
for sentence in [snippet, phrase]
I know that it is a "for" loop and it creates a "sentence" variable, but how does the loop know that it need to look in a key and value of hash "PHRASES"
And my second "wall" is:
question, answer = convert(snippet, phrase)
It looks like it creates and assigns "question" and "answer variables to the "convert" method with "snippet" and "phrase" parameters... again how does it assigns "question" to a key and answer to a value.
I know that this is probably very simple but as for now it blocks my mind :(
For your first question about the for-loop:
Look at where the for-loop is defined. It's inside the convert() method, right? And the convert() method is passed two arguments: one snippet and one phrase. So the loop isn't "looking" for values in the PHRASES hash, you are the one supplying it. You're using the method's arguments.
For your second question about assignment:
In Ruby we can do something called "destructuring assignment". What this means is that we can assign an array to multiple variables, and each variable will hold one value in the array. That's what's happening in your program. The convert() method returns a two-item array, and you're giving a name (question and answer) to each item in the array.
Here's another example of a destructuring assignment:
a, b, c = [1, 2, 3]
a # => returns 1
b # => returns 2
c # returns 3
Try this out in IRB and see if you get the hang of it. Let me know if I can help clarify anything, or if I misunderstood your question. You should never feel bad about asking "simple" questions!

Converting string into class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
What I do need:
I pass a string that has to set an unmutable object inside an array, but I do not know hot how to make the transition from the string that the user inputs to the object name I need.
What I am intending to do:
I am working on a conversational adventure. The key point is to have a function that creates a command prompt so the user can interact with the game. Whenever the user says "go to somewhere", there is another function called "goto" that compares whether the input is included in the exits of the place where the player is; if so, the attribute "place" for the player takes a new place.
What I did:
I made a command prompt that actually works*
loop do
print "\n >>> "
input = gets.chomp
sentence = input.split
case
when sentence[0] == "inspect"
$action.inspect(sentence[1])
when sentence[0] == "go" && sentence[1] == "to"
$action.goto(sentence[2])
when sentence[0] == "quit"
break
else
puts "\nNo le entiendo Senor..."
end
And I initialized the objects as I need them (the third attribute goes for the exits):
room = Place.new("room", "Room", [newroom], "This is a blank room. You can _inspect_ the -clock- or go to [newroom].", ["this this"])
newroom = Place.new("newroom", "New Room", [room], "This is another blank room. You can _inspect_ the -clock-", ["this this"])
Then I made a method inside the action controller that has to compare and set the places properly. (Beware: monster newbie code following. Protect you eyes).
def goto(destiny) #trying to translate the commands into variable names
if (send "#{destiny}").is_in? $player.place.exits
$player.place = send "#{sentence[2]}"
puts destiny.description
else
puts "I cannot go there."
end
end
I think you want to convert a string to constant. Well it is easy. Read an example:
string = 'Hash'
const = Object.const_get(string) #=> Hash
const.new #=> {}; <- it is an empty Hash!
But be careful. If there's no such a constant you will get uninitialized constant error. In this case your adventures will stop.
I hope I understood your question and you will understand my answer.
How to change string to object, there are few options:
Bad(eval family):
eval("name_of_your_variable = #{21+21}")
eval("puts name_of_your_variable") #42
You can see that eval can make everything. So use with caution.
However, as pointed by #user2422869 you need(be in) scope - place where your variables are saved. So above code won't run everywhere
Everytime you run following method you create another scope
def meth1
puts "defined: #{(defined? local_a) ? 'yes' : 'no'}!"
eval 'local_a = 42'
local_a += 100
eval 'puts local_a'
end
meth1
and here is output:
defined: no!
142
If you want to grab local_a from one of scopes of meth1 you need binding.
def meth2
var_a = 222
binding
end
bin = meth2
bin.eval 'var_a'
#output:
#222
About binding you can read in doc. As for scopes, I don't have good site.
Better:
hash_variable = Hash.new # or just {}
hash[your_string_goes_here] = "some value #{42}"
puts hash[your_string_goes_here]
I don't know if good or bad:
As for this: send "#{destiny}". I assume that your destiny doesn't exist, so you can use method_missing:
def method_missing arg, *args, &block
#do some with "destiny"; save into variable/hash, check if "destiny" is in right place etc.
# return something
end

Resources