timetrap 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CONTRIBUTORS CHANGED
@@ -1,3 +1,4 @@
1
1
  * Sam Goldstein
2
2
  * Ian Smith-Heisters
3
3
  * Ammar Ali
4
+ * Brian V. Hughes
data/README.md CHANGED
@@ -64,6 +64,31 @@ You check out with the `out` command.
64
64
  $ t out
65
65
  Checked out of sheet "coding"
66
66
 
67
+ You can edit entries that aren't running using `edit`'s `--id` or `-i` flag.
68
+ `t display --verbose` will tell you the ids.
69
+
70
+ $ # note id column in output
71
+ $ t d -v
72
+ Timesheet: coding
73
+ Id Day Start End Duration Notes
74
+ 43 Sun Nov 28, 2010 12:26:10 - 13:41:03 1:14:53 writing readme
75
+ 1:14:53
76
+ ---------------------------------------------------------
77
+ Total 1:14:53
78
+
79
+ $ # -i43 to edit entry 43
80
+ $ t e -i43 --end "2010-11-28 13:45"
81
+ editing entry #43
82
+
83
+ $ t d
84
+ Timesheet: coding
85
+ Day Start End Duration Notes
86
+ Sun Nov 28, 2010 12:26:10 - 13:45:00 1:18:50 writing readme
87
+ 1:18:50
88
+ ---------------------------------------------------------
89
+ Total 1:18:50
90
+
91
+
67
92
  ### Natural Language Times
68
93
 
69
94
  Commands such as `in`, `out`, `edit`, and `display` have flags that accept
@@ -91,7 +116,14 @@ list of parsable time formats, but all of these should work.
91
116
 
92
117
  ### Output Formats
93
118
 
94
- Timetrap supports several output formats. The default is a plain text format.
119
+ #### Built-in Formatters
120
+
121
+ Timetrap has built-in support for 5 output formats.
122
+
123
+ These are **text**, **csv**, **ical**, **json**, and **ids**
124
+
125
+ The default is a plain **text** format. (You can change the default format using
126
+ `t configure`).
95
127
 
96
128
  $ t display
97
129
  Timesheet: coding
@@ -107,7 +139,7 @@ Timetrap supports several output formats. The default is a plain text format.
107
139
  ---------------------------------------------------------
108
140
  Total 3:46:05
109
141
 
110
- You can also output csv for easy import into a spreadsheet.
142
+ The **CSV** formatters is easy to import into a spreadsheet.
111
143
 
112
144
  $ t display --format csv
113
145
  start,end,note,sheet
@@ -120,10 +152,73 @@ You can also output csv for easy import into a spreadsheet.
120
152
  "2010-08-29 21:15:58","2010-08-29 21:30:31","backups","coding"
121
153
  "2010-08-29 21:40:56","2010-08-29 22:32:26","backups","coding"
122
154
 
123
- Or to ical format for import into a calendar program (remember commands can be abbreviated).
155
+ **iCal** format lets you get your time into your favorite calendar program
156
+ (remember commands can be abbreviated).
124
157
 
125
158
  $ t d -f ical > MyTimeSheet.ics
126
159
 
160
+ The **ids** formatter is provided to facilitate scripting within timetrap. It only
161
+ outputs numeric id for the entries. This is handy if you want to move all entries
162
+ from one sheet to another sheet. You could do something like this:
163
+
164
+ $ for id in `t display sheet1 -f ids`; do t edit --id $id --move sheet2; done
165
+ editing entry #36
166
+ editing entry #37
167
+ editing entry #44
168
+ editing entry #46
169
+
170
+ A *json* formatter is also provided, because hackers love json.
171
+
172
+ $ t d -fjson
173
+
174
+ #### Custom Formatters
175
+
176
+ Timetrap tries to make it easy to define custom output formats.
177
+
178
+ You're encouraged to submit these back to timetrap for inclusion in a future
179
+ version.
180
+
181
+ To create a custom formatter you create a ruby class and implement two methods
182
+ on it.
183
+
184
+ As an example we'll create a formatter that only outputs the notes from
185
+ entries.
186
+
187
+ To ensure that timetrap can find your formatter put it in
188
+ `~/.timetrap/formatters/notes.rb`. The filename should be the same as the
189
+ string you will pass to `t d --format` to invoke it. If you want to put your
190
+ formatter in a different place you can run `t configure` and edit the
191
+ `formatter_search_paths` option.
192
+
193
+ All timetrap formatters live under the namespace `Timetrap::Formatters` so
194
+ define your class like this:
195
+
196
+ class Timetrap::Formatters::Notes
197
+ end
198
+
199
+ When `t display` is invoked, timetrap initializes a new instance of the
200
+ formatter passing it an Array of entries. It then calls `#output` which should
201
+ return a string to be printed to the screen.
202
+
203
+ This means we need to implement an `#initialize` method and an `#output`
204
+ method for the class. Something like this:
205
+
206
+ class Timetrap::Formatters::Notes
207
+ def initialize(entries)
208
+ @entries = entries
209
+ end
210
+
211
+ def output
212
+ @entries.map{|entry| entry[:note]}.join("\n")
213
+ end
214
+ end
215
+
216
+ Now when I invoke it:
217
+
218
+ $ t d -f notes
219
+ working on issue #123
220
+ working on issue #234
221
+
127
222
  Commands
