I started writing this program to get a better understanding of different aspects of Ruby. I tried to follow the ruby style guide here.
What it's supposed to do is take the exercises/tasks you give it, and record those tasks. It uses a record of those tasks to automatically create/update the header row of a .csv file for the month, and to automatically create a row for every day that information (repetitions of a given exercise) is inputted. I know this program may seem a little useless, after all, many of us own excel, and currently it just gets input from gets, but I was thinking I might do more with it in the future.
I wrote two versions:
Version one:
# Requires
require "date"
require "csv"
# Functions
def standardize(string)
# 'Standardizes' strings so that "word word" becomes "Word-Word"
new_string = ""
string_parts = string.strip.split
string_parts.each do |part|
part.capitalize!
new_string << part + "-"
end
return new_string[0..-2]
end
def ensure_file(file_path)
# Checks if a file exists and creates it if it doesn't exist
if !File.file?(file_path)
file = File.new(file_path, "w")
file.close
end
end
def overwrite_csv(path, csv_table)
# Overwrites a CSV file
# Made this a function so I can change how I do it throughout the file
# from one place
CSV.open(path, "w") do |csv_file|
csv_table.each { |row| csv_file << row }
end
end
# Constants
KNOWN_EXERCISES = "known_exercises.txt"
MONTH_FILE = Date::MONTHNAMES[Date.today.month] + ".csv"
# Gets an array of known exercises
ensure_file(KNOWN_EXERCISES)
exercises = []
File.foreach(KNOWN_EXERCISES) do |exercise|
exercise.strip!
exercise != "" ? exercises << exercise.strip : nil
end
# Gets information from the user
print "Exercise: "
exercise = standardize(gets.strip)
print "Repetitions: "
reps = gets.strip
# Checks if the exercise is in the known exercises file, writes it in if not
if !exercises.include?(exercise)
File.open(KNOWN_EXERCISES, "a") do |known_exercises|
known_exercises.write("\n" + exercise)
end
exercises << exercise
end
# Creates/modifies the .CSV file if necessary
current_day = Date.today.month.to_s + "/" + Date.today.day.to_s
if !File.file?(MONTH_FILE)
CSV.open(MONTH_FILE, "w") do |csv_file|
header_row = ["Day"] + exercises
csv_file << header_row
end
end
# Writes any new exercises to the file on disk
records = CSV.read(MONTH_FILE, headers:true, return_headers:true, converters: :numeric)
if !records[0].include?(exercise)
records[0] << exercise
overwrite_csv(MONTH_FILE, records)
end
# Enters user inputted data into the records in memory to edit
records = CSV.read(MONTH_FILE, headers:true, return_headers:true, converters: :numeric)
exercise_col = records.headers.index(exercise)
if !records["Day"].include?(current_day)
data = [current_day]
data[exercise_col] = reps
records << data
elsif records["Day"].include?(current_day)
cur_day_row_i = records["Day"].index(current_day) # Index of the current day's row
records[cur_day_row_i][exercise] = reps
end
# Overwrites file on disk with edits in memory
overwrite_csv(MONTH_FILE, records)
Version two:
# Requires
require "date"
require "csv"
# Classes
class CSVFile
attr_accessor :path, :new_file
alias new_file? new_file
def initialize(path)
@path = path
@new_file = false
# Creates file if necessary
if !File.file?(@path)
@new_file = true
create_file(path)
end
yield(self) if block_given?
end
def overwrite_table(csv_table)
# Overwrites a CSV file with data from a Table object
CSV.open(@path, "w") do |csv_file|
csv_table.each { |row| csv_file << row }
end
end
def overwrite(csv)
# Overwrites a CSV file with anything that can be appended to CSV.open
CSV.open(@path, "w") do |csv_file|
csv_file << csv
end
end
def append(csv)
# Overwrites the whole csv file to append a line
records = CSV.read(@path, headers:true, return_headers:true)
records << csv
overwrite_table(records)
end
def read(**args)
# CSV.read but without having to specify path
CSV.read(@path, args)
end
alias << append
def to_s
CSV.read(@path).to_s
end
end
# Functions
def create_file(file_path)
# Creates a blank file at file_path
file = File.new(file_path, "w")
file.close
end
def standardize(string)
# 'Standardizes' strings so that "word word" becomes "Word-Word"
new_string = ""
string_parts = string.strip.split
string_parts.each do |part|
part.capitalize!
new_string << part + "-"
end
new_string[0..-2]
end
# Constants
KNOWN_EXERCISES = "known_exercises.txt"
RECORDS = Date::MONTHNAMES[Date.today.month] + ".csv"
# Creates exercises file if necessary
create_file(KNOWN_EXERCISES) if !File.file?(KNOWN_EXERCISES)
# Gets an array of known exercises
exercises = []
File.foreach(KNOWN_EXERCISES) do |exercise|
exercise.strip!
exercises << exercise if exercise != ""
end
# Gets information from the user
print "Exercise: "
exercise = standardize(gets.strip)
print "Repetitions: "
reps = gets.strip
# Checks if the exercise is in the known exercises file, writes it in if not
if !exercises.include?(exercise)
File.open(KNOWN_EXERCISES, "a") do |known_exercises|
known_exercises.write("\n" + exercise)
end
exercises << exercise
end
# Creates/modifies the .CSV file
current_day = Date.today.month.to_s + "/" + Date.today.day.to_s
CSVFile.new(RECORDS) do |csv_file|
# Creates the header row if necessary
if csv_file.new_file?
header_row = ["Day"] + exercises
csv_file << header_row
end
# Enters user inputted data into the records in memory to edit
records = csv_file.read(headers:true, return_headers:true)
# Edits the header row when necessary
if !records[0].include?(exercise)
records[0] << exercise
end
# Edits the other rows when necessary
if !records["Day"].include?(current_day)
exercise_col = records.headers.index(exercise)
data = [current_day]
data[exercise_col] = reps
records << data
elsif records["Day"].include?(current_day)
cur_day_row_i = records["Day"].index(current_day) # Index of the current day's row
records[cur_day_row_i][exercise] = reps
end
# Overwrites file on disk with edits in memory
csv_file.overwrite_table(records)
end
So if you entered room cleaning for the exercise, and 1 for the reps on June 11, you would get a .csv file that looked like:
Day,Room-Cleaning 6/11,1
And the next month, automatically the header row would look like:
Day,Room-Cleaning
Without you having to tell the program that that is one of the tasks you want to add.
I have a slight background in Python, if that helps in explaining any mistakes I may have made.
!
operatorif !(some command)
. \$\endgroup\$