paradeiser 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Guardfile +1 -0
  4. data/README.md +98 -6
  5. data/TODO.md +22 -6
  6. data/VISION.md +171 -26
  7. data/bin/par +20 -4
  8. data/lib/paradeiser/controllers/breaks_controller.rb +0 -1
  9. data/lib/paradeiser/controllers/controller.rb +15 -1
  10. data/lib/paradeiser/controllers/paradeiser_controller.rb +23 -1
  11. data/lib/paradeiser/controllers/pomodori_controller.rb +23 -1
  12. data/lib/paradeiser/errors.rb +6 -0
  13. data/lib/paradeiser/executor.rb +1 -1
  14. data/lib/paradeiser/initializers/inflections.rb +3 -0
  15. data/lib/paradeiser/models/break.rb +1 -0
  16. data/lib/paradeiser/models/pomodoro.rb +13 -1
  17. data/lib/paradeiser/models/repository.rb +11 -1
  18. data/lib/paradeiser/models/scheduled.rb +7 -1
  19. data/lib/paradeiser/refinements/pluralize.rb +10 -0
  20. data/lib/paradeiser/router.rb +0 -2
  21. data/lib/paradeiser/version.rb +1 -1
  22. data/lib/paradeiser/view.rb +1 -1
  23. data/lib/paradeiser/views/breaks/finish.erb +1 -0
  24. data/lib/paradeiser/views/breaks/start.erb +1 -0
  25. data/lib/paradeiser/views/paradeiser/init.erb +1 -1
  26. data/lib/paradeiser/views/paradeiser/report.erb +10 -4
  27. data/lib/paradeiser/views/paradeiser/status.erb +2 -1
  28. data/lib/paradeiser/views/pomodori/annotate.erb +1 -0
  29. data/lib/paradeiser/views/pomodori/cancel.erb +1 -0
  30. data/lib/paradeiser/views/pomodori/interrupt.erb +1 -0
  31. data/lib/paradeiser/views/pomodori/log.erb +1 -0
  32. data/lib/paradeiser/views/pomodori/start.erb +1 -1
  33. data/paradeiser.gemspec +2 -0
  34. data/test/bin/notify-send +1 -0
  35. data/test/helper.rb +7 -24
  36. data/test/integration/test_annotate.rb +19 -0
  37. data/test/integration/test_finish.rb +9 -0
  38. data/test/integration/test_interrupt.rb +9 -0
  39. data/test/integration/test_log.rb +12 -0
  40. data/test/integration/test_no_args.rb +7 -0
  41. data/test/integration/test_start.rb +7 -0
  42. data/test/integration/test_status.rb +10 -0
  43. data/test/integration/test_unknown.rb +7 -0
  44. data/test/lib/at_mock.rb +1 -1
  45. data/test/lib/controller_test.rb +25 -0
  46. data/test/lib/integration_test.rb +45 -0
  47. data/test/lib/paradeiser_controller_test.rb +7 -0
  48. data/test/lib/view_test.rb +12 -0
  49. data/test/unit/test_break.rb +7 -44
  50. data/test/unit/test_break_view.rb +22 -0
  51. data/test/unit/test_breaks_controller.rb +66 -0
  52. data/test/unit/test_paradeiser_controller_export.rb +107 -0
  53. data/test/unit/test_paradeiser_controller_report.rb +73 -26
  54. data/test/unit/test_paradeiser_controller_status.rb +42 -24
  55. data/test/unit/test_paradeiser_view_init.rb +7 -0
  56. data/test/unit/test_paradeiser_view_report.rb +132 -0
  57. data/test/unit/test_paradeiser_view_status.rb +17 -0
  58. data/test/unit/test_pomodori_controller.rb +241 -33
  59. data/test/unit/test_pomodori_view.rb +26 -13
  60. data/test/unit/test_pomodoro.rb +23 -81
  61. data/test/unit/test_pomodoro_hooks.rb +12 -25
  62. data/test/unit/test_repository.rb +5 -21
  63. data/test/unit/test_scheduler.rb +1 -1
  64. metadata +61 -8
  65. data/test/integration/test_par.rb +0 -17
  66. data/test/unit/test_break_controller.rb +0 -56
  67. data/test/unit/test_paradeiser_view.rb +0 -66
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bee8d6c4f066abbede76f32b8bd4bb6eaffadce7
4
- data.tar.gz: 220abdcc0e1bcdf6ef2d2819c5c903508f42da8a
3
+ metadata.gz: dd9b4f1eb7fe225041e03d1824dcfce44b17e680
4
+ data.tar.gz: 010a924c64c9ffc32d18a68324afd6a8a79b46fe
5
5
  SHA512:
