Ruby command line program that saves and updates users/preferences - ruby

I'm building an application that takes in stdin to save a user and their preferences. Should I write the stdin to a text file and save the user input there?
commandline.rb
class CommandLine
def initialize(filename)
#file = File.open(filename, 'w')
end
def add_user(input)
#file = File.open('new_accounts.txt', 'r+')
#file.write(input)
puts input
end
def run
puts "Welcome to the Command Line Client!"
command = ''
while command != 'quit'
printf "enter command: "
input = gets.chomp
parts = input.split
command = parts[0]
case command
when 'quit' then puts 'Goodbye!'
when '-a' then add_user(parts[1..-1].join(" "))
else
puts 'Invalid command #{command}, please try again.'
end
end
end
end
a = CommandLine.new('new_accounts.txt')
a.run
Let's say I want the user to enter '-a tommy likes apples' in the command line, I want it to output:
tommy likes apples
The same user tommy could also input '-a tommy likes oranges' which would then update his previous preference:
tommy likes oranges
Any help/direction is appreciated, thanks!

I don't see a problem with using a text file if you are doing something simple. Alternatives are many and without more detail I'm afraid I can't make a good recommendation.
def add_user(input)
File.open('new_accounts.txt', 'w') {|file|
file.write(input)
}
puts input
end
FYI: This will make it so that your text file updates. :-)
EDIT: Changed the add_user method.

Related

Ruby | Trying to check password by comparing to a file

I have some troubles with my code using Ruby. its just for a terminal program, so no website or anything.
In my code I Will have the user create a login. Then I will have the user to login, but I cant seem to figure out how to check if password or username is correct.
The program should compare whatever the user types in as a username/password with the file (userdatabase) - I think i got that right.
Now I am trying to stop the user if the input is not found in the user database, using a while loop, but i cant seem to make that work.
Code:
puts "What will be your user name?"
username = gets.chomp
puts "What will be your password?"
password = gets.chomp
puts "Please repeat your password."
passwordsafe = gets.chomp
f = File.new("student.txt", "w+")
f.puts username + ";" + password + ";" + passwordsafe
f.close
puts "well done, you have created a new user."
lines = IO.readlines("student.txt")
lines.each{|line| print(line)}
puts "now you need to login."
puts "What is your username?"
username = gets.chomp
File.open("student.txt") do |f|
f.any? do |line|
while line.include?(username)
end
end
elsif puts "Sorry your username was incorrect"
end
#lines = IO.readlines("student.txt")
#lines.each{|line| (line)}
puts "what is your password?"
password = gets.chomp
The while is unnecessary.
The username check currently like this:
File.open("student.txt") do |f|
f.any? do |line|
while line.include?(username)
end
end
Could be like this:
File.open("student.txt").each_line.any? do |line|
line.include?(username)
end
Or collapsed to a single line like this:
File.open("student.txt").each_line.any?{ |l| l.include?(username) }
Check the docs on the any? method to make sure you understand what it's expecting: http://ruby-doc.org/core-2.4.2/Enumerable.html#method-i-any-3F
As for the rest of the syntax errors, I'll leave those up to you ;)

How do I search a text file for a string and then print/return/put out what line of the file it was found on as a number in Ruby

So, I want to use the number I get from it in this:
line = answer to question
database.read.lines[line]
Database being the text file I am searching in.
You can also do it this way :
text_to_find = 'some random text' # use gets method to take input from user
text_found_at_index = database.readlines.index{|line| not line[text].nil? }
Hope, this is what you require : )
I would try something like this:
query = gets.chomp
database.each_line.with_index do |line, index|
if line.include?(query)
puts "Line #{index}: #{line}"
end
end

Delete a line of information from a text file

I have a text file called text.txt, and it has the following text:
123,shirt,9.99
234,pants,19.50
456,socks,3.99
How do I delete one row (e.g 123,shirt,9.99). How would I go about deleting this row?
My code so far:
test_file = File.new('text.txt', "a")
while (line = test_file)
puts 'Enter the products item number you wish to delete. '
user_delete = gets.chomp.to_i
line.delete(user_delete)
end
You're making a lot of mistakes here.
First of all opening the file with a (you need to use r+ or w+).
In Ruby we use a more elegant to iterate over files.
Check this answer, it will help you with your problem.
After that a look at IO library to understand how it all works
I imagine there are a bunch of better ways to do this, but here's quick and dirty:
puts "What's the item number?"
item_num = gets.chomp
read_file = File.new('read.txt', "r").read
write_file = File.new('read.txt', "w")
read_file.each_line do |line|
write_file.write(line) unless line.include? item_num
end

Ruby: gets.chomp with default value

