doing 0.1.9 → 0.2.2.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +73 -9
- data/bin/doing +217 -30
- data/lib/doing.rb +2 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +225 -58
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4b26436b15b40cf894c0d3b15dfaf367e299f95
|
4
|
+
data.tar.gz: d13cf54255ec6db1b5d24c7fec73455cb6e642f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fdaadd019f03f7a93e1fc211c20ed017502d16eade73f7f6eb616e123f14988422296c17b2a759643efcb7abbcc721a451d47fe1ede0c30e8f719c1cafc94e5
|
7
|
+
data.tar.gz: 75907e9acf02fadfa7416550cca0bbfe487452a660a8c494c4228b9e87f47b0306e79188718395da56e48e6a6c15c631e7bb34590655ec830ca59115fdf89b7e
|
data/README.md
CHANGED
@@ -20,6 +20,8 @@ _Side note:_ I actually use the library behind this utility as part of another s
|
|
20
20
|
|
21
21
|
Only use `sudo` if your environment requires it. If you're using the system Ruby on a Mac, for example, it will likely be necessary. If `gem install doing` fails, then run `sudo gem install doing` and provide your administrator password.
|
22
22
|
|
23
|
+
Run `doing config` to open your `~/.doingrc` file in the editor defined in the $EDITOR environment variable. Set up your `doing_file` right away (where you want entries to be stored), and cover the rest after you've read the docs.
|
24
|
+
|
23
25
|
See the [support](#support) section below for troubleshooting details.
|
24
26
|
|
25
27
|
## The "doing" file
|
@@ -28,7 +30,9 @@ The file that stores all of your entries is generated the first time you add an
|
|
28
30
|
|
29
31
|
The format of the "doing" file is TaskPaper-compatible. You can edit it by hand at any time (in TaskPaper or any text editor), but it uses a specific format for parsing, so be sure to maintain the dates and pipe characters.
|
30
32
|
|
31
|
-
Notes are anything in the list without a leading hyphen and date. They belong to the entry directly before them, and they should be indented one level beyond the parent item.
|
33
|
+
Notes are anything in the list without a leading hyphen and date. They belong to the entry directly before them, and they should be indented one level beyond the parent item. When using the `now` and `later` commands on the command line, you can start the entry with a quote and hit return, then type the note and close the quote. Anything after the first line will be turned into a TaskPaper-compatible note for the task and can be displayed in templates using `%note`.
|
34
|
+
|
35
|
+
Notes can be prevented from ever appearing in output with the global option `--no-notes`: `doing --no-notes show all`.
|
32
36
|
|
33
37
|
## Configuration
|
34
38
|
|
@@ -39,6 +43,14 @@ A basic configuration looks like this:
|
|
39
43
|
current_section: Currently
|
40
44
|
default_template: '%date: %title%note'
|
41
45
|
default_date_format: '%Y-%m-%d %H:%M'
|
46
|
+
views:
|
47
|
+
color:
|
48
|
+
date_format: '%F %_I:%M%P'
|
49
|
+
section: Currently
|
50
|
+
count: 10
|
51
|
+
wrap_width: 0
|
52
|
+
template: '%boldblack%date %boldgreen| %boldwhite%title%default%note'
|
53
|
+
order: desc
|
42
54
|
templates:
|
43
55
|
default:
|
44
56
|
date_format: '%Y-%m-%d %H:%M'
|
@@ -79,7 +91,7 @@ You can rename the section that holds your current tasks. By default, this is "C
|
|
79
91
|
|
80
92
|
The setting `editor_app` only applies to Mac OS X users. It's the default application that the command `doing open` will open your WWID file in. If this is blank, it will be opened by whatever the system default is, or you can use `-a app_name` or `-b bundle_id` to override.
|
81
93
|
|
82
|
-
In the case of the `doing now -e` command, your $EDITOR environment variable will be used to complete the entry text and notes. Set it in your
|
94
|
+
In the case of the `doing now -e` command, your $EDITOR environment variable will be used to complete the entry text and notes. Set it in your `~/.bash_profile` or whatever is appropriate for your system:
|
83
95
|
|
84
96
|
export EDITOR="mate -w"
|
85
97
|
|
@@ -184,7 +196,10 @@ You can create your own "views" in the `~/.doingrc` file and view them with `doi
|
|
184
196
|
count: 5
|
185
197
|
wrap_width: 0
|
186
198
|
date_format: '%F %_I:%M%P'
|
187
|
-
template: '%date | %title%note'
|
199
|
+
template: '%date | %title%note'
|
200
|
+
order: asc
|
201
|
+
tags: done finished cancelled
|
202
|
+
tags_bool: ANY
|
188
203
|
|
189
204
|
You can add additional custom views, just nest them under the "views" key (indented two spaces from the edge). Multiple views would look like this:
|
190
205
|
|
@@ -202,9 +217,13 @@ You can add additional custom views, just nest them under the "views" key (inden
|
|
202
217
|
date_format: '%F %_I:%M%P'
|
203
218
|
template: '%date | %title%note'
|
204
219
|
|
205
|
-
The "section" key is the default section to pull entries from. Count and section can be overridden at runtime with the `-c` and `-s` flags.
|
220
|
+
The "section" key is the default section to pull entries from. Count and section can be overridden at runtime with the `-c` and `-s` flags. Setting `section` to All will combine all sections in the output.
|
221
|
+
|
222
|
+
You can add new sections with `doing add_section section_name`. You can also create them on the fly by using the `-s section_name` flag when running `doing now`. For example, `doing now -s Misc just a random side note` would create the "just a random side note" entry in a new section called "Misc," if Misc didn't already exist.
|
206
223
|
|
207
|
-
|
224
|
+
The `tags` and `tags_bool` keys allow you to specify tags that the view is filtered by. You can list multiple tags separated by spaces, and then use `tags_bool` to specify "ALL," "ANY," or "NONE" to determine how it handles the multiple tags.
|
225
|
+
|
226
|
+
The `order` key defines the sort order of the output. This is applied _after_ the tasks are retrieved and cut off at the maximum number specified in `count`.
|
208
227
|
|
209
228
|
Regarding colors, you can use them to create very nice displays if you're outputting to a color terminal. Example:
|
210
229
|
|
@@ -231,13 +250,35 @@ Outputs:
|
|
231
250
|
|
232
251
|
### Commands:
|
233
252
|
|
234
|
-
help
|
253
|
+
help - Shows a list of commands and global options
|
254
|
+
help [command] - Shows help for any command (`doing help now`)
|
235
255
|
|
236
256
|
#### Adding entries:
|
237
257
|
|
238
258
|
now - Add an entry
|
239
259
|
later - Add an item to the Later section
|
240
|
-
done - Add
|
260
|
+
done - Add a completed item with @done(date). No argument finishes last entry.
|
261
|
+
|
262
|
+
The `doing now` command can accept `-s section_name` to send the new entry straight to a non-default section.
|
263
|
+
|
264
|
+
`doing done` is used to add an entry that you've already completed. Like `now`, you can specify a section with `-s section_name`. You can also skip straight to Archive with `-a`.
|
265
|
+
|
266
|
+
You can also backdate entries using natural language with `--back 15m` or `--back "3/15 3pm"`. That will modify the timestamp of the entry. When used with `doing done`, this allows time intervals to be accurately counted when entering items after the fact.
|
267
|
+
|
268
|
+
All of these commands accept a `-e` argument. This opens your command line editor as defined in the environment variable `$EDITOR`. Add your entry, save the temp file and close it, and the new entry will be added. Anything after the first line is included as a note on the entry.
|
269
|
+
|
270
|
+
#### Modifying entries:
|
271
|
+
|
272
|
+
finish - Mark last X entries as @done
|
273
|
+
tag - Tag last entry
|
274
|
+
|
275
|
+
`doing finish` by itself is the same as `doing done` by itself. It adds `@done(timestamp)` to the last entry. It also accepts a numeric argument to complete X number of tasks back in history. Add `-a` to also archive the affected entries.
|
276
|
+
|
277
|
+
`tag` adds one or more tags to the last entry, or specify a count with `-c X`. Tags are specified as basic arguments, separated by spaces. For example:
|
278
|
+
|
279
|
+
doing tag -c 3 client cancelled
|
280
|
+
|
281
|
+
... will mark the last three entries as "@client @cancelled." Add `-r` as a switch to remove the listed tags instead.
|
241
282
|
|
242
283
|
#### Displaying entries:
|
243
284
|
|
@@ -246,18 +287,41 @@ Outputs:
|
|
246
287
|
today - List entries from today
|
247
288
|
last - Show the last entry
|
248
289
|
|
290
|
+
`doing show` on its own will list all entries in the "Currently" section. Add a section name as an argument to display that section instead. Use "all" to display all entries from all sections.
|
291
|
+
|
292
|
+
You can filter the `show` command by tags. Simply list them after the section name (or "all"). The boolean defaults to "ANY," meaning any entry that contains any of the listed tags will be shown. You can use `-b ALL` or `-b NONE` to change the filtering behavior: `doing show all done cancelled -b NONE` will show all tasks from all sections that do not have either "@done" or "@cancelled" tags.
|
293
|
+
|
294
|
+
Use `-c X` to limit the displayed results. Combine it with `-a newest` or `-a oldest` to choose which chronological end it trims from. You can also set the sort order of the output with `-s asc` or `-s desc`.
|
295
|
+
|
296
|
+
If you have a use for it, you can use `--csv` on the show or view commands to output the results as a comma-separated CSV to STDOUT. Redirect to a file to save it: `doing show all done --csv > ~/Desktop/done.csv`.
|
297
|
+
|
298
|
+
#### Views
|
299
|
+
|
300
|
+
view - Display a user-created view
|
301
|
+
views - List available custom views
|
302
|
+
|
303
|
+
Display any of the custom views you make in `~/.doingrc` with the `view` command. Use `doing views` to get a list of available views. Any time a section or view is specified on the command line, fuzzy matching will be used to find the closest match. Thus, `lat` will match `Later`, etc..
|
304
|
+
|
249
305
|
#### Sections
|
250
306
|
|
251
|
-
sections
|
252
|
-
choose
|
307
|
+
sections - List sections
|
308
|
+
choose - Select a section to display from a menu
|
309
|
+
add_section - Add a new section to the "doing" file
|
253
310
|
|
254
311
|
#### Utilities
|
255
312
|
|
256
313
|
archive - Move all but the most recent 5 entries to the Archive section
|
314
|
+
open - Open the "doing" file in an editor (OS X)
|
257
315
|
config - Edit the default configuration
|
258
316
|
|
259
317
|
---
|
260
318
|
|
319
|
+
## Extras
|
320
|
+
|
321
|
+
### Bash completion
|
322
|
+
|
323
|
+
Add basic command line completion for Bash with [this gist](https://gist.github.com/fcrespo82/9609318).
|
324
|
+
|
261
325
|
## Troubleshooting
|
262
326
|
|
263
327
|
### Errors after "Successfully installed..."
|
data/bin/doing
CHANGED
@@ -31,24 +31,37 @@ command :now do |c|
|
|
31
31
|
c.desc 'Section'
|
32
32
|
c.arg_name 'section_name'
|
33
33
|
c.default_value wwid.current_section
|
34
|
-
c.flag [:s,:section]
|
34
|
+
c.flag [:s,:section], :default_value => wwid.current_section
|
35
35
|
|
36
36
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
37
37
|
c.switch [:e,:editor]
|
38
38
|
|
39
|
+
c.desc 'Backdate to "date_string" (natural language)'
|
40
|
+
c.flag [:back]
|
41
|
+
|
39
42
|
# c.desc "Edit entry with specified app"
|
40
43
|
# c.arg_name 'editor_app'
|
41
44
|
# c.default_value wwid.config.has_key?('editor_app') && wwid.config['editor_app'] ? wwid.config['editor_app'] : false
|
42
45
|
# c.flag [:a,:app]
|
43
46
|
|
44
47
|
c.action do |global_options,options,args|
|
48
|
+
if options[:back]
|
49
|
+
date = wwid.chronify(options[:back])
|
50
|
+
raise "Unable to parse date string" if date.nil?
|
51
|
+
else
|
52
|
+
date = Time.now
|
53
|
+
end
|
54
|
+
|
55
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
56
|
+
|
45
57
|
if options[:e] || (args.length == 0 && STDIN.stat.size == 0)
|
58
|
+
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
46
59
|
input = ""
|
47
60
|
input += args.join(" ") if args.length > 0
|
48
61
|
input = wwid.fork_editor(input)
|
49
62
|
if input
|
50
63
|
title, note = wwid.format_input(input)
|
51
|
-
wwid.add_item(title.cap_first,
|
64
|
+
wwid.add_item(title.cap_first, section, {:note => note, :back => date})
|
52
65
|
wwid.write(wwid.doing_file)
|
53
66
|
else
|
54
67
|
raise "No content"
|
@@ -56,11 +69,11 @@ command :now do |c|
|
|
56
69
|
else
|
57
70
|
if args.length > 0
|
58
71
|
title, note = wwid.format_input(args.join(" "))
|
59
|
-
wwid.add_item(title.cap_first,
|
72
|
+
wwid.add_item(title.cap_first, section, {:note => note, :back => date})
|
60
73
|
wwid.write(wwid.doing_file)
|
61
74
|
elsif STDIN.stat.size > 0
|
62
75
|
title, note = wwid.format_input(STDIN.read)
|
63
|
-
wwid.add_item(title.cap_first,
|
76
|
+
wwid.add_item(title.cap_first, section, {:note => note, :back => date})
|
64
77
|
wwid.write(wwid.doing_file)
|
65
78
|
else
|
66
79
|
raise "You must provide content when creating a new entry"
|
@@ -80,14 +93,25 @@ command :later do |c|
|
|
80
93
|
c.default_value wwid.config.has_key?('editor_app') && wwid.config['editor_app'] ? wwid.config['editor_app'] : false
|
81
94
|
c.flag [:a,:app]
|
82
95
|
|
96
|
+
c.desc 'Backdate to "date_string" (natural language)'
|
97
|
+
c.flag [:back]
|
98
|
+
|
83
99
|
c.action do |global_options,options,args|
|
100
|
+
if options[:back]
|
101
|
+
date = wwid.chronify(options[:back])
|
102
|
+
raise "Unable to parse date string" if date.nil?
|
103
|
+
else
|
104
|
+
date = Time.now
|
105
|
+
end
|
106
|
+
|
84
107
|
if options[:e] || (args.length == 0 && STDIN.stat.size == 0)
|
108
|
+
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
85
109
|
input = ""
|
86
110
|
input += args.join(" ") if args.length > 0
|
87
111
|
input = wwid.fork_editor(input)
|
88
112
|
if input
|
89
113
|
title, note = wwid.format_input(input)
|
90
|
-
wwid.add_item(title.cap_first, "Later", {:note => note})
|
114
|
+
wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
|
91
115
|
wwid.write(wwid.doing_file)
|
92
116
|
else
|
93
117
|
raise "No content"
|
@@ -95,11 +119,11 @@ command :later do |c|
|
|
95
119
|
else
|
96
120
|
if args.length > 0
|
97
121
|
title, note = wwid.format_input(args.join(" "))
|
98
|
-
wwid.add_item(title.cap_first, "Later", {:note => note})
|
122
|
+
wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
|
99
123
|
wwid.write(wwid.doing_file)
|
100
124
|
elsif STDIN.stat.size > 0
|
101
125
|
title, note = wwid.format_input(STDIN.read)
|
102
|
-
wwid.add_item(title.cap_first, "Later", {:note => note})
|
126
|
+
wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
|
103
127
|
wwid.write(wwid.doing_file)
|
104
128
|
else
|
105
129
|
raise "You must provide content when creating a new entry"
|
@@ -108,11 +132,15 @@ command :later do |c|
|
|
108
132
|
end
|
109
133
|
end
|
110
134
|
|
111
|
-
desc 'Add a completed item with @done(date)'
|
135
|
+
desc 'Add a completed item with @done(date). No argument finishes last entry.'
|
112
136
|
arg_name 'entry'
|
113
137
|
command :done do |c|
|
114
138
|
c.desc 'Immediately archive the entry'
|
115
|
-
c.
|
139
|
+
c.default_value false
|
140
|
+
c.switch [:a,:archive], :negatable => false, :default_value => false
|
141
|
+
|
142
|
+
c.desc 'Backdate to "date_string" (natural language)'
|
143
|
+
c.flag [:backdate]
|
116
144
|
|
117
145
|
c.desc 'Section'
|
118
146
|
c.default_value wwid.current_section
|
@@ -127,31 +155,43 @@ command :done do |c|
|
|
127
155
|
# c.flag [:a,:app]
|
128
156
|
|
129
157
|
c.action do |global_options,options,args|
|
130
|
-
if options[:
|
158
|
+
if options[:back]
|
159
|
+
date = wwid.chronify(options[:back])
|
160
|
+
raise "Unable to parse date string" if date.nil?
|
161
|
+
else
|
162
|
+
date = Time.now
|
163
|
+
end
|
164
|
+
|
165
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
166
|
+
|
167
|
+
if options[:e]
|
168
|
+
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
131
169
|
input = ""
|
132
170
|
input += args.join(" ") if args.length > 0
|
133
171
|
input = wwid.fork_editor(input)
|
134
172
|
if input
|
135
173
|
title, note = wwid.format_input(input)
|
136
174
|
title += " @done(#{Time.now.strftime('%F %R')})"
|
137
|
-
section =
|
138
|
-
wwid.add_item(title.cap_first, section.cap_first, {:note => note})
|
175
|
+
section = "Archive" if options[:a]
|
176
|
+
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
139
177
|
wwid.write(wwid.doing_file)
|
140
178
|
else
|
141
179
|
raise "No content"
|
142
180
|
end
|
181
|
+
elsif args.length == 0 && STDIN.stat.size == 0
|
182
|
+
wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => date})
|
143
183
|
else
|
144
184
|
if args.length > 0
|
145
185
|
title, note = wwid.format_input(args.join(" "))
|
146
186
|
title += " @done(#{Time.now.strftime('%F %R')})"
|
147
|
-
section =
|
148
|
-
wwid.add_item(title.cap_first, section.cap_first, {:note => note})
|
187
|
+
section = "Archive" if options[:a]
|
188
|
+
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
149
189
|
wwid.write(wwid.doing_file)
|
150
190
|
elsif STDIN.stat.size > 0
|
151
191
|
title, note = wwid.format_input(STDIN.read)
|
152
192
|
title += " @done(#{Time.now.strftime('%F %R')})"
|
153
|
-
section = options[:a] ? "Archive" :
|
154
|
-
wwid.add_item(title.cap_first, section.cap_first, {:note => note})
|
193
|
+
section = options[:a] ? "Archive" : section
|
194
|
+
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
155
195
|
wwid.write(wwid.doing_file)
|
156
196
|
else
|
157
197
|
raise "You must provide content when creating a new entry"
|
@@ -160,20 +200,124 @@ command :done do |c|
|
|
160
200
|
end
|
161
201
|
end
|
162
202
|
|
203
|
+
desc 'Mark last X entries as @done'
|
204
|
+
arg_name 'count'
|
205
|
+
command :finish do |c|
|
206
|
+
c.desc 'Archive entries'
|
207
|
+
c.default_value false
|
208
|
+
c.switch [:a,:archive], :negatable => false, :default_value => false
|
209
|
+
|
210
|
+
c.desc 'Section'
|
211
|
+
c.default_value wwid.current_section
|
212
|
+
c.flag [:s,:section], :default_value => wwid.current_section
|
213
|
+
|
214
|
+
c.action do |global_options,options,args|
|
215
|
+
|
216
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
217
|
+
|
218
|
+
if args.length > 1
|
219
|
+
raise "Only one argument allowed"
|
220
|
+
elsif args.length == 0 || args[0] =~ /\d+/
|
221
|
+
count = args[0] ? args[0].to_i : 1
|
222
|
+
wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a]})
|
223
|
+
else
|
224
|
+
raise "Invalid argument (specify number of recent items to mark @done)"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
desc 'Tag last entry'
|
230
|
+
arg_name 'tag1 [tag2...]'
|
231
|
+
command :tag do |c|
|
232
|
+
c.desc 'Section'
|
233
|
+
c.default_value wwid.current_section
|
234
|
+
c.flag [:s,:section], :default_value => wwid.current_section
|
235
|
+
|
236
|
+
c.desc 'How many recent entries to tag'
|
237
|
+
c.default_value 1
|
238
|
+
c.flag [:c,:count], :default_value => 1
|
239
|
+
|
240
|
+
c.desc 'Include current date/time with tag'
|
241
|
+
c.default_value false
|
242
|
+
c.switch [:d,:date], :negatable => false, :default_value => false
|
243
|
+
|
244
|
+
c.desc 'Remove given tag(s)'
|
245
|
+
c.default_value false
|
246
|
+
c.switch [:r,:remove], :negatable => false, :default_value => false
|
247
|
+
|
248
|
+
c.action do |global_options,options,args|
|
249
|
+
if args.length == 0
|
250
|
+
raise "You must specify at least one tag"
|
251
|
+
else
|
252
|
+
|
253
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
254
|
+
|
255
|
+
count = options[:c].to_i
|
256
|
+
if args.join("") =~ /,/
|
257
|
+
tags = args.join("").split(/,/)
|
258
|
+
else
|
259
|
+
tags = args.join(" ").split(" ") # in case tags are quoted as one arg
|
260
|
+
end
|
261
|
+
|
262
|
+
tags.map!{|tag| tag.sub(/^@/,'').strip }
|
263
|
+
|
264
|
+
wwid.tag_last({:tags => tags, :count => count, :section => section, :date => options[:d], :remove => options[:r]})
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
163
270
|
desc 'List all entries'
|
164
|
-
arg_name 'section'
|
271
|
+
arg_name 'section [tags]'
|
165
272
|
command :show do |c|
|
273
|
+
c.desc 'Tag boolean (AND,OR,NONE)'
|
274
|
+
c.default_value "OR"
|
275
|
+
c.flag [:b,:boolean], :default_value => "OR"
|
276
|
+
|
277
|
+
c.desc 'Max count to show'
|
278
|
+
c.default_value 0
|
279
|
+
c.flag [:c,:count], :default_value => 0
|
280
|
+
|
281
|
+
c.desc 'Age (oldest/newest)'
|
282
|
+
c.default_value 'newest'
|
283
|
+
c.flag [:a,:age], :default_value => 'newest'
|
284
|
+
|
285
|
+
c.desc 'Sort order (asc/desc)'
|
286
|
+
c.default_value 'asc'
|
287
|
+
c.flag [:s,:sort], :default_value => 'asc'
|
288
|
+
|
289
|
+
c.desc 'Output to csv'
|
290
|
+
c.default_value 'false'
|
291
|
+
c.switch [:csv], :default_value => false, :negatable => false
|
292
|
+
|
166
293
|
c.action do |global_options,options,args|
|
294
|
+
tag_filter = false
|
295
|
+
tags = []
|
167
296
|
if args.length > 0
|
168
|
-
if
|
169
|
-
section =
|
297
|
+
if args[0] =~ /^all$/i
|
298
|
+
section = "All"
|
299
|
+
elsif args[0] =~ /^@/
|
300
|
+
section = "All"
|
301
|
+
tags.push(args[0].sub(/^@/,''))
|
170
302
|
else
|
171
|
-
|
303
|
+
section = wwid.guess_section(args[0])
|
304
|
+
raise "No such section: #{args[0]}" unless section
|
305
|
+
end
|
306
|
+
if args.length > 1
|
307
|
+
tags += args[1..-1].map{|tag| tag.sub(/^@/,'').strip}
|
172
308
|
end
|
173
309
|
else
|
174
310
|
section = wwid.current_section
|
175
311
|
end
|
176
|
-
|
312
|
+
|
313
|
+
unless tags.empty?
|
314
|
+
tag_filter = {
|
315
|
+
'tags' => tags,
|
316
|
+
'bool' => options[:b]
|
317
|
+
}
|
318
|
+
end
|
319
|
+
|
320
|
+
puts wwid.list_section({:section => section, :count => options[:c].to_i, :tag_filter => tag_filter, :age => options[:a], :order => options[:s], :csv => options[:csv]})
|
177
321
|
end
|
178
322
|
end
|
179
323
|
|
@@ -183,15 +327,18 @@ arg_name 'count'
|
|
183
327
|
command :recent do |c|
|
184
328
|
c.desc 'Section'
|
185
329
|
c.default_value wwid.current_section
|
186
|
-
c.flag [:s,:section]
|
330
|
+
c.flag [:s,:section], :default_value => wwid.current_section
|
187
331
|
c.action do |global_options,options,args|
|
332
|
+
|
333
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
334
|
+
|
188
335
|
unless global_options[:version]
|
189
336
|
if args.length > 0
|
190
337
|
count = args[0].to_i
|
191
338
|
else
|
192
339
|
count = 10
|
193
340
|
end
|
194
|
-
puts wwid.recent(count,
|
341
|
+
puts wwid.recent(count,section.cap_first)
|
195
342
|
end
|
196
343
|
end
|
197
344
|
end
|
@@ -241,26 +388,48 @@ end
|
|
241
388
|
desc 'Display a user-created view'
|
242
389
|
arg_name 'view_name'
|
243
390
|
command :view do |c|
|
244
|
-
c.desc 'Section'
|
391
|
+
c.desc 'Section (override view settings)'
|
245
392
|
c.flag [:s,:section]
|
246
393
|
|
247
|
-
c.desc 'Count to display'
|
394
|
+
c.desc 'Count to display (override view settings)'
|
248
395
|
c.flag [:c,:count], :must_match => /^\d+$/, :type => Integer
|
249
396
|
|
397
|
+
c.desc 'Output to csv'
|
398
|
+
c.default_value 'false'
|
399
|
+
c.switch [:csv], :default_value => false, :negatable => false
|
400
|
+
|
250
401
|
c.action do |global_options,options,args|
|
251
402
|
if args.empty?
|
252
403
|
title = wwid.choose_view
|
253
404
|
else
|
254
|
-
title = args[0]
|
405
|
+
title = wwid.guess_view(args[0])
|
255
406
|
end
|
407
|
+
|
408
|
+
if options[:s]
|
409
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
410
|
+
end
|
411
|
+
|
256
412
|
view = wwid.get_view(title)
|
257
413
|
if view
|
258
414
|
template = view.has_key?('template') ? view['template'] : nil
|
259
415
|
format = view.has_key?('date_format') ? view['date_format'] : nil
|
416
|
+
tags_color = view.has_key?('tags_color') ? view['tags_color'] : nil
|
417
|
+
tag_filter = false
|
418
|
+
if view.has_key?('tags')
|
419
|
+
unless view['tags'].nil? || view['tags'].empty?
|
420
|
+
tag_filter = {'tags' => [], 'bool' => "OR"}
|
421
|
+
if view['tags'].class == Array
|
422
|
+
tag_filter['tags'] = view['tags'].map{|tag| tag.strip }
|
423
|
+
else
|
424
|
+
tag_filter['tags'] = view['tags'].split(" ").map{|tag| tag.strip }
|
425
|
+
end
|
426
|
+
tag_filter['bool'] = view.has_key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].upcase : "OR"
|
427
|
+
end
|
428
|
+
end
|
260
429
|
count = options[:c] ? options[:c] : view.has_key?('count') ? view['count'] : 10
|
261
|
-
section = options[:s] ?
|
430
|
+
section = options[:s] ? section : view.has_key?('section') ? view['section'] : wwid.current_section
|
262
431
|
order = view.has_key?('order') ? view['order'] : "asc"
|
263
|
-
puts wwid.list_section({:section => section, :count => count, :template => template, :format => format, :order => order })
|
432
|
+
puts wwid.list_section({:section => section, :count => count, :template => template, :format => format, :order => order, :tag_filter => tag_filter, :csv => options[:csv], :tags_color => tags_color })
|
264
433
|
else
|
265
434
|
raise "View #{title} not found in config"
|
266
435
|
end
|
@@ -317,6 +486,7 @@ command :open do |c|
|
|
317
486
|
elsif options[:b]
|
318
487
|
system %Q{open -b "#{options[:b]}" "#{File.expand_path(wwid.doing_file)}"}
|
319
488
|
elsif options[:e]
|
489
|
+
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
320
490
|
system %Q{$EDITOR "#{File.expand_path(wwid.doing_file)}"}
|
321
491
|
else
|
322
492
|
if wwid.config.has_key?('editor_app') && !wwid.config['editor_app'].nil?
|
@@ -335,10 +505,26 @@ desc 'Edit the configuration file'
|
|
335
505
|
command :config do |c|
|
336
506
|
c.desc 'Editor to use'
|
337
507
|
c.default_value ENV['EDITOR']
|
338
|
-
c.flag [:e,:editor]
|
508
|
+
c.flag [:e,:editor], :default_value => nil
|
509
|
+
|
510
|
+
c.desc 'Application to use (OS X only)'
|
511
|
+
c.flag [:a]
|
512
|
+
|
513
|
+
c.desc 'Application bundle id to use (OS X only)'
|
514
|
+
c.flag [:b]
|
339
515
|
|
340
516
|
c.action do |global_options,options,args|
|
341
|
-
|
517
|
+
if options[:a] || options[:b]
|
518
|
+
if options[:a]
|
519
|
+
%x{open -a "#{options[:a]}" "#{File.expand_path(DOING_CONFIG)}"}
|
520
|
+
elsif options[:b]
|
521
|
+
%x{open -b #{options[:b]} "#{File.expand_path(DOING_CONFIG)}"}
|
522
|
+
end
|
523
|
+
else
|
524
|
+
raise "No EDITOR variable defined in environment" if options[:e].nil? && ENV['EDITOR'].nil?
|
525
|
+
editor = options[:e].nil? ? ENV['EDITOR'] : options[:e]
|
526
|
+
system %Q{#{editor} "#{File.expand_path(DOING_CONFIG)}"}
|
527
|
+
end
|
342
528
|
end
|
343
529
|
end
|
344
530
|
|
@@ -347,6 +533,7 @@ pre do |global,command,options,args|
|
|
347
533
|
if global[:version]
|
348
534
|
puts "doing v" + Doing::VERSION
|
349
535
|
end
|
536
|
+
|
350
537
|
# Return true to proceed; false to abort and not call the
|
351
538
|
# chosen command
|
352
539
|
# Use skips_pre before a command to skip this block
|
data/lib/doing.rb
CHANGED
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -41,13 +41,15 @@ class WWID
|
|
41
41
|
'wrap_width' => 88
|
42
42
|
}
|
43
43
|
@config['views'] ||= {
|
44
|
-
'
|
44
|
+
'done' => {
|
45
45
|
'date_format' => '%_I:%M%P',
|
46
46
|
'template' => '%date | %title%note',
|
47
47
|
'wrap_width' => 0,
|
48
|
-
'section' => '
|
49
|
-
'count' =>
|
50
|
-
'order' =>
|
48
|
+
'section' => 'All',
|
49
|
+
'count' => 0,
|
50
|
+
'order' => 'desc',
|
51
|
+
'tags' => 'done complete cancelled',
|
52
|
+
'tags_bool' => 'OR'
|
51
53
|
},
|
52
54
|
'color' => {
|
53
55
|
'date_format' => '%F %_I:%M%P',
|
@@ -89,7 +91,7 @@ class WWID
|
|
89
91
|
|
90
92
|
lines.each {|line|
|
91
93
|
next if line =~ /^\s*$/
|
92
|
-
if line =~ /^(\
|
94
|
+
if line =~ /^(\S[\S ]+):\s*(@\S+\s*)*$/
|
93
95
|
section = $1
|
94
96
|
@content[section] = {}
|
95
97
|
@content[section]['original'] = line
|
@@ -184,6 +186,25 @@ class WWID
|
|
184
186
|
[title, note]
|
185
187
|
end
|
186
188
|
|
189
|
+
def chronify(input)
|
190
|
+
if input =~ /^(\d+)([mhd])?$/i
|
191
|
+
amt = $1
|
192
|
+
type = $2.nil? ? "m" : $2
|
193
|
+
input = case type.downcase
|
194
|
+
when "m"
|
195
|
+
amt + " minutes ago"
|
196
|
+
when "h"
|
197
|
+
amt + " hours ago"
|
198
|
+
when "d"
|
199
|
+
amt + " days ago"
|
200
|
+
else
|
201
|
+
input
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
Chronic.parse(input, {:context => :past, :ambiguous_time_range => 8})
|
206
|
+
end
|
207
|
+
|
187
208
|
def sections
|
188
209
|
@content.keys
|
189
210
|
end
|
@@ -192,19 +213,109 @@ class WWID
|
|
192
213
|
@content[title.cap_first] = {'original' => "#{title}:", 'items' => []}
|
193
214
|
end
|
194
215
|
|
216
|
+
def guess_section(frag)
|
217
|
+
sections.each {|section| return section if frag.downcase == section.downcase}
|
218
|
+
section = false
|
219
|
+
re = frag.split('').join(".*?")
|
220
|
+
sections.each {|sect|
|
221
|
+
if sect =~ /#{re}/i
|
222
|
+
$stderr.puts "Assuming you meant #{sect}"
|
223
|
+
section = sect
|
224
|
+
break
|
225
|
+
end
|
226
|
+
}
|
227
|
+
unless section
|
228
|
+
alt = guess_view(frag)
|
229
|
+
if alt
|
230
|
+
raise "Did you mean `doing view #{alt}`?"
|
231
|
+
else
|
232
|
+
raise "Invalid section: #{frag}"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
section.cap_first
|
236
|
+
end
|
237
|
+
|
238
|
+
def guess_view(frag)
|
239
|
+
views.each {|view| return view if frag.downcase == view.downcase}
|
240
|
+
view = false
|
241
|
+
re = frag.split('').join(".*?")
|
242
|
+
views.each {|v|
|
243
|
+
if v =~ /#{re}/i
|
244
|
+
$stderr.puts "Assuming you meant #{v}"
|
245
|
+
view = v
|
246
|
+
break
|
247
|
+
end
|
248
|
+
}
|
249
|
+
unless view
|
250
|
+
alt = guess_section(frag)
|
251
|
+
if alt
|
252
|
+
raise "Did you mean `doing show #{alt}`?"
|
253
|
+
else
|
254
|
+
raise "Invalid view: #{frag}"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
view
|
258
|
+
end
|
259
|
+
|
195
260
|
def add_item(title,section=nil,opt={})
|
196
261
|
section ||= @current_section
|
197
262
|
add_section(section) unless @content.has_key?(section)
|
198
263
|
opt[:date] ||= Time.now
|
199
264
|
opt[:note] ||= []
|
265
|
+
opt[:back] ||= Time.now
|
200
266
|
|
201
|
-
entry = {'title' => title.strip.cap_first, 'date' => opt[:
|
267
|
+
entry = {'title' => title.strip.cap_first, 'date' => opt[:back]}
|
202
268
|
unless opt[:note] =~ /^\s*$/s
|
203
269
|
entry['note'] = opt[:note]
|
204
270
|
end
|
205
271
|
@content[section]['items'].push(entry)
|
206
272
|
end
|
207
273
|
|
274
|
+
def tag_last(opt={})
|
275
|
+
opt[:section] ||= @current_section
|
276
|
+
opt[:count] ||= 1
|
277
|
+
opt[:archive] ||= false
|
278
|
+
opt[:tags] ||= ["done"]
|
279
|
+
opt[:date] ||= false
|
280
|
+
opt[:remove] ||= false
|
281
|
+
|
282
|
+
opt[:section] = guess_section(opt[:section])
|
283
|
+
|
284
|
+
if @content.has_key?(opt[:section])
|
285
|
+
# sort_section(opt[:section])
|
286
|
+
# items = @content[opt[:section]]['items'].sort_by{|item| item['date'] }.reverse
|
287
|
+
|
288
|
+
@content[opt[:section]]['items'].each_with_index {|item, i|
|
289
|
+
break if i == opt[:count]
|
290
|
+
title = item['title']
|
291
|
+
opt[:tags].each {|tag|
|
292
|
+
if opt[:remove]
|
293
|
+
title.gsub!(/ @#{tag}/,'')
|
294
|
+
else
|
295
|
+
unless title =~ /@#{tag}/
|
296
|
+
if tag == "done" || opt[:date]
|
297
|
+
title += " @#{tag}(#{Time.now.strftime('%F %R')})"
|
298
|
+
else
|
299
|
+
title += " @#{tag}"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
}
|
304
|
+
@content[opt[:section]]['items'][i]['title'] = title
|
305
|
+
}
|
306
|
+
|
307
|
+
if opt[:archive] && opt[:section] != "Archive"
|
308
|
+
archived = @content[opt[:section]]['items'][0..opt[:count]-1]
|
309
|
+
@content[opt[:section]]['items'] = @content[opt[:section]]['items'][opt[:count]..-1]
|
310
|
+
@content['Archive']['items'] = archived + @content['Archive']['items']
|
311
|
+
end
|
312
|
+
|
313
|
+
write(@doing_file)
|
314
|
+
else
|
315
|
+
raise "Section not found"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
208
319
|
def write(file=nil)
|
209
320
|
if @other_content_top.empty?
|
210
321
|
output = ""
|
@@ -264,17 +375,23 @@ class WWID
|
|
264
375
|
opt[:section] ||= nil
|
265
376
|
opt[:format] ||= @default_date_format
|
266
377
|
opt[:template] ||= @default_template
|
378
|
+
opt[:age] ||= "newest"
|
267
379
|
opt[:order] ||= "desc"
|
268
380
|
opt[:today] ||= false
|
381
|
+
opt[:tag_filter] ||= false
|
382
|
+
opt[:tags_color] ||= false
|
269
383
|
|
270
384
|
if opt[:section].nil?
|
271
385
|
opt[:section] = @content[choose_section]
|
272
386
|
elsif opt[:section].class == String
|
273
|
-
if
|
274
|
-
|
387
|
+
if opt[:section] =~ /^all$/i
|
388
|
+
combined = {'items' => []}
|
389
|
+
@content.each {|k,v|
|
390
|
+
combined['items'] += v['items']
|
391
|
+
}
|
392
|
+
opt[:section] = combined
|
275
393
|
else
|
276
|
-
|
277
|
-
return
|
394
|
+
opt[:section] = @content[guess_section(opt[:section])]
|
278
395
|
end
|
279
396
|
end
|
280
397
|
|
@@ -285,78 +402,127 @@ class WWID
|
|
285
402
|
|
286
403
|
items = opt[:section]['items'].sort_by{|item| item['date'] }
|
287
404
|
|
405
|
+
if opt[:tag_filter] && !opt[:tag_filter]['tags'].empty?
|
406
|
+
items.delete_if {|item|
|
407
|
+
if opt[:tag_filter]['bool'] =~ /(AND|ALL)/
|
408
|
+
score = 0
|
409
|
+
opt[:tag_filter]['tags'].each {|tag|
|
410
|
+
score += 1 if item['title'] =~ /@#{tag}/
|
411
|
+
}
|
412
|
+
score < opt[:tag_filter]['tags'].length
|
413
|
+
elsif opt[:tag_filter]['bool'] =~ /NONE/
|
414
|
+
del = false
|
415
|
+
opt[:tag_filter]['tags'].each {|tag|
|
416
|
+
del = true if item['title'] =~ /@#{tag}/
|
417
|
+
}
|
418
|
+
del
|
419
|
+
elsif opt[:tag_filter]['bool'] =~ /(OR|ANY)/
|
420
|
+
del = true
|
421
|
+
opt[:tag_filter]['tags'].each {|tag|
|
422
|
+
del = false if item['title'] =~ /@#{tag}/
|
423
|
+
}
|
424
|
+
del
|
425
|
+
end
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
288
429
|
if opt[:today]
|
289
430
|
items.delete_if {|item|
|
290
431
|
item['date'] < Date.today.to_time
|
291
432
|
}.reverse!
|
292
433
|
else
|
293
|
-
|
434
|
+
if opt[:age] =~ /oldest/i
|
435
|
+
items = items[0..count]
|
436
|
+
else
|
437
|
+
items = items.reverse[0..count]
|
438
|
+
end
|
294
439
|
end
|
295
440
|
|
296
|
-
|
441
|
+
if opt[:order] =~ /^a/i
|
442
|
+
items.reverse!
|
443
|
+
end
|
297
444
|
|
298
445
|
out = ""
|
299
446
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
if opt[:wrap_width] && opt[:wrap_width] > 0
|
304
|
-
width = opt[:wrap_width]
|
305
|
-
note_lines.map! {|line|
|
306
|
-
line.strip.gsub(/(.{1,#{width}})(\s+|\Z)/, "\t\\1\n")
|
307
|
-
}
|
308
|
-
end
|
309
|
-
note = "\n#{note_lines.join("\n").chomp}"
|
310
|
-
else
|
447
|
+
if opt[:csv]
|
448
|
+
output = [['date','title','note'].to_csv]
|
449
|
+
items.each {|i|
|
311
450
|
note = ""
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
if colors.has_key?(m.sub(/^%/,''))
|
316
|
-
colors[m.sub(/^%/,'')]
|
317
|
-
else
|
318
|
-
m
|
319
|
-
end
|
320
|
-
end
|
321
|
-
output.sub!(/%date/,item['date'].strftime(opt[:format]))
|
322
|
-
output.sub!(/%shortdate/) {
|
323
|
-
if item['date'] > Date.today.to_time
|
324
|
-
item['date'].strftime('%_I:%M%P')
|
325
|
-
elsif item['date'] > (Date.today - 7).to_time
|
326
|
-
item['date'].strftime('%a %-I:%M%P')
|
327
|
-
elsif item['date'].year == Date.today.year
|
328
|
-
item['date'].strftime('%b %d, %-I:%M%P')
|
329
|
-
else
|
330
|
-
item['date'].strftime('%b %d %Y, %-I:%M%P')
|
451
|
+
if i['note']
|
452
|
+
arr = i['note'].map{|line| line.strip}.delete_if{|e| e =~ /^\s*$/}
|
453
|
+
note = arr.join("\n") unless arr.nil?
|
331
454
|
end
|
455
|
+
output.push([i['date'],i['title'],note].to_csv)
|
332
456
|
}
|
333
|
-
output.
|
334
|
-
|
335
|
-
|
457
|
+
out = output.join()
|
458
|
+
else
|
459
|
+
|
460
|
+
items.each {|item|
|
461
|
+
if (item.has_key?('note') && !item['note'].empty?) && @config[:include_notes]
|
462
|
+
note_lines = item['note'].delete_if{|line| line =~ /^\s*$/ }.map{|line| "\t\t" + line.sub(/^\t\t/,'') }
|
463
|
+
if opt[:wrap_width] && opt[:wrap_width] > 0
|
464
|
+
width = opt[:wrap_width]
|
465
|
+
note_lines.map! {|line|
|
466
|
+
line.strip.gsub(/(.{1,#{width}})(\s+|\Z)/, "\t\\1\n")
|
467
|
+
}
|
468
|
+
end
|
469
|
+
note = "\n#{note_lines.join("\n").chomp}"
|
336
470
|
else
|
337
|
-
|
471
|
+
note = ""
|
338
472
|
end
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
473
|
+
output = opt[:template].dup
|
474
|
+
|
475
|
+
output.gsub!(/%[a-z]+/) do |m|
|
476
|
+
if colors.has_key?(m.sub(/^%/,''))
|
477
|
+
colors[m.sub(/^%/,'')]
|
478
|
+
else
|
479
|
+
m
|
480
|
+
end
|
346
481
|
end
|
347
|
-
o
|
348
|
-
end
|
349
482
|
|
483
|
+
output.sub!(/%date/,item['date'].strftime(opt[:format]))
|
484
|
+
output.sub!(/%shortdate/) {
|
485
|
+
if item['date'] > Date.today.to_time
|
486
|
+
item['date'].strftime('%_I:%M%P')
|
487
|
+
elsif item['date'] > (Date.today - 7).to_time
|
488
|
+
item['date'].strftime('%a %-I:%M%P')
|
489
|
+
elsif item['date'].year == Date.today.year
|
490
|
+
item['date'].strftime('%b %d, %-I:%M%P')
|
491
|
+
else
|
492
|
+
item['date'].strftime('%b %d %Y, %-I:%M%P')
|
493
|
+
end
|
494
|
+
}
|
495
|
+
output.sub!(/%title/) {|m|
|
496
|
+
if opt[:wrap_width] && opt[:wrap_width] > 0
|
497
|
+
item['title'].gsub(/(.{1,#{opt[:wrap_width]}})(\s+|\Z)/, "\\1\n\t ").strip
|
498
|
+
else
|
499
|
+
item['title'].strip
|
500
|
+
end
|
501
|
+
}
|
502
|
+
if opt[:tags_color]
|
503
|
+
output.gsub!(/\s(@\S+(?:\(.*?\))?)/," #{colors[opt[:tags_color]]}\\1")
|
504
|
+
end
|
505
|
+
output.sub!(/%note/,note)
|
506
|
+
output.sub!(/%odnote/,note.gsub(/\t\t/,"\t"))
|
507
|
+
output.gsub!(/%hr(_under)?/) do |m|
|
508
|
+
o = ""
|
509
|
+
`tput cols`.to_i.times do
|
510
|
+
o += $1.nil? ? "-" : "_"
|
511
|
+
end
|
512
|
+
o
|
513
|
+
end
|
350
514
|
|
351
|
-
|
352
|
-
|
515
|
+
|
516
|
+
out += output + "\n"
|
517
|
+
}
|
518
|
+
end
|
353
519
|
|
354
520
|
return out
|
355
521
|
end
|
356
522
|
|
357
523
|
def archive(section=nil,count=10)
|
358
524
|
section = choose_section if section.nil? || section =~ /choose/i
|
359
|
-
section = section
|
525
|
+
section = guess_section(section)
|
360
526
|
if sections.include?(section)
|
361
527
|
items = @content[section]['items']
|
362
528
|
return if items.length < count
|
@@ -422,6 +588,7 @@ class WWID
|
|
422
588
|
def recent(count=10,section=nil)
|
423
589
|
cfg = @config['templates']['recent']
|
424
590
|
section ||= @current_section
|
591
|
+
section = guess_section(section)
|
425
592
|
list_section({:section => section, :wrap_width => cfg['wrap_width'], :count => count, :format => cfg['date_format'], :template => cfg['template'], :order => "asc"})
|
426
593
|
end
|
427
594
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -72,6 +72,26 @@ dependencies:
|
|
72
72
|
- - '='
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 2.9.0
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: chronic
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ~>
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0.10'
|
82
|
+
- - '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 0.10.2
|
85
|
+
type: :runtime
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0.10'
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.10.2
|
75
95
|
description: A tool for managing a TaskPaper-like file of recent activites. Perfect
|
76
96
|
for the late-night hacker on too much caffeine to remember what they accomplished
|
77
97
|
at 2 in the morning.
|
@@ -110,9 +130,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
130
|
version: '0'
|
111
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
132
|
requirements:
|
113
|
-
- - '
|
133
|
+
- - '>'
|
114
134
|
- !ruby/object:Gem::Version
|
115
|
-
version:
|
135
|
+
version: 1.3.1
|
116
136
|
requirements: []
|
117
137
|
rubyforge_project:
|
118
138
|
rubygems_version: 2.2.2
|