6
- metadata.gz: 82e436e805e7159115ef9b814140f7e62ba1363d9e4af9fc6b18b9cf0bdbbb1efb355fe74f3febe19a61780989ff70df917b8dfbbf7f1229d7f1c79684bc9854
7
- data.tar.gz: 40435ad4870ec1e3479bd9f82ef6168cd515cd89f6b0f437646092e1ab8d6d5e34301f93b5a8460f8286847365f7554c43bfeb3a1ba654b119568a8d50a03016
6
+ metadata.gz: e0ab299f7782dd479bc50981b203a02a8e69725a3b89559ac6683dcdbcadd8197c6bacccf34b9084193d08d46cbb6b704a2013bea2234a23717d350a3378406b
7
+ data.tar.gz: 46eb79b934a8210f6ceff2f25855905f06dbcae751a445039e33d49e5ee44b4f57663bff1c9ca29c1001bc6c5dd19ee5b78201e0c71e575207920c9ea4027cfa
@@ -6,3 +6,4 @@ rvm:
6
6
  before_install:
7
7
  - sudo apt-get update
8
8
  - sudo apt-get install at
9
+ - export PATH=${TRAVIS_BUILD_DIR}/test/bin:${PATH}
data/Guardfile CHANGED
@@ -14,4 +14,5 @@ guard 'minitest' do
14
14
  # Integration tests
15
15
  watch(%r{^bin/([^/]+)$}){|m| "test/integration/test_#{m[1]}.rb"}
16
16
  watch(%r|^test/integration/test_(.*)\.rb|){|m| "test/integration/test_#{m[1]}.rb"}
