module Timeless::CommandSemantics
Constants
- APPNAME
- VERSION
Public Class Methods
balance(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 245 def self.balance opts, argv from = opts.to_hash[:from] ? Chronic.parse(opts.to_hash[:from]) : nil to = opts.to_hash[:to] ? Chronic.parse(opts.to_hash[:to]) : nil # {key1 => {value1 => total .. } , ... } hash = Timeless::Storage::balance from, to, opts.to_hash[:filter] report "Projects", "p", hash report "Clients", "c", hash report "Activities", "a", hash remaining_tags = hash.reject! { |k| ["p", "c", "a"].include? k } remaining_tags.keys.each do |k| report k, k, remaining_tags end end
clock(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 135 def self.clock opts, argv start = Chronic.parse(opts.to_hash[:start]) # nil if no option specified stop_opt = Chronic.parse(opts.to_hash[:stop]) # nil if no option specified end_opt = Chronic.parse(opts.to_hash[:end]) # nil if no option specified stop = stop_opt ? stop_opt : end_opt # stop_opt if --stop, end_opt if --end, nil otherwise notes = argv.join(" ") # empty string if no args specified if stop_opt and end_opt then puts "Timeless error: specify end time with either --end or --stop (not both)" exit end manage_stop start, stop, notes, opts[:last] end
console(opts, argv = [])
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 42 def self.console opts, argv = [] all_commands = CommandSyntax.commands all_commands.delete(:console) i = 0 while true string = Readline.readline("#{APPNAME}:%03d> " % i, true) string.gsub!(/^#{APPNAME} /, "") # as a courtesy, remove any leading appname string if string == "exit" or string == "quit" or string == "." then exit 0 end reps all_commands, string.split(' ') i = i + 1 end end
current(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 150 def self.current opts, argv if Timeless::Stopwatch.clocking? then start, notes = Timeless::Stopwatch.get_start puts "Timeless: you have been clocking #{"%.0d" % ((Time.now- Time.parse(start)) / 60)} minutes" puts "on: #{notes}" if notes else puts "There is no clock started." end end
export(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 172 def self.export opts, argv Timeless::Storage.export end
forget(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 117 def self.forget opts, argv if File.exists?(Timeless::Stopwatch::START_FILENAME) entry = Timeless::Storage.last Timeless::Stopwatch.forget puts "Forgotten timer started at #{entry[0]} (#{entry[2]})." else puts "You don't have an active timer" end end
gaps(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 176 def self.gaps opts, argv from = opts.to_hash[:from] ? Chronic.parse(opts.to_hash[:from]) : nil to = opts.to_hash[:to] ? Chronic.parse(opts.to_hash[:to]) : nil interval = opts.to_hash[:interval] || 1 entries = Timeless::Storage.get(from, to) previous_stop = from || Time.parse(entries[0][0]) day = "" printf "%-18s %-5s - %-5s %-6s %-s\n", "Day", "Start", "End", "Gap", "Command to fix" entries.sort { |x,y| Time.parse(x[0]) <=> Time.parse(y[0]) }.each do |entry| current_start = Time.parse(entry[0]) current_day = current_start.strftime("%a %b %d, %Y") if (current_start.day == previous_stop.day and current_start - previous_stop > interval * 60) then if current_day != day then day = current_day else current_day = "" # avoid printing the day if same as before end duration = (current_start - previous_stop) / 60 printf "%-18s %5s - %5s %02i:%02i %s\n", current_day, previous_stop.strftime("%H:%M"), current_start.strftime("%H:%M"), duration / 60, duration % 60, "timeless clock --start '#{previous_stop}' --end '#{current_start}'" end previous_stop = Time.parse(entry[1]) end end
help(opts = nil, argv = [])
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 26 def self.help opts = nil, argv = [] all_commands = CommandSyntax.commands if argv != [] argv.map { |x| puts all_commands[x.to_sym][2] } else puts "#{APPNAME} command [options] [args]" puts "" puts "Available commands:" puts "" all_commands.keys.each do |key| puts " " + all_commands[key][0].banner end end end
last(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 160 def self.last opts, argv puts last_entry end
list(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 164 def self.list opts, argv values = Timeless::Storage.get_key argv[0] puts "Timeless: list of keys #{argv[0]} found in timesheets:" values.each do |value| puts value end end
man(opts = nil, argv = [])
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 19 def self.man opts = nil, argv = [] path = File.join(File.dirname(__FILE__), "/../../../README.org") file = File.open(path, "r") contents = file.read puts contents end
pom(opts, argv)
click to toggle source
APP SPECIFIC COMMANDS
# File lib/timeless/cli/command_semantics.rb, line 92 def self.pom opts, argv duration = opts.to_hash[:duration] || (opts.to_hash[:long] ? Timeless::Pomodoro::WORKING_LONG : Timeless::Pomodoro::WORKING) start, stop, notes = Timeless::Pomodoro.run_pomodoro_timer(duration, argv.join(" ")) Timeless::Storage.store(start, stop, notes) puts last_entry end
reps(all_commands, argv)
click to toggle source
read-eval-print step
# File lib/timeless/cli/command_semantics.rb, line 59 def self.reps all_commands, argv if argv == [] or argv[0] == "--help" or argv[0] == "-h" CommandSemantics.help exit 0 else command = argv[0] syntax_and_semantics = all_commands[command.to_sym] if syntax_and_semantics opts = syntax_and_semantics[0] function = syntax_and_semantics[1] begin parser = Slop::Parser.new(opts) result = parser.parse(argv[1..-1]) options = result.to_hash arguments = result.arguments eval "CommandSemantics::#{function}(options, arguments)" rescue Slop::Error => e puts "#{APPNAME}: #{e}" rescue Exception => e puts e end else puts "#{APPNAME}: '#{command}' is not a valid command. See '#{APPNAME} help'" end end end
start(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 102 def self.start opts, argv start = Chronic.parse(opts.to_hash[:at]) # nil if no option specified notes = argv.join(" ") # empty string is no args specified force = opts.to_hash[:force] if Timeless::Stopwatch.clocking? and not force start, notes = Timeless::Stopwatch.get_start # for information purposes only puts "There is a clock started at #{start} (notes: \"#{notes}\"). Use --force to override." else Timeless::Stopwatch.start(start, notes) puts "Clock started at #{start ? start : Time.now}." puts "You may want to specify notes for the entry when you stop clocking." if notes == "" end end
statement(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 213 def self.statement opts, argv from = opts.to_hash[:from] ? Chronic.parse(opts.to_hash[:from]) : nil to = opts.to_hash[:to] ? Chronic.parse(opts.to_hash[:to]) : nil entries = Timeless::Storage.get(from, to, opts.to_hash[:filter]) # it could become a function of a reporting module printf "%-18s %-5s - %-5s %-8s %-s\n", "Day", "Start", "End", "Duration", "Notes" total = 0 day = "" entries.sort { |x,y| Time.parse(x[0]) <=> Time.parse(y[0]) }.each do |entry| current_day = Time.parse(entry[0]).strftime("%a %b %d, %Y") if current_day != day then day = current_day else current_day = "" # avoid printing the day if same as before end duration = (Time.parse(entry[1]) - Time.parse(entry[0])) / 60 total = total + duration printf "%-18s %5s - %5s %5s %s\n", current_day, Time.parse(entry[0]).strftime("%H:%M"), Time.parse(entry[1]).strftime("%H:%M"), in_hours(duration), entry[2] end puts "----------------------------------------------------------------------" printf "Total %02i:%02i\n", total / 60, total % 60 end
stop(opts, argv)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 127 def self.stop opts, argv start = Chronic.parse(opts.to_hash[:start]) # nil if no option specified stop = Chronic.parse(opts.to_hash[:at]) # nil if no option specified notes = argv.join(" ") # empty string if no args specified manage_stop start, stop, notes, opts[:last] end
version(opts = nil, argv = [])
click to toggle source
Main App Starts Here!
# File lib/timeless/cli/command_semantics.rb, line 15 def self.version opts = nil, argv = [] puts "#{APPNAME} version #{VERSION}" end
Private Class Methods
backup(filename)
click to toggle source
GENERAL UTILITIES
# File lib/timeless/cli/command_semantics.rb, line 332 def self.backup filename FileUtils::cp filename, filename + "~" puts "Backup copy #{filename} created in #{filename}~." end
backup_and_write(filename, content)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 337 def self.backup_and_write filename, content backup(filename) if File.exist?(filename) File.open(filename, "w") { |f| f.puts content } end
in_hours(value)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 277 def self.in_hours value sprintf "%02i:%02i", value / 60, value % 60 end
last_entry()
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 281 def self.last_entry start, stop, notes = Timeless::Storage.last interval = Time.parse(stop) - Time.parse(start) seconds = interval % 60 minutes = (interval / 60) % 60 hours = interval / 3600 sprintf "Timeless: you clocked %02d:%02d:%02d on %s\nYou stopped clocking at: %s", hours, minutes, seconds, notes, stop end
manage_stop(start, stop, notes, reuse_last)
click to toggle source
code shared by stop and clock (which accept slightly different options, but behave in the same way
# File lib/timeless/cli/command_semantics.rb, line 296 def self.manage_stop start, stop, notes, reuse_last # syntax check: # - --start is illegal if there is a running clock # - --last is illegal if there are notes # # however: # - --last and notes prevail over notes stored when starting the clock if Timeless::Stopwatch.clocking? and start puts "Timeless error: you specified --start with a running clock. Use 'timeless forget' or drop --start" end if reuse_last and notes != "" then puts "Timeless error: you specified both --last and notes. Choose one or the other" end if reuse_last then _, _, notes = Timeless::Storage.last end if Timeless::Stopwatch.clocking? start, stop, notes = Timeless::Stopwatch.stop(start, stop, notes) # merge passed with data in running clock Timeless::Storage.store(start, stop, notes) puts "Clock stopped at #{stop}." puts last_entry else start = start ? start : Timeless::Storage.last[1] stop = stop ? stop : Time.now Timeless::Storage.store(start, stop, notes) puts "Clock stopped at #{stop}." puts last_entry end end
report(title, key, hash)
click to toggle source
# File lib/timeless/cli/command_semantics.rb, line 264 def self.report title, key, hash total = 0 puts "" puts title puts "=" * title.size (hash[key] || []).each do |k, v| printf "%-20s%5s\n", k, in_hours(v) total += v end puts "-------------------------" printf "%-20s%5s\n", "Total", in_hours(total) end