128
223
  --------
129
224
  **archive**
@@ -139,9 +234,9 @@ Commands
139
234
 
140
235
  **configure**
141
236
  Creates a config file at ``~/.timetrap.yml`` or ``ENV['TIMETRAP_CONFIG_FILE']`` if
142
- one doesn't exist. Prints path to config file. Currently allows configuration
143
- of path to database file, and the number of seconds used when the `--round`
144
- flag is set (defaults to 15 minutes.)
237
+ one doesn't exist. If one does exist it will update it with new
238
+ configuration options preserving any user overrides. Prints path to config
239
+ file. This file may contain ERB.
145
240
 
146
241
  usage: ``t configure``
147
242
 
@@ -153,7 +248,7 @@ Commands
153
248
 
154
249
  Display is designed to support a variety of export formats that can be
155
250
  specified by passing the ``--format`` flag. This currently defaults to
156
- text. iCal and csv output are also supported.
251
+ text. iCal, csv, json, and numeric id output are also supported.
157
252
 
158
253
  Display also allows the use of a ``--round`` or ``-r`` flag which will round
159
254
  all times in the output. See global options below.
@@ -227,14 +322,20 @@ Global Options
227
322
  Configuration
228
323
  --------
229
324
 
230
- Configuration of TimeTrap's behavior can be done through a YAML config file.
325
+ Configuration of TimeTrap's behavior can be done through an ERB interpolated
326
+ YAML config file.
327
+
231
328
  See ``t configure`` for details. Currently supported options are:
232
329
 
233
- ``round_in_seconds``: The duration of time to use for rounding with the -r flag
330
+ **round_in_seconds**: The duration of time to use for rounding with the -r flag
331
+
332
+ **database_file**: The file path of the sqlite database
333
+
334
+ **append_notes_delimiter**: delimiter used when appending notes via `t edit --append`
234
335
 
235
- ``database_file``: The file path of the sqlite database
336
+ **formatter_search_paths**: an array of directories to search for user defined fomatter classes
236
337
 
237
- ``append_notes_delimiter``: delimiter used when appending notes via ``t edit --append``
338
+ **default_formatter**: The format to use when display is invoked without a `--format` option
238
339
 
239
340
  Special Thanks
240
341
  --------------
data/Rakefile CHANGED
@@ -36,7 +36,6 @@ begin
36
36
  s.add_dependency("sqlite3-ruby", ">= 1.2.5")
37
37
  s.add_dependency("chronic", "~> 0.3.0")
38
38
  s.add_dependency("getopt-declare", ">= 1.28")
39
- s.add_dependency("icalendar", ">= 1.1.2")
40
39
  end
41
40
  rescue LoadError
42
41
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 6
4
- :patch: 1
3
+ :minor: 7
4
+ :patch: 0
data/lib/timetrap.rb CHANGED
@@ -2,22 +2,20 @@ require 'rubygems'
2
2
  require 'chronic'
3
3
  require 'sequel'
4
4
  require 'yaml'
5
+ require 'erb'
5
6
  require 'sequel/extensions/inflector'
6
7
  require 'Getopt/Declare'
7
8
  require File.join(File.dirname(__FILE__), 'timetrap', 'config')
8
9
  require File.join(File.dirname(__FILE__), 'timetrap', 'helpers')