17
+ watch(%r|^test/lib/*\.rb|){'test'}
17
18
  end
data/README.md CHANGED
@@ -32,20 +32,42 @@ This is scoped to a single user account (not just the `$PAR_DIR` directory, but
32
32
 
33
33
  $ par pomodoro start
34
34
 
35
+ # Abbreviated version:
36
+ $ par start
37
+
35
38
  If a break is still active, it will be stopped before the new pomodoro is started. Because of Rule #1, calling start while a pomodoro is active will print an error message.
36
39
 
37
40
  ### Finish the pomodoro
38
41
 
39
42
  $ par pomodoro finish
40
43
 
44
+ # With annotation:
45
+ $ par pomodoro finish This one went very well.
46
+
47
+ # Abbreviated version:
48
+ $ par finish
49
+
50
+ # Abbreviated version with annotation:
51
+ $ par finish This one went very well.
52
+
41
53
  If a pomodoro is active, it will be marked as successful after stopping it, regardless of whether the 25 minutes are over or not. Remaining arguments, if present, will be added to the pomodoro as annotation.
42
54
 
43
55
  If there is no active pomodoro, an error message will be printed.
44
56
 
45
57
  ### Record an interruption of the current pomodoro
46
58
 
59
+ $ par pomodoro interrupt
60
+ $ par pomodoro interrupt --external
61
+
62
+ # Abbreviated version:
47
63
  $ par interrupt
48
- $ par interrupt --external
64
+
65
+ # With annotation:
66
+ $ par pomodoro interrupt Could not help checking my mail
67
+ $ par pomodoro interrupt --external VP of engineering walked into my office
68
+
69
+ # Abbreviated version with annotation:
70
+ $ par interrupt Could not help checking my mail
49
71
 
50
72
  Remaining arguments, if present, will be added to the interrupt as annotation. If no pomodoro is active, the command will throw an error.
51
73
 
@@ -55,15 +77,48 @@ Remaining arguments, if present, will be added to the interrupt as annotation. I
55
77
 
56
78
  If there is an active pomodoro, an error message will be printed. The `start` command is optional and may be omitted (it's only there for symmetry with `par break finish`, see the section about `at`).
57
79
 
58
- By default the break will be five minutes long.
80
+ There is a command to stop a break (see also the section about `at`):
81
+
82
+ $ par break finish
83
+
84
+ From a user's perspective it isn't really necessary to call `par break finish`, because either a new pomodoro is started, which will implicitely stop the active break, or the break ends naturally because it is over.
59
85
 
60
- While there is a command to stop a break (see the section about `at`), it isn't really necessary to call it from a user's perspective. Either a new pomodoro is started, which will implicitely stop the break, or the break ends naturally because it is over. We do not track break time.
86
+ We do not track break time.
87
+
88
+ ### Annotate a pomodoro
89
+
90
+ $ par pomodoro annotate This was intense, but I am happy about the work I finished.
91
+
92
+ # Abbreviated version:
93
+ $ par annotate This was intense, but I am happy about the work I finished.
94
+
95
+ The annotation will be added to the active or, if none is active, to the most recently finished or cancelled pomodoro. If no text is given, the annotation text is read from STDIN.
96
+
97
+ Breaks cannot have annotations.
61
98
 
62
99
  ### Cancel the pomodoro
63
100
 
101
+ $ par pomodoro cancel
64
102
  $ par pomodoro cancel Just couldn't concentrate anymore.
65
103
 
66
- It will be marked as unsuccessful (remember, a pomodoro is indivisible). If no pomodoro is active, the command will throw an error. If a break is active, the command will do nothing except printing a warning. Remaining arguments, if present, will be added to the pomodoro as annotation.
104
+ # Abbreviated version:
105
+ $ par cancel
106
+
107
+ # Abbreviated version with annotation:
108
+ $ par cancel Just couldn't concentrate anymore.
109
+
110
+ The pomodoro will be marked as canceled and the timer will be cleared. If no pomodoro is active, the command will throw an error. If a break is active, the command will do nothing except printing a warning. Remaining arguments, if present, will be added to the pomodoro as annotation.
111
+
112
+ ### Log a pomodoro or break
113
+
114
+ Add a successfully finished pomodoro that was never recorded as being started (maybe the user forgot to call `par pomodoro start`):
115
+
116
+ $ par pomodoro log
117
+
118
+ # Abbreviated version:
119
+ $ par log
120
+
121
+ It will appear in the reports and will count towards efficiency calculations. The current time will be used for the finish timestamp, and the start time will be calculated backwards from the finish time based on the default length of a pomodoro / break.
67
122
 
68
123
  ### Initialize Paradeiser
69
124
 
@@ -106,7 +161,7 @@ Paradeiser uses a dedicated at queue named 'p' to organize its jobs and to preve
106
161
 
107
162
  ## Status
108
163
 
109
- Paradeiser can print the current status to STDOUT with the `par status` command. The current state is provided as process exit status (which is also useful when the output is suppressed).
164
+ Paradeiser can print the current status to STDOUT with the `par status` command. The current state is also provided as process exit status (which is useful when the output is suppressed).
110
165
 
111
166
  * Given an active pomodoro:
112
167
 
@@ -146,7 +201,30 @@ Paradeiser can print the current status to STDOUT with the `par status` command.
146
201
 
147
202
  ## Reports
148
203
 
204
+ Without arguments, a report is shown for all pomodori and breaks.
205
+
149
206
  $ par report
207
+ # Pomodoro Report
208
+ - 6 pomodori finished
209
+ - 1 pomodoro canceled
210
+ - 2 internal interrupts
211
+ - 2 external interrupts
212
+ - 4 breaks (14 minutes in total)
213
+
214
+ ## Annotations
215
+ * You may pass an annotation to finish.
216
+ * Interrupts take annotations, too.
217
+ * Internal interrupts take annotations, too.
218
+ * And the last annotation is added via cancel.
219
+
220
+ Note that the annotations section is not shown if there are no annotations.
221
+
222
+ ### Report Formatting
223
+ By default The output of reports is formatted as [markdown](http://TODO), so that it can easily be read at the command line, but also piped into a markdown processor, e.g. for HTML generation with [redcloth](http://TODO):
224
+
225
+ $ par report | redcloth | bcat
226
+
227
+ Here, the HTML produced by redcloth is piped into `bcat`, which opens a browser with the produced HTML.
150
228
 
151
229
  ## Output Policy
152
230
  Paradeiser follows the [Rule of Silence](http://www.faqs.org/docs/artu/ch01s06.html#id2878450). If all goes well, a command will not print any output to `STDOUT` unless `--verbose` is given. `status`, `report` and `timesheet` are exempted from this rule, as their primary purpose is to print to STDOUT.
@@ -169,8 +247,10 @@ Instead of handling tasks itself, Paradeiser integrates with external tools via
169
247
  * `after-start-break` is called after the processing of the break start action ended.
170
248
  * `before-finish-break` is called after the timer of the current break fired (the break is over), but before the processing of the break finish action begins.
171
249
  * `after-finish-break` is called after the processing of the break finish action ended.
250
+
172
251
  * `before-interrupt-pomodoro` is called when the `interrupt` command was received, but before the action processing begins.
173
252
  * `after-interrupt-pomodoro` is called after the processing of the `interrupt` action ended.
253
+
174
254
  * `before-cancel-pomodoro` is called when the `cancel` command was received, but before the processing of the cancel action begins.
175
255
  * `after-cancel-pomodoro` is called after the processing of the `cancel` action ended.
176
256
 
@@ -192,6 +272,13 @@ Variable | Used in | Description
192
272
  `$PAR_BREAK_ID` | Hooks | Identifier of the break
193
273
  `$PAR_BREAK_STARTED_AT` | Hooks | Timestamp of when the break was started
194
274
 
275
+ ## Export
276
+
277
+ Paradeiser can export the pomodori and breaks it has stored to JSON:
278
+
279
+ $ par export
280
+ [{"type":"Pomodoro","length":1500,"status":"finished","interrupts":[],"annotati ...
281
+
195
282
  ## Similar Projects
196
283
 
197
284
  These and many more exist, why another tool?
@@ -204,9 +291,14 @@ They have a lot of what I wanted, but pomo focuses very much on the tasks themse
204
291
  ## Implementation Notes
205
292
 
206
293
  ### State Machine
207
- Paradeiser uses a [state machine](https://github.com/pluginaweek/state_machine) to model a pomodoro. Internal event handlers do the actual work; among them is the task of calling the external hooks.
294
+ Paradeiser uses a [state machine](https://github.com/pluginaweek/state_machine) to model the state of pomodori and breaks. Internal event handlers do the actual work. Calling the external hooks is one of these tasks.
295
+
296
+ Pomodoro:
208
297
 
209
298
  ![State Transition Diagram for Pomodoro](https://rawgithub.com/nerab/paradeiser/master/doc/Paradeiser::Pomodoro_status.svg)
299
+
300
+ Break:
301
+
210
302
  ![State Transition Diagram for Break](https://rawgithub.com/nerab/paradeiser/master/doc/Paradeiser::Break_status.svg)
211
303
 
212
304
  The graph was created using the rake task that comes with `state_machine`:
data/TODO.md CHANGED
@@ -1,16 +1,32 @@
1
1
  # Paradeiser Backlog
2
2
 
3
- * Add `par report` with a single (global) view that implements the report format described in the vision document (but isn't scoped yet)
3
+ * By default, hooks copied by `par init` should not be executable, otherwise the hooks will fail if the optional dependencies (e.g. `notify-send` on Linux) are not present
4
4
 
5
- * Implement `par pomodoro annotate` and annotations for most commands. Alias it it `par annotate`.
5
+ * Add validations to models. `finished_at` must occur at after created at, etc.
6
+
7
+ * There must be no overlap in pomodori, even if we log one.
8
+ - Logging one while another one is active must fail unless finished at is before the active one's started at.
9
+
10
+ * `par log` needs options for when the logged pomodoro was started and / or stopped
11
+
12
+ * Improve tests with more doubles
13
+ - Sandy Metz rules about testing messages:
14
+ - Incoming: Assert state
15
+ - Outgoing
16
+ * Queries: Ignore
17
+ * Commands: Expect behavior
18
+
19
+ * Implement scoped reports
20
+
21
+ * `par timesheet`
22
+ - Implement basic timesheet (global; not grouped by anything)
23
+ - Show all annotations next to each pomodoro, interrupt and break
6
24
 
7
25
  * Improve status messages with relative times and dates (`distance_of_time_in_words_to_now`)
8
26
  => action_view/helpers/date_helper
9
27
 
10
28
  * Simplify the status view. Separate views by class (break vs. pomodoro).
11
29
 
12
- * Refactor the hooks tests: extract the common code
13
-
14
30
  * Whenever par runs, it should garbage-collect pomodori or breaks (finish them and adjust their finish time) that weren't finished after they were over (e.g. because at isn't there or the hooks did not fire)
15
31
 
16
32
  * Extend commander to allow abbreviated commands with Ruby's `Abbrev` module
@@ -42,7 +58,7 @@
42
58
  - test with `if $stdin.tty?`
43
59
  - If that approach works well, suggest it for TaskWarrior too (for bulk actions, e.g. in scripts)
44
60
 
45
- * Implement documentation Approach
61
+ * Implement documentation approach
46
62
  - `par help` is what the user will use to get information.
47
63
  - Not sure how to allow the user to look at features that are not related to a command. Either extend `par help` to accept arbitrary keywords, or look into 'gem man`.
48
64
 
@@ -55,7 +71,7 @@
55
71
  - As part of finishing a feature, the feature file is moved from the backlog file to in individual doc file, and the README is updated to mention that feature.
56
72
 
57
73
  * Promote Paradeiser
58
- - Publish an [ASCII cast](http://ascii.io/)
74
+ - Publish an [ASCII cast](http://ascii.io/) or with [Showterm](http://showterm.io/)
59
75
  - Tell the TaskWarrior community about Paradeiser
60
76
  - Tell the Pomodoro community about Paradeiser
61
77
  - Tell the Ruby community about Paradeiser (e.g. @neverbendeasy does kanban)
data/VISION.md CHANGED
@@ -32,21 +32,42 @@ This is scoped to a single user account (not just the `$PAR_DIR` directory, but
32
32
 
33
33
  $ par pomodoro start
34
34
 
35
+ # Abbreviated version:
36
+ $ par start
37
+
35
38
  If a break is still active, it will be stopped before the new pomodoro is started. Because of Rule #1, calling start while a pomodoro is active will print an error message.
36
39
 
37
40
  ### Finish the pomodoro
38
41
 
39
42
  $ par pomodoro finish
43
+
44
+ # With annotation:
40
45
  $ par pomodoro finish This one went very well.
41
46
 
47
+ # Abbreviated version:
48
+ $ par finish
49
+
50
+ # Abbreviated version with annotation:
51
+ $ par finish This one went very well.
52
+
42
53
  If a pomodoro is active, it will be marked as successful after stopping it, regardless of whether the 25 minutes are over or not. Remaining arguments, if present, will be added to the pomodoro as annotation.
43
54
 
44
55
  If there is no active pomodoro, an error message will be printed.
45
56
 
46
57
  ### Record an interruption of the current pomodoro
47
58
 
59
+ $ par pomodoro interrupt
60
+ $ par pomodoro interrupt --external
61
+
62
+ # Abbreviated version:
48
63
  $ par interrupt
49
- $ par interrupt --external
64
+
65
+ # With annotation:
66
+ $ par pomodoro interrupt Could not help checking my mail
67
+ $ par pomodoro interrupt --external VP of engineering walked into my office
68
+
69
+ # Abbreviated version with annotation:
70
+ $ par interrupt Could not help checking my mail
50
71
 
51
72
  Remaining arguments, if present, will be added to the interrupt as annotation. If no pomodoro is active, the command will throw an error.
52
73
 
@@ -58,29 +79,63 @@ If there is an active pomodoro, an error message will be printed. The `start` co
58
79
 
59
80
  By default the break will be five minutes long. After four pomodori within a day, the break will be 30 minutes long. This can be overridden with `--short` or `--long`, with an optional argument value that determines the lenght of the break in minutes (e.g. `par break --short=10`).
60
81
 
61
- While there is a command to stop a break (see the section about `at`), it isn't really necessary to call it from a user's perspective. Either a new pomodoro is started, which will implicitely stop the break, or the break ends naturally because it is over. We do not track break time.
82
+ There is a command to stop a break (see also the section about `at`):
83
+
84
+ $ par break finish
85
+
86
+ From a user's perspective it isn't really necessary to call `par break finish`, because either a new pomodoro is started, which will implicitely stop the active break, or the break ends naturally because it is over.
87
+
88
+ We do not track break time.
62
89
 
63
90
  ### Annotate a pomodoro
64
91
 
65
92
  $ par pomodoro annotate This was intense, but I am happy about the work I finished.
66
93
 
94
+ # Abbreviated version:
95
+ $ par annotate This was intense, but I am happy about the work I finished.
96
+
67
97
  The annotation will be added to the active or, if none is active, to the most recently finished or cancelled pomodoro. If no text is given, the annotation text is read from STDIN.
68
98
 
69
99
  Breaks cannot have annotations.
70
100
 
71
101
  ### Cancel the pomodoro
72
102
 
103
+ $ par pomodoro cancel
73
104
  $ par pomodoro cancel Just couldn't concentrate anymore.
74
105
 
75
- It will be marked as unsuccessful (remember, a pomodoro is indivisible). If no pomodoro is active, the command will throw an error. If a break is active, the command will do nothing except printing a warning. Remaining arguments, if present, will be added to the pomodoro as annotation.
106
+ # Abbreviated version:
107
+ $ par cancel
108
+
109
+ # Abbreviated version with annotation:
110
+ $ par cancel Just couldn't concentrate anymore.
76
111
 
77
- ### Log a pomodoro
112
+ The pomodoro will be marked as canceled and the timer will be cleared. If no pomodoro is active, the command will throw an error. If a break is active, the command will do nothing except printing a warning. Remaining arguments, if present, will be added to the pomodoro as annotation.
113
+
114
+ ### Log a pomodoro or break
115
+
116
+ Add a successfully finished pomodoro that was never recorded as being started (maybe the user forgot to call `par pomodoro start`):
78
117
 
79
118
  $ par pomodoro log
80
119
 
81
- Add a successfully finished pomodoro that was never recorded as being started (maybe the user forgot to call `par pomodoro start`). It will appear in the reports and will count towards efficiency calculations.
120
+ # Abbreviated version:
121
+ $ par log
122
+
123
+ # Logging a break is also possible:
124
+ $ par break log
82
125
 
83
- The current time will be used for the finish timestamp, and the start time will be calculated from the finish time backwards.
126
+ It will appear in the reports and will count towards efficiency calculations. The current time will be used for the finish timestamp, and the start time will be calculated backwards from the finish time based on the default length of a pomodoro / break.
127
+
128
+ ### Delete a pomodoro or break
129
+
130
+ $ par delete
131
+
132
+ Without arguments, the active pomodoro or break will be canceled and then deleted. If none is active, the most recently finished or cancelled pomodoro or break is deleted. Note that there is no long form of this command as it pertains to pomodori _and_ breaks.
133
+
134
+ A specific pomodoro or break to be deleted can be specified as argument:
135
+
136
+ $ par delete 42
137
+
138
+ This will delete the pomodoro or break identified as #42.
84
139
 
85
140
  ### Initialize Paradeiser
86
141
 
@@ -183,7 +238,7 @@ Paradeiser uses a dedicated at queue named 'p' to organize its jobs and to preve
183
238
 
184
239
  ## Status
185
240
 
186
- Paradeiser can print the current status to STDOUT with the `par status` command. The current state is provided as process exit status (which is also useful when the output is suppressed).
241
+ Paradeiser can print the current status to STDOUT with the `par status` command. The current state is also provided as process exit status (which is useful when the output is suppressed).
187
242
 
188
243
  * Given an active pomodoro:
189
244
 
@@ -246,37 +301,96 @@ Paradeiser can print the current status to STDOUT with the `par status` command.
246
301
 
247
302
  ## Reports
248
303
 
304
+ Without arguments, a report is shown for the most recent pomodoro or break.
305
+
306
+ * Given the most recent item was a pomodoro, finished today:
307
+
249
308
  $ par report
250
- Daily Pomodoro Report for 2013-07-16
309
+ # Report for pomodoro #12
310
+
311
+ Started 17:07, finished 17:32
312
+
313
+ ## Interrupts
314
+ 0 internal
315
+ 0 external
316
+
317
+ ## Annotations
318
+ * This one went very well.
319
+
320
+ A report can produced for a specific pomodoro or break (here, it was started earlier today and then cancelled after a few interruptions):
321
+
322
+ $ par report 11
323
+ # Report for pomodoro #11
324
+
325
+ Started 11:34, canceled 11:40
251
326
 
252
- 3 pomodori finished
253
- 1 pomodoro cancelled
254
- 1 internal interruptions
255
- 2 external interruptions
256
- 4 breaks (3 short, 1 long; 45 minutes in total)
327
+ ## Interrupts
328
+ 2 internal:
257
329
 
258
- Most efficient location: Home Office
259
- Least efficient location: Coffeshop
330
+ * Could not help checking my mail
331
+ * Surfin' the web
260
332
 
261
- By default, the command groups by `--day`. Alternative options are `--week`, `--month` or `--year`. Without a value, the argument assumes the current day / week / month / year. The first day of the period can be specified as argument, e.g. `par report --day=2013-07-18`. The period is parsed with [Chronic](http://chronic.rubyforge.org/), which also enables symbolic values like `par report --month="last month"`.
333
+ 1 external:
334
+ * VP of engineering walked into my office
335
+
336
+ # Annotations
337
+ * Right before lunch doesn't seem like a good time for a pomodoro.
338
+
339
+ Reports can also be grouped by `--day`, `--week`, `--month`, `--year`, or `--all`:
340
+
341
+ $ par report --day
342
+ # Daily Report for 2013-07-16
343
+
344
+ ## Pomodori
345
+ - 3 finished
346
+ - 1 cancelled
347
+
348
+ ## Interrupts
349
+ - 1 internal
350
+ - 2 external
351
+
352
+ ## Breaks
353
+ - 3 short
354
+ - 1 long
355
+
356
+ Total: 4 breaks, 45 minutes
357
+
358
+ ## Locations
359
+ Most efficient: Home Office
360
+ Least efficient: Coffeshop
361
+
362
+ Without a value, the argument assumes the current day / week / month / year. The first day of the period can be specified as argument, e.g. `par report --day=2013-07-18`. The period is parsed with [Chronic](http://chronic.rubyforge.org/), which also enables symbolic values like `par report --month="last month"`.
363
+
364
+ Note that the annotations section is not shown if there are no annotations.
262
365
 
263
366
  The report can also be grouped by location:
264
367
 
265
- $ par report location
266
- Pomodoro Location Report
368
+ $ par report --location
369
+ # Location Report
370
+
371
+ ## Home Office
372
+ 38 finished
373
+ 12 cancelled
374
+ 21 interrupts
267
375
 
268
- Home Office: 38 finished, 12 cancelled, 21 interrupts
269
- Starbucks: 12 finished, 2 cancelled, 45 interrupts
270
- On the road: 14 finished, 0 cancelled, 12 interrupts
376
+ ## Starbucks
377
+ 12 finished
378
+ 2 cancelled
379
+ 45 interrupts
380
+
381
+ ## On the road
382
+ 14 finished
383
+ 0 cancelled
384
+ 12 interrupts
271
385
 
272
386
  The following locations do not have a label. Assign it with
273
387
 
274
- $ par location macbook@01:23:45:67:89:0A "Your Label"
388
+ $ par --location macbook@01:23:45:67:89:0A "Your Label"
275
389
 
276
390
  Detailed report for a single location:
277
391
 
278
- $ par report location "Home Office"
279
- Pomodoro Location Report for Home Office
392
+ $ par report --location="Home Office"
393
+ # Location Report for Home Office
280
394
 
281
395
  58 pomodori finished
282
396
  12 pomodoro cancelled
@@ -288,7 +402,7 @@ Detailed report for a single location:
288
402
 
289
403
  Further grouping is also possible, e.g. by year:
290
404
 
291
- $ par report location --year=2012
405
+ $ par report --location --year=2012
292
406
  Pomodoro Location Report for 2012
293
407
 
294
408
  233 pomodori finished
@@ -323,6 +437,13 @@ Efficiency can be reported by day, week, month, year, or location:
323
437
 
324
438
  The same options as for regular reports apply. The timesheet report also details the efficiency of each location.
325
439
 
440
+ ### Report Formatting
441
+ By default The output of reports is formatted as [markdown](http://TODO), so that it can easily be read at the command line, but also piped into a markdown processor, e.g. for HTML generation with [redcloth](http://TODO):
442
+
443
+ $ par report | redcloth | bcat
444
+
445
+ Here, the HTML produced by redcloth is piped into `bcat`, which opens a browser with the produced HTML.
446
+
326
447
  ### Exporting a Report
327
448
 
328
449
  $ par report --weekly --format JSON # weekly report in JSON format
@@ -407,6 +528,25 @@ The configuration is stored in a config file. It is user-editable file, but edit
407
528
  `PAR_DIR` | Directory where the data store and the hooks are stored. Defaults to `~/.paradeiser/`. Overridden by `$PAR_DIR`.
408
529
  `AT_QUEUE` | Name of the `at` queue to use. Defaults to `p`.
409
530
 
531
+ ## Export
532
+
533
+ Paradeiser can export the pomodori and breaks it has stored to JSON:
534
+
535
+ $ par export
536
+ [{"type":"Pomodoro","length":1500,"status":"finished","interrupts":[],"annotati ...
537
+
538
+ ## Import
539
+
540
+ Paradeiser can import pomodori and breaks from a JSON file:
541
+
542
+ $ par import pomodori.json
543
+
544
+ If the second argument is missing, `par import` will expect the JSON that is to be imported to appear on STDIN:
545
+
546
+ $ cat pomodori.json | par import
547
+
548
+ If the import succeeds, no further message will printed and the exit status will be zero. If there is an existing pomodoro or break that overlaps with one imported from JSON, the entire import will fail and paradeiser will exit with a non-zero exit status.
549
+
410
550
  ## Taskwarrior Integration
411
551
 
412
552
  This is deployed to `~/.paradeiser/hooks/after-finish` by default.
@@ -433,9 +573,14 @@ They have a lot of what I wanted, but pomo focuses very much on the tasks themse
433
573
  ## Implementation Notes
434
574
 
435
575
  ### State Machine
436
- Paradeiser uses a [state machine](https://github.com/pluginaweek/state_machine) to model a pomodoro. Internal event handlers do the actual work; among them is the task of calling the external hooks.
576
+ Paradeiser uses a [state machine](https://github.com/pluginaweek/state_machine) to model the state of pomodori and breaks. Internal event handlers do the actual work. Calling the external hooks is one of these tasks.
577
+
578
+ Pomodoro:
437
579
 
438
580
  ![State Transition Diagram for Pomodoro](https://rawgithub.com/nerab/paradeiser/master/doc/Paradeiser::Pomodoro_status.svg)
581
+
582
+ Break:
583
+
439
584
  ![State Transition Diagram for Break](https://rawgithub.com/nerab/paradeiser/master/doc/Paradeiser::Break_status.svg)
440
585
 
441
586
  The graph was created using the rake task that comes with `state_machine`: