A Drinks Tracker: Really?

This is a CLI app which allows the daily tracking of alcoholic beverages, not for the purpose of bragging, but of moderating or quitting. It also tracks mood and weight. This is yet another work in progress, with the following ideas:

  1. starting with a plain text parsing CLI,
  2. potentially making a basic web app with Sequel and Roda,
  3. eventually turning this into an API, which could be used by various apps.

This post will only cover the beginning of part 1.

To make it as simple as can be, one could use this by taking a note in plain text in the following format:

DATE $NUMBER_OF_DRINKS $MOOD(0 to 10) $WEIGHT(optional).

It would look something like:

31/12 0 7
30/12 5 3 93
29/12 8 5
28/12 6 6
27/12 0 9 90

And one could update it each day on a phone’s notes app.

To begin with, we will need to parse these lines.

class DrinksTracker

def initialize(data_file)
  file = File.open(data_file)
  file_data = file.readlines.map(&:chomp)
  # Get data into arrays of strings
  days = (0...file_data.length).each_with_object([]) do |day, days|
    days.push(file_data[day].split)
  end

We don’t necessarily weigh ourselves every day, so if no weight is provided, we shall use the value from the previous day. Since no value could be provided for multiple days, we start back at the first day when parsing the whole file, with .downto below.

  # If no weight provided, same as yesterday
  (days.length - 1).downto(0) do |day|
    days[day][3] = days[day + 1][3] unless days[day][3]
  end
  # Convert relevant numbers to float for calculation
  self.days = days.each do |day|
    (1..3).each do |idx|
      day[idx] = day[idx].to_f
    end
  end
  file.close
end

And we convert to float so that we can make averages without worrying about number format.

For what comes next, I expect that I will improve it dramatically later. It looks to me like there is the potential for a much better formulation, but I’m not there yet. So I will show what I have now:

# Average drinks per day, average mood, average weight
  def past_x_days(x)
    descriptor,
    duration,
    average_drinks,
    average_mood,
    average_weight = calculate(1, x)
    REPORT % {descriptor:, duration:, average_drinks:, average_mood:, average_weight:}
  end

  def previous_x_days(x)
    descriptor,
    duration,
    average_drinks,
    average_mood,
    average_weight = calculate(1 + x, 2 * x)
    REPORT % {descriptor:, duration:, average_drinks:, average_mood:, average_weight:}
  end
def calculate(first_day, last_day)
    drinks = 0
    mood = 0
    weight = 0
    ((first_day - 1)..(last_day - 1)).each do |day|
      drinks += days[day][1]
      mood += days[day][2]
      weight += days[day][3]
    end
    descriptor = first_day == 1 ? "past" : "previous"
    number_of_days = last_day - first_day + 1
    average_drinks = drinks / number_of_days
    average_mood = mood / number_of_days
    average_weight = weight / number_of_days
    [descriptor, number_of_days, average_drinks, average_mood, average_weight]
  end

The values then get formatted into a “Report” string:

REPORT = "In the %<descriptor>s %<duration>d days, your drinks per day average was %<average_drinks>d, your average mood was %<average_mood>d out of 10, and your weight averaged %<average_weight>d kilos."

And getting some data is as easy as:

if __FILE__ == $PROGRAM_NAME
  FILE = './drinks.txt'
  record = DrinksTracker.new(FILE)
  p record.days
  p record.past_x_days(7)
  p record.previous_x_days(7)
  p record.past_x_days(17)
  p record.previous_x_days(17)
  p record.past_x_days(30)
  p record.previous_x_days(30)
end

Returning (skipping the example data):

"In the past 7 days, your drinks per day average was 3, your average mood was 5 out of 10, and your weight averaged 90 kilos."  
"In the previous 7 days, your drinks per day average was 0, your average mood was 9 out of 10, and your weight averaged 88 kilos."
"In the past 17 days, your drinks per day average was 2, your average mood was 7 out of 10, and your weight averaged 89 kilos."  
"In the previous 17 days, your drinks per day average was 2, your average mood was 7 out of 10, and your weight averaged 89 kilos."  
"In the past 30 days, your drinks per day average was 1, your average mood was 7 out of 10, and your weight averaged 89 kilos."  
"In the previous 30 days, your drinks per day average was 2, your average mood was 7 out of 10, and your weight averaged 89 kilos."  

Next steps

The above can be considered basically interesting, or interestingly basic. What next?