9
10
  require File.join(File.dirname(__FILE__), 'timetrap', 'cli')
10
11
  require File.join(File.dirname(__FILE__), 'timetrap', 'timer')
11
- DB_NAME = defined?(TEST_MODE) ? nil : Timetrap::Config['database_file']
12
- # connect to database. This will create one if it doesn't exist
13
- DB = Sequel.sqlite DB_NAME
14
- require File.join(File.dirname(__FILE__), 'timetrap', 'models')
15
- Dir["#{File.dirname(__FILE__)}/timetrap/formatters/*.rb"].each do |path|
16
- require path
17
- end
18
-
12
+ require File.join(File.dirname(__FILE__), 'timetrap', 'formatters')
19
13
  module Timetrap
14
+ DB_NAME = defined?(TEST_MODE) ? nil : Timetrap::Config['database_file']
15
+ # connect to database. This will create one if it doesn't exist
16
+ DB = Sequel.sqlite DB_NAME
20
17
  CLI.args = Getopt::Declare.new(<<-EOF)
21
18
  #{CLI::USAGE}
22
19
  EOF
23
20
  end
21
+ require File.join(File.dirname(__FILE__), 'timetrap', 'models')
data/lib/timetrap/cli.rb CHANGED
@@ -23,7 +23,8 @@ COMMAND is one of:
23
23
  * backend - Open an sqlite shell to the database.
24
24
  usage: t backend
25
25
 
26
- * configure - Write out a config file. print path to config file.
26
+ * configure - Write out a YAML config file. Print path to config file. The
27
+ file may contain ERB.
27
28
  usage: t configure
28
29
  Currently supported options are:
29
30
  round_in_seconds: The duration of time to use for rounding with
@@ -38,8 +39,11 @@ COMMAND is one of:
38
39
  -v, --ids Print database ids (for use with edit)
39
40
  -s, --start <date:qs> Include entries that start on this date or later
40
41
  -e, --end <date:qs> Include entries that start on this date or earlier
41
- -f, --format <format> The output format. Currently supports ical, csv, and
42
- text (default).
42
+ -f, --format <format> The output format. Valid built-in formats are
43
+ ical, csv, json, ids, and text (default).
44
+ Documentation on defining custom formats can be
45
+ found in the README included in this
46
+ distribution.
43
47
 
44
48
  * edit - Alter an entry's note, start, or end time. Defaults to the active entry.
45
49
  usage: t edit [--id ID] [--start TIME] [--end TIME] [--append] [NOTES]
@@ -106,7 +110,7 @@ COMMAND is one of:
106
110
 
107
111
  def invoke
108
112
  args['-h'] ? puts(USAGE) : invoke_command_if_valid
109
- rescue => e
113
+ rescue StandardError, LoadError => e
110
114
  raise e if args['--debug']
111
115
  warn e.message
112
116
  exit 1 unless defined? TEST_MODE
@@ -240,21 +244,11 @@ COMMAND is one of:
240
244
  end
241
245
 
242
246
  def display
243
- begin
244
- fmt_klass = if args['-f']
245
- Timetrap::Formatters.const_get("#{args['-f'].classify}")
246
- else
247
- Timetrap::Formatters::Text
248
- end
249
- rescue
250
- warn "Invalid format #{args['-f'].inspect} specified."
251
- return
252
- end
253
247
  entries = selected_entries.order(:start).all
254
248
  if entries == []
255
249
  warn "No entries were selected to display."
256
250
  else
257
- puts fmt_klass.new(entries).output
251
+ puts load_formatter(args['-f'] || Config['default_formatter']).new(entries).output
258
252
  end
259
253
  end
260
254
 
@@ -16,12 +16,18 @@ module Timetrap
16
16
  # Unit of time for rounding (-r) in seconds
17
17
  'round_in_seconds' => 900,
18
18
  # delimiter used when appending notes with `t edit --append`
19
- 'append_notes_delimiter' => ' '
19
+ 'append_notes_delimiter' => ' ',
20
+ # an array of directories to search for user defined fomatter classes
21
+ 'formatter_search_paths' => [
22
+ "#{ENV['HOME']}/.timetrap/formatters"
23
+ ],
24
+ # formatter to use when display is invoked without a --format option
25
+ 'default_formatter' => 'text'
20
26
  }
21
27
  end
22
28
 
23
29
  def [](key)