Is there some simple way how to ask for a user input in Ruby WHILE providing a default value?
Consider this code in bash:
function ask_q {
local PROMPT="$1"
local DEF_V="$2"
read -e -p "$PROMPT" -i "$DEF_V" REPLY
echo $REPLY
}
TEST=$(ask_q "Are you hungry?" "Yes")
echo "Answer was \"$TEST\"."
Can you achieve similar behaviour with Ruby's gets.chomp?
function ask_q(prompt, default="")
puts prompt
reply = gets.chomp() # ???
return reply
def
reply = ask_q("Are you hungry?", "Yes")
I understand I can sort replicate the functionality in Ruby this way ...
def ask_q(prompt, default="")
default_msg = (default.to_s.empty?) ? "" : "[default: \"#{default}\"]"
puts "${prompt} ${default}"
reply = gets.chomp()
reply = (default.to_s.empty?) ? default : reply
return reply
end
... but it does not seem very pretty. I also need to show the default value manually and the user needs to retype it in the prompt line, if he wants to use modified version of it (say yes! instead of yes).
I'm starting with Ruby now, so there may be a lot of syntax mistakes and I also may be missing something obvious ... Also, I googled a lot but surprisingly found no clue.
TL; DR
To make the question clearer, this is what you should see in terminal and what I am able to achieve in bash (and not in Ruby, so far):
### Terminal output of `reply=ask_q("Are you hungry?" "Yes")`
$ Are you hungry?
$ Yes # default editable value
### Terminal output of `reply=ask_q("What do you want to eat?")`
$ What do you want to eat?
$ # blank line waiting for user input, since there is no second parameter
And the actual situation: I am building bootstrap script for my web apps. I need to provide users with existing configuration data, that they can change if needed.
### Terminal output of `reply=ask_q("Define name of database." "CURR_DB_NAME")`
I don't think it's that fancy functionality, that would require switch to GUI app world.
And as I've said before, this is quite easily achievable in bash. Problem is, that other things are pure pain (associative arrays, no return values from functions, passing parameters, ...). I guess I just need to decide what sucks the least in my case ...
You need to do one of two things:
1) Create a gui program.
2) Use curses.
Personally, I think it's a waste of time to spend any time learning curses. Curses has even been removed from the Ruby Standard Library.
A GUI program:
Here is what a gui app looks like using the Tkinter GUI Framework:
def ask_q(prompt, default="")
require 'tk'
root = TkRoot.new
root.title = "Your Info"
#Display the prompt:
TkLabel.new(root) do
text "#{prompt}: "
pack("side" => "left")
end
#Create a textbox that displays the default value:
results_var = TkVariable.new
results_var.value = default
TkEntry.new(root) do
textvariable results_var
pack("side" => "left")
end
user_input = nil
#Create a button for the user to click to send the input to your program:
TkButton.new(root) do
text "OK"
command(Proc.new do
user_input = results_var.value
root.destroy
end)
pack("side" => "right", "padx"=> "50", "pady"=> "10")
end
Tk.mainloop
user_input
end
puts ask_q("What is your name", "Petr Cibulka")
Calling a function in a bash script from ruby:
.../bash_programs/ask_q.sh:
#!/usr/bin/env bash
function ask_q {
local QUESTION="$1"
local DEFAULT_ANSWER="$2"
local PROMPT="$QUESTION"
read -p "$PROMPT $DEFAULT_ANSWER" USERS_ANSWER #I left out the -i stuff, because it doesn't work for my version of bash
echo $USERS_ANSWER
}
ruby_prog.rb:
answer = %x{
source ../bash_programs/ask_q.sh; #When ask_q.sh is not in a directory in your $PATH, this allows the file to be seen.
ask_q 'Are you Hungry?' 'Yes' #Now you can call functions defined inside ask_q.sh
}
p answer.chomp #=> "Maybe"
Using curses:
require 'rbcurse/core/util/app'
def help_text
<<-eos
Enter as much help text
here as you want
eos
end
user_answer = "error"
App.new do #Ctrl+Q to terminate curses, or F10(some terminals don't process function keys)
#form.help_manager.help_text = help_text() #User can hit F1 to get help text (some terminals do not process function keys)
question = "Are You Hungry?"
default_answer = "Yes"
row_position = 1
column_position = 10
text_field = Field.new(#form).
name("textfield1").
label(question).
text(default_answer).
display_length(20).
bgcolor(:white).
color(:black).
row(row_position).
col(column_position)
text_field.cursor_end
text_field.bind_key(13, 'return') do
user_answer = text_field.text
throw :close
end
end
puts user_answer

Separating console message from the code

I'm trying to make command line apps. The puts line makes the code looks messy. For example, I have help command that has several puts
def help()
puts "Welcome to my app"
puts "..."
puts "..."
puts "..."
puts "..."
end
If I combine the puts into one, the output will include the trailing space
def help()
puts "Welcome to my app
...
..."
end
# The output in the console will be like:
# Welcome to my app
# ...
# ...
What's the best way to separate the message from the code? I can only think of using variable to store the message, but I believe there is a better, tidier way like markdown or using txt.
For what you are asking, I think you are looking for the OptParser library in STDLIB.
It allows you to build command line options for doing things like usage and command line reporting for the user.
However, you can do this in your help method:
def help
<<-EOS.lines.each {|line| line.strip!}
Welcome to my app
...
...
EOS
end
puts help
puts "Thank you for using my app!"
This will display like this.
Welcome to my app
...
...
Thank you for using my app!
Update: I changed the EOF delimiter to EOS for End of String.
def help
puts \
"Welcome to my app"\
"..."\
"..."\
"..."\
"..."\
"..."
end
In your specific example, You can do within the help function
puts "Welcome to my app", "...\n"*3
If you have a lots of such static messages, you can try using a hash somewhere at the beginning
messages = {"welcome" => "Welcome to my app\n" + "...\n"*3,
"thanks" => "Thank you for the action"}
Then you can access them as
puts messages["welcome"]

Resources