Class: TTimeTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/t_time_tracker.rb

Overview

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ TTimeTracker

A new instance of TTimeTracker.

Parameters:

  • params (Hash) (defaults to: {})

    Options hash

Options Hash (params):

  • :now (Symbol)

    the date to consider when deciding which log file to use

  • :directory (Symbol)

    the parent directory that the log files are stored in

  • :subdirectory (Symbol)

    the subdirectory in which the current task will be stored

  • :filename (Symbol)

    the full path to the log file of the current task



22
23
24
25
26
27
28
# File 'lib/t_time_tracker.rb', line 22

def initialize(params = {})
  @now          = params[:now]          || Time.now
  @directory    = params[:directory]    || File.join(Dir.home, '.ttimetracker')
  @subdirectory = params[:subdirectory] || File.join(@directory, now.year.to_s, now.strftime("%m_%b"), '')
  @filename     = params[:filename]     || File.join(@subdirectory, now.strftime('%Y-%m-%d') + '.csv')
  self.class.mkdir @subdirectory
end

Instance Attribute Details

#directoryObject

the parent directory that the log files are stored in



14
15
16
# File 'lib/t_time_tracker.rb', line 14

def directory
  @directory
end

#filenameObject

the full path to the log file of the current task



14
# File 'lib/t_time_tracker.rb', line 14

attr_accessor :directory, :subdirectory, :filename, :task, :now

#nowObject

Returns the value of attribute now.



14
15
16
# File 'lib/t_time_tracker.rb', line 14

def now
  @now
end

#subdirectoryObject

the subdirectory in which the current task will be stored



14
# File 'lib/t_time_tracker.rb', line 14

attr_accessor :directory, :subdirectory, :filename, :task, :now

#task(task_name) ⇒ Object

Returns information about the specified task.

Parameters:

  • task_name (Symbol)

    the stored task to return, ‘:current` or `:last`



14
# File 'lib/t_time_tracker.rb', line 14

attr_accessor :directory, :subdirectory, :filename, :task, :now

Class Method Details

.format_minutes(minutes) ⇒ String

Converts an integer of minutes into a more human readable format.

Examples:

format_minutes(95) #=> "1:15"
format_minutes(5)  #=> "0:05"

Parameters:

  • minutes (Integer)

    a number of minutes

Returns:

  • (String)

    the formatted minutes



121
122
123
# File 'lib/t_time_tracker.rb', line 121

def self.format_minutes(minutes)
  "#{minutes.to_i / 60}:#{'%02d' % (minutes % 60)}"
end

.mkdir(dir) ⇒ Object

Create directory if it doesn’t exist, creating intermediate directories as required. Equivalent to ‘mkdir -p`.

Parameters:

  • dir (String)

    a directory name



170
171
172
173
# File 'lib/t_time_tracker.rb', line 170

def self.mkdir(dir)
  mkdir(File.dirname dir) unless File.dirname(dir) == dir
  Dir.mkdir(dir) unless dir.empty? || File.directory?(dir)
end

Instance Method Details

#at=(value) ⇒ Object

the time that the task (or range) starts at



14
# File 'lib/t_time_tracker.rb', line 14

attr_accessor :directory, :subdirectory, :filename, :task, :now

#current_taskObject

equivalent to task(:current)



44
# File 'lib/t_time_tracker.rb', line 44

def current_task; task(:current); end

#format_time(time) ⇒ String

Converts a Time object into a human readable condensed string. Options for strftime may be found here: www.ruby-doc.org/core-1.9.3/Time.html#method-i-strftime

Examples:

time = Time.new   #=> 2012-05-16 00:32:31 +0800
format_time(time) #=> "00:32:31"

Parameters:

  • time (Time)

    a time

Returns:

  • (String)

    the formatted time



185
186
187
# File 'lib/t_time_tracker.rb', line 185

def format_time(time)
  time.strftime("%H:%M:%S")
end

#last_taskObject

equivalent to task(:last)



47
# File 'lib/t_time_tracker.rb', line 47

def last_task; task(:last); end

#parse_task(line, params = {}) ⇒ {:start=>Time, :finish=>Time, :description=>String, :duration=>Integer}

Parses a comma separated stored task in csv form

Examples:

parse_task("12:56, 13:10, did the dishes") 
#=> {:start=>2012-05-16 12:56:00, :finish=>2012-05-16 13:10:00, :description=>"did the dishes", :duration=>14}
parse_task("14:32, homework")
#=> {:start=>2012-05-16 14:32:00, :finish=>Time.now, :description=>"homework", :duration=>36}