24
- overrides = File.exist?(PATH) ? YAML.load(File.read(PATH)) : {}
30
+ overrides = File.exist?(PATH) ? YAML.load(erb_render(File.read(PATH))) : {}
25
31
  defaults.merge(overrides)[key]
26
32
  rescue => e
27
33
  warn "invalid config file"
@@ -29,6 +35,10 @@ module Timetrap
29
35
  defaults[key]
30
36
  end
31
37
 
38
+ def erb_render(content)
39
+ ERB.new(content).result
40
+ end
41
+
32
42
  def configure!
33
43
  configs = if File.exist?(PATH)
34
44
  defaults.merge(YAML.load_file(PATH))
@@ -0,0 +1,3 @@
1
+ # Namespace for formatter classes
2
+ module Timetrap::Formatters
3
+ end
@@ -1,4 +1,13 @@
1
- require 'icalendar'
1
+ begin
2
+ require 'icalendar'
3
+ rescue LoadError
4
+ raise <<-ERR
5
+ The icalendar gem must be installed for ical output.
6
+ To install it:
7
+ $ [sudo] gem install icalendar -v"~>1.1.5"
8
+ ERR
9
+ end
10
+
2
11
  require 'date'
3
12
  module Timetrap
4
13
  module Formatters
@@ -0,0 +1,11 @@
1
+ module Timetrap
2
+ module Formatters
3
+ class Ids
4
+ attr_reader :output
5
+
6
+ def initialize entries
7
+ @output = entries.map(&:id).join(' ')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ begin
2
+ require 'json'
3
+ rescue LoadError
4
+ raise <<-ERR
5
+ The json gem must be installed for json output.
6
+ To install it:
7
+ $ [sudo] gem install json -v"~>1.4.6"
8
+ ERR
9
+ end
10
+
11
+ module Timetrap
12
+ module Formatters
13
+ class Json
14
+ attr_accessor :output
15
+
16
+ def initialize entries
17
+ @output = entries.map do |e|
18
+ next unless e.end
19
+ e.values
20
+ end.compact.to_json
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,33 @@
1
1
  module Timetrap
2
2
  module Helpers
3
3
 
4
+ def load_formatter(formatter)
5
+ err_msg = "Can't load #{formatter.inspect} formatter."
6
+ begin
7
+ paths = (
8
+ Array(Config['formatter_search_paths']) +
9
+ [ File.join( File.dirname(__FILE__), 'formatters') ]
10
+ )
11
+ if paths.detect do |path|
12
+ begin
13
+ fp = File.join(path, formatter)
14
+ require File.join(path, formatter)
15
+ true
16
+ rescue LoadError
17
+ nil
18
+ end
19
+ end
20
+ else
21
+ raise LoadError, "Couldn't find #{formatter}.rb in #{paths.inspect}"
22
+ end
23
+ Timetrap::Formatters.const_get(formatter.camelize)
24
+ rescue LoadError, NameError => e
25
+ err = e.class.new("#{err_msg} (#{e.message})")
26
+ err.set_backtrace(e.backtrace)
27
+ raise err
28
+ end
29
+ end
30
+
4
31
  def selected_entries
5
32
  ee = if (sheet = sheet_name_from_string(unused_args)) == 'all'
6
33
  Timetrap::Entry.filter('sheet not like ? escape "!"', '!_%')
@@ -9,8 +36,8 @@ module Timetrap
9
36
  else
10
37
  Timetrap::Entry.filter('sheet = ?', Timer.current_sheet)
11
38
  end
12
- ee = ee.filter('start >= ?', Date.parse(args['-s'])) if args['-s']
13
- ee = ee.filter('start <= ?', Date.parse(args['-e']) + 1) if args['-e']
39
+ ee = ee.filter('start >= ?', Date.parse(Chronic.parse(args['-s']).to_s)) if args['-s']
40
+ ee = ee.filter('start <= ?', Date.parse(Chronic.parse(args['-e']).to_s) + 1) if args['-e']
14
41
  ee
15
42
  end
16
43
 
@@ -161,31 +161,44 @@ describe Timetrap do
161
161
 
162
162
  describe "backend" do
163
163
  it "should open an sqlite console to the db" do
