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)
Related
Instead of doing:
puts "what type of input?"
input = gets.chomp
if %W[Int INT i I Ints ints].include?(input)
puts "enter int"
i = gets.to_i
I want to use regex to interpret string user input. For example,
puts "are you entering in a string, an int or a float?"
case gets
when /\A(string|s)\z/i
puts "enter in a string"
gets.chomp
when /\A(int|i)\z/i
puts "enter an int"
gets.to_i
when /\A(float|f)\z/i
puts "enter a float"
gets.to_f
end
What is the syntax in order to get the same result but using if statements instead of case statement?
gets returns a string with a trailing carriage return. What you need is to match the ending against \Z, not \z.
puts "are you entering in a string, an int or a float?"
case gets
when /\As(tring)?\Z/i
puts "enter in a string"
gets.chomp
when /\Ai(nt)?\Z/i
puts "enter an int"
gets.to_i
when /\Af(loat)?\z/i
puts "enter a float"
gets.to_f
else puts "Didn’t work"
end
I also slightly updated regexps to clearly show the intent.
If you want to turn your case into an if, you have to store the expression intended for the gets into a variable:
response=gets.chomp
if /..../ =~ response
...
elsif /.../ =~ response
....
....
else
...
end
In this program, I look for a file on the hard drive to choose by name, extension, name and extension, until the code became large, I wanted to know how to reduce it a little.
How to reduce if conditions number of lines in Ruby?
What is the best way to reduce the following condition in Ruby?
require "colorize"
new_name_file = {}
loop do
puts
puts "Will we search for the file by name(1), extension(2), name extension(3) or exit programm(4)?"
print "\n>>>>>> ".magenta
name_extension = gets.to_i
if name_extension == 1 # =========== search file name =================
puts "Enter file name (test, lesson, ruby....etc.) "
print "\n>>>>>> ".cyan
file_name = gets.strip.downcase
puts "Name the hard drive on which we will search for the file(C, D, E, F....e.t.c.): "
print "\n>>>>>> ".green
hdd_search = gets.strip.capitalize
# search file hdd
contents = Dir.glob("#{hdd_search}:/**/#{file_name}.*")
elsif name_extension == 2 # ========= search by file extension =============
puts "Enter file extension(txt, rb, jpg, csv, json) "
print "\n>>>>>> ".cyan
file_extension = gets.strip.downcase
# on which drive we will search put the letter
puts "Name the hard drive on which we will search for the file(C, D, E, F....e.t.c.): "
print "\n>>>>>> ".green
hdd_search = gets.strip.capitalize
# search file hdd
contents = Dir.glob("#{hdd_search}:/**/*.#{file_extension}")
elsif name_extension == 3 # ========= search by name and file extension =============
puts "Enter a name and file extension(test.txt, test.rb, test.jpg, test.csv, test.json..etc) "
print "\n>>>>>> ".cyan
file_extension_name = gets.strip
# on which drive we will search put the letter
puts "Name the hard drive on which we will search for the file(C, D, E, F....e.t.c.): "
print "\n>>>>>> ".green
hdd_search = gets.strip.capitalize
# search file hdd
contents = Dir.glob("#{hdd_search}:/**/#{file_extension_name}")
elsif name_extension == 4
puts "Exit programm".red
exit
end
contents.each do |txt_name|
z_name = File.basename(txt_name) # file name
path = File.expand_path(txt_name) # path file
new_name_file[z_name] = path # everything in the hash
end
new_name_file.each do |k, v| # hash output
puts "file : ".cyan + "#{k} " + " path:".cyan + "#{v}"
end
end
You can wrap the code inside the conditions in a method:
def process_file(file_types)
puts "Enter file name (#{file_types.join(',')}....etc.) "
print "\n>>>>>> ".cyan
file_name = gets.strip.downcase
puts "Name the hard drive on which we will search for the file(C, D, E, F....e.t.c.): "
print "\n>>>>>> ".green
hdd_search = gets.strip.capitalize
# search file hdd
contents = Dir.glob("#{hdd_search}:/**/#{file_name}.*")
end
file_types = {
"1" => ['test', 'lesson', 'ruby']
"2" =>
}
loop do
puts
puts "Will we search for the file by name(1), extension(2), name extension(3) or exit programm(4)?"
print "\n>>>>>> ".magenta
name_extension = gets
if name_extension == '4'
puts "Exit programm".red
exit
end
process_file(file_types[name_extension])
end
You can Rubyize this code a lot by trimming down what the main loop does and focus on the job of getting input and delegating:
class Tester
def select
loop do
puts
puts "Will we search for the file by name(1), extension(2), name extension(3) or exit programm(4)?"
print "\n>>>>>> "
input = gets.chomp
search_method = "search_#{input}"
if (respond_to?(search_method))
contents = send(search_method)
contents.each do |txt_name|
z_name = File.basename(txt_name) # file name
path = File.expand_path(txt_name) # path file
new_name_file[z_name] = path # everything in the hash
end
else
puts "Unknown input: #{input.inspect}, method #{search_method} not defined."
end
end
end
end
Then you can engage this with:
Tester.new.select
This dynamically dispatches to methods that follow a simple naming
convention. To add another method, define one:
def search_1
puts "Enter file name (test, lesson, ruby....etc.) "
print "\n>>>>>> ".cyan
file_name = gets.strip.downcase
puts "Name the hard drive on which we will search for the file(C, D, E, F....e.t.c.): "
print "\n>>>>>> ".green
hdd_search = gets.strip.capitalize
# search file hdd
Dir.glob("#{hdd_search}:/**/#{file_name}.*")
end
These methods should return the contents to be displayed. That's pretty simple.
You can take this a step further by defining classes instead of methods where you can instantiate them and iterate over their results, moving this a lot closer to recommended object-oriented design patterns.
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
I have a school assignment that I need help with.
This is the description of the assignment:
Ruby program that can hold these values:
Artifacts
Values
Assumptions
It shall be possible for a user:
To enter these three types of values.
Search for a value of type Artifacts, Values or Assumptions.
The program shall use loops and at least one class definition.
The only function that won't work out for me are these lines:
f= File.new("Artefacts", "r")
puts "Search for information regarding cultural information"
userinput = gets.chomp
if File.readlines("Artefacts").include?('userinput')
puts "We have found your input."
else
puts "We have not found your input."
f.close
No matter what the user inserts, it only displays "We have not found your input".
Part A: get user input and write to file
def write_to_file(path, string)
# 'a' means append
# it will create the file if it doesnt exist
File.open(path, 'a') do |file|
file.write string + "\n"
end
end
path = "Artefacts"
num_inputs = 3
num_inputs.times do |i|
puts "enter input (#{i + 1} / #{num_inputs}):"
write_to_file path, gets.chomp
end
puts `cat #{path}`
# if you entered "foo" for each input,
# this will show:
# foo
# foo
# foo
Part B: read a file and check if it contains a string:
path = "./Artefacts"
query = "foo"
text = File.read path
# this will be a string with all the text
lines = File.readlines path
# this will be an array of strings (one for each line)
is_text_found = text.include? query
# or
is_text_found = lines.any? do |line|
line.include? query
end
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