friends 0.30 → 0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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