Module: Timeless::CommandSemantics

Defined in:
lib/timeless/cli/command_semantics.rb

Constant Summary collapse

APPNAME =
'timeless'
VERSION =
Timeless::VERSION

Class Method Summary collapse

Class Method Details

.balance(opts, argv) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/timeless/cli/command_semantics.rb', line 244

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]

  total = 0
  puts "Projects"
  puts "========"
  hash["p"].each do |key, value|
    printf "%-20s%5s\n", key, in_hours(value)
    total += value
  end
  puts "-------------------------"
  printf "%-20s%5s\n", "Total", in_hours(total)

  total = 0
  puts ""
  puts "Clients"
  puts "======="
  hash["c"].each do |key, value|
    printf "%-20s%5s\n", key, in_hours(value)
    total += value
  end
  puts "-------------------------"
  printf "%-20s%5s\n", "Total", in_hours(total)

  total = 0
  puts ""
  puts "Activities"
  puts "=========="
  hash["a"].each do |key, value|
    printf "%-20s%5s\n", key, in_hours(value)
    total += value
  end
  puts "-------------------------"
  printf "%-20s%5s\n", "Total", in_hours(total)
end

.clock(opts, argv) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
# 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 = []) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 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) ⇒ Object



150
151
152
153
154
155
156
157
158
# 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) ⇒ Object



172
173
174
# File 'lib/timeless/cli/command_semantics.rb', line 172

def self.export opts, argv
  Timeless::Storage.export
end

.forget(opts, argv) ⇒ Object



117
118
119
120
121
122
123
124
125
# 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) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# 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 = []) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 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) ⇒ Object



160
161
162
# File 'lib/timeless/cli/command_semantics.rb', line 160

def self.last opts, argv
  puts last_entry
end

.list(opts, argv) ⇒ Object



164
165
166
167
168
169
170
# 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 = []) ⇒ Object



19
20
21
22
23
24
# File 'lib/timeless/cli/command_semantics.rb', line 19

def self.man opts = nil, argv = []
  path = File.join(File.dirname(__FILE__), "/../../../README.md")
  file = File.open(path, "r")
  contents = file.read
  puts contents
end

.pom(opts, argv) ⇒ Object

APP SPECIFIC COMMANDS



92
93
94
95
96
97
98
99
# 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) ⇒ Object

read-eval-print step



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
86
87
# 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) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 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) ⇒ Object



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# 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) ⇒ Object



127
128
129
130
131
132
133
# 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 = []) ⇒ Object

Main App Starts Here!



15
16
17
# File 'lib/timeless/cli/command_semantics.rb', line 15

def self.version opts = nil, argv = []
  puts "#{APPNAME} version #{VERSION}"
end