Parameters:

  • line (String)

    the CSV stored task

  • params (Hash) (defaults to: {})

    Options hash

Options Hash (params):

  • :day (Symbol)

    the default day to assign to times parsed. Defaults to @now.

Returns:

  • ({:start=>Time, :finish=>Time, :description=>String, :duration=>Integer})

    the parsed data in the line



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/t_time_tracker.rb', line 137

def parse_task(line, params = {})
  def parse_time(time_string, day)
    # if the time already has a date, parse that time
    # else assign a date
    if time_string =~ /\d{4}-\d{2}-\d{2}/
      Time.parse(time_string)
    else
      Time.parse(day.strftime("%F ") + time_string)
    end
  end

  day   = params[:day] || @now
  data  = line.split(",").map(&:strip)
  start = parse_time(data.shift, day)

  if data.length == 2
    # if there are two more values, they are the finished time and the description
    finish = parse_time(data.shift, day)
  else 
    # otherwise the last value is the description; get finish elsewhere
    finish = @now
  end

  description = data.shift
  duration = ((finish - start).to_f / 60).ceil

  return {:start => start, :finish => finish, :description => description, :duration => duration}
end

#parse_time(time_string, day) ⇒ Object



138
139
140
141
142
143
144
145
146
# File 'lib/t_time_tracker.rb', line 138

def parse_time(time_string, day)
  # if the time already has a date, parse that time
  # else assign a date
  if time_string =~ /\d{4}-\d{2}-\d{2}/
    Time.parse(time_string)
  else
    Time.parse(day.strftime("%F ") + time_string)
  end
end

#save(task = {}) ⇒ Object

warning: this will overwrite the current task. You need to save the current task before saving a new one.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/t_time_tracker.rb', line 88

def save(task = {})
  # forget the last task
  last = File.join(@directory, "last")
  File.unlink(last) if File.exists?(last)

  task[:start] ||= @now

  # save this as the current task if it doesn't have an ending time
  if !task[:finish]
    File.open(File.join(@directory, "current"),'w') do |f|
      f.puts [format_time(task[:start]), task[:description].strip].join(", ")
    end
  else
    # task has start and finish time, so append it to today's log...
    File.open(@filename,'a') do |f|
      f.puts [format_time(task[:start]), format_time(task[:finish]), task[:description].strip].join(", ")
    end

    # ...and save it as "last" in case you want to resume it
    File.rename(File.join(@directory, 'current'), File.join(@directory, 'last'))
  end

  task
end

#tasks(params = {}) ⇒ Object

TODO:

figure out how to make this work with an arbitrary directory structure

returns an array of hashed tasks between the specified times. Defaults to today.

Parameters:

  • params (Hash) (defaults to: {})

    Options hash

Options Hash (params):

  • :from (Symbol)

    the starting time; includes any task that starts after it (inclusive)

  • :to (Symbol)

    the ending time; includes any task that starts before it (inclusive)



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/t_time_tracker.rb', line 54

def tasks(params = {})
  require 'active_support/core_ext/time/calculations'
  require 'active_support/core_ext/date/calculations'

  # Time.parse(Time.new.strftime("%F 0:00:00 %z"))
  from = params[:from] || Time.new.beginning_of_day
  # Time.parse(Time.new.strftime("%F 23:59:59 %z"))
  to   = params[:to]   || Time.new.end_of_day
  # ensure from < to
  from, to = [from, to].sort 

  tasks = []

  # first, get every task for the correct days
  now = from
  while now <= to
    # TODO: make this work for arbitrary folder organisation structures
    subdirectory = File.join(@directory, now.year.to_s, now.strftime("%m_%b"), '')
    filename     = File.join(subdirectory, now.strftime('%Y-%m-%d') + '.csv')
    File.open(filename, 'r').each do |line|
      tasks << parse_task(line, :day => now)
    end if File.exists?(filename)
    now = now.tomorrow
  end

  # now filter out tasks that don't fall within the requested timespan
  tasks.delete_if{|t|
    t[:start] < from || t[:start] > to
  }

  tasks
end

#to=(value) ⇒ Object

the time that the task (or range) ends at



14
# File 'lib/t_time_tracker.rb', line 14

attr_accessor :directory, :subdirectory, :filename, :task, :now