friends 0.30 → 0.31

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81e378aa8d3e1a7285adcb3f92cc91977c22eca2
4
- data.tar.gz: f48b3ccd7d4006679c7b072b06a980432c759a6c
3
+ metadata.gz: d644149046a9df58031ed1aefcd34ca28d45fb91
4
+ data.tar.gz: f4964423489ad13fcdfc789c3e9ccc025c65a0e9
5
5
  SHA512:
6
- metadata.gz: ee11daf225f5c245b68a732267b0fafd7041d478d8cff7d68860f9b50a71f9a3db51de2edd4a7dac723a6db5c5c26045a697a21bc7215acc770bed3a2390ee10
7
- data.tar.gz: e47d850e7cc62ea74a0c212f0315de2cc5bd1eb72f331526ccee67dd39d7599b091a546770d14ba2af7132f929ab8d9076f61b28cb8a68a36432ccda3d481f56
6
+ metadata.gz: 2c5189966fe28ac95307bab8375cd31075deb6e928847950dd7e7af1e5f9c4b4b186d2da8ca91da9021324dbf8f720a9799c0a4ef6327afe2a7bac67b2573c4c
7
+ data.tar.gz: dd219dc75e1f7a01e7f8f0131f5980490b122641fbafbdf87d09221aa18a672cce34707a7c9cb4d9c91282e84710ff874783e570c49d8988f73180c5e593c152
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.31](https://github.com/JacobEvelyn/friends/tree/v0.31) (2017-06-02)
4
+ [Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.30...v0.31)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Change graph commands to display filtered graphs within total [\#171](https://github.com/JacobEvelyn/friends/issues/171)
9
+
10
+ **Fixed bugs:**
11
+
12
+ - Graph does not display more than 42 activities per month [\#172](https://github.com/JacobEvelyn/friends/issues/172)
13
+
14
+ **Closed issues:**
15
+
16
+ - Reduce dependencies [\#167](https://github.com/JacobEvelyn/friends/issues/167)
17
+ - Add standalone distribution [\#160](https://github.com/JacobEvelyn/friends/issues/160)
18
+ - Integrate with cron for regular reminders [\#56](https://github.com/JacobEvelyn/friends/issues/56)
19
+
20
+ **Merged pull requests:**
21
+
22
+ - Improve graph command [\#174](https://github.com/JacobEvelyn/friends/pull/174) ([JacobEvelyn](https://github.com/JacobEvelyn))
23
+ - Remove Memoist dependency and bump gem dependencies [\#170](https://github.com/JacobEvelyn/friends/pull/170) ([JacobEvelyn](https://github.com/JacobEvelyn))
24
+ - Remove warnings when running tests [\#169](https://github.com/JacobEvelyn/friends/pull/169) ([JacobEvelyn](https://github.com/JacobEvelyn))
25
+
3
26
  ## [v0.30](https://github.com/JacobEvelyn/friends/tree/v0.30) (2017-05-30)
4
27
  [Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.29...v0.30)
5
28
 
@@ -9,6 +32,10 @@
9
32
  - Improve display of favorites for ties [\#158](https://github.com/JacobEvelyn/friends/issues/158)
10
33
  - Filter activities based on more than one friend/tag/etc. [\#88](https://github.com/JacobEvelyn/friends/issues/88)
11
34
 
35
+ **Closed issues:**
36
+
37
+ - Reduce warnings [\#166](https://github.com/JacobEvelyn/friends/issues/166)
38
+
12
39
  **Merged pull requests:**
13
40
 
14
41
  - Be able to filter output by more than one friend or tag [\#168](https://github.com/JacobEvelyn/friends/pull/168) ([JacobEvelyn](https://github.com/JacobEvelyn))
@@ -1,3 +1,5 @@
1
+ ---
2
+
1
3
  Hi there! Thanks so much for submitting a pull request!
2
4
 
3
5
  Let's just make sure together that all of these boxes are checked before we
data/README.md CHANGED
@@ -18,6 +18,7 @@ lots of help), and give feedback!**
18
18
  - [Core concepts](#core-concepts)
19
19
  - [Global flags](#global-flags)
20
20
  - [Syncing across multiple machines](#syncing-across-multiple-machines)
21
+ - [Setting reminders](#setting-reminders)
21
22
  - [Command reference](#command-reference)
22
23
  - `add`
23
24
  - [`add activity`](#add-activity)
@@ -124,10 +125,10 @@ The `friends.md` Markdown file that stores all of your data contains:
124
125
 
125
126
  ```markdown
126
127
  ### Activities:
127
- - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute.
128
- - 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**.
129
- - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**.
130
- - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
128
+ - 2018-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute.
129
+ - 2018-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**.
130
+ - 2017-12-31: Celebrated the new year in _Paris_ with **Marie Curie**.
131
+ - 2017-11-15: Talked to **George Washington Carver** on the phone for an hour.
131
132
  ```
132
133
 
133
134
  See the example
@@ -188,6 +189,29 @@ do this for you, like so:
188
189
  alias friends="friends --filename '~/Dropbox/friends.md'"
189
190
  ```
190
191
 
192
+ ### Setting reminders
193
+
194
+ Though `friends` has no built-in reminder functionality, it's easy to use a
195
+ system like `cron` (Mac or Linux) or `Task Scheduler` (Windows) to set various
196
+ reminders.
197
+
198
+ For example, on a Mac, the following `crontab` configuration results in every day
199
+ at 9:00 p.m. a Terminal tab opening, printing "Time to journal!" and then launching
200
+ an `add activity` prompt through `friends`:
201
+
202
+ ```
203
+ 0 21 * * * osascript -e 'activate application "Terminal"' &> /dev/null && osascript -e 'tell application "Terminal" to do script "clear && echo Time to journal! && friends add activity"' &> /dev/null
204
+ ```
205
+
206
+ Here's another example (also for Mac) of using `friends` to suggest some people to
207
+ hang out with every Saturday morning:
208
+
209
+ ```
210
+ 0 10 * * 6 osascript -e 'activate application "Terminal"' &> /dev/null && osascript -e 'tell application "Terminal" to do script "clear && echo Consider hanging out with one of these friends today: && friends suggest"' &> /dev/null
211
+ ```
212
+
213
+ (If you use other tools, please share and we'll add to these examples!)
214
+
191
215
  ### Command reference*
192
216
 
193
217
  *Note that the command-line output is colored, which this README cannot show.
@@ -196,7 +220,7 @@ alias friends="friends --filename '~/Dropbox/friends.md'"
196
220
 
197
221
  ```bash
198
222
  $ friends add activity Got lunch with Grace and George.
199
- Activity added: "2015-01-04: Got lunch with Grace Hopper and George Washington Carver."
223
+ Activity added: "2018-01-04: Got lunch with Grace Hopper and George Washington Carver."
200
224
  ```
201
225
 
202
226
  `friends` will **automatically** figure out which "Grace" and "George" you're referring to, *even if you're friends with lots of different Graces and Georges*.
@@ -206,7 +230,7 @@ just like formal names:
206
230
 
207
231
  ```bash
208
232
  $ friends add activity Invented debugging with The Admiral.
209
- Activity added: "2016-01-06: Invented debugging with Grace Hopper."
233
+ Activity added: "2017-01-06: Invented debugging with Grace Hopper."
210
234
  ```
211
235
 
212
236
  You can also use the first initial of a last name instead of the whole thing.
@@ -215,14 +239,14 @@ them) based on whether you're in the middle of a sentence or not:
215
239
 
216
240
  ```bash
217
241
  $ friends add activity Got lunch with Earnest H and Earnest S. in the park. Man, I like Earnest H. but really love Earnest S.
218
- Activity added: "2016-05-01: Got lunch with Earnest Hemingway and Earnest Shackleton in the park. Man, I like Earnest Hemingway but really love Earnest Shackleton."
242
+ Activity added: "2017-05-01: Got lunch with Earnest Hemingway and Earnest Shackleton in the park. Man, I like Earnest Hemingway but really love Earnest Shackleton."
219
243
  ```
220
244
 
221
245
  And locations will be matched as well:
222
246
 
223
247
  ```bash
224
248
  $ friends add activity Went swimming near atlantis with George.
225
- Activity added: "2016-01-06: Went swimming near Atlantis with George Washington Carver."
249
+ Activity added: "2017-01-06: Went swimming near Atlantis with George Washington Carver."
226
250
  ```
227
251
 
228
252
  Tags will be colored if they're provided (though this README can't display
@@ -230,35 +254,35 @@ color so you'll just have to have faith here):
230
254
 
231
255
  ```bash
232
256
  $ friends add activity The office softball team wins a game! @work @exercise
233
- Activity added: "2016-05-05: The office softball team wins a game! @work @exercise"
257
+ Activity added: "2017-05-05: The office softball team wins a game! @work @exercise"
234
258
  ```
235
259
 
236
260
  You can of course specify a date for the activity:
237
261
 
238
262
  ```bash
239
263
  $ friends add activity Yesterday: Celebrated the new year with Marie.
240
- Activity added: "2014-12-31: Celebrated the new year with Marie Curie."
264
+ Activity added: "2017-12-31: Celebrated the new year with Marie Curie."
241
265
  ```
242
266
 
243
267
  Or get an **interactive prompt** by just typing `friends add activity`, with or without a date specified:
244
268
 
245
269
  ```bash
246
- $ friends add activity 2015-11-01
247
- 2015-11-01: <type description here>
270
+ $ friends add activity 2018-11-01
271
+ 2018-11-01: <type description here>
248
272
  ```
249
273
 
250
274
  **Natural-language dates** work just fine:
251
275
 
252
276
  ```bash
253
277
  $ friends add activity last Monday
254
- 2016-03-07: <type description here>
278
+ 2017-03-07: <type description here>
255
279
  ```
256
280
 
257
281
  You can escape the names of friends you don't want `friends` to match with a backslash:
258
282
 
259
283
  ```bash
260
- $ friends add activity "2015-11-01: Grace and I went to \Marie's Diner. \George had to cancel at the last minute."
261
- Activity added: "2015-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute."
284
+ $ friends add activity "2018-11-01: Grace and I went to \Marie's Diner. \George had to cancel at the last minute."
285
+ Activity added: "2018-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute."
262
286
  ```
263
287
 
264
288
  #### `add friend`
@@ -327,78 +351,88 @@ Graphs (in color!) your activities over time:
327
351
 
328
352
  ```bash
329
353
  $ friends graph
330
- Nov 2014 |███
331
- Dec 2014 |██
332
- Jan 2015 |███████
333
- Feb 2015 |█████
354
+ Nov 2017 |███
355
+ Dec 2017 |██
356
+ Jan 2018 |███████
357
+ Feb 2018 |█████
334
358
  ```
335
359
 
336
360
  Or graph only activities with a certain friend:
337
361
 
338
362
  ```bash
339
363
  $ friends graph --with George
340
- Nov 2014 |█
341
- Dec 2014 |
342
- Jan 2015 |█████
343
- Feb 2015 |███
364
+ Nov 2017 |█∙∙|
365
+ Dec 2017 |∙∙|
366
+ Jan 2018 |█████∙∙|
367
+ Feb 2018 |███∙∙|
344
368
  ```
345
369
 
346
- Or a certain group of friends:
370
+ The dots represent the total activities that month, so you can get a feel for the
371
+ proportion of activities with that friend vs. the total you've logged.
372
+
373
+ You can also graph a certain group of friends:
347
374
 
348
375
  ```bash
349
376
  $ friends graph --with George --with Grace
350
- Jan 2015 |█
377
+ Nov 2017 |∙∙∙|
378
+ Dec 2017 |∙∙|
379
+ Jan 2018 |█∙∙∙∙∙∙|
380
+ Feb 2018 |∙∙∙∙∙|
351
381
  ```
352
382
 
353
383
  Or graph only activities with a certain tag:
354
384
 
355
385
  ```bash
356
386
  $ friends graph --tagged food
357
- Nov 2014 |█
358
- Dec 2014 |
359
- Jan 2015 |
360
- Feb 2015 |███
387
+ Nov 2017 |█∙∙|
388
+ Dec 2017 |∙∙|
389
+ Jan 2018 |∙∙∙∙∙∙∙|
390
+ Feb 2018 |███∙∙|
361
391
  ```
362
392
 
363
393
  Or with multiple tags:
364
394
 
365
395
  ```bash
366
396
  $ friends graph --tagged @fun --tagged @work
367
- Jul 2017 |█
397
+ Nov 2017 |∙∙∙|
398
+ Dec 2017 |█∙|
399
+ Jan 2018 |∙∙∙∙∙∙∙|
400
+ Feb 2018 |█∙∙∙∙|
368
401
  ```
369
402
 
370
403
  Or graph only activities in a certain location:
371
404
 
372
405
  ```bash
373
406
  $ friends graph --in Paris
374
- Nov 2014 |█
375
- Dec 2014 |
376
- Jan 2015 |
377
- Feb 2015 |█
407
+ Nov 2017 |█∙∙|
408
+ Dec 2017 |∙∙|
409
+ Jan 2018 |∙∙∙∙∙∙∙|
410
+ Feb 2018 |█∙∙∙∙|
378
411
  ```
379
412
 
380
413
  Or graph only activities on or after a certain date:
381
414
 
382
415
  ```bash
383
- $ friends graph --since 'January 1st 2015'
384
- Jan 2015 |███████
385
- Feb 2015 |█████
416
+ $ friends graph --since 'January 1st 2018'
417
+ Jan 2018 |███████
418
+ Feb 2018 |█████
386
419
  ```
387
420
 
388
421
  Or graph only activities before or on a certain date:
389
422
 
390
423
  ```bash
391
- $ friends graph --until 'January 1st 2015'
392
- Nov 2014 |███
393
- Dec 2014 |██
394
- Jan 2015 |███████
424
+ $ friends graph --until 'January 1st 2018'
425
+ Nov 2017 |███
426
+ Dec 2017 |██
427
+ Jan 2018 |███████
395
428
  ```
396
429
 
397
430
  And you can use multiple of these flags together:
398
431
 
399
432
  ```bash
400
- $ friends graph --in Paris --tagged food --with George --after 'September 2014'
401
- Nov 2014 |█
433
+ $ friends graph --in Paris --tagged food --with George --since 'Jan 2018'
434
+ Jan 2018 |∙∙∙∙∙∙∙|
435
+ Fen 2017 |█∙∙∙∙|
402
436
  ```
403
437
 
404
438
  #### `help`
@@ -436,74 +470,74 @@ Lists recent activities:
436
470
 
437
471
  ```bash
438
472
  $ friends list activities
439
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
440
- 2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
441
- 2014-11-15: Talked to George Washington Carver on the phone for an hour.
473
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
474
+ 2017-12-31: Celebrated the new year with Marie Curie in New York City. @partying
475
+ 2017-11-15: Talked to George Washington Carver on the phone for an hour.
442
476
  ```
443
477
 
444
478
  You can adjust how many activities are shown:
445
479
 
446
480
  ```bash
447
481
  $ friends list activities --limit 2
448
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
449
- 2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
482
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
483
+ 2017-12-31: Celebrated the new year with Marie Curie in New York City. @partying
450
484
  ```
451
485
 
452
486
  Or only list the activities you did with a certain friend:
453
487
 
454
488
  ```bash
455
489
  $ friends list activities --with George
456
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
457
- 2014-11-15: Talked to George Washington Carver on the phone for an hour.
490
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
491
+ 2017-11-15: Talked to George Washington Carver on the phone for an hour.
458
492
  ```
459
493
 
460
494
  Or only filter activities done with a group of friends:
461
495
 
462
496
  ```bash
463
497
  $ friends list activities --with George --with Grace
464
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
498
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
465
499
  ```
466
500
 
467
501
  Or filter your activities by location:
468
502
 
469
503
  ```bash
470
504
  $ friends list activities --in "New York"
471
- 2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
505
+ 2017-12-31: Celebrated the new year with Marie Curie in New York City. @partying
472
506
  ```
473
507
 
474
508
  Or by tag:
475
509
 
476
510
  ```bash
477
511
  $ friends list activities --tagged food
478
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
512
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
479
513
  ```
480
514
 
481
515
  Or use more than one tag:
482
516
 
483
517
  ```bash
484
518
  $ friends list activities --tagged @fun --tagged @work
485
- 2017-07-04: Summer picnic with @work colleagues. @fun
519
+ 2018-07-04: Summer picnic with @work colleagues. @fun
486
520
  ```
487
521
 
488
522
  Or by date:
489
523
 
490
524
  ```bash
491
- $ friends list activities --since 'December 31st 2014'
492
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
493
- 2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
525
+ $ friends list activities --since 'December 31st 2017'
526
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
527
+ 2017-12-31: Celebrated the new year with Marie Curie in New York City. @partying
494
528
  ```
495
529
 
496
530
  ```bash
497
- $ friends list activities --until 'December 31st 2014'
498
- 2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
499
- 2014-11-15: Talked to George Washington Carver on the phone for an hour.
531
+ $ friends list activities --until 'December 31st 2017'
532
+ 2017-12-31: Celebrated the new year with Marie Curie in New York City. @partying
533
+ 2017-11-15: Talked to George Washington Carver on the phone for an hour.
500
534
  ```
501
535
 
502
536
  And you can mix and match these options to your heart's content:
503
537
 
504
538
  ```bash
505
539
  $ friends list activities --tagged food --with Grace --with George
506
- 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
540
+ 2018-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
507
541
  ```
508
542
 
509
543
  #### `list favorite friends`
data/friends.gemspec CHANGED
@@ -25,9 +25,8 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency "chronic", "~> 0.10"
27
27
  spec.add_dependency "gli", "~> 2.12"
28
- spec.add_dependency "memoist", "~> 0.15"
29
- spec.add_dependency "paint", "~> 1.0"
30
- spec.add_dependency "semverse", "~> 1.2"
28
+ spec.add_dependency "paint", "~> 2.0"
29
+ spec.add_dependency "semverse", "~> 2.0"
31
30
 
32
31
  spec.add_development_dependency "bundler", "~> 1.6"
33
32
  spec.add_development_dependency "coveralls", "~> 0.8"
data/friends.md CHANGED
@@ -1,8 +1,8 @@
1
1
  ### Activities:
2
- - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
3
- - 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
4
- - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
5
- - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
2
+ - 2018-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
3
+ - 2018-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
4
+ - 2017-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
5
+ - 2017-11-15: Talked to **George Washington Carver** on the phone for an hour.
6
6
 
7
7
  ### Friends:
8
8
  - George Washington Carver
data/lib/friends.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "friends/introvert"
4
3
  require "friends/version"
5
4
 
6
5
  module Friends
@@ -3,7 +3,6 @@
3
3
  # Activity represents an activity you've done with one or more Friends.
4
4
 
5
5
  require "chronic"
6
- require "memoist"
7
6
  require "paint"
8
7
  require "set"
9
8
 
@@ -12,7 +11,6 @@ require "friends/serializable"
12
11
  module Friends
13
12
  class Activity
14
13
  extend Serializable
15
- extend Memoist
16
14
 
17
15
  SERIALIZATION_PREFIX = "- "
18
16
  DATE_PARTITION = ": "
@@ -143,16 +141,14 @@ module Friends
143
141
  # Find the names of all friends in this description.
144
142
  # @return [Array] list of all friend names in the description
145
143
  def friend_names
146
- @description.scan(/(?<=\*\*)\w[^\*]*(?=\*\*)/).uniq
144
+ @_friend_names ||= @description.scan(/(?<=\*\*)\w[^\*]*(?=\*\*)/).uniq
147
145
  end
148
- memoize :friend_names
149
146
 
150
147
  # Find the names of all locations in this description.
151
148
  # @return [Array] list of all location names in the description
152
149
  def location_names
153
- @description.scan(/(?<=_)\w[^_]*(?=_)/).uniq
150
+ @_location_names ||= @description.scan(/(?<=_)\w[^_]*(?=_)/).uniq
154
151
  end
155
- memoize :location_names
156
152
 
157
153
  private
158
154
 
@@ -30,29 +30,12 @@ command :graph do |graph|
30
30
  type: InputDate
31
31
 
32
32
  graph.action do |_, options|
33
- # This math is taken from Minitest's Pride plugin (the PrideLOL class).
34
- PI_3 = Math::PI / 3
35
-
36
- colors = (0...(6 * 7)).map do |n|
37
- n *= 1.0 / 6
38
- r = (3 * Math.sin(n) + 3).to_i
39
- g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
40
- b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i
41
-
42
- [r, g, b].map { |c| c * 51 }
43
- end
44
-
45
- data = @introvert.graph(
33
+ @introvert.graph(
46
34
  with: options[:with],
47
35
  location_name: options[:in],
48
36
  tagged: options[:tagged],
49
37
  since_date: options[:since],
50
38
  until_date: options[:until]
51
39
  )
52
-
53
- data.each do |month, count|
54
- print "#{month} |"
55
- puts colors.take(count).map { |rgb| Paint["█", rgb] }.join
56
- end
57
40
  end
58
41
  end
data/lib/friends/graph.rb CHANGED
@@ -7,47 +7,65 @@ module Friends
7
7
  DATE_FORMAT = "%b %Y"
8
8
 
9
9
  # @param activities [Array<Friends::Activity>] a list of activities to graph
10
- def initialize(activities:)
11
- @activities = activities
12
- unless @activities.empty?
13
- @start_date = @activities.last.date
14
- @end_date = @activities.first.date
10
+ def initialize(filtered_activities:, all_activities:)
11
+ @filtered_activities = filtered_activities
12
+ @all_activities = all_activities
13
+ unless @all_activities.empty?
14
+ @start_date = @all_activities.last.date
15
+ @end_date = @all_activities.first.date
15
16
  end
16
17
  end
17
18
 
19
+ # Prints the graph to STDOUT, with colors.
20
+ def draw
21
+ to_h.each do |month, (filtered_count, total_count)|
22
+ str = "#{month} |"
23
+ str += Array.new(filtered_count) do |count|
24
+ Paint["█", color(count)]
25
+ end.join
26
+ if total_count > filtered_count
27
+ str += Array.new(total_count - filtered_count) do |count|
28
+ Paint["∙", color(filtered_count + count)]
29
+ end.join + Paint["|", color(total_count + 1)]
30
+ end
31
+ puts str
32
+ end
33
+ end
34
+
35
+ private
36
+
18
37
  # Render the graph as a hash in the format:
19
38
  #
20
39
  # {
21
- # "Jan 2015" => 3, # The number of activities during each month.
22
- # "Feb 2015" => 0,
23
- # "Mar 2015" => 9
40
+ # "Jan 2015" => [3, 4], # [# filtered activities, # total activities]
41
+ # "Feb 2015" => [0, 0],
42
+ # "Mar 2015" => [0, 9]
24
43
  # }
25
44
  #
26
45
  # @return [Hash{String => Integer}]
27
46
  def to_h
28
47
  empty_graph.tap do |graph|
29
- activities.each do |activity|
30
- graph[format_date(activity.date)] += 1
48
+ @filtered_activities.each do |activity|
49
+ graph[format_date(activity.date)][0] += 1
50
+ end
51
+ @all_activities.each do |activity|
52
+ graph[format_date(activity.date)][1] += 1
31
53
  end
32
54
  end
33
55
  end
34
56
 
35
- private
36
-
37
- attr_accessor :start_date, :end_date, :activities
38
-
39
57
  # Render an empty graph as a hash in the format:
40
58
  #
41
59
  # {
42
- # "Jan 2015" => 0,
43
- # "Feb 2015" => 0,
44
- # "Mar 2015" => 0
60
+ # "Jan 2015" => [0, 0] # [# filtered activities, # total activities]
61
+ # "Feb 2015" => [0, 0]
62
+ # "Mar 2015" => [0, 0]
45
63
  # }
46
64
  #
47
65
  # @return [Hash{String => Integer}]
48
66
  def empty_graph
49
- Hash[(start_date && end_date ? (start_date..end_date) : []).map do |date|
50
- [format_date(date), 0]
67
+ Hash[(@start_date && @end_date ? (@start_date..@end_date) : []).map do |date|
68
+ [format_date(date), [0, 0]]
51
69
  end]
52
70
  end
53
71
 
@@ -57,5 +75,38 @@ module Friends
57
75
  def format_date(date)
58
76
  date.strftime(DATE_FORMAT)
59
77
  end
78
+
79
+ # @param x [Integer] the x coordinate we want to color; x >= 0
80
+ # @return [Array<Integer>] the color we should use to paint
81
+ # a point on the graph at the given x coordinate
82
+ def color(x)
83
+ COLORS[x % COLORS.size]
84
+ end
85
+
86
+ # Originally generated by executing the code in Minitest's Pride plugin (the PrideLOL class),
87
+ # and then pulling the unique values out and doubling them to create a more even distribution
88
+ # of colors.
89
+ COLORS = [
90
+ [153, 255, 0], [153, 255, 0],
91
+ [153, 204, 0], [153, 204, 0],
92
+ [204, 204, 0], [204, 204, 0],
93
+ [255, 153, 0], [255, 153, 0],
94
+ [255, 102, 0], [255, 102, 0],
95
+ [255, 51, 51], [255, 51, 51],
96
+ [255, 0, 102], [255, 0, 102],
97
+ [255, 0, 153], [255, 0, 153],
98
+ [204, 0, 204], [204, 0, 204],
99
+ [153, 0, 255], [153, 0, 255],
100
+ [102, 0, 255], [102, 0, 255],
101
+ [51, 51, 255], [51, 51, 255],
102
+ [0, 102, 255], [0, 102, 255],
103
+ [0, 153, 255], [0, 153, 255],
104
+ [0, 204, 204], [0, 204, 204],
105
+ [0, 255, 153], [0, 255, 153],
106
+ [0, 255, 102], [0, 255, 102],
107
+ [51, 255, 51], [51, 255, 51],
108
+ [102, 255, 0], [102, 255, 0]
109
+ ].freeze
110
+ private_constant :COLORS
60
111
  end
61
112
  end
@@ -310,7 +310,7 @@ module Friends
310
310
  # @raise [FriendsError] if friend, location or tag cannot be found or
311
311
  # is ambiguous
312
312
  def graph(with:, location_name:, tagged:, since_date:, until_date:)
313
- activities_to_graph = filtered_activities(
313
+ filtered_activities_to_graph = filtered_activities(
314
314
  with: with,
315
315
  location_name: location_name,
316
316
  tagged: tagged,
@@ -318,7 +318,24 @@ module Friends
318
318
  until_date: until_date
319
319
  )
320
320
 
321
- Graph.new(activities: activities_to_graph).to_h
321
+ # If the user wants to graph in a specific date range, we explicitly
322
+ # limit our output to that date range. We don't just use the date range
323
+ # of the first and last `filtered_activities_to_graph` because those
324
+ # activities might not include others in the full range (for instance,
325
+ # if only one filtered activity matches a query, we don't want to only
326
+ # show unfiltered activities that occurred on that specific day).
327
+ all_activities_to_graph = filtered_activities(
328
+ with: [],
329
+ location_name: nil,
330
+ tagged: [],
331
+ since_date: since_date,
332
+ until_date: until_date
333
+ )
334
+
335
+ Graph.new(
336
+ filtered_activities: filtered_activities_to_graph,
337
+ all_activities: all_activities_to_graph
338
+ ).draw
322
339
  end
323
340
 
324
341
  # Suggest friends to do something with.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Friends
4
- VERSION = "0.30"
4
+ VERSION = "0.31"
5
5
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "date"
4
+
3
5
  require "./test/helper"
4
6
 
5
7
  def date_parsing_specs(test_stdout: true)
@@ -4,12 +4,15 @@ require "./test/helper"
4
4
 
5
5
  clean_describe "clean" do
6
6
  subject { run_cmd("clean") }
7
+ let(:content) { nil }
7
8
 
8
9
  it "outputs a message" do
9
10
  stdout_only "File cleaned: \"#{filename}\""
10
11
  end
11
12
 
12
13
  describe "when file does not exist" do
14
+ let(:content) { nil }
15
+
13
16
  it "does not create the file" do
14
17
  File.exist?(filename).must_equal false
15
18
  end
@@ -6,6 +6,8 @@ clean_describe "graph" do
6
6
  subject { run_cmd("graph") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "prints no output" do
10
12
  stdout_only ""
11
13
  end
@@ -20,13 +22,35 @@ clean_describe "graph" do
20
22
  end
21
23
 
22
24
  describe "when file has content" do
23
- let(:content) { CONTENT } # Content must be sorted to avoid errors.
25
+ # Content must be sorted to avoid errors.
26
+ let(:content) do
27
+ <<-FILE
28
+ ### Activities:
29
+ - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
30
+ - 2015-01-14: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
31
+ - 2015-01-06: Did some other things in _Paris_.
32
+ - 2015-01-06: Did even more things in _Paris_.
33
+ - 2015-01-05: Did even more things in _Paris_.
34
+ - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying @food
35
+ - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
36
+
37
+ ### Friends:
38
+ - George Washington Carver
39
+ - Marie Curie [Atlantis] @science
40
+ - Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
41
+
42
+ ### Locations:
43
+ - Atlantis
44
+ - Marie's Diner
45
+ - Paris
46
+ FILE
47
+ end
24
48
 
25
49
  it "graphs all activities" do
26
50
  stdout_only <<-OUTPUT
27
51
  Nov 2014 |█
28
52
  Dec 2014 |█
29
- Jan 2015 |█
53
+ Jan 2015 |████
30
54
  Feb 2015 |
31
55
  Mar 2015 |
32
56
  Apr 2015 |
@@ -40,6 +64,16 @@ Nov 2015 |█
40
64
  OUTPUT
41
65
  end
42
66
 
67
+ describe "when there are more activities than colors" do
68
+ let(:content) do
69
+ (["### Activities:"] + (["- 2017-06-01: Did something."] * 100)).join("\n")
70
+ end
71
+
72
+ it "displays the correct number of activities" do
73
+ stdout_only("Jun 2017 |" + ("█" * 100))
74
+ end
75
+ end
76
+
43
77
  describe "--in" do
44
78
  subject { run_cmd("graph --in #{location_name}") }
45
79
 
@@ -54,7 +88,19 @@ Nov 2015 |█
54
88
  let(:location_name) { "paris" }
55
89
  it "matches location case-insensitively" do
56
90
  stdout_only <<-OUTPUT
91
+ Nov 2014 |∙|
57
92
  Dec 2014 |█
93
+ Jan 2015 |███∙|
94
+ Feb 2015 |
95
+ Mar 2015 |
96
+ Apr 2015 |
97
+ May 2015 |
98
+ Jun 2015 |
99
+ Jul 2015 |
100
+ Aug 2015 |
101
+ Sep 2015 |
102
+ Oct 2015 |
103
+ Nov 2015 |∙|
58
104
  OUTPUT
59
105
  end
60
106
  end
@@ -85,8 +131,18 @@ Dec 2014 |█
85
131
  it "matches friend case-insensitively" do
86
132
  stdout_only <<-OUTPUT
87
133
  Nov 2014 |█
88
- Dec 2014 |
89
- Jan 2015 |█
134
+ Dec 2014 |∙|
135
+ Jan 2015 |█∙∙∙|
136
+ Feb 2015 |
137
+ Mar 2015 |
138
+ Apr 2015 |
139
+ May 2015 |
140
+ Jun 2015 |
141
+ Jul 2015 |
142
+ Aug 2015 |
143
+ Sep 2015 |
144
+ Oct 2015 |
145
+ Nov 2015 |∙|
90
146
  OUTPUT
91
147
  end
92
148
  end
@@ -97,7 +153,21 @@ Jan 2015 |█
97
153
  let(:friend_name2) { "grace" }
98
154
 
99
155
  it "matches all friends case-insensitively" do
100
- stdout_only "Jan 2015 |█"
156
+ stdout_only <<-OUTPUT
157
+ Nov 2014 |∙|
158
+ Dec 2014 |∙|
159
+ Jan 2015 |█∙∙∙|
160
+ Feb 2015 |
161
+ Mar 2015 |
162
+ Apr 2015 |
163
+ May 2015 |
164
+ Jun 2015 |
165
+ Jul 2015 |
166
+ Aug 2015 |
167
+ Sep 2015 |
168
+ Oct 2015 |
169
+ Nov 2015 |∙|
170
+ OUTPUT
101
171
  end
102
172
  end
103
173
  end
@@ -107,7 +177,9 @@ Jan 2015 |█
107
177
 
108
178
  it "matches tag case-sensitively" do
109
179
  stdout_only <<-OUTPUT
110
- Jan 2015 |█
180
+ Nov 2014 |∙|
181
+ Dec 2014 |█
182
+ Jan 2015 |█∙∙∙|
111
183
  Feb 2015 |
112
184
  Mar 2015 |
113
185
  Apr 2015 |
@@ -125,33 +197,33 @@ Nov 2015 |█
125
197
  subject { run_cmd("graph --tagged #{tag1} --tagged #{tag2}") }
126
198
  let(:tag1) { "food" }
127
199
  let(:tag2) { "partying" }
128
- let(:content) do
129
- <<-FILE
130
- ### Activities:
131
- - 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
132
- - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
133
- - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
134
- - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying @food
135
-
136
- ### Friends:
137
- - George Washington Carver
138
- - Marie Curie [Atlantis] @science
139
- - Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
140
- FILE
141
- end
142
200
 
143
201
  it "matches all tags case-sensitively" do
144
- stdout_only "Dec 2014 |█"
202
+ stdout_only <<-OUTPUT
203
+ Nov 2014 |∙|
204
+ Dec 2014 |█
205
+ Jan 2015 |∙∙∙∙|
206
+ Feb 2015 |
207
+ Mar 2015 |
208
+ Apr 2015 |
209
+ May 2015 |
210
+ Jun 2015 |
211
+ Jul 2015 |
212
+ Aug 2015 |
213
+ Sep 2015 |
214
+ Oct 2015 |
215
+ Nov 2015 |∙|
216
+ OUTPUT
145
217
  end
146
218
  end
147
219
  end
148
220
 
149
221
  describe "--since" do
150
- subject { run_cmd("graph --since 'January 4th 2015'") }
222
+ subject { run_cmd("graph --since 'January 6th 2015'") }
151
223
 
152
224
  it "graphs activities on and after the specified date" do
153
225
  stdout_only <<-OUTPUT
154
- Jan 2015 |█
226
+ Jan 2015 |███
155
227
  Feb 2015 |
156
228
  Mar 2015 |
157
229
  Apr 2015 |
@@ -166,14 +238,36 @@ Nov 2015 |█
166
238
  end
167
239
  end
168
240
 
169
- describe "--after" do
170
- subject { run_cmd("graph --until 'January 4th 2015'") }
241
+ describe "--until" do
242
+ subject { run_cmd("graph --until 'January 6th 2015'") }
171
243
 
172
244
  it "graphs activities before and on the specified date" do
173
245
  stdout_only <<-OUTPUT
174
246
  Nov 2014 |█
175
247
  Dec 2014 |█
176
- Jan 2015 |█
248
+ Jan 2015 |███
249
+ OUTPUT
250
+ end
251
+ end
252
+
253
+ describe "combining filters" do
254
+ subject { run_cmd("graph --since 'January 6th 2015' --with Grace") }
255
+
256
+ it "only shows other activities within the same period as the filtered ones" do
257
+ # If we just rounded to the month, there would be three unfiltered activities in
258
+ # January displayed (due to the one on 1/5/2015). Instead, we correctly display two.
259
+ stdout_only <<-OUTPUT
260
+ Jan 2015 |█∙∙|
261
+ Feb 2015 |
262
+ Mar 2015 |
263
+ Apr 2015 |
264
+ May 2015 |
265
+ Jun 2015 |
266
+ Jul 2015 |
267
+ Aug 2015 |
268
+ Sep 2015 |
269
+ Oct 2015 |
270
+ Nov 2015 |█
177
271
  OUTPUT
178
272
  end
179
273
  end
@@ -4,6 +4,7 @@ require "./test/helper"
4
4
 
5
5
  clean_describe "help" do
6
6
  subject { run_cmd("help") }
7
+ let(:content) { nil }
7
8
 
8
9
  describe "with no subcommand passed" do
9
10
  it "prints overall help message" do
@@ -6,6 +6,8 @@ clean_describe "list activities" do
6
6
  subject { run_cmd("list activities") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "does not list anything" do
10
12
  stdout_only ""
11
13
  end
@@ -157,7 +159,7 @@ FILE
157
159
  end
158
160
  end
159
161
 
160
- describe "--after" do
162
+ describe "--until" do
161
163
  subject { run_cmd("list activities --until 'January 4th 2015'") }
162
164
 
163
165
  it "lists activities before and on the specified date" do
@@ -6,6 +6,8 @@ clean_describe "list favorite friends" do
6
6
  subject { run_cmd("list favorite friends") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "prints a no-data message" do
10
12
  stdout_only "Your favorite friends:"
11
13
  end
@@ -6,6 +6,8 @@ clean_describe "list favorite locations" do
6
6
  subject { run_cmd("list favorite locations") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "prints a no-data message" do
10
12
  stdout_only "Your favorite locations:"
11
13
  end
@@ -6,6 +6,8 @@ clean_describe "list friends" do
6
6
  subject { run_cmd("list friends") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "does not list anything" do
10
12
  stdout_only ""
11
13
  end
@@ -6,6 +6,8 @@ clean_describe "list locations" do
6
6
  subject { run_cmd("list locations") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "does not list anything" do
10
12
  stdout_only ""
11
13
  end
@@ -6,6 +6,8 @@ clean_describe "list tags" do
6
6
  subject { run_cmd("list tags") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "does not list anything" do
10
12
  stdout_only ""
11
13
  end
@@ -6,6 +6,8 @@ clean_describe "stats" do
6
6
  subject { run_cmd("stats") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "returns the stats" do
10
12
  stdout_only <<-FILE
11
13
  Total activities: 0
@@ -6,6 +6,8 @@ clean_describe "suggest" do
6
6
  subject { run_cmd("suggest") }
7
7
 
8
8
  describe "when file does not exist" do
9
+ let(:content) { nil }
10
+
9
11
  it "prints a no-data message" do
10
12
  stdout_only <<-FILE
11
13
  Distant friend: None found
@@ -4,6 +4,7 @@ require "./test/helper"
4
4
 
5
5
  clean_describe "update" do
6
6
  subject { run_cmd("update") }
7
+ let(:content) { nil }
7
8
 
8
9
  it "prints a status message" do
9
10
  subject[:stderr].must_equal ""
data/test/helper.rb CHANGED
@@ -89,6 +89,7 @@ def ensure_trailing_newline_unless_empty(str)
89
89
  end
90
90
 
91
91
  def stdout_only(expected)
92
+ puts subject[:stderr] unless subject[:stderr] == ""
92
93
  subject[:stdout].must_equal ensure_trailing_newline_unless_empty(expected)
93
94
  subject[:stderr].must_equal ""
94
95
  subject[:status].must_equal 0
@@ -123,7 +124,6 @@ end
123
124
  def clean_describe(desc, *additional_desc, &block)
124
125
  describe desc, *additional_desc do
125
126
  let(:filename) { "test/tmp/friends#{SecureRandom.uuid}.md" }
126
- let(:content) { nil }
127
127
 
128
128
  before { File.write(filename, content) unless content.nil? }
129
129
  after { File.delete(filename) if File.exist?(filename) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friends
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.30'
4
+ version: '0.31'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Evelyn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-30 00:00:00.000000000 Z
11
+ date: 2017-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chronic
@@ -38,48 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.12'
41
- - !ruby/object:Gem::Dependency
42
- name: memoist
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.15'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.15'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: paint
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '1.0'
47
+ version: '2.0'
62
48
  type: :runtime
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '1.0'
54
+ version: '2.0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: semverse
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '1.2'
61
+ version: '2.0'
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '1.2'
68
+ version: '2.0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: bundler
85
71
  requirement: !ruby/object:Gem::Requirement