164
- Timetrap::CLI.should_receive(:exec).with("sqlite3 #{DB_NAME}")
164
+ Timetrap::CLI.should_receive(:exec).with("sqlite3 #{Timetrap::DB_NAME}")
165
165
  invoke 'backend'
166
166
  end
167
167
  end
168
168
 
169
- describe "display" do
169
+ describe "format" do
170
170
  before do
171
- Timetrap::Entry.create( :sheet => 'another',
172
- :note => 'entry 4', :start => '2008-10-05 18:00:00'
173
- )
174
- Timetrap::Entry.create( :sheet => 'SpecSheet',
175
- :note => 'entry 2', :start => '2008-10-03 16:00:00', :end => '2008-10-03 18:00:00'
176
- )
177
- Timetrap::Entry.create( :sheet => 'SpecSheet',
178
- :note => 'entry 1', :start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00'
179
- )
180
- Timetrap::Entry.create( :sheet => 'SpecSheet',
181
- :note => 'entry 3', :start => '2008-10-05 16:00:00', :end => '2008-10-05 18:00:00'
182
- )
183
- Timetrap::Entry.create( :sheet => 'SpecSheet',
184
- :note => 'entry 4', :start => '2008-10-05 18:00:00'
185
- )
171
+ create_entry
172
+ end
173
+ it "should be deprecated" do
174
+ invoke 'format'
175
+ $stderr.string.should == <<-WARN
176
+ The "format" command is deprecated in favor of "display". Sorry for the inconvenience.
177
+ WARN
178
+ end
179
+ end
186
180
 
187
- Time.stub!(:now).and_return Time.at(1223254800 + (60*60*2))
188
- @desired_output = <<-OUTPUT
181
+ describe "display" do
182
+ describe "text" do
183
+ before do
184
+ Timetrap::Entry.create( :sheet => 'another',
185
+ :note => 'entry 4', :start => '2008-10-05 18:00:00'
186
+ )
187
+ Timetrap::Entry.create( :sheet => 'SpecSheet',
188
+ :note => 'entry 2', :start => '2008-10-03 16:00:00', :end => '2008-10-03 18:00:00'
189
+ )
190
+ Timetrap::Entry.create( :sheet => 'SpecSheet',
191
+ :note => 'entry 1', :start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00'
192
+ )
193
+ Timetrap::Entry.create( :sheet => 'SpecSheet',
194
+ :note => 'entry 3', :start => '2008-10-05 16:00:00', :end => '2008-10-05 18:00:00'
195
+ )
196
+ Timetrap::Entry.create( :sheet => 'SpecSheet',
197
+ :note => 'entry 4', :start => '2008-10-05 18:00:00'
198
+ )
199
+
200
+ Time.stub!(:now).and_return Time.at(1223254800 + (60*60*2))
201
+ @desired_output = <<-OUTPUT
189
202
  Timesheet: SpecSheet
190
203
  Day Start End Duration Notes
191
204
  Fri Oct 03, 2008 12:00:00 - 14:00:00 2:00:00 entry 1
@@ -196,9 +209,9 @@ Timesheet: SpecSheet
196
209
  4:00:00
197
210
  ---------------------------------------------------------
198
211
  Total 8:00:00
199
- OUTPUT
212
+ OUTPUT
200
213
 
201
- @desired_output_with_ids = <<-OUTPUT
214
+ @desired_output_with_ids = <<-OUTPUT
202
215
  Timesheet: SpecSheet
203
216
  Id Day Start End Duration Notes
204
217
  3 Fri Oct 03, 2008 12:00:00 - 14:00:00 2:00:00 entry 1
@@ -209,9 +222,9 @@ Id Day Start End Duration Notes
209
222
  4:00:00
210
223
  ---------------------------------------------------------
211
224
  Total 8:00:00
212
- OUTPUT
225
+ OUTPUT
213
226
 
214
- @desired_output_for_all = <<-OUTPUT
227
+ @desired_output_for_all = <<-OUTPUT
215
228
  Timesheet: SpecSheet
216
229
  Day Start End Duration Notes
217
230
  Fri Oct 03, 2008 12:00:00 - 14:00:00 2:00:00 entry 1
@@ -231,72 +244,116 @@ Timesheet: another
231
244
  Total 2:00:00
232
245
  -------------------------------------------------------------
233
246
  Grand Total 10:00:00
234
- OUTPUT
235
- end
247
+ OUTPUT
248
+ end
236
249
 
