lib/timetrap/cli.rb in timetrap-1.5.3 vs lib/timetrap/cli.rb in timetrap-1.6.0
- old
+ new
@@ -62,36 +62,38 @@
-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.
+ * now - Show all running entries.
usage: t now
- * out - Stop the timer for the current timesheet.
- usage: t out [--at TIME]
+ * out - Stop the timer for the a timesheet.
+ usage: t out [--at TIME] [TIMESHEET]
-a, --at <time:qs> Use this time instead of now
- * running - Show all running timesheets.
- usage: t running
+ * running - Deprecated: alias for now.
- * switch - Switch to a new timesheet.
- usage: t switch TIMESHEET
+ * sheet - Switch to a timesheet creating it if necessary.
+ usage: t sheet TIMESHEET
+ * switch - Deprecated: renamed to sheet.
+
* 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.
-y, --yes Noninteractive, assume yes as answer to all prompts.
+ --debug Display stack traces for errors.
EXAMPLES
# create the "MyTimesheet" timesheet
- $ t switch MyTimesheet
+ $ t sheet MyTimesheet
# check in 5 minutes ago with a note
$ t in --at '5 minutes ago' doing some stuff
# check out
@@ -106,33 +108,32 @@
def parse arguments
args.parse arguments
end
def invoke
- args['-h'] ? say(USAGE) : invoke_command_if_valid
+ args['-h'] ? puts(USAGE) : invoke_command_if_valid
rescue => e
- say e.message
- exit 1
+ raise e if args['--debug']
+ warn e.message
+ exit 1 unless defined? TEST_MODE
end
def commands
Timetrap::CLI::USAGE.scan(/\* \w+/).map{|s| s.gsub(/\* /, '')}
end
- def say *something
- puts *something
- end
-
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]
+ when 0 then puts "Invalid command: #{command}"
else
- say "Ambiguous command: #{command}" if command
- say(USAGE)
+ if command
+ send valid[0]
+ else
+ puts USAGE
+ end
end
end
# currently just sets whether output should be rounded to 15 min intervals
def set_global_options
@@ -145,29 +146,34 @@
ee.all.each do |e|
next unless e.end
e.update :sheet => "_#{e.sheet}"
end
else
- say "archive aborted!"
+ warn "archive aborted!"
end
end
def configure
Config.configure!
- say "Config file is at #{Config::PATH.inspect}"
+ puts "Config file is at #{Config::PATH.inspect}"
end
def edit
- entry = args['-i'] ? Entry[args['-i']] : Timetrap.active_entry
- say "can't find entry" && return unless entry
+ entry = args['-i'] ? Entry[args['-i']] : Timer.active_entry
+ unless entry
+ warn "can't find entry"
+ return
+ else
+ warn "editing entry ##{entry.id.inspect}"
+ end
entry.update :start => args['-s'] if args['-s'] =~ /.+/
entry.update :end => args['-e'] if args['-e'] =~ /.+/
# update sheet
if args['-m'] =~ /.+/
- if entry == Timetrap.active_entry
- Timetrap.current_sheet = args['-m']
+ if entry == Timer.active_entry
+ Timer.current_sheet = args['-m']
end
entry.update :sheet => args['-m']
end
# update notes
@@ -183,38 +189,44 @@
def backend
exec "sqlite3 #{DB_NAME}"
end
def in
- Timetrap.start unused_args, args['-a']
+ Timer.start unused_args, args['-a']
+ warn "Checked into sheet #{Timer.current_sheet.inspect}."
end
def out
- Timetrap.stop args['-a']
+ sheet = sheet_name_from_string(unused_args)
+ if Timer.stop sheet, args['-a']
+ warn "Checked out of sheet #{sheet.inspect}."
+ else
+ warn "No running entry on sheet #{sheet.inspect}."
+ end
end
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 =~ /.+/
if ask_user out
e.destroy
- say "it's dead"
+ warn "it's dead"
else
- say "will not kill"
+ warn "will not kill"
end
elsif (sheets = Entry.map{|e| e.sheet }.uniq).include?(sheet = unused_args)
victims = Entry.filter(:sheet => sheet).count
if ask_user "are you sure you want to delete #{victims} entries on sheet #{sheet.inspect}? "
- Timetrap.kill_sheet sheet
- say "killed #{victims} entries"
+ Entry.filter(:sheet => sheet).destroy
+ warn "killed #{victims} entries"
else
- say "will not kill"
+ warn "will not kill"
end
else
victim = args['-i'] ? args['-i'].to_s.inspect : sheet.inspect
- say "can't find #{victim} to kill", 'sheets:', *sheets
+ warn "can't find #{victim} to kill", 'sheets:', *sheets
end
end
def display
begin
@@ -222,64 +234,77 @@
Timetrap::Formatters.const_get("#{args['-f'].classify}")
else
Timetrap::Formatters::Text
end
rescue
- say "Invalid format specified `#{args['-f']}'"
+ warn "Invalid format #{args['-f'].inspect} specified."
return
end
- say Timetrap.format(fmt_klass, selected_entries.order(:start).all)
+ entries = selected_entries.order(:start).all
+ if entries == []
+ warn "No entries were selected to display."
+ else
+ puts fmt_klass.new(entries).output
+ end
end
alias_method :format, :display
-
- def switch
+ def sheet
sheet = unused_args
- if not sheet =~ /.+/ then say "No sheet specified"; return end
- say "Switching to sheet " + Timetrap.switch(sheet)
+ unless sheet =~ /.+/
+ warn "No sheet specified"
+ else
+ Timer.current_sheet = sheet
+ warn "Switching to sheet #{sheet.inspect}"
+ end
end
+ alias_method :switch, :sheet
+
def list
- sheets = Entry.sheets.map do |sheet|
+ sheets = ([Timer.current_sheet] | 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
+ entries = Timetrap::Entry.filter(:sheet => sheet)
+ if entries.empty?
+ sheet_atts.merge(:name => sheet)
+ else
+ entries.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
- end
- if sheets.empty? then say "No sheets found"; return end
+ end.sort_by{|sheet| sheet[:name].downcase}
width = sheets.sort_by{|h|h[:name].length }.last[:name].length + 4
- say " %-#{width}s%-12s%-12s%s" % ["Timesheet", "Running", "Today", "Total Time"]
+ puts " %-#{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" % [
+ star = sheet[:name] == Timer.current_sheet ? '*' : ' '
+ puts "#{star}%-#{width}s%-12s%-12s%s" % [
sheet[:running],
sheet[:today],
sheet[:total]
].map(&method(:format_seconds)).unshift(sheet[:name])
end
end
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"
+ if !Timer.running?
+ puts "*#{Timer.current_sheet}: not running"
end
+ Timer.running_entries.each do |entry|
+ current = entry[:sheet] == Timer.current_sheet
+ out = current ? '*' : ' '
+ out << "#{entry[:sheet]}: #{format_duration(entry.start, entry.end_or_now)}".gsub(/ /, ' ')
+ out << " (#{entry.note})" if entry.note =~ /.+/
+ puts out
+ end
end
+ alias_method :running, :display
- def running
- say "Running Timesheets:"
- say Timetrap::Entry.filter(:end => nil).map{|e| " #{e.sheet}: #{e.note}"}.uniq.sort
- end
-
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
@@ -289,10 +314,10 @@
args.unused.join(' ')
end
def ask_user question
return true if args['-y']
- print question
+ $stderr.print question
$stdin.gets =~ /\Aye?s?\Z/i
end
end
end