timetrap 1.10.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CONTRIBUTORS +1 -0
- data/README.md +18 -2
- data/lib/timetrap.rb +1 -0
- data/lib/timetrap/cli.rb +41 -9
- data/lib/timetrap/config.rb +3 -1
- data/lib/timetrap/formatters/text.rb +50 -8
- data/lib/timetrap/version.rb +1 -1
- data/spec/timetrap_spec.rb +172 -46
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 271617ba22c6a444786172a06c319c130e520e3e
|
4
|
+
data.tar.gz: 58a80a95272541cf095d4727e580a1feda1b49f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75ac29be79462ac44122fedbe8255b48091d749cd08eed5ef672327c7d1a8e949f40ffdb584d3a203e2a3a42ea4ff0ef2ba81ca13c25477555e5d0d96556d409
|
7
|
+
data.tar.gz: d85f15fd101a3a3a321b2d6283c744ac1f7fdc919ee292a8366ad71543841fb70253c2274b8bbd691fae9ef6ac260386e51adf23c1b22fd344b6e287ed989dfb
|
data/.travis.yml
CHANGED
data/CONTRIBUTORS
CHANGED
data/README.md
CHANGED
@@ -301,7 +301,7 @@ Commands
|
|
301
301
|
Archives the selected entries (by moving them to a sheet called ``_[SHEET]``)
|
302
302
|
These entries can be seen by running ``t display _[SHEET]``.
|
303
303
|
|
304
|
-
usage: ``t archive [--start DATE] [--end DATE] [SHEET]``
|
304
|
+
usage: ``t archive [--start DATE] [--end DATE] [--grep REGEX] [SHEET]``
|
305
305
|
|
306
306
|
**backend**
|
307
307
|
Run an interactive database session on the timetrap database. Requires the
|
@@ -331,7 +331,7 @@ Commands
|
|
331
331
|
Display also allows the use of a ``--round`` or ``-r`` flag which will round
|
332
332
|
all times in the output. See global options below.
|
333
333
|
|
334
|
-
usage: ``t display [--ids] [--round] [--start DATE] [--end DATE] [--format FMT] [SHEET | all | full]``
|
334
|
+
usage: ``t display [--ids] [--round] [--start DATE] [--end DATE] [--format FMT] [--grep REGEX] [SHEET | all | full]``
|
335
335
|
|
336
336
|
**edit**
|
337
337
|
Inserts a note associated with the an entry in the timesheet, or edits the
|
@@ -454,6 +454,11 @@ See ``t configure`` for details. Currently supported options are:
|
|
454
454
|
**auto_sheet_search_paths**: an array of directories to search for user
|
455
455
|
defined auto_sheet classes
|
456
456
|
|
457
|
+
**note_editor**: The command to start editing notes. Defaults to false which
|
458
|
+
means no external editor is used. Please see the section below
|
459
|
+
on Notes Editing for tips on using non-terminal based editors.
|
460
|
+
Example: note_editor: "vim"
|
461
|
+
|
457
462
|
|
458
463
|
### Autocomplete
|
459
464
|
|
@@ -494,6 +499,17 @@ Then add this to source the completions:
|
|
494
499
|
fpath=(/path/to/timetrap-1.x.y/gem/completions/zsh $fpath)
|
495
500
|
```
|
496
501
|
|
502
|
+
#### Notes editing
|
503
|
+
If you use the note_editor setting, then it is possible to use
|
504
|
+
an editor for writing your notes. If you use a non terminal based
|
505
|
+
editor (like atom, sublime etc.) then you will need to make timetrap
|
506
|
+
wait until the editor has finished. If you're using the "core.editor"
|
507
|
+
flag in git, then it'll be the same flags you'll use.
|
508
|
+
|
509
|
+
As of when this command was added, for atom you would use `atom --wait`
|
510
|
+
and for sublime `subl -w`. If you use a console based editor (vim, emacs,
|
511
|
+
nano) then it should just work.
|
512
|
+
|
497
513
|
Special Thanks
|
498
514
|
--------------
|
499
515
|
|
data/lib/timetrap.rb
CHANGED
data/lib/timetrap/cli.rb
CHANGED
@@ -42,6 +42,9 @@ COMMAND is one of:
|
|
42
42
|
you check in or out
|
43
43
|
require_note: Prompt for a note if one isn't provided when
|
44
44
|
checking in
|
45
|
+
note_editor: Command to launch notes editor or false if no editor use.
|
46
|
+
If you use a non terminal based editor (e.g. sublime, atom)
|
47
|
+
please read the notes in the README.
|
45
48
|
|
46
49
|
* display - Display the current timesheet or a specific. Pass `all' as SHEET
|
47
50
|
to display all unarchived sheets or `full' to display archived and
|
@@ -74,7 +77,7 @@ COMMAND is one of:
|
|
74
77
|
|
75
78
|
* kill - Delete a timesheet or an entry.
|
76
79
|
usage: t kill [--id ID] [TIMESHEET]
|
77
|
-
-i, --id <id:i>
|
80
|
+
-i, --id <id:i> Delete entry with id <id> instead of timesheet
|
78
81
|
|
79
82
|
* list - Show the available timesheets.
|
80
83
|
usage: t list
|
@@ -239,15 +242,24 @@ COMMAND is one of:
|
|
239
242
|
entry.update :sheet => args['-m']
|
240
243
|
end
|
241
244
|
|
242
|
-
|
243
|
-
if unused_args =~ /.+/
|
244
|
-
note = unused_args
|
245
|
+
if Config['note_editor']
|
245
246
|
if args['-z']
|
246
|
-
note = [entry.note,
|
247
|
+
note = [entry.note, get_note_from_external_editor].join(Config['append_notes_delimiter'])
|
248
|
+
entry.update :note => note
|
249
|
+
elsif args.size == 0 # no arguments supplied
|
250
|
+
entry.update :note => get_note_from_external_editor(entry.note)
|
251
|
+
end
|
252
|
+
else
|
253
|
+
if unused_args =~ /.+/
|
254
|
+
note = unused_args
|
255
|
+
if args['-z']
|
256
|
+
note = [entry.note, note].join(Config['append_notes_delimiter'])
|
257
|
+
end
|
258
|
+
entry.update :note => note
|
247
259
|
end
|
248
|
-
entry.update :note => note
|
249
260
|
end
|
250
261
|
|
262
|
+
|
251
263
|
puts format_entries(entry)
|
252
264
|
end
|
253
265
|
|
@@ -262,12 +274,17 @@ COMMAND is one of:
|
|
262
274
|
end
|
263
275
|
end
|
264
276
|
|
277
|
+
note = unused_args
|
265
278
|
if Config['require_note'] && !Timer.running? && unused_args.empty?
|
266
|
-
|
267
|
-
|
279
|
+
if Config['note_editor']
|
280
|
+
note = get_note_from_external_editor
|
281
|
+
else
|
282
|
+
$stderr.print("Please enter a note for this entry:\n> ")
|
283
|
+
note = $stdin.gets.strip
|
284
|
+
end
|
268
285
|
end
|
269
286
|
|
270
|
-
Timer.start
|
287
|
+
Timer.start note, args['-a']
|
271
288
|
warn "Checked into sheet #{Timer.current_sheet.inspect}."
|
272
289
|
end
|
273
290
|
|
@@ -453,6 +470,21 @@ COMMAND is one of:
|
|
453
470
|
$stdin.gets =~ /\Aye?s?\Z/i
|
454
471
|
end
|
455
472
|
|
473
|
+
def get_note_from_external_editor(contents = "")
|
474
|
+
file = Tempfile.new('get_note')
|
475
|
+
unless contents.empty?
|
476
|
+
file.open
|
477
|
+
file.write(contents)
|
478
|
+
file.close
|
479
|
+
end
|
480
|
+
|
481
|
+
system("#{Config['note_editor']} #{file.path}")
|
482
|
+
file.open.read
|
483
|
+
ensure
|
484
|
+
file.close
|
485
|
+
file.unlink
|
486
|
+
end
|
487
|
+
|
456
488
|
extend Helpers::AutoLoad
|
457
489
|
def format_entries(entries)
|
458
490
|
load_formatter(args['-f'] || Config['default_formatter']).new(Array(entries)).output
|
data/lib/timetrap/config.rb
CHANGED
@@ -35,7 +35,9 @@ module Timetrap
|
|
35
35
|
# automatically check out of any running tasks when checking in.
|
36
36
|
'auto_checkout' => false,
|
37
37
|
# interactively prompt for a note if one isn't passed when checking in.
|
38
|
-
'require_note' => false
|
38
|
+
'require_note' => false,
|
39
|
+
# command to launch external editor (false if no external editor used)
|
40
|
+
'note_editor' => false
|
39
41
|
}
|
40
42
|
end
|
41
43
|
|
@@ -1,22 +1,19 @@
|
|
1
1
|
module Timetrap
|
2
2
|
module Formatters
|
3
3
|
class Text
|
4
|
+
LONGEST_NOTE_LENGTH = 50
|
4
5
|
attr_accessor :output
|
5
6
|
include Timetrap::Helpers
|
6
7
|
|
7
8
|
def initialize entries
|
9
|
+
@entries = entries
|
8
10
|
self.output = ''
|
9
11
|
sheets = entries.inject({}) do |h, e|
|
10
12
|
h[e.sheet] ||= []
|
11
13
|
h[e.sheet] << e
|
12
14
|
h
|
13
15
|
end
|
14
|
-
|
15
|
-
max_id_length = if Timetrap::CLI.args['-v']
|
16
|
-
entries.inject(3) {|l, e| [e.id.to_s.length, l].max}
|
17
|
-
else
|
18
|
-
3
|
19
|
-
end
|
16
|
+
|
20
17
|
(sheet_names = sheets.keys.sort).each do |sheet|
|
21
18
|
|
22
19
|
self.output << "Timesheet: #{sheet}\n"
|
@@ -25,7 +22,6 @@ module Timetrap
|
|
25
22
|
last_start = nil
|
26
23
|
from_current_day = []
|
27
24
|
|
28
|
-
|
29
25
|
sheets[sheet].each_with_index do |e, i|
|
30
26
|
from_current_day << e
|
31
27
|
self.output << "%-#{max_id_length + 1}s%16s%11s -%9s%10s %s\n" % [
|
@@ -34,7 +30,7 @@ module Timetrap
|
|
34
30
|
format_time(e.start),
|
35
31
|
format_time(e.end),
|
36
32
|
format_duration(e.duration),
|
37
|
-
e.note
|
33
|
+
format_note(e.note)
|
38
34
|
]
|
39
35
|
|
40
36
|
nxt = sheets[sheet].to_a[i+1]
|
@@ -53,7 +49,53 @@ module Timetrap
|
|
53
49
|
self.output << "%s\n" % ('-'*(4+52+longest_note))
|
54
50
|
self.output << "Grand Total%41s\n" % format_total(sheets.values.flatten)
|
55
51
|
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_reader :entries
|
60
|
+
|
61
|
+
def longest_note
|
62
|
+
@longest_note ||= begin
|
63
|
+
entries.inject('Notes'.length) {|l, e| [e.note.to_s.rstrip.length, LONGEST_NOTE_LENGTH].min}
|
64
|
+
end
|
56
65
|
end
|
66
|
+
|
67
|
+
def max_id_length
|
68
|
+
@max_id_length ||= begin
|
69
|
+
if Timetrap::CLI.args['-v']
|
70
|
+
entries.inject(3) {|l, e| [e.id.to_s.length, l].max}
|
71
|
+
else
|
72
|
+
3
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def format_note(note)
|
78
|
+
return "" unless note
|
79
|
+
|
80
|
+
lines = []
|
81
|
+
line_number = 0
|
82
|
+
note.lines.each do |line|
|
83
|
+
while index = line.index(/\s/, LONGEST_NOTE_LENGTH) do
|
84
|
+
shorter_line = line.slice!(0..(index - 1))
|
85
|
+
lines << padded_line(shorter_line.strip, line_number)
|
86
|
+
line_number += 1
|
87
|
+
end
|
88
|
+
lines << padded_line(line.strip, line_number)
|
89
|
+
line_number += 1
|
90
|
+
end
|
91
|
+
lines.join("\n")
|
92
|
+
end
|
93
|
+
|
94
|
+
def padded_line(content, line_number)
|
95
|
+
return content if line_number == 0
|
96
|
+
"#{" " * (56 + max_id_length - 3) }#{content}"
|
97
|
+
end
|
98
|
+
|
57
99
|
end
|
58
100
|
end
|
59
101
|
end
|
data/lib/timetrap/version.rb
CHANGED
data/spec/timetrap_spec.rb
CHANGED
@@ -3,6 +3,18 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'timetra
|
|
3
3
|
require 'rspec'
|
4
4
|
require 'fakefs/safe'
|
5
5
|
|
6
|
+
RSpec.configure do |config|
|
7
|
+
# as we are stubbing stderr and stdout, if you want to capture
|
8
|
+
# any of your output in tests, simply add :write_stdout_stderr => true
|
9
|
+
# as metadata to the end of your test
|
10
|
+
config.after(:each, write_stdout_stderr: true) do
|
11
|
+
$stderr.rewind
|
12
|
+
$stdout.rewind
|
13
|
+
File.write("stderr.txt", $stderr.read)
|
14
|
+
File.write("stdout.txt", $stdout.read)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
def local_time(str)
|
7
19
|
Timetrap::Timer.process_time(str)
|
8
20
|
end
|
@@ -14,7 +26,7 @@ end
|
|
14
26
|
module Timetrap::StubConfig
|
15
27
|
def with_stubbed_config options = {}
|
16
28
|
defaults = Timetrap::Config.defaults.dup
|
17
|
-
Timetrap::Config.stub(:[])
|
29
|
+
Timetrap::Config.stub(:[]) do |k|
|
18
30
|
defaults.merge(options)[k]
|
19
31
|
end
|
20
32
|
yield if block_given?
|
@@ -129,9 +141,9 @@ describe Timetrap do
|
|
129
141
|
FileUtils.mkdir_p(ENV['HOME'])
|
130
142
|
config_file = ENV['HOME'] + '/.timetrap.yml'
|
131
143
|
FileUtils.rm(config_file) if File.exist? config_file
|
132
|
-
File.exist?(config_file).should
|
144
|
+
File.exist?(config_file).should be_falsey
|
133
145
|
invoke "configure"
|
134
|
-
File.exist?(config_file).should
|
146
|
+
File.exist?(config_file).should be_truthy
|
135
147
|
end
|
136
148
|
end
|
137
149
|
|
@@ -232,12 +244,63 @@ describe Timetrap do
|
|
232
244
|
not_running.refresh.sheet.should == 'default'
|
233
245
|
Timetrap::Timer.current_sheet.should == 'another second sheet'
|
234
246
|
end
|
247
|
+
|
248
|
+
context "with external editor" do
|
249
|
+
let(:note_editor_command) { 'vim' }
|
250
|
+
|
251
|
+
before do
|
252
|
+
with_stubbed_config 'note_editor' => note_editor_command, 'append_notes_delimiter' => '//'
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should open an editor for editing the note" do |example|
|
256
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
257
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
258
|
+
File.write(path[:path], "edited note")
|
259
|
+
end
|
260
|
+
Timetrap::Timer.active_entry.note.should == 'running entry'
|
261
|
+
invoke "edit"
|
262
|
+
Timetrap::Timer.active_entry.note.should == 'edited note'
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should pass existing note to editor" do |example|
|
266
|
+
capture = nil
|
267
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
268
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
269
|
+
|
270
|
+
capture = File.read(path[:path])
|
271
|
+
end
|
272
|
+
invoke "edit"
|
273
|
+
expect(capture).to eq("running entry")
|
274
|
+
end
|
275
|
+
|
276
|
+
context "appending" do
|
277
|
+
it "should open an editor for editing the note with -z" do |example|
|
278
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
279
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
280
|
+
File.write(path[:path], "appended in editor")
|
281
|
+
end
|
282
|
+
Timetrap::Timer.active_entry.note.should == 'running entry'
|
283
|
+
invoke "edit -z"
|
284
|
+
Timetrap::Timer.active_entry.note.should == 'running entry//appended in editor'
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should open a editor for editing the note with --append" do |example|
|
288
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
289
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
290
|
+
File.write(path[:path], "appended in editor")
|
291
|
+
end
|
292
|
+
Timetrap::Timer.active_entry.note.should == 'running entry'
|
293
|
+
invoke "edit --append"
|
294
|
+
Timetrap::Timer.active_entry.note.should == 'running entry//appended in editor'
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
235
298
|
end
|
236
299
|
|
237
300
|
describe 'auto_sheet' do
|
238
301
|
describe "using dotfiles auto_sheet" do
|
239
302
|
describe 'with a .timetrap-sheet in cwd' do
|
240
|
-
it 'should use sheet defined in
|
303
|
+
it 'should use sheet defined in dotfile' do
|
241
304
|
Dir.chdir('spec/dotfile') do
|
242
305
|
with_stubbed_config('auto_sheet' => 'dotfiles')
|
243
306
|
Timetrap::Timer.current_sheet.should == 'dotfile-sheet'
|
@@ -357,6 +420,12 @@ The "format" command is deprecated in favor of "display". Sorry for the inconven
|
|
357
420
|
Timetrap::Entry.create( :sheet => 'SpecSheet',
|
358
421
|
:note => 'entry 4', :start => '2008-10-05 18:00:00'
|
359
422
|
)
|
423
|
+
Timetrap::Entry.create( :sheet => 'LongNoteSheet',
|
424
|
+
:note => "long notesheet " * 20, :start => '2008-10-05 16:00:00', :end => '2008-10-05 18:00:00'
|
425
|
+
)
|
426
|
+
Timetrap::Entry.create( :sheet => 'SheetWithLineBreakNote',
|
427
|
+
:note => "first line\nand a second line ", :start => '2008-10-05 16:00:00', :end => '2008-10-05 18:00:00'
|
428
|
+
)
|
360
429
|
|
361
430
|
now = local_time('2008-10-05 20:00:00')
|
362
431
|
Time.stub(:now).and_return now
|
@@ -410,26 +479,42 @@ Id Day Start End Duration Notes
|
|
410
479
|
Total 8:00:00
|
411
480
|
OUTPUT
|
412
481
|
|
413
|
-
@
|
414
|
-
Timesheet:
|
482
|
+
@desired_output_for_long_note_sheet = <<-OUTPUT
|
483
|
+
Timesheet: LongNoteSheet
|
415
484
|
Day Start End Duration Notes
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
485
|
+
Sun Oct 05, 2008 16:00:00 - 18:00:00 2:00:00 long notesheet long notesheet long notesheet long notesheet
|
486
|
+
long notesheet long notesheet long notesheet long
|
487
|
+
notesheet long notesheet long notesheet long notesheet
|
488
|
+
long notesheet long notesheet long notesheet long
|
489
|
+
notesheet long notesheet long notesheet long notesheet
|
490
|
+
long notesheet long notesheet
|
491
|
+
2:00:00
|
492
|
+
------------------------------------------------------------------------------------------------------
|
493
|
+
Total 2:00:00
|
494
|
+
OUTPUT
|
495
|
+
|
496
|
+
@desired_output_for_long_note_sheet_with_ids = <<-OUTPUT
|
497
|
+
Timesheet: LongNoteSheet
|
498
|
+
Id Day Start End Duration Notes
|
499
|
+
60000 Sun Oct 05, 2008 16:00:00 - 18:00:00 2:00:00 long notesheet long notesheet long notesheet long notesheet
|
500
|
+
long notesheet long notesheet long notesheet long
|
501
|
+
notesheet long notesheet long notesheet long notesheet
|
502
|
+
long notesheet long notesheet long notesheet long
|
503
|
+
notesheet long notesheet long notesheet long notesheet
|
504
|
+
long notesheet long notesheet
|
505
|
+
2:00:00
|
506
|
+
------------------------------------------------------------------------------------------------------
|
507
|
+
Total 2:00:00
|
508
|
+
OUTPUT
|
424
509
|
|
425
|
-
|
510
|
+
@desired_output_for_note_with_linebreak = <<-OUTPUT
|
511
|
+
Timesheet: SheetWithLineBreakNote
|
426
512
|
Day Start End Duration Notes
|
427
|
-
Sun Oct 05, 2008
|
513
|
+
Sun Oct 05, 2008 16:00:00 - 18:00:00 2:00:00 first line
|
514
|
+
and a second line
|
428
515
|
2:00:00
|
429
|
-
|
516
|
+
--------------------------------------------------------------------------------
|
430
517
|
Total 2:00:00
|
431
|
-
-------------------------------------------------------------------------
|
432
|
-
Grand Total 10:00:00
|
433
518
|
OUTPUT
|
434
519
|
end
|
435
520
|
|
@@ -484,10 +569,23 @@ Grand Total 10:00:00
|
|
484
569
|
end
|
485
570
|
|
486
571
|
|
487
|
-
it "should display
|
488
|
-
Timetrap::Timer.current_sheet = '
|
489
|
-
invoke 'display
|
490
|
-
$stdout.string.should == @
|
572
|
+
it "should display long notes nicely" do
|
573
|
+
Timetrap::Timer.current_sheet = 'LongNoteSheet'
|
574
|
+
invoke 'display'
|
575
|
+
$stdout.string.should == @desired_output_for_long_note_sheet
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should display long notes with linebreaks nicely" do
|
579
|
+
Timetrap::Timer.current_sheet = 'SheetWithLineBreakNote'
|
580
|
+
invoke 'display'
|
581
|
+
$stdout.string.should == @desired_output_for_note_with_linebreak
|
582
|
+
end
|
583
|
+
|
584
|
+
it "should display long notes with ids nicely" do
|
585
|
+
Timetrap::DB["UPDATE entries SET id = 60000 WHERE id = 6"].all
|
586
|
+
Timetrap::Timer.current_sheet = 'LongNoteSheet'
|
587
|
+
invoke 'display --ids'
|
588
|
+
$stdout.string.should == @desired_output_for_long_note_sheet_with_ids
|
491
589
|
end
|
492
590
|
|
493
591
|
it "should not display archived for all timesheets" do
|
@@ -617,17 +715,17 @@ start,end,note,sheet
|
|
617
715
|
invoke 'in'
|
618
716
|
invoke 'display --format ical'
|
619
717
|
|
620
|
-
$stdout.string.scan(/BEGIN:VEVENT/).
|
718
|
+
expect($stdout.string.scan(/BEGIN:VEVENT/).size).to eq(2)
|
621
719
|
end
|
622
720
|
|
623
721
|
it "should filter events by the passed dates" do
|
624
722
|
invoke 'display --format ical --start 2008-10-03 --end 2008-10-03'
|
625
|
-
$stdout.string.scan(/BEGIN:VEVENT/).
|
723
|
+
expect($stdout.string.scan(/BEGIN:VEVENT/).size).to eq(1)
|
626
724
|
end
|
627
725
|
|
628
726
|
it "should not filter events by date when none are passed" do
|
629
727
|
invoke 'display --format ical'
|
630
|
-
$stdout.string.scan(/BEGIN:VEVENT/).
|
728
|
+
expect($stdout.string.scan(/BEGIN:VEVENT/).size).to eq(2)
|
631
729
|
end
|
632
730
|
|
633
731
|
it "should export a sheet to an ical format" do
|
@@ -701,28 +799,56 @@ END:VCALENDAR
|
|
701
799
|
end
|
702
800
|
|
703
801
|
describe "with require_note config option set" do
|
704
|
-
|
705
|
-
|
706
|
-
|
802
|
+
context "without a note_editor" do
|
803
|
+
before do
|
804
|
+
with_stubbed_config 'require_note' => true, 'note_editor' => false
|
805
|
+
end
|
707
806
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
807
|
+
it "should prompt for a note if one isn't passed" do
|
808
|
+
$stdin.string = "an interactive note\n"
|
809
|
+
invoke "in"
|
810
|
+
$stderr.string.should include('enter a note')
|
811
|
+
Timetrap::Timer.active_entry.note.should == "an interactive note"
|
812
|
+
end
|
714
813
|
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
814
|
+
it "should not prompt for a note if one is passed" do
|
815
|
+
$stdin.string = "an interactive note\n"
|
816
|
+
invoke "in a normal note"
|
817
|
+
Timetrap::Timer.active_entry.note.should == "a normal note"
|
818
|
+
end
|
819
|
+
|
820
|
+
it "should not stop the running entry or prompt" do
|
821
|
+
invoke "in a normal note"
|
822
|
+
$stdin.string = "an interactive note\n"
|
823
|
+
invoke "in"
|
824
|
+
Timetrap::Timer.active_entry.note.should == "a normal note"
|
825
|
+
end
|
719
826
|
end
|
720
827
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
828
|
+
context "with a note editor" do
|
829
|
+
let(:note_editor_command) { 'vim' }
|
830
|
+
before do
|
831
|
+
with_stubbed_config 'require_note' => true, 'note_editor' => note_editor_command
|
832
|
+
end
|
833
|
+
|
834
|
+
it "should open an editor for writing the note" do |example|
|
835
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
836
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
837
|
+
File.write(path[:path], "written in editor")
|
838
|
+
end
|
839
|
+
invoke "in"
|
840
|
+
$stderr.string.should_not include('enter a note')
|
841
|
+
Timetrap::Timer.active_entry.note.should == "written in editor"
|
842
|
+
end
|
843
|
+
|
844
|
+
it "should preserve linebreaks from editor" do |example|
|
845
|
+
Timetrap::CLI.stub(:system) do |editor_command|
|
846
|
+
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
847
|
+
File.write(path[:path], "line1\nline2")
|
848
|
+
end
|
849
|
+
invoke "in"
|
850
|
+
Timetrap::Timer.active_entry.note.should == "line1\nline2"
|
851
|
+
end
|
726
852
|
end
|
727
853
|
end
|
728
854
|
|
@@ -868,10 +994,10 @@ END:VCALENDAR
|
|
868
994
|
describe "kill" do
|
869
995
|
it "should give me a chance not to fuck up" do
|
870
996
|
entry = create_entry
|
871
|
-
|
997
|
+
expect do
|
872
998
|
$stdin.string = ""
|
873
999
|
invoke "kill #{entry.sheet}"
|
874
|
-
end.
|
1000
|
+
end.not_to change(Timetrap::Entry, :count)
|
875
1001
|
end
|
876
1002
|
|
877
1003
|
it "should delete a timesheet" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timetrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Goldstein
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|