237
- it "should display the current timesheet" do
238
- Timetrap::Timer.current_sheet = 'SpecSheet'
239
- invoke 'display'
240
- $stdout.string.should == @desired_output
241
- end
250
+ it "should display the current timesheet" do
251
+ Timetrap::Timer.current_sheet = 'SpecSheet'
252
+ invoke 'display'
253
+ $stdout.string.should == @desired_output
254
+ end
242
255
 
243
- it "should display a non current timesheet" do
244
- Timetrap::Timer.current_sheet = 'another'
245
- invoke 'display SpecSheet'
246
- $stdout.string.should == @desired_output
247
- end
256
+ it "should display a non current timesheet" do
257
+ Timetrap::Timer.current_sheet = 'another'
258
+ invoke 'display SpecSheet'
259
+ $stdout.string.should == @desired_output
260
+ end
248
261
 
249
- it "should display a non current timesheet based on a partial name match" do
250
- Timetrap::Timer.current_sheet = 'another'
251
- invoke 'display S'
252
- $stdout.string.should == @desired_output
253
- end
262
+ it "should display a non current timesheet based on a partial name match" do
263
+ Timetrap::Timer.current_sheet = 'another'
264
+ invoke 'display S'
265
+ $stdout.string.should == @desired_output
266
+ end
254
267
 
255
- it "should prefer an exact match of a named sheet to a partial match" do
256
- Timetrap::Timer.current_sheet = 'Spec'
257
- Timetrap::Entry.create( :sheet => 'Spec',
258
- :note => 'entry 5', :start => '2008-10-05 18:00:00'
259
- )
260
- invoke 'display Spec'
261
- $stdout.string.should include("entry 5")
262
- end
268
+ it "should prefer an exact match of a named sheet to a partial match" do
269
+ Timetrap::Timer.current_sheet = 'Spec'
270
+ Timetrap::Entry.create( :sheet => 'Spec',
271
+ :note => 'entry 5', :start => '2008-10-05 18:00:00'
272
+ )
273
+ invoke 'display Spec'
274
+ $stdout.string.should include("entry 5")
275
+ end
263
276
 
264
- it "should display a timesheet with ids" do
265
- invoke 'display S --ids'
266
- $stdout.string.should == @desired_output_with_ids
267
- end
277
+ it "should display a timesheet with ids" do
278
+ invoke 'display S --ids'
279
+ $stdout.string.should == @desired_output_with_ids
280
+ end
268
281
 
269
- it "should display all timesheets" do
270
- Timetrap::Timer.current_sheet = 'another'
271
- invoke 'display all'
272
- $stdout.string.should == @desired_output_for_all
282
+ it "should display all timesheets" do
283
+ Timetrap::Timer.current_sheet = 'another'
284
+ invoke 'display all'
285
+ $stdout.string.should == @desired_output_for_all
286
+ end
287
+
288
+ it "should not display archived for all timesheets" do
289
+ $stdin.string = "yes\n"
290
+ invoke 'archive SpecSheet'
291
+ $stdout.string = ''
292
+ invoke 'display all'
293
+ $stdout.string.should_not =~ /_SpecSheet/
294
+ end
295
+
296
+ it "it should find a user provided formatter class and require it" do
297
+ create_entry
298
+ create_entry
299
+ dir = '/tmp/timetrap/foo/bar'
300
+ with_stubbed_config('formatter_search_paths' => dir)
301
+ FileUtils.mkdir_p(dir)
302
+ File.open(dir + '/baz.rb', 'w') do |f|
303
+ f.puts <<-RUBY
304
+ class Timetrap::Formatters::Baz
305
+ def initialize(entries); end
306
+ def output
307
+ "yeah I did it"
308
+ end
309
+ end
310
+ RUBY
311
+ end
312
+ invoke 'd -fbaz'
313
+ $stderr.string.should == ''
314
+ $stdout.string.should == "yeah I did it\n"
315
+ FileUtils.rm_r dir
316
+ end
273
317
  end
274
318
 
