Module: Timetrap::CLI

Extended by:
CLI, Helpers
Included in:
CLI
Defined in:
lib/timetrap/cli.rb

Constant Summary collapse

USAGE =
<<-EOF

Timetrap - Simple Time Tracking

Usage: #{File.basename $0} COMMAND [OPTIONS] [ARGS...]

where COMMAND is one of:
  * archive - move entries to a hidden sheet (by default named '_[SHEET]') so
  they're out of the way.
usage: t archive [--start DATE] [--end DATE] [SHEET]
-s, --start <date:qs>     Include entries that start on this date or later
-e, --end <date:qs>       Include entries that start on this date or earlier
  * backend - open an sqlite shell to the database
usage: t backend
  * display - display the current timesheet or a specific. Pass `all' as
  SHEET to display all sheets.
usage: t display [--ids] [--start DATE] [--end DATE] [--format FMT] [SHEET | all]
-v, --ids                 Print database ids (for use with edit)
-s, --start <date:qs>     Include entries that start on this date or later
-e, --end <date:qs>       Include entries that start on this date or earlier
-f, --format <format>     The output format.  Currently supports ical, csv, and
                            text (default).
  * edit - alter an entry's note, start, or end time. Defaults to the active entry
usage: t edit [--id ID] [--start TIME] [--end TIME] [NOTES]
-i, --id <id:i>           Alter entry with id <id> instead of the running entry
-s, --start <time:qs>     Change the start time to <time>
-e, --end <time:qs>       Change the end time to <time>
  * format - deprecated: alias for display
  * in - start the timer for the current timesheet
usage: t in [--at TIME] [NOTES]
-a, --at <time:qs>        Use this time instead of now
  * kill - delete a timesheet
usage: t kill [--id ID] [TIMESHEET]
-i, --id <id:i>           Alter entry with id <id> instead of the running entry
  * list - show the available timesheets
usage: t list
  * now - show the status of the current timesheet
usage: t now
  * out - stop the timer for the current timesheet
usage: t out [--at TIME]
-a, --at <time:qs>        Use this time instead of now
  * running - show all running timesheets
usage: t running
  * switch - switch to a new timesheet
usage: t switch TIMESHEET
  * week - shortcut for display with start date set to monday of this week
usage: t week [--ids] [--end DATE] [--format FMT] [SHEET | all]

OTHER OPTIONS
-h, --help     Display this help
-r, --round    Round output  to 15 minute start and end times.
EOF

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Helpers

format_date, format_date_if_new, format_duration, format_seconds, format_time, format_total, same_day?, selected_entries, sheet_name_from_string

Instance Attribute Details

#argsObject

Returns the value of attribute args.



4
5
6
# File 'lib/timetrap/cli.rb', line 4

def args
  @args
end

Instance Method Details

#archiveObject



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/timetrap/cli.rb', line 93

def archive
  ee = selected_entries
  out = "Archive #{ee.count} entries? "
  print out
  if $stdin.gets =~ /\Aye?s?\Z/i
    ee.all.each do |e|
      next unless e.end
      e.update :sheet => "_#{e.sheet}"
    end
  else
    say "archive aborted!"
  end
end

#backendObject



115
116
117
# File 'lib/timetrap/cli.rb', line 115

def backend
  exec "sqlite3 #{DB_NAME}"
end

#commandsObject



68
69
70
# File 'lib/timetrap/cli.rb', line 68

def commands
  Timetrap::CLI::USAGE.scan(/\* \w+/).map{|s| s.gsub(/\* /, '')}
end

#displayObject Also known as: format



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/timetrap/cli.rb', line 153

def display
  begin
    fmt_klass = if args['-f']
      Timetrap::Formatters.const_get("#{args['-f'].classify}")
    else
      Timetrap::Formatters::Text
    end
  rescue
    say "Invalid format specified `#{args['-f']}'"
    return
  end
  say Timetrap.format(fmt_klass, selected_entries.order(:start).all)
end

#editObject



107
108
109
110
111
112
113
# File 'lib/timetrap/cli.rb', line 107

def edit
  entry = args['-i'] ? Entry[args['-i']] : Timetrap.active_entry
  say "can't find entry" && return unless entry
  entry.update :start => args['-s'] if args['-s'] =~ /.+/
  entry.update :end => args['-e'] if args['-e'] =~ /.+/
  entry.update :note => unused_args if unused_args =~ /.+/
end

#inObject



119
120
121
# File 'lib/timetrap/cli.rb', line 119

def in
  Timetrap.start unused_args, args['-a']
end

#invokeObject



64
65
66
# File 'lib/timetrap/cli.rb', line 64

