paradeiser 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +8 -0
- data/Gemfile +6 -0
- data/Guardfile +17 -0
- data/README.md +76 -187
- data/Rakefile +12 -1
- data/TODO.md +62 -0
- data/VISION.md +474 -0
- data/bin/pom +60 -0
- data/doc/Paradeiser::Pomodoro_status.svg +50 -0
- data/lib/paradeiser.rb +25 -2
- data/lib/paradeiser/controllers/controller.rb +30 -0
- data/lib/paradeiser/controllers/paradeiser_controller.rb +10 -0
- data/lib/paradeiser/controllers/pomodori_controller.rb +38 -0
- data/lib/paradeiser/errors.rb +31 -0
- data/lib/paradeiser/executor.rb +15 -0
- data/lib/paradeiser/models/hook.rb +26 -0
- data/lib/paradeiser/models/job.rb +25 -0
- data/lib/paradeiser/models/pomodoro.rb +58 -0
- data/lib/paradeiser/models/repository.rb +57 -0
- data/lib/paradeiser/models/scheduler.rb +43 -0
- data/lib/paradeiser/refinements.rb +5 -0
- data/lib/paradeiser/router.rb +29 -0
- data/lib/paradeiser/version.rb +1 -1
- data/lib/paradeiser/view.rb +21 -0
- data/lib/paradeiser/views/paradeiser/init.erb +1 -0
- data/lib/paradeiser/views/pomodori/finish.erb +1 -0
- data/lib/paradeiser/views/pomodori/report.erb +5 -0
- data/lib/paradeiser/views/pomodori/start.erb +1 -0
- data/lib/paradeiser/views/pomodori/status.erb +9 -0
- data/paradeiser.gemspec +21 -4
- data/templates/linux/hooks/after-finish +10 -0
- data/templates/linux/hooks/after-start +7 -0
- data/templates/mac/hooks/after-finish +10 -0
- data/templates/mac/hooks/after-start +7 -0
- data/test/helper.rb +24 -0
- data/test/integration/test_pom.rb +17 -0
- data/test/lib/assertions.rb +10 -0
- data/test/lib/at_mock.rb +6 -0
- data/test/lib/options_mock.rb +7 -0
- data/test/lib/pomodoro_mock.rb +11 -0
- data/test/lib/process_status_mock.rb +2 -0
- data/test/lib/pstore_mock.rb +16 -0
- data/test/templates/hooks/pre-finish +1 -0
- data/test/unit/test_paradeiser_controller.rb +88 -0
- data/test/unit/test_pomodori_controller.rb +103 -0
- data/test/unit/test_pomodori_view.rb +78 -0
- data/test/unit/test_pomodoro.rb +100 -0
- data/test/unit/test_pomodoro_hooks.rb +83 -0
- data/test/unit/test_repository.rb +127 -0
- data/test/unit/test_router.rb +36 -0
- data/test/unit/test_scheduler.rb +44 -0
- metadata +244 -13
data/VISION.md
ADDED
@@ -0,0 +1,474 @@
|
|
1
|
+
# Paradeiser
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/paradeiser.png)](http://badge.fury.io/rb/paradeiser)
|
4
|
+
[![Build Status](https://secure.travis-ci.org/nerab/paradeiser.png?branch=master)](http://travis-ci.org/nerab/paradeiser)
|
5
|
+
|
6
|
+
_This project is developed with the [readme-driven development](http://tom.preston-werner.com/2010/08/23/readme-driven-development.html) method. This file contains the vision, whereas the [README](README.md) reflects the functionality that is actually implemented._
|
7
|
+
|
8
|
+
Paradeiser is a command-line tool for the [Pomodoro Technique](http://www.pomodorotechnique.com/). It keeps track of the current pomodoro and assists the user in managing active and past pomodori:
|
9
|
+
|
10
|
+
* Records finished and cancelled pomodori as well as internal and external interruptions and other events
|
11
|
+
* Keeps track of the timer for the active pomodoro and the break
|
12
|
+
* Provides out-of-the-box reports that show details about finished and cancelled pomodori
|
13
|
+
* Shows information about breaks and interruptions
|
14
|
+
|
15
|
+
Paradeiser itself is not concerned with the actual management of tasks. There are plenty of tools for that; e.g. [TaskWarrior](http://taskwarrior.org/).
|
16
|
+
|
17
|
+
## Concepts
|
18
|
+
|
19
|
+
### Rule #1
|
20
|
+
|
21
|
+
There must never be more than one pomodoro [xor](http://en.wikipedia.org/wiki/Xor) break at any given time.
|
22
|
+
|
23
|
+
This is scoped to a single user account (not just the `$POM_DIR` directory, but also the `at` queue).
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
$ gem install paradeiser
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
### Start a new pomodoro
|
32
|
+
|
33
|
+
$ pom start
|
34
|
+
|
35
|
+
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
|
+
|
37
|
+
### Finish the pomodoro
|
38
|
+
|
39
|
+
$ pom finish
|
40
|
+
$ pom finish This one went very well.
|
41
|
+
|
42
|
+
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
|
+
|
44
|
+
If there is no active pomodoro, an error message will be printed.
|
45
|
+
|
46
|
+
### Record an interruption of the current pomodoro
|
47
|
+
|
48
|
+
$ pom interrupt --external Phone call from boss
|
49
|
+
$ pom interrupt --internal "Couldn't stay away from Twitter"
|
50
|
+
|
51
|
+
Remaining arguments, if present, will be added to the interrupt as annotation. If no pomodoro is active, the command will throw an error.
|
52
|
+
|
53
|
+
### Start a break
|
54
|
+
|
55
|
+
$ pom break [start] [--short | --long]
|
56
|
+
|
57
|
+
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 `pom break end`, see the section about `at`).
|
58
|
+
|
59
|
+
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. `pom break --short=10`).
|
60
|
+
|
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.
|
62
|
+
|
63
|
+
### Annotate a pomodoro
|
64
|
+
|
65
|
+
$ pom annotate This was intense, but I am happy about the work I finished.
|
66
|
+
|
67
|
+
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
|
+
|
69
|
+
Breaks cannot have annotations.
|
70
|
+
|
71
|
+
### Cancel the pomodoro
|
72
|
+
|
73
|
+
$ pom cancel Just couldn't concentrate anymore.
|
74
|
+
|
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.
|
76
|
+
|
77
|
+
### Log a pomodoro
|
78
|
+
|
79
|
+
$ pom log
|
80
|
+
|
81
|
+
Add a successfully finished pomodoro that was never recorded as being started (maybe the user forgot to call `pom start`). It will appear in the reports and will count towards efficiency calculations.
|
82
|
+
|
83
|
+
The current time will be used for the finish timestamp, and the start time will be calculated from the finish time backwards.
|
84
|
+
|
85
|
+
### Initialize Paradeiser
|
86
|
+
|
87
|
+
* Initialize the default directory that is used to store the Paradeiser configuration and data:
|
88
|
+
|
89
|
+
$ pom init
|
90
|
+
|
91
|
+
Creates the `$POM_DIR` directory and the sample hooks in `$POM_DIR/hooks`. The data store will not be created on `pom init`, but when the first write operation happens (e.g. `pom start`, but not `pom report`).
|
92
|
+
|
93
|
+
* Initialize an abritrary directory
|
94
|
+
|
95
|
+
$ pom init /tmp
|
96
|
+
|
97
|
+
This command initializes `/tmp` as `$POM_DIR`. It also sets the config variable `dir` in `~/.pomrc`:
|
98
|
+
|
99
|
+
$ pom config
|
100
|
+
|
101
|
+
If the `at` command is not available or not enabled, `pom init` will issue a warning. The program will continue because it is still useful for recording, although it will not be able to enqueue itself in order to execute the (time-based) `before-finish` and `before-break` hooks.
|
102
|
+
|
103
|
+
### Troubleshooting
|
104
|
+
|
105
|
+
`pom doctor` performs a number of checks that ensure that Paradeiser can run with best results.
|
106
|
+
|
107
|
+
It checks if
|
108
|
+
|
109
|
+
* `at` is there and enabled
|
110
|
+
* ...
|
111
|
+
|
112
|
+
`pom doctor` also provides a hint on how to correct that situation.
|
113
|
+
|
114
|
+
### Location
|
115
|
+
Recording the location of a pomodoro allows Paradeiser to compare the average count of successful and cancelled pomodori and the number of interruptions by location, so that a report can tell in which environment we get the most work done.
|
116
|
+
|
117
|
+
* Show the current location
|
118
|
+
|
119
|
+
$ pom location
|
120
|
+
Home Office
|
121
|
+
|
122
|
+
$ pom location --verbose
|
123
|
+
Home Office (macbook@01:23:45:67:89:0A)
|
124
|
+
|
125
|
+
* List all locations
|
126
|
+
|
127
|
+
$ pom locations
|
128
|
+
Home Office
|
129
|
+
Starbucks
|
130
|
+
|
131
|
+
$ pom locations --verbose
|
132
|
+
Home Office (macbook@01:23:45:67:89:0A)
|
133
|
+
Starbucks (macbook@45:01:89:0A:67:23)
|
134
|
+
|
135
|
+
* Show the label of a location identifier
|
136
|
+
|
137
|
+
$ pom location macbook@01:23:45:67:89:0A
|
138
|
+
Home Office
|
139
|
+
|
140
|
+
* Show the identifier of a location
|
141
|
+
|
142
|
+
$ pom location "Home Office"
|
143
|
+
macbook@01:23:45:67:89:0A
|
144
|
+
|
145
|
+
* Label a location
|
146
|
+
|
147
|
+
$ pom location macbook@01:23:45:67:89:0A "Your Label"
|
148
|
+
|
149
|
+
Paradeiser will automatically figure out the current location from the hostname and the MAC address of the default gateway (see below for details). This can be overridden by setting `$POM_LOCATION` or with a command line option:
|
150
|
+
|
151
|
+
$ pom location --location="On the road"
|
152
|
+
On the road
|
153
|
+
|
154
|
+
$ POM_LOCATION="On the road" pom location
|
155
|
+
On the road
|
156
|
+
|
157
|
+
Both the `--location` option and the environment variable can be passed to almost all commands.
|
158
|
+
|
159
|
+
## Timer with `at`
|
160
|
+
|
161
|
+
A central aspect of the Pomodoro Technique is the timer function:
|
162
|
+
|
163
|
+
* The remaining time of the active pomodoro or break must be displayed to the user.
|
164
|
+
* When the pomodoro or break is over, the user also needs to get a notification.
|
165
|
+
|
166
|
+
The `at` command is used for this. We just tell it to call
|
167
|
+
|
168
|
+
pom finish
|
169
|
+
|
170
|
+
when the pomodoro is over. A similar command exists as
|
171
|
+
|
172
|
+
pom break finish
|
173
|
+
|
174
|
+
which is called by `at` when the break is over.
|
175
|
+
|
176
|
+
When a pomodoro is started, Paradeiser enqueues itself to `at` like this:
|
177
|
+
|
178
|
+
echo pom finish | at now + 25 minutes
|
179
|
+
|
180
|
+
When `at` calls Paradeiser with this command, the pomodoro / break will be over and Paradeiser can do all the internal processing related to stopping the pomodoro / break (incl. calling the appropriate hooks, see below).
|
181
|
+
|
182
|
+
Paradeiser uses a dedicated at queue named 'p' to organize its jobs and to prevent accidentially overwriting other scheduled tasks.
|
183
|
+
|
184
|
+
## Status
|
185
|
+
|
186
|
+
Paradeiser can print the current status to STDOUT with the `pom status` command. The current state is provided as process exit status (which is also useful when the output is suppressed).
|
187
|
+
|
188
|
+
* Given an active pomodoro:
|
189
|
+
|
190
|
+
$ pom status
|
191
|
+
Pomodoro #2 is active (started 11:03, 14 minutes remaining).
|
192
|
+
|
193
|
+
$ pom status > /dev/null
|
194
|
+
$ echo $?
|
195
|
+
0
|
196
|
+
|
197
|
+
* Given no active pomodoro and the last one (not earlier as today) was finished:
|
198
|
+
|
199
|
+
$ pom status
|
200
|
+
No active pomodoro. Last one was finished at 16:58.
|
201
|
+
|
202
|
+
$ pom status > /dev/null
|
203
|
+
$ echo $?
|
204
|
+
1
|
205
|
+
|
206
|
+
* Given no active pomodoro and the last one (not earlier as today) was cancelled:
|
207
|
+
|
208
|
+
$ pom status
|
209
|
+
No pomodoro active. Last pomodoro was cancelled at 17:07.
|
210
|
+
|
211
|
+
$ pom status > /dev/null
|
212
|
+
$ echo $?
|
213
|
+
2
|
214
|
+
|
215
|
+
* Given a break (implies no active pomodoro):
|
216
|
+
|
217
|
+
$ pom status
|
218
|
+
Taking a 5 minute break until 2013-07-16 17.07 (4 minutes remaining).
|
219
|
+
|
220
|
+
$ pom status > /dev/null
|
221
|
+
$ echo $?
|
222
|
+
3
|
223
|
+
|
224
|
+
* Short status (03:39 remaining in the active pomodoro or break):
|
225
|
+
|
226
|
+
$ pom status --short
|
227
|
+
03:39
|
228
|
+
|
229
|
+
* Given a break and a custom status format (resembles the format switch analog to `date +%Y-%m-%dT%H:%M:%S`):
|
230
|
+
|
231
|
+
$ pom status --format %C-%M:%S
|
232
|
+
B03:39
|
233
|
+
|
234
|
+
* Output in JSON format
|
235
|
+
|
236
|
+
$ pom status --format JSON
|
237
|
+
{
|
238
|
+
"status": {
|
239
|
+
"state": "break",
|
240
|
+
"length": 600,
|
241
|
+
"remaining": 363,
|
242
|
+
"start": 1373988295,
|
243
|
+
"end": 1373988595
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
## Reports
|
248
|
+
|
249
|
+
$ pom report
|
250
|
+
Daily Pomodoro Report for 2013-07-16
|
251
|
+
|
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)
|
257
|
+
|
258
|
+
Most efficient location: Home Office
|
259
|
+
Least efficient location: Coffeshop
|
260
|
+
|
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. `pom report --day=2013-07-18`. The period is parsed with [Chronic](http://chronic.rubyforge.org/), which also enables symbolic values like `pom report --month="last month"`.
|
262
|
+
|
263
|
+
The report can also be grouped by location:
|
264
|
+
|
265
|
+
$ pom report location
|
266
|
+
Pomodoro Location Report
|
267
|
+
|
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
|
271
|
+
|
272
|
+
The following locations do not have a label. Assign it with
|
273
|
+
|
274
|
+
$ pom location macbook@01:23:45:67:89:0A "Your Label"
|
275
|
+
|
276
|
+
Detailed report for a single location:
|
277
|
+
|
278
|
+
$ pom report location "Home Office"
|
279
|
+
Pomodoro Location Report for Home Office
|
280
|
+
|
281
|
+
58 pomodori finished
|
282
|
+
12 pomodoro cancelled
|
283
|
+
8 internal interruptions
|
284
|
+
13 external interruptions
|
285
|
+
18 breaks (13 short, 5 long; 4 hours in total)
|
286
|
+
|
287
|
+
Efficiency: 0.8 (10% over median)
|
288
|
+
|
289
|
+
Further grouping is also possible, e.g. by year:
|
290
|
+
|
291
|
+
$ pom report location --year=2012
|
292
|
+
Pomodoro Location Report for 2012
|
293
|
+
|
294
|
+
233 pomodori finished
|
295
|
+
41 pomodoro cancelled
|
296
|
+
33 internal interruptions
|
297
|
+
123 external interruptions
|
298
|
+
98 breaks (63 short, 35 long; 45 hours in total)
|
299
|
+
|
300
|
+
Most efficient month: September (0.75)
|
301
|
+
Least efficient month: July (0.58)
|
302
|
+
|
303
|
+
### Efficiency
|
304
|
+
The efficiency is calculated from the number of successful vs. cancelled pomodori, together with the number interruptions. Breaks are not counted towards efficiency.
|
305
|
+
|
306
|
+
Efficiency can be reported by day, week, month, year, or location:
|
307
|
+
|
308
|
+
$ pom report efficiency
|
309
|
+
Efficiency Report for 2013-07-16
|
310
|
+
|
311
|
+
TODO
|
312
|
+
|
313
|
+
### Analytics
|
314
|
+
|
315
|
+
* Influence of interrupts to efficiency
|
316
|
+
- 80% of the internal interruptions happen within 5 minutes after the start
|
317
|
+
- In the last 3 months, the ratio between (internal / external) interrupts and cancelled pomodori improved by 10% from 0.6 to 0.5.
|
318
|
+
|
319
|
+
### Timesheet
|
320
|
+
|
321
|
+
$ pom timesheet
|
322
|
+
TODO Ordered list of pomodori and breaks, each with annotations (like a time sheet)
|
323
|
+
|
324
|
+
The same options as for regular reports apply. The timesheet report also details the efficiency of each location.
|
325
|
+
|
326
|
+
### Exporting a Report
|
327
|
+
|
328
|
+
$ pom report --weekly --format JSON # weekly report in JSON format
|
329
|
+
{
|
330
|
+
"TODO": "Specify"
|
331
|
+
}
|
332
|
+
|
333
|
+
## Output Policy
|
334
|
+
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.
|
335
|
+
|
336
|
+
## Hooks
|
337
|
+
Instead of handling tasks itself, Paradeiser integrates with external tools via hooks. Every event will attempt to find and execute an appropriate script in `$POM_DIR/hooks/`. Sufficient information will be made available via environment variables.
|
338
|
+
|
339
|
+
`before-` hooks will be called before the action is executed internally. If a `before-`hook exits non-zero, paradeiser will abort the action and exit non-zero itself; indicating in a message to STDERR which hook caused the abort.
|
340
|
+
|
341
|
+
`after-` hooks will be called after the action was executed internally. The exit status of a `post`-hook will be passed through paradeiser, but it will not affect the execution of the action anymore.
|
342
|
+
|
343
|
+
### Available Hooks
|
344
|
+
|
345
|
+
* `before-start` is called after the `start` command was received, but before internal processing for the `start` action begins
|
346
|
+
* `after-start` is called after all interal processing for the `start` action ended
|
347
|
+
* `before-finish` is called after the timer of the current pomodoro fired (the pomodoro is over), but before internal processing for the `finish` action begins
|
348
|
+
* `after-finish` is called after all interal processing for the `finish` action ended
|
349
|
+
* `before-interrupt` is called after the `interrupt` command was received, but before internal action processing begins
|
350
|
+
* `after-interrupt` is called after all interal processing for the `interrupt` action ended
|
351
|
+
* `before-cancel` is called after the `cancel` command was received, but before internal action processing begins
|
352
|
+
* `after-cancel` is called after all interal processing for the `cancel` action ended
|
353
|
+
* `before-break` is called after the `break` command was received, but before internal processing for the `break` action begins
|
354
|
+
* `after-break` is called after the timer of the current break fired (the break is over), but after internal processing for the `break` action ended
|
355
|
+
|
356
|
+
Examples for the use of hooks are:
|
357
|
+
|
358
|
+
* Displaying a desktop notification on `after-finish`
|
359
|
+
* tmux status bar integration like [pomo](https://github.com/visionmedia/pomo) by writing the status to `~/.pomo_stat` from the `after-` hooks.
|
360
|
+
* Displaying a desktop notification
|
361
|
+
|
362
|
+
`$POM_TITLE` is one of the environment variables set by Paradeiser that provides the context for hooks. See below for the full list of available environment variables.
|
363
|
+
|
364
|
+
### Edit a hook
|
365
|
+
|
366
|
+
$ pom edit after-stop
|
367
|
+
|
368
|
+
Launches `$VISUAL` (or, if empty, `$EDITOR`) with the given hook.
|
369
|
+
|
370
|
+
## Environment Variables
|
371
|
+
|
372
|
+
Variable | Used in | Description
|
373
|
+
--- | --- | ---
|
374
|
+
`$POM_DIR` | Everywhere | Directory where the data store and the hooks are stored. Defaults to `~/.paradeiser/`.
|
375
|
+
`$POM_ID` | Hooks | Identifier of the pomodoro
|
376
|
+
`$POM_STARTED_AT` | Hooks | Timestamp of when the pomodoro was started
|
377
|
+
`$POM_TITLE` | Hooks | Title of the pomodoro
|
378
|
+
`$POM_LOCATION` | Location Commands | Location of the pomodoro
|
379
|
+
|
380
|
+
## Configuration File
|
381
|
+
|
382
|
+
The configuration is stored in a config file. It is user-editable file, but editing the configuration is also exposed with `pom config`.
|
383
|
+
|
384
|
+
$ pom config dir
|
385
|
+
/home/nerab/.paradeiser
|
386
|
+
|
387
|
+
# Note how setting $POM_DIR affects pom config
|
388
|
+
$ POM_DIR=/tmp pom config dir
|
389
|
+
/tmp
|
390
|
+
|
391
|
+
$ pom config dir /var/tmp
|
392
|
+
$ pom config dir
|
393
|
+
/var/tmp
|
394
|
+
|
395
|
+
`pom config` shows the _active_ config when called, i.e. it takes `$POM_DIR` into account.
|
396
|
+
|
397
|
+
Available config variables:
|
398
|
+
|
399
|
+
Variable | Description
|
400
|
+
--- | ---
|
401
|
+
`POM_DIR` | Directory where the data store and the hooks are stored. Defaults to `~/.paradeiser/`. Overridden by `$POM_DIR`.
|
402
|
+
`AT_QUEUE` | Name of the `at` queue to use. Defaults to `p`.
|
403
|
+
|
404
|
+
## Taskwarrior Integration
|
405
|
+
|
406
|
+
This is deployed to `~/.paradeiser/hooks/after-finish` by default.
|
407
|
+
|
408
|
+
# exit unless $(task)
|
409
|
+
|
410
|
+
# find all active
|
411
|
+
active = $(task active) # doesn't work yet; find the right column with 'task columns' and the info in http://taskwarrior.org/projects/taskwarrior/wiki/Feature_custom_reports
|
412
|
+
|
413
|
+
# TODO tag all active tasks so that we can re-start them
|
414
|
+
|
415
|
+
# stop all active
|
416
|
+
task $(task active) stop
|
417
|
+
|
418
|
+
## Similar Projects
|
419
|
+
|
420
|
+
These and many more exist, why another tool?
|
421
|
+
|
422
|
+
* https://github.com/visionmedia/pomo
|
423
|
+
* https://github.com/stefanoverna/redpomo
|
424
|
+
|
425
|
+
They have a lot of what I wanted, but pomo focuses very much on the tasks themselves and less on the pomodori.
|
426
|
+
|
427
|
+
## Implementation Notes
|
428
|
+
|
429
|
+
### State Machine
|
430
|
+
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.
|
431
|
+
|
432
|
+
![State Transition Diagram](https://rawgithub.com/nerab/paradeiser/master/doc/Paradeiser::Pomodoro_status.svg)
|
433
|
+
|
434
|
+
The graph was created using the rake task that comes with `state_machine`:
|
435
|
+
|
436
|
+
rake state_machine:draw CLASS=Paradeiser::Pomodoro TARGET=doc FORMAT=svg HUMAN_NAMES=true ORIENTATION=landscape
|
437
|
+
|
438
|
+
### I18N
|
439
|
+
Paradeiser uses [I18N](https://github.com/svenfuchs/i18n) to translate messages and localize time and date formats.
|
440
|
+
|
441
|
+
## API
|
442
|
+
The actual storage backend is *not a public API* and may change at any given time. External tools should use the Ruby API instead, or rely on the JSON export / import.
|
443
|
+
|
444
|
+
## Sync
|
445
|
+
In todays world of distributed devices, synching data is a problem almost every app needs to solve. Paradeiser is no exception - it is very easy to come up with use cases that involve many computers. Maybe the user has different devices (mobile and desktop), maybe the user works in different environments, and wants to record all pomodori into a single system.
|
446
|
+
|
447
|
+
There are many potential solutions to this problem:
|
448
|
+
|
449
|
+
1. A centralized server could host a data store (relational database, NoSQL store, etc.)
|
450
|
+
1. A shared directory could host a single file and access could be coordinated using lock files
|
451
|
+
1. Commercial solutions like the [Dropbox Sync API](https://www.dropbox.com/developers/sync)
|
452
|
+
1. Custom solutions like [toystore](https://github.com/jnunemaker/toystore) with a [git adapter](https://github.com/bkeepers/adapter-git)
|
453
|
+
|
454
|
+
All of these are too much overhead right now, so the decision was made to keep Paradeiser simple and not implement any sync features. This may me revisited in a later version of the app.
|
455
|
+
|
456
|
+
## Location
|
457
|
+
In order to record the current location at the start of the pomodoro, Paradeiser will record the hostname and the MAC address of the default gateway:
|
458
|
+
|
459
|
+
* OSX
|
460
|
+
|
461
|
+
arp 0.0.0.0 | head -1 | awk {'print $4'}
|
462
|
+
|
463
|
+
* Linux:
|
464
|
+
|
465
|
+
GATEWAY=$(netstat -rn | grep "^0.0.0.0" | cut -c17-31); ping -c1 $GATEWAY >/dev/null; arp -n $GATEWAY | tail -n1 | cut -c34-50
|
466
|
+
|
467
|
+
The location is then used to assign a label to one or more hostname@MAC strings, which will be used in a report.
|
468
|
+
|
469
|
+
## Issues
|
470
|
+
|
471
|
+
1. `at` is disabled on MacOS by default. You will need to [turn it on](https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man8/atrun.8.html) in order to make Paradeiser work correctly.
|
472
|
+
|
473
|
+
## What about the app's name?
|
474
|
+
In Austrian German, "Paradeiser" means tomato, of which the Italian translation is pomodoro.
|