275
- it "should not display archived for all timesheets" do
276
- $stdin.string = "yes\n"
277
- invoke 'archive SpecSheet'
278
- $stdout.string = ''
279
- invoke 'display all'
280
- $stdout.string.should_not =~ /_SpecSheet/
319
+ describe "default" do
320
+ before do
321
+ create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
322
+ create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
323
+ end
324
+
325
+ it "should allow another formatter to be set as the default" do
326
+ with_stubbed_config 'default_formatter' => 'ids',
327
+ 'formatter_search_paths' => nil
328
+
329
+ invoke 'd'
330
+ $stdout.string.should == Timetrap::Entry.all.map(&:id).join(" ") + "\n"
331
+ end
281
332
  end
282
- end
283
333
 
284
- describe "format" do
285
- before do
286
- create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
287
- create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
334
+ describe 'ids' do
335
+ before do
336
+ create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
337
+ create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
338
+ end
339
+
340
+ it "should not export running items" do
341
+ invoke 'in'
342
+ invoke 'display --format ids'
343
+ $stdout.string.should == Timetrap::Entry.all.map(&:id).join(" ") + "\n"
344
+ end
345
+
288
346
  end
347
+
289
348
  describe 'csv' do
290
- it "should be deprecated" do
291
- invoke 'format'
292
- $stderr.string.should == <<-WARN
293
- The "format" command is deprecated in favor of "display". Sorry for the inconvenience.
294
- WARN
349
+ before do
350
+ create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
351
+ create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
295
352
  end
296
353
 
297
354
  it "should not export running items" do
298
355
  invoke 'in'
299
- invoke 'format --format csv'
356
+ invoke 'display --format csv'
300
357
  $stdout.string.should == <<-EOF
301
358
  start,end,note,sheet
302
359
  "2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
@@ -305,7 +362,7 @@ start,end,note,sheet
305
362
  end
306
363
 
307
364
  it "should filter events by the passed dates" do
308
- invoke 'format --format csv --start 2008-10-03 --end 2008-10-03'
365
+ invoke 'display --format csv --start 2008-10-03 --end 2008-10-03'
309
366
  $stdout.string.should == <<-EOF
310
367
  start,end,note,sheet
311
368
  "2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
@@ -313,7 +370,7 @@ start,end,note,sheet
313
370
  end
314
371
 
315
372
  it "should not filter events by date when none are passed" do
316
- invoke 'format --format csv'
373
+ invoke 'display --format csv'
317
374
  $stdout.string.should == <<-EOF
318
375
  start,end,note,sheet
319
376
  "2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
@@ -322,26 +379,45 @@ start,end,note,sheet
322
379
  end
323
380
  end
324
381
 