def invoke
  args['-h'] ? say(USAGE) : invoke_command_if_valid
end

#invoke_command_if_validObject



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/timetrap/cli.rb', line 76

def invoke_command_if_valid
  command = args.unused.shift
  set_global_options
  case (valid = commands.select{|name| name =~ %r|^#{command}|}).size
  when 0 then say "Invalid command: #{command}"
  when 1 then send valid[0]
  else
    say "Ambiguous command: #{command}" if command
    say(USAGE)
  end
end

#killObject



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/timetrap/cli.rb', line 127

def kill
  if e = Entry[args['-i']]
    out = "are you sure you want to delete entry #{e.id}? "
    out << "(#{e.note}) " if e.note.to_s =~ /.+/
    print out
    if $stdin.gets =~ /\Aye?s?\Z/i
      e.destroy
      say "it's dead"
    else
      say "will not kill"
    end
  elsif (sheets = Entry.map{|e| e.sheet }.uniq).include?(sheet = unused_args)
    victims = Entry.filter(:sheet => sheet).count
    print "are you sure you want to delete #{victims} entries on sheet #{sheet.inspect}? "
    if $stdin.gets =~ /\Aye?s?\Z/i
      Timetrap.kill_sheet sheet
      say "killed #{victims} entries"
    else
      say "will not kill"
    end
  else
    victim = args['-i'] ? args['-i'].to_s.inspect : sheet.inspect
    say "can't find #{victim} to kill", 'sheets:', *sheets
  end
end

#listObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/timetrap/cli.rb', line 175

def list
  sheets = Entry.sheets.map do |sheet|
    sheet_atts = {:total => 0, :running => 0, :today => 0}
    Timetrap::Entry.filter(:sheet => sheet).inject(sheet_atts) do |m, e|
      e_end = e.end_or_now
      m[:name] ||= sheet
      m[:total] += (e_end.to_i - e.start.to_i)
      m[:running] += (e_end.to_i - e.start.to_i) unless e.end
      m[:today] += (e_end.to_i - e.start.to_i) if same_day?(Time.now, e.start)
      m
    end
  end
  if sheets.empty? then say "No sheets found"; return end
  width = sheets.sort_by{|h|h[:name].length }.last[:name].length + 4
  say " %-#{width}s%-12s%-12s%s" % ["Timesheet", "Running", "Today", "Total Time"]
  sheets.each do |sheet|
    star = sheet[:name] == Timetrap.current_sheet ? '*' : ' '
    say "#{star}%-#{width}s%-12s%-12s%s" % [
      sheet[:running],
      sheet[:today],
      sheet[:total]
    ].map(&method(:format_seconds)).unshift(sheet[:name])
  end
end

#nowObject



200
201
202
203
204
205
206
207
208
# File 'lib/timetrap/cli.rb', line 200

def now
  if Timetrap.running?
    out = "#{Timetrap.current_sheet}: #{format_duration(Timetrap.active_entry.start, Timetrap.active_entry.end_or_now)}".gsub(/  /, ' ')
    out << " (#{Timetrap.active_entry.note})" if Timetrap.active_entry.note =~ /.+/
    say out
  else
    say "#{Timetrap.current_sheet}: not running"
  end
end

#outObject



123
124
125
# File 'lib/timetrap/cli.rb', line 123

def out
  Timetrap.stop args['-a']
end

#parse(arguments) ⇒ Object



60
61
62
# File 'lib/timetrap/cli.rb', line 60

def parse arguments
  args.parse arguments
end

#runningObject



210
211
212
213
# File 'lib/timetrap/cli.rb', line 210

def running
  say "Running Timesheets:"
  say Timetrap::Entry.filter(:end => nil).map{|e| "  #{e.sheet}: #{e.note}"}.uniq.sort
end

#say(*something) ⇒ Object



72
73
74
# File 'lib/timetrap/cli.rb', line 72

def say *something
  puts *something
end

#set_global_optionsObject

currently just sets whether output should be rounded to 15 min intervals



89
90
91
# File 'lib/timetrap/cli.rb', line 89

def set_global_options
  Timetrap::Entry.round = true if args['-r']
end

#switchObject



169
170
171
172
173
# File 'lib/timetrap/cli.rb', line 169

def switch
  sheet = unused_args
  if not sheet =~ /.+/ then say "No sheet specified"; return end
  say "Switching to sheet " + Timetrap.switch(sheet)
end

#weekObject



215
216
217
218
# File 'lib/timetrap/cli.rb', line 215

def week
  args['-s'] = Date.today.wday == 1 ? Date.today.to_s : Date.parse(Chronic.parse(%q(last monday)).to_s).to_s
  display
end