This is a program that ask input from the user about the characteristics of a gemstone then prints to the screen. Things like color, price and name. I have written it to an extend where the user enters all this and prints them out. Am now stuck where I should loop and enable the user to enter any number of gemstones. Like if he/she enters 3 gemstones then it should loop and allow the user to enter the characteristics of the 3 gemstone types. I would also like to sort the resulting output of gemstone names in alphabetical order. Appreciated
class GemStones
# input variables
name = ""
color = ""
price = 0
gemstoneNumber = 0
# output variable
gemstoneNumber = 0
# processing
print "How many gemstones do you want to enter? "
gemstoneNumber = gets
print "What is the name of the gemstone? "
name = gets
print "What is the color of the gemstone? "
color = gets
print "What is the price of the gemstone? "
price = gets
puts " You entered #{gemstoneNumber} The name is #{name}, the color is #{color} and price is
$ #{price}"
end
You should not wrap the code in class in the first place. There is no OOP in your code, hence the class is not needed as well. Also, gets returns a string, while for number you likely need an integer.
Here would be a [more-or-less] rubyish version of your code:
print "How many gemstones do you want to enter? "
# ⇓⇓⇓⇓⇓ get rid of trailing CR/LF
# ⇓⇓⇓⇓ convert to integer
gemstoneNumber = gets.chomp.to_i
gemstones =
1.upto(gemstoneNumber).map do |i|
puts
puts "Please enter data for the gemstone ##{i}:"
print "What is the name of the gemstone? "
name = gets.chomp # shave the trailing CR/LF off
print "What is the color of the gemstone? "
color = gets.chomp
print "What is the price of the gemstone? "
price = gets.chomp.to_f # convert to float
# in Ruby we normally use hashes to store
# the named values
{name: name, color: color, price: price}
end
puts "You entered #{gemstoneNumber} gemstones. They are:"
gemstones.each do |gemstone|
puts "Name: #{gemstone[:name]}. " \
"Color: #{gemstone[:color]}. " \
"Price: $#{gemstone[:price]}."
end
Alternatively, you might use the class instead of hash to store the gemstone info.
To sort the gemstones by the name:
puts "You entered #{gemstoneNumber} gemstones. They are:"
# ⇓⇓⇓⇓⇓⇓⇓ HERE
gemstones.sort_by { |gemstone| gemstone[:name] }.each do |gemstone|
puts "Name: #{gemstone[:name]}. " \
"Color: #{gemstone[:color]}. " \
"Price: $#{gemstone[:price]}."
end
The good documentation on enumerations might be found in the official ruby docs: https://ruby-doc.org/core/Enumerable.html#method-i-sort_by (and around.)
You can try this as well.
def gem_stones num
#gem_stones = []
num.times do |a|
print "Enter the name of gemstone #{a+1} "
name=gets.chomp
print "Enter the color of gemstone #{a+1} "
color = gets.chomp
print "Enter the price of gemstone #{a+1} "
price = gets.chomp.to_f
#gem_stones.push({name: name, color: color, price: price})
end
puts #gem_stones.sort_by {|a| a[:name]}.map{|gem| "Name: #{gem[:name]}, Color: #{gem[:color]}, Price: #{gem[:price]}"}.join("\n")
end
puts "Ener the number of gem stones you want to enter?"
num = gets.to_i
gem_stones num
Related
I want to check a string entered by a user. If it is a string, then move along, if not, then throw an error. I do not know how to check if the user input is a string or an int. Below is my code:
puts "what is your name?"
name = gets.chomp
if name == Int
puts "error enter a string"
end
if birthdate != Int
puts "error enter your birthdate"
end
puts "how old are you "
age = gets.to_i
if age == String
puts "error please enter your age"
end
puts "hello" + name + " wow that is a good day to be born" + "thats a great age"
puts "the half of your age is #{age/2.0} that is good to know"
It may be checked as this:
puts "what is your name?"
name = gets.chomp
if !(name =~ /[0-9]/).nil?
puts "error enter a string"
end
puts "what is your age?"
age = gets.chomp
if age.to_i.to_s == age
puts "error enter a integer"
end
I think this is what you are looking for.
if name.class == String
Also this will always be false
age = gets.to_i # this is converting to integer
if age.class == String # I think this is what you meant
age will always be an Integer her because you have cast it as such with .to_i
I am trying to accept the first_name, the middle name, and the last name of the user and then display the abbreviated first, middle name of the user with the unaltered last name. I've written the following code and managed to get for a single user.
h = Hash.new
puts "Enter the first name for user"
h["First_name"] = gets.capitalize
puts "Enter the Middle name for user"
h["Middle_name"] = gets.capitalize
puts "Enter the Last name for user"
h["Last_name"]= gets.capitalize
puts "The name entered is #{h["First_name"][0]}" +
"." + "#{h["Middle_name"][0]}" + "." + "#{h["Last_name"]}"
I want this to happen for five users repeatedly, and display all five name at the end. Can any one help me find a solution for this problem?
Put the whole thing in an array (and end the block with h):
a = Array.new(5) do
h = Hash.new
puts "Enter the first name for user"
h["First_name"] = gets.capitalize
puts "Enter the Middle name for user"
h["Middle_name"] = gets.capitalize
puts "Enter the Last name for user"
h["Last_name"] = gets.capitalize
h
end
In the end, a will have five hashes of the kind you had. You might want to put chomp after each gets to get rid of the newline character.
You can print each name by iterating over a.
a.each do |h|
puts "The name entered is " + h["First_name"][0] +
"." + h["Middle_name"][0] + "." + h["Last_name"]
end
Couldn't find a better way to write the following:
def get_name
print "Please enter your name: "
name = ""
loop do
break if (name = gets.chomp).match(/^[[:alpha:]]+$/)
print "Please enter your name again (must be one or more letters): "
end
name
end
How can I write this ruby method in a better way?
Problem with your code is that it's trying to do two quite different functions at the same time: validating format and handling user input. Better to separate the two. What do you think of this?
def format_ok?(name)
name =~ /\A[[:alpha:]]+\z/
end
def get_name
print "Please enter your name: "
loop do
name = gets.chomp
return name if format_ok?(name)
print "Please enter your name again (must be one or more letters): "
end
end
Here's another way to write it:
def get_name
print "Please enter your name: "
until gets =~ /^[[:alpha:]]+$/
print "Please enter your name again (must be one or more letters): "
end
$_.chomp
end
It reads a line from standard input until it matches the regular expression, printing an error message otherwise. Upon success, it returns the chomped line (gets assigns to $_).
Just to provide one more variation:
def prompt_name(p)
puts p
gets.chomp.strip
end
def get_name
name = ''
name = prompt_name("Please enter your name #{name.empty? ? '' : 'again '}:") while name !~ /\A[[:alpha:]]+\z/
name
end
how about this?
def get_name
print "Please enter your name: "
name = gets.chomp
until name =~ /[[:alpha:]]/
print "Please enter your name again (must be one or more letters): "
name = gets.chomp
end
puts "your name is #{name}"
end
get_name
> get_name
# Please enter your name: 3212
# Please enter your name again (must be one or more letters): 12Gagan
# your name is 12Gagan
Demo
This seems to work correctly and display the results I want
Dir["/Users/ondrovic/RubyTest/**/*.txt"].each do |i|
puts i.green if File.readlines(i).grep(/test/).any?
end
Why when I try like this does it not populate info
print "Enter search dir"
src = gets
print "Enter search term"
trm = gets
puts "Looking in #{src} for #{trm}"
Dir["#{src}/**/*.txt"].each do |i|
puts i.green if File.readlines(i).grep(/"#{trm}"/).any?
end
I have also tried it this way
Dir[src + "/**/*.txt"].each do |i|
puts i.green if File.readlines(i).grep(/ + trm + /).any?
end
Working code
require 'colorize'
print "Enter search dir\n".green
src = gets.chomp
print "Enter search term\n".blue
trm = gets.chomp
puts "Looking in #{src} for #{trm}"
Dir["#{src}/**/*.txt"].each do |i|
puts i.green if File.readlines(i).grep(/#{trm}/).any?
end
The return value of the gets includes trailing newline:
>> gets
asdf
=> "asdf\n" # <----
>>
Remove it using String#chomp:
print "Enter search dir"
src = gets.chomp
print "Enter search term"
trm = gets.chomp
...
In addition to that, the pattern /"#{trm}"/ includes ". Remove them:
/#{trm}/
Alternatively, you can use Regexp::new:
Regexp.new(trm)
Hey I'm just starting to learn Ruby over at codeacademy and I've come across an exercise that had an optional challenge that I can't get. The program takes a user defined string and "redacts" the words that the user wants "redacted". As you can see it turns the strings into arrays and then cycles through each value in the arrays (aka the individual words) and attempts to cross check the values of the original string with those of the words the user wants "redacted". The original problem was to get it to redact one variable, the challenge was to get multiple words redacted. My problem is that when it goes through the checking loops it keeps returning values wrong. I understand what's wrong, sort of, the looping has to cross check values more than once and when it fails to '==' it keeps on printing out the word, but is there a way to fix this? Or is there a better angle to approach this?
puts "Give me what you've got"
text = gets.chomp
text.downcase!
puts "What words do you wish to redact"
redact = gets.chomp
redact.downcase!
bye_words = redact.split(" ")
words = text.split(" ")
words.each do |single_word|
bye_words.each do |word_in_question|
if word_in_question == single_word
print "REDACTED "
else
print single_word + " "
end
end
end
Maybe just use include? instead of another loop:
puts "Give me what you've got"
text = gets.chomp
text.downcase!
puts "What words do you wish to redact"
redact = gets.chomp
redact.downcase!
bye_words = redact.split(" ")
words = text.split(" ")
words.each do |single_word|
if bye_words.include? single_word
print "REDACTED "
else
print single_word + " "
end
end
Or even gsub but maybe that's cheating...?
How about something like this? You dont have to loop through two different sets:
puts "Give me what you've got"
text = gets.chomp
text.downcase!
puts "What words do you wish to redact"
redact = gets.chomp
redact.downcase!
bye_words = redact.split(" ")
words = text.split(" ")
ouput_words = []
words.each do |single_word|
if bye_words.include?(single_word)
ouput_words << "REDACTED"
else
ouput_words << single_word
end
end
print ouput_words.join(" ") + "\n"
The fastest way to get (almost) what you need is using -:
puts "Give me what you've got"
text = gets.chomp
text.downcase!
puts "What words do you wish to redact"
redact = gets.chomp
redact.downcase!
bye_words = redact.split(" ")
words = text.split(" ")
puts (words - bye_words).join(' ')
The problem is that the redacted words will simply be removed from the text ('REDACTED' will not be added).
For that requirement to be filled, you need to find if each word is included? in the bye_words. What can do to improve on the others' suggestions is to turn the list of bye_words to a Set.
require 'set'
puts "Give me what you've got"
text = gets.chomp
text.downcase!
puts "What words do you wish to redact"
redact = gets.chomp
redact.downcase!
bye_words = Set.new(redact.split(" "))
words = text.split(" ")
puts words.map { |word| bye_words.include?(word) ? 'REDACTED':word }.join(' ')