382
+ describe 'json' do
383
+ before do
384
+ create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
385
+ create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
386
+ end
387
+
388
+ it "should export to json not including running items" do
389
+ invoke 'in'
390
+ invoke 'display -f json'
391
+ JSON.parse($stdout.string).should == JSON.parse(<<-EOF)
392
+ [{\"sheet\":\"default\",\"end\":\"Fri Oct 03 14:00:00 -0700 2008\",\"start\":\"Fri Oct 03 12:00:00 -0700 2008\",\"note\":\"note\",\"id\":1},{\"sheet\":\"default\",\"end\":\"Sun Oct 05 14:00:00 -0700 2008\",\"start\":\"Sun Oct 05 12:00:00 -0700 2008\",\"note\":\"note\",\"id\":2}]
393
+ EOF
394
+ end
395
+ end
396
+
325
397
  describe 'ical' do
398
+ before do
399
+ create_entry(:start => '2008-10-03 12:00:00', :end => '2008-10-03 14:00:00')
400
+ create_entry(:start => '2008-10-05 12:00:00', :end => '2008-10-05 14:00:00')
401
+ end
326
402
 
327
403
  it "should not export running items" do
328
404
  invoke 'in'
329
- invoke 'format --format ical'
405
+ invoke 'display --format ical'
330
406
  $stdout.string.scan(/BEGIN:VEVENT/).should have(2).item
331
407
  end
332
408
 
333
409
  it "should filter events by the passed dates" do
334
- invoke 'format --format ical --start 2008-10-03 --end 2008-10-03'
410
+ invoke 'display --format ical --start 2008-10-03 --end 2008-10-03'
335
411
  $stdout.string.scan(/BEGIN:VEVENT/).should have(1).item
336
412
  end
337
413
 
338
414
  it "should not filter events by date when none are passed" do
339
- invoke 'format --format ical'
415
+ invoke 'display --format ical'
340
416
  $stdout.string.scan(/BEGIN:VEVENT/).should have(2).item
341
417
  end
342
418
 
343
419
  it "should export a sheet to an ical format" do
344
- invoke 'format --format ical --start 2008-10-03 --end 2008-10-03'
420
+ invoke 'display --format ical --start 2008-10-03 --end 2008-10-03'
345
421
  desired = <<-EOF
346
422
  BEGIN:VCALENDAR
347
423
  VERSION:2.0
data/timetrap.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{timetrap}
8
- s.version = "1.6.1"
8
+ s.version = "1.7.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sam Goldstein"]
12
- s.date = %q{2010-11-29}
12
+ s.date = %q{2010-12-08}
13
13
  s.default_executable = %q{t}
14
14
  s.description = %q{Command line time tracker}
15
15
  s.email = %q{sgrock@gmail.com}
@@ -30,8 +30,11 @@ Gem::Specification.new do |s|
30
30
  "lib/timetrap.rb",
31
31
  "lib/timetrap/cli.rb",
32
32
  "lib/timetrap/config.rb",
33
+ "lib/timetrap/formatters.rb",
33
34
  "lib/timetrap/formatters/csv.rb",
34
35
  "lib/timetrap/formatters/ical.rb",
36
+ "lib/timetrap/formatters/ids.rb",
37
+ "lib/timetrap/formatters/json.rb",
35
38
  "lib/timetrap/formatters/text.rb",
36
39
  "lib/timetrap/helpers.rb",
37
40
  "lib/timetrap/models.rb",
@@ -58,20 +61,17 @@ Gem::Specification.new do |s|
58
61
  s.add_runtime_dependency(%q<sqlite3-ruby>, [">= 1.2.5"])
59
62
  s.add_runtime_dependency(%q<chronic>, ["~> 0.3.0"])
60
63
  s.add_runtime_dependency(%q<getopt-declare>, [">= 1.28"])
61
- s.add_runtime_dependency(%q<icalendar>, [">= 1.1.2"])
62
64
  else
63
65
  s.add_dependency(%q<sequel>, [">= 3.9.0"])
64
66
  s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.5"])
65
67
  s.add_dependency(%q<chronic>, ["~> 0.3.0"])
66
68
  s.add_dependency(%q<getopt-declare>, [">= 1.28"])
67
- s.add_dependency(%q<icalendar>, [">= 1.1.2"])
68
69
  end
69
70
  else
70
71
  s.add_dependency(%q<sequel>, [">= 3.9.0"])
71
72
  s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.5"])
72
73
  s.add_dependency(%q<chronic>, ["~> 0.3.0"])
73
74
  s.add_dependency(%q<getopt-declare>, [">= 1.28"])
74
- s.add_dependency(%q<icalendar>, [">= 1.1.2"])
75
75
  end
76
76
  end
77
77
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timetrap
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 6
9
- - 1
10
- version: 1.6.1
8
+ - 7
9
+ - 0
10
+ version: 1.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sam Goldstein
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-29 00:00:00 -08:00
18
+ date: 2010-12-08 00:00:00 -08:00
19
19
  default_executable: t
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -81,22 +81,6 @@ dependencies:
81
81
  version: "1.28"
82
82
  type: :runtime
83
83
  version_requirements: *id004
84
- - !ruby/object:Gem::Dependency
85
- name: icalendar
86
- prerelease: false
87
- requirement: &id005 !ruby/object:Gem::Requirement
88
- none: false
89
- requirements:
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- hash: 23
93
- segments:
94
- - 1
95
- - 1
96
- - 2
97
- version: 1.1.2
98
- type: :runtime
99
- version_requirements: *id005
100
84
  description: Command line time tracker
101
85
  email: sgrock@gmail.com
102
86
  executables:
@@ -118,8 +102,11 @@ files:
118
102
  - lib/timetrap.rb
119
103
  - lib/timetrap/cli.rb
120
104
  - lib/timetrap/config.rb
105
+ - lib/timetrap/formatters.rb
121
106
  - lib/timetrap/formatters/csv.rb
122
107
  - lib/timetrap/formatters/ical.rb
108
+ - lib/timetrap/formatters/ids.rb
109
+ - lib/timetrap/formatters/json.rb
123
110
  - lib/timetrap/formatters/text.rb
124
111
  - lib/timetrap/helpers.rb
125
112
  - lib/timetrap/models.rb