friends 0.23 → 0.24
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +47 -47
- data/bin/friends +37 -37
- data/friends.md +5 -5
- data/lib/friends.rb +1 -1
- data/lib/friends/activity.rb +11 -10
- data/lib/friends/friend.rb +16 -16
- data/lib/friends/introvert.rb +42 -31
- data/lib/friends/version.rb +1 -1
- data/test/activity_spec.rb +17 -17
- data/test/friend_spec.rb +12 -12
- data/test/introvert_spec.rb +47 -47
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d3011809caabfa111b478a57a39b562a260ada1
|
4
|
+
data.tar.gz: 8a3d2a2b250ea85c44950a2bffbe3142940d2481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e3df7a84a7b2033a093de24ce0728961857db8cb99b0d34da1d661fc541a7c0df4386452717894dc3c7c515c9b62ad6e8653f3e27277d50b0a194e526afa8e0
|
7
|
+
data.tar.gz: 9c61b1fd7eb6796462f32afaa756b3a11bf2510567d36fedbd40df2fa61043062ec8f01d540d6c47bba04156bdac9bac74b680351779d0f5b814ed53e4bd0791
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v0.24](https://github.com/JacobEvelyn/friends/tree/v0.24) (2016-05-17)
|
4
|
+
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.23...v0.24)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Change \#hashtags to @tags [\#122](https://github.com/JacobEvelyn/friends/issues/122)
|
9
|
+
|
10
|
+
**Fixed bugs:**
|
11
|
+
|
12
|
+
- Uninitialized constant Friends::Activity::Set when graphing by tag [\#133](https://github.com/JacobEvelyn/friends/issues/133)
|
13
|
+
|
14
|
+
**Merged pull requests:**
|
15
|
+
|
16
|
+
- Change tags to `@tag` format, auto-migrate old tags, and fix set loading issue [\#134](https://github.com/JacobEvelyn/friends/pull/134) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
17
|
+
|
3
18
|
## [v0.23](https://github.com/JacobEvelyn/friends/tree/v0.23) (2016-05-16)
|
4
19
|
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.22...v0.23)
|
5
20
|
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ Extrovert-approved.
|
|
17
17
|
- `add`
|
18
18
|
- [`add activity`](#add-activity)
|
19
19
|
- [`add friend`](#add-friend)
|
20
|
-
- [`add
|
20
|
+
- [`add tag`](#add-tag)
|
21
21
|
- [`add location`](#add-location)
|
22
22
|
- [`add nickname`](#add-nickname)
|
23
23
|
- [`clean`](#clean)
|
@@ -29,10 +29,10 @@ Extrovert-approved.
|
|
29
29
|
- [`list favorite friends`](#list-favorite-friends)
|
30
30
|
- [`list favorite locations`](#list-favorite-locations)
|
31
31
|
- [`list friends`](#list-friends)
|
32
|
-
- [`list
|
32
|
+
- [`list tags`](#list-tags)
|
33
33
|
- [`list locations`](#list-locations)
|
34
34
|
- `remove`
|
35
|
-
- [`remove
|
35
|
+
- [`remove tag`](#remove-tag)
|
36
36
|
- [`remove nickname`](#remove-nickname)
|
37
37
|
- `rename`
|
38
38
|
- [`rename friend`](#rename-friend)
|
@@ -88,13 +88,13 @@ Easy, huh?
|
|
88
88
|
|
89
89
|
- **Activities**: The things you do. Each activity has a date associated with
|
90
90
|
it. Activities may optionally contain any number of *friends*, *locations*,
|
91
|
-
and *
|
91
|
+
and *tags*.
|
92
92
|
- **Friends**: The people you do *activities* with. Each friend has a name and,
|
93
93
|
optionally, one or several nicknames. (Examples: `John`, `Grace Hopper`)
|
94
94
|
- **Locations**: The places in which *activities* happen. (Examples: `Paris`,
|
95
95
|
`Marie's Diner`)
|
96
|
-
- **
|
97
|
-
choosing. (Examples:
|
96
|
+
- **Tags**: A way to categorize your *activities* with tags of your
|
97
|
+
choosing. (Examples: `@exercise`, `@school`)
|
98
98
|
|
99
99
|
The `friends.md` Markdown file that stores all of your data contains:
|
100
100
|
|
@@ -209,7 +209,7 @@ You can also use the first initial of a last name instead of the whole thing.
|
|
209
209
|
them) based on whether you're in the middle of a sentence or not:
|
210
210
|
|
211
211
|
```bash
|
212
|
-
$ friends add activity
|
212
|
+
$ friends add activity Got lunch with Earnest H and Earnest S. in the park. Man, I like Earnest H. but really love Earnest S.
|
213
213
|
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."
|
214
214
|
```
|
215
215
|
|
@@ -220,12 +220,12 @@ $ friends add activity Went swimming near atlantis with George.
|
|
220
220
|
Activity added: "2016-01-06: Went swimming near Atlantis with George Washington Carver."
|
221
221
|
```
|
222
222
|
|
223
|
-
|
223
|
+
Tags will be colored if they're provided (though this README can't display
|
224
224
|
color so you'll just have to have faith here):
|
225
225
|
|
226
226
|
```bash
|
227
|
-
$ friends add activity
|
228
|
-
Activity added: "2016-05-05: The office softball team wins a game!
|
227
|
+
$ friends add activity The office softball team wins a game! @work @exercise
|
228
|
+
Activity added: "2016-05-05: The office softball team wins a game! @work @exercise"
|
229
229
|
```
|
230
230
|
|
231
231
|
You can of course specify a date for the activity:
|
@@ -263,11 +263,11 @@ $ friends add friend Grace Hopper
|
|
263
263
|
Friend added: "Grace Hopper"
|
264
264
|
```
|
265
265
|
|
266
|
-
#### `add
|
266
|
+
#### `add tag`
|
267
267
|
|
268
268
|
```bash
|
269
|
-
$ friends add
|
270
|
-
|
269
|
+
$ friends add tag "Grace Hopper" science
|
270
|
+
Tag added to friend: "Grace Hopper @science"
|
271
271
|
```
|
272
272
|
|
273
273
|
#### `add location`
|
@@ -338,7 +338,7 @@ Jan 2015 |█████
|
|
338
338
|
Feb 2015 |███
|
339
339
|
```
|
340
340
|
|
341
|
-
Or graph only activities with a certain
|
341
|
+
Or graph only activities with a certain tag:
|
342
342
|
|
343
343
|
```bash
|
344
344
|
$ friends graph --tagged food
|
@@ -400,8 +400,8 @@ Lists recent activities:
|
|
400
400
|
|
401
401
|
```bash
|
402
402
|
$ friends list activities
|
403
|
-
2015-01-04: Got lunch with Grace Hopper and George Washington Carver.
|
404
|
-
2014-12-31: Celebrated the new year with Marie Curie in New York City.
|
403
|
+
2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
|
404
|
+
2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
|
405
405
|
2014-11-15: Talked to George Washington Carver on the phone for an hour.
|
406
406
|
```
|
407
407
|
|
@@ -409,15 +409,15 @@ You can adjust how many activities are shown:
|
|
409
409
|
|
410
410
|
```bash
|
411
411
|
$ friends list activities --limit 2
|
412
|
-
2015-01-04: Got lunch with Grace Hopper and George Washington Carver.
|
413
|
-
2014-12-31: Celebrated the new year with Marie Curie in New York City.
|
412
|
+
2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
|
413
|
+
2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
|
414
414
|
```
|
415
415
|
|
416
416
|
Or only list the activities you did with a certain friend:
|
417
417
|
|
418
418
|
```bash
|
419
419
|
$ friends list activities --with George
|
420
|
-
2015-01-04: Got lunch with Grace Hopper and George Washington Carver.
|
420
|
+
2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
|
421
421
|
2014-11-15: Talked to George Washington Carver on the phone for an hour.
|
422
422
|
```
|
423
423
|
|
@@ -425,21 +425,21 @@ Or filter your activities by location:
|
|
425
425
|
|
426
426
|
```bash
|
427
427
|
$ friends list activities --in "New York"
|
428
|
-
2014-12-31: Celebrated the new year with Marie Curie in New York City.
|
428
|
+
2014-12-31: Celebrated the new year with Marie Curie in New York City. @partying
|
429
429
|
```
|
430
430
|
|
431
|
-
Or by
|
431
|
+
Or by tag:
|
432
432
|
|
433
433
|
```bash
|
434
434
|
$ friends list activities --tagged food
|
435
|
-
2015-01-04: Got lunch with Grace Hopper and George Washington Carver.
|
435
|
+
2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
|
436
436
|
```
|
437
437
|
|
438
438
|
And you can mix and match these options to your heart's content:
|
439
439
|
|
440
440
|
```bash
|
441
441
|
$ friends list activities --tagged food --with Grace
|
442
|
-
2015-01-04: Got lunch with Grace Hopper and George Washington Carver.
|
442
|
+
2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
|
443
443
|
```
|
444
444
|
|
445
445
|
#### `list favorite friends`
|
@@ -495,13 +495,13 @@ Grace Hopper
|
|
495
495
|
Marie Curie
|
496
496
|
```
|
497
497
|
|
498
|
-
You can also include friend nicknames, locations, and
|
498
|
+
You can also include friend nicknames, locations, and tags:
|
499
499
|
|
500
500
|
```bash
|
501
501
|
$ friends list friends --verbose
|
502
502
|
George Washington Carver
|
503
|
-
Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris]
|
504
|
-
Marie Curie [Atlantis]
|
503
|
+
Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
|
504
|
+
Marie Curie [Atlantis] @science
|
505
505
|
```
|
506
506
|
|
507
507
|
You can filter your friends by location:
|
@@ -511,7 +511,7 @@ $ friends list friends --in Paris
|
|
511
511
|
Marie Curie
|
512
512
|
```
|
513
513
|
|
514
|
-
And you can also filter your friends by
|
514
|
+
And you can also filter your friends by tag:
|
515
515
|
|
516
516
|
```bash
|
517
517
|
$ friends list friends --tagged science
|
@@ -519,33 +519,33 @@ Grace Hopper
|
|
519
519
|
Marie Curie
|
520
520
|
```
|
521
521
|
|
522
|
-
#### `list
|
522
|
+
#### `list tags`
|
523
523
|
|
524
|
-
Lists all
|
524
|
+
Lists all tags you've used, in alphabetical order:
|
525
525
|
|
526
526
|
```bash
|
527
|
-
$ friends list
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
527
|
+
$ friends list tags
|
528
|
+
@dancing
|
529
|
+
@food
|
530
|
+
@school
|
531
|
+
@swanky
|
532
532
|
```
|
533
533
|
|
534
|
-
You can limit this to only
|
534
|
+
You can limit this to only tags from activities:
|
535
535
|
|
536
536
|
```bash
|
537
|
-
$ friends list
|
538
|
-
|
539
|
-
|
540
|
-
|
537
|
+
$ friends list tags --from activities
|
538
|
+
@dancing
|
539
|
+
@food
|
540
|
+
@swanky
|
541
541
|
```
|
542
542
|
|
543
|
-
Or only
|
543
|
+
Or only tags from friends:
|
544
544
|
|
545
545
|
```bash
|
546
|
-
$ friends list
|
547
|
-
|
548
|
-
|
546
|
+
$ friends list tags --from friends
|
547
|
+
@school
|
548
|
+
@swanky
|
549
549
|
```
|
550
550
|
|
551
551
|
#### `list locations`
|
@@ -559,13 +559,13 @@ New York City
|
|
559
559
|
Paris
|
560
560
|
```
|
561
561
|
|
562
|
-
#### `remove
|
562
|
+
#### `remove tag`
|
563
563
|
|
564
|
-
Removes a specific
|
564
|
+
Removes a specific tag from a friend:
|
565
565
|
|
566
566
|
```bash
|
567
|
-
$ friends remove
|
568
|
-
|
567
|
+
$ friends remove tag "Grace Hopper" fun
|
568
|
+
Tag removed from friend: "Grace Hopper (a.k.a. Amazing Grace) @OtherTag"
|
569
569
|
```
|
570
570
|
|
571
571
|
#### `remove nickname`
|
data/bin/friends
CHANGED
@@ -19,21 +19,21 @@ version Friends::VERSION
|
|
19
19
|
subcommand_option_handling :normal
|
20
20
|
arguments :strict
|
21
21
|
|
22
|
-
class
|
23
|
-
# @param str [String] of the form "
|
24
|
-
# @return [String] the string, with whitespace stripped and a
|
22
|
+
class Tag
|
23
|
+
# @param str [String] of the form "tag" or "@tag"
|
24
|
+
# @return [String] the string, with whitespace stripped and a tag
|
25
25
|
# prepended if there isn't one already
|
26
26
|
# NOTE: This logic could be only in the accept block if GLI allowed type
|
27
27
|
# conversions for arguments.
|
28
28
|
# See: https://github.com/davetron5000/gli/issues/241
|
29
|
-
def self.
|
29
|
+
def self.convert_to_tag(str)
|
30
30
|
str = str.strip
|
31
|
-
!str.empty? && str[0] == "
|
31
|
+
!str.empty? && str[0] == "@" ? str : "@#{str}"
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
accept(
|
36
|
-
|
35
|
+
accept(Tag) do |value|
|
36
|
+
Tag.convert_to_tag(value)
|
37
37
|
end
|
38
38
|
|
39
39
|
class Stripped; end
|
@@ -97,13 +97,13 @@ command :list do |list|
|
|
97
97
|
type: Stripped
|
98
98
|
|
99
99
|
list_friends.flag [:tagged],
|
100
|
-
arg_name: "
|
101
|
-
desc: "List only friends with the given
|
102
|
-
type:
|
100
|
+
arg_name: "@TAG",
|
101
|
+
desc: "List only friends with the given tag",
|
102
|
+
type: Tag
|
103
103
|
|
104
104
|
list_friends.switch [:verbose],
|
105
105
|
negatable: false,
|
106
|
-
desc: "Output friend nicknames, locations, and
|
106
|
+
desc: "Output friend nicknames, locations, and tags"
|
107
107
|
|
108
108
|
list_friends.action do |_, options|
|
109
109
|
puts @introvert.list_friends(
|
@@ -133,9 +133,9 @@ command :list do |list|
|
|
133
133
|
type: Stripped
|
134
134
|
|
135
135
|
list_activities.flag [:tagged],
|
136
|
-
arg_name: "
|
137
|
-
desc: "List only activities with the given
|
138
|
-
type:
|
136
|
+
arg_name: "@TAG",
|
137
|
+
desc: "List only activities with the given tag",
|
138
|
+
type: Tag
|
139
139
|
|
140
140
|
list_activities.action do |_, options|
|
141
141
|
puts @introvert.list_activities(
|
@@ -154,14 +154,14 @@ command :list do |list|
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
list.desc "List all
|
158
|
-
list.command :
|
159
|
-
|
157
|
+
list.desc "List all tags used"
|
158
|
+
list.command :tags do |list_tags|
|
159
|
+
list_tags.flag [:from],
|
160
160
|
arg_name: '"activities" or "friends" (default: both)',
|
161
|
-
desc: "List only
|
161
|
+
desc: "List only tags from activities or friends "\
|
162
162
|
"instead of both"
|
163
|
-
|
164
|
-
puts @introvert.
|
163
|
+
list_tags.action do |_, options|
|
164
|
+
puts @introvert.list_tags(from: options[:from])
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -266,15 +266,15 @@ command :add do |add|
|
|
266
266
|
end
|
267
267
|
end
|
268
268
|
|
269
|
-
add.desc "Adds a
|
270
|
-
add.arg_name "NAME
|
271
|
-
add.command :
|
272
|
-
|
273
|
-
friend = @introvert.
|
269
|
+
add.desc "Adds a tag to a friend"
|
270
|
+
add.arg_name "NAME @TAG"
|
271
|
+
add.command :tag do |add_tag|
|
272
|
+
add_tag.action do |_, _, args|
|
273
|
+
friend = @introvert.add_tag(
|
274
274
|
name: args.first,
|
275
|
-
|
275
|
+
tag: Tag.convert_to_tag(args[1])
|
276
276
|
)
|
277
|
-
@message = "
|
277
|
+
@message = "Tag added to friend: \"#{friend}\""
|
278
278
|
@dirty = true # Mark the file for cleaning.
|
279
279
|
end
|
280
280
|
end
|
@@ -305,15 +305,15 @@ command :remove do |remove|
|
|
305
305
|
end
|
306
306
|
end
|
307
307
|
|
308
|
-
remove.desc "Removes a
|
309
|
-
remove.arg_name "NAME
|
310
|
-
remove.command :
|
311
|
-
|
312
|
-
friend = @introvert.
|
308
|
+
remove.desc "Removes a tag from a friend"
|
309
|
+
remove.arg_name "NAME @TAG"
|
310
|
+
remove.command :tag do |remove_tag|
|
311
|
+
remove_tag.action do |_, _, args|
|
312
|
+
friend = @introvert.remove_tag(
|
313
313
|
name: args.first,
|
314
|
-
|
314
|
+
tag: Tag.convert_to_tag(args[1])
|
315
315
|
)
|
316
|
-
@message = "
|
316
|
+
@message = "Tag removed from friend: \"#{friend}\""
|
317
317
|
@dirty = true # Mark the file for cleaning.
|
318
318
|
end
|
319
319
|
end
|
@@ -332,9 +332,9 @@ command :graph do |graph|
|
|
332
332
|
type: Stripped
|
333
333
|
|
334
334
|
graph.flag [:tagged],
|
335
|
-
arg_name: "
|
336
|
-
desc: "Graph activities with the given
|
337
|
-
type:
|
335
|
+
arg_name: "@TAG",
|
336
|
+
desc: "Graph activities with the given tag",
|
337
|
+
type: Tag
|
338
338
|
|
339
339
|
graph.action do |_, options|
|
340
340
|
# This math is taken from Minitest's Pride plugin (the PrideLOL class).
|
data/friends.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
### Activities:
|
2
|
-
- 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute.
|
3
|
-
- 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**.
|
4
|
-
- 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**.
|
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
5
|
- 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
|
6
6
|
|
7
7
|
### Friends:
|
8
8
|
- George Washington Carver
|
9
|
-
- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris]
|
10
|
-
- Marie Curie [Atlantis]
|
9
|
+
- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
|
10
|
+
- Marie Curie [Atlantis] @science
|
11
11
|
|
12
12
|
### Locations:
|
13
13
|
- Atlantis
|
data/lib/friends.rb
CHANGED
data/lib/friends/activity.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
require "chronic"
|
6
6
|
require "memoist"
|
7
7
|
require "paint"
|
8
|
+
require "set"
|
8
9
|
|
9
10
|
require "friends/serializable"
|
10
11
|
|
@@ -71,7 +72,7 @@ module Friends
|
|
71
72
|
end
|
72
73
|
|
73
74
|
description_s = description_s.
|
74
|
-
gsub(
|
75
|
+
gsub(TAG_REGEX, Paint['\0', :bold, :cyan])
|
75
76
|
|
76
77
|
"#{date_s}: #{description_s}"
|
77
78
|
end
|
@@ -118,25 +119,25 @@ module Friends
|
|
118
119
|
|
119
120
|
# @param location [Location] the location to test
|
120
121
|
# @return [Boolean] true iff this activity includes the given location
|
121
|
-
def includes_location?(location
|
122
|
+
def includes_location?(location)
|
122
123
|
@description.scan(/(?<=_)[^_]+(?=_)/).include? location.name
|
123
124
|
end
|
124
125
|
|
125
126
|
# @param friend [Friend] the friend to test
|
126
127
|
# @return [Boolean] true iff this activity includes the given friend
|
127
|
-
def includes_friend?(friend
|
128
|
+
def includes_friend?(friend)
|
128
129
|
friend_names.include? friend.name
|
129
130
|
end
|
130
131
|
|
131
|
-
# @param
|
132
|
-
# @return [Boolean] true iff this activity includes the given
|
133
|
-
def
|
134
|
-
|
132
|
+
# @param tag [String] the tag to test, of the form "@tag"
|
133
|
+
# @return [Boolean] true iff this activity includes the given tag
|
134
|
+
def includes_tag?(tag)
|
135
|
+
tags.include? tag
|
135
136
|
end
|
136
137
|
|
137
|
-
# @return [Set] all
|
138
|
-
def
|
139
|
-
Set.new(@description.scan(
|
138
|
+
# @return [Set] all tags in this activity (including the "@")
|
139
|
+
def tags
|
140
|
+
Set.new(@description.scan(TAG_REGEX))
|
140
141
|
end
|
141
142
|
|
142
143
|
# Find the names of all friends in this description.
|
data/lib/friends/friend.rb
CHANGED
@@ -17,7 +17,7 @@ module Friends
|
|
17
17
|
def self.deserialization_regex
|
18
18
|
# Note: this regex must be on one line because whitespace is important
|
19
19
|
# rubocop:disable Metrics/LineLength
|
20
|
-
/(#{SERIALIZATION_PREFIX})?(?<name>[^\(\[#]*[^\(\[#\s])(\s+\(#{NICKNAME_PREFIX}(?<nickname_str>.+)\))?(\s+\[(?<location_name>[^\]]+)\])?(\s+(?<
|
20
|
+
/(#{SERIALIZATION_PREFIX})?(?<name>[^\(\[#]*[^\(\[#\s])(\s+\(#{NICKNAME_PREFIX}(?<nickname_str>.+)\))?(\s+\[(?<location_name>[^\]]+)\])?(\s+(?<tags_str>(#{TAG_REGEX}\s*)+))?/
|
21
21
|
# rubocop:enable Metrics/LineLength
|
22
22
|
end
|
23
23
|
|
@@ -31,19 +31,19 @@ module Friends
|
|
31
31
|
name:,
|
32
32
|
nickname_str: nil,
|
33
33
|
location_name: nil,
|
34
|
-
|
34
|
+
tags_str: nil
|
35
35
|
)
|
36
36
|
@name = name
|
37
37
|
@nicknames = nickname_str &&
|
38
38
|
nickname_str.split(" #{NICKNAME_PREFIX}") ||
|
39
39
|
[]
|
40
40
|
@location_name = location_name
|
41
|
-
@
|
41
|
+
@tags = tags_str && tags_str.split(/\s+/) || []
|
42
42
|
end
|
43
43
|
|
44
44
|
attr_accessor :name
|
45
45
|
attr_accessor :location_name
|
46
|
-
attr_reader :
|
46
|
+
attr_reader :tags
|
47
47
|
|
48
48
|
# @return [String] the file serialization text for the friend
|
49
49
|
def serialize
|
@@ -61,25 +61,25 @@ module Friends
|
|
61
61
|
|
62
62
|
location_str = " [#{@location_name}]" unless @location_name.nil?
|
63
63
|
|
64
|
-
|
64
|
+
tag_str = " #{@tags.join(' ')}" unless @tags.empty?
|
65
65
|
|
66
|
-
"#{@name}#{nickname_str}#{location_str}#{
|
66
|
+
"#{@name}#{nickname_str}#{location_str}#{tag_str}"
|
67
67
|
end
|
68
68
|
|
69
|
-
# Adds a
|
70
|
-
# @param
|
71
|
-
def
|
72
|
-
@
|
73
|
-
@
|
69
|
+
# Adds a tag, ignoring duplicates.
|
70
|
+
# @param tag [String] the tag to add, of the format: "@tag"
|
71
|
+
def add_tag(tag)
|
72
|
+
@tags << tag
|
73
|
+
@tags.uniq!
|
74
74
|
end
|
75
75
|
|
76
|
-
# @param
|
77
|
-
def
|
78
|
-
unless @
|
79
|
-
raise FriendsError, "
|
76
|
+
# @param tag [String] the tag to remove, of the format: "@tag"
|
77
|
+
def remove_tag(tag)
|
78
|
+
unless @tags.include? tag
|
79
|
+
raise FriendsError, "Tag \"#{tag}\" not found for \"#{name}\""
|
80
80
|
end
|
81
81
|
|
82
|
-
@
|
82
|
+
@tags.delete(tag)
|
83
83
|
end
|
84
84
|
|
85
85
|
# Adds a nickname, ignoring duplicates.
|
data/lib/friends/introvert.rb
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
# able to be used directly within another Ruby program, without needing to call
|
5
5
|
# the command-line script explicitly.
|
6
6
|
|
7
|
+
require "set"
|
8
|
+
|
7
9
|
require "friends/activity"
|
8
10
|
require "friends/friend"
|
9
11
|
require "friends/graph"
|
@@ -158,26 +160,26 @@ module Friends
|
|
158
160
|
friend
|
159
161
|
end
|
160
162
|
|
161
|
-
# Add a
|
163
|
+
# Add a tag to an existing friend.
|
162
164
|
# @param name [String] the name of the friend
|
163
|
-
# @param
|
165
|
+
# @param tag [String] the tag to add to the friend, of the form: "@tag"
|
164
166
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
165
167
|
# @return [Friend] the existing friend
|
166
|
-
def
|
168
|
+
def add_tag(name:, tag:)
|
167
169
|
friend = friend_with_name_in(name)
|
168
|
-
friend.
|
170
|
+
friend.add_tag(tag)
|
169
171
|
friend
|
170
172
|
end
|
171
173
|
|
172
|
-
# Remove a
|
174
|
+
# Remove a tag from an existing friend.
|
173
175
|
# @param name [String] the name of the friend
|
174
|
-
# @param
|
176
|
+
# @param tag [String] the tag to remove from the friend, of the form: "@tag"
|
175
177
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
176
178
|
# @raise [FriendsError] if the friend does not have the given nickname
|
177
179
|
# @return [Friend] the existing friend
|
178
|
-
def
|
180
|
+
def remove_tag(name:, tag:)
|
179
181
|
friend = friend_with_name_in(name)
|
180
|
-
friend.
|
182
|
+
friend.remove_tag(tag)
|
181
183
|
friend
|
182
184
|
end
|
183
185
|
|
@@ -196,10 +198,10 @@ module Friends
|
|
196
198
|
# List all friend names in the friends file.
|
197
199
|
# @param location_name [String] the name of a location to filter by, or nil
|
198
200
|
# for unfiltered
|
199
|
-
# @param tagged [String] the name of a
|
200
|
-
# unfiltered
|
201
|
+
# @param tagged [String] the name of a tag to filter by (of the form:
|
202
|
+
# "@tag"), or nil for unfiltered
|
201
203
|
# @param verbose [Boolean] true iff we should output friend names with
|
202
|
-
# nicknames, locations, and
|
204
|
+
# nicknames, locations, and tags; false for names only
|
203
205
|
# @return [Array] a list of all friend names
|
204
206
|
def list_friends(location_name:, tagged:, verbose:)
|
205
207
|
fs = @friends
|
@@ -210,8 +212,8 @@ module Friends
|
|
210
212
|
fs = fs.select { |friend| friend.location_name == location.name }
|
211
213
|
end
|
212
214
|
|
213
|
-
# Filter by
|
214
|
-
fs = fs.select { |friend| friend.
|
215
|
+
# Filter by tag if one is passed.
|
216
|
+
fs = fs.select { |friend| friend.tags.include? tagged } if tagged
|
215
217
|
|
216
218
|
verbose ? fs.map(&:to_s) : fs.map(&:name)
|
217
219
|
end
|
@@ -239,10 +241,10 @@ module Friends
|
|
239
241
|
# unfiltered
|
240
242
|
# @param location_name [String] the name of a location to filter by, or nil
|
241
243
|
# for unfiltered
|
242
|
-
# @param tagged [String] the name of a
|
243
|
-
# unfiltered
|
244
|
+
# @param tagged [String] the name of a tag to filter by (of the form:
|
245
|
+
# "@tag"), or nil for unfiltered
|
244
246
|
# @return [Array] a list of all activity text values
|
245
|
-
# @raise [FriendsError] if friend, location or
|
247
|
+
# @raise [FriendsError] if friend, location or tag cannot be found or
|
246
248
|
# is ambiguous
|
247
249
|
def list_activities(limit:, with:, location_name:, tagged:)
|
248
250
|
acts = filtered_activities(
|
@@ -264,21 +266,21 @@ module Friends
|
|
264
266
|
end
|
265
267
|
|
266
268
|
# @param from [String] one of: ["activities", "friends", nil]
|
267
|
-
# If not nil, limits the
|
269
|
+
# If not nil, limits the tags returned to only those from either
|
268
270
|
# activities or friends.
|
269
|
-
# @return [Array] a sorted list of all
|
270
|
-
def
|
271
|
+
# @return [Array] a sorted list of all tags in activity descriptions
|
272
|
+
def list_tags(from:)
|
271
273
|
output = Set.new
|
272
274
|
|
273
275
|
unless from == "friends" # If from is "activities" or nil.
|
274
276
|
@activities.each_with_object(output) do |activity, set|
|
275
|
-
set.merge(activity.
|
277
|
+
set.merge(activity.tags)
|
276
278
|
end
|
277
279
|
end
|
278
280
|
|
279
281
|
unless from == "activities" # If from is "friends" or nil.
|
280
282
|
@friends.each_with_object(output) do |friend, set|
|
281
|
-
set.merge(friend.
|
283
|
+
set.merge(friend.tags)
|
282
284
|
end
|
283
285
|
end
|
284
286
|
|
@@ -286,7 +288,7 @@ module Friends
|
|
286
288
|
end
|
287
289
|
|
288
290
|
# Find data points for graphing activities over time.
|
289
|
-
# Optionally filter by friend, location and
|
291
|
+
# Optionally filter by friend, location and tag
|
290
292
|
#
|
291
293
|
# The returned hash uses the following format:
|
292
294
|
# {
|
@@ -301,10 +303,10 @@ module Friends
|
|
301
303
|
# unfiltered
|
302
304
|
# @param location_name [String] the name of a location to filter by, or nil
|
303
305
|
# for unfiltered
|
304
|
-
# @param tagged [String] the name of a
|
305
|
-
# unfiltered
|
306
|
+
# @param tagged [String] the name of a tag to filter by (of the form:
|
307
|
+
# "@tag"), or nil for unfiltered
|
306
308
|
# @return [Hash{String => Integer}]
|
307
|
-
# @raise [FriendsError] if friend, location or
|
309
|
+
# @raise [FriendsError] if friend, location or tag cannot be found or
|
308
310
|
# is ambiguous
|
309
311
|
def graph(with:, location_name:, tagged:)
|
310
312
|
# There is no point trying to graph no activities
|
@@ -463,15 +465,15 @@ module Friends
|
|
463
465
|
|
464
466
|
private
|
465
467
|
|
466
|
-
# Filter activities by friend, location and
|
468
|
+
# Filter activities by friend, location and tag
|
467
469
|
# @param with [String] the name of a friend to filter by, or nil for
|
468
470
|
# unfiltered
|
469
471
|
# @param location_name [String] the name of a location to filter by, or nil
|
470
472
|
# for unfiltered
|
471
|
-
# @param tagged [String] the name of a
|
473
|
+
# @param tagged [String] the name of a tag to filter by, or nil for
|
472
474
|
# unfiltered
|
473
475
|
# @return [Array] an array of activities
|
474
|
-
# @raise [FriendsError] if friend, location or
|
476
|
+
# @raise [FriendsError] if friend, location or tag cannot be found or
|
475
477
|
# is ambiguous
|
476
478
|
def filtered_activities(with:, location_name:, tagged:)
|
477
479
|
acts = @activities
|
@@ -479,18 +481,18 @@ module Friends
|
|
479
481
|
# Filter by friend name if argument is passed.
|
480
482
|
unless with.nil?
|
481
483
|
friend = friend_with_name_in(with)
|
482
|
-
acts = acts.select { |act| act.includes_friend?(friend
|
484
|
+
acts = acts.select { |act| act.includes_friend?(friend) }
|
483
485
|
end
|
484
486
|
|
485
487
|
# Filter by location name if argument is passed.
|
486
488
|
unless location_name.nil?
|
487
489
|
location = location_with_name_in(location_name)
|
488
|
-
acts = acts.select { |act| act.includes_location?(location
|
490
|
+
acts = acts.select { |act| act.includes_location?(location) }
|
489
491
|
end
|
490
492
|
|
491
493
|
# Filter by tag if argument is passed.
|
492
494
|
unless tagged.nil?
|
493
|
-
acts = acts.select { |act| act.
|
495
|
+
acts = acts.select { |act| act.includes_tag?(tagged) }
|
494
496
|
end
|
495
497
|
|
496
498
|
acts
|
@@ -567,6 +569,15 @@ module Friends
|
|
567
569
|
# Parse the line and update the parsing state.
|
568
570
|
state = parse_line!(line, line_num: line_num, state: state)
|
569
571
|
end
|
572
|
+
|
573
|
+
# Migrate old tag format (#tag) into new tag format (@tag). This code will
|
574
|
+
# be removed in the 1.0 release.
|
575
|
+
unless @friends.any? { |f| f.tags.any? } ||
|
576
|
+
@activities.any? { |a| a.tags.any? }
|
577
|
+
contents = File.read(@filename)
|
578
|
+
File.write(@filename, contents.gsub(/#(\p{Alnum}+)/, "@\\1"))
|
579
|
+
read_file
|
580
|
+
end
|
570
581
|
end
|
571
582
|
|
572
583
|
# Parse the given line, adding to the various internal data structures as
|
data/lib/friends/version.rb
CHANGED
data/test/activity_spec.rb
CHANGED
@@ -430,7 +430,7 @@ describe Friends::Activity do
|
|
430
430
|
end
|
431
431
|
|
432
432
|
describe "#includes_location?" do
|
433
|
-
subject { activity.includes_location?(
|
433
|
+
subject { activity.includes_location?(loc) }
|
434
434
|
let(:loc) { Friends::Location.new(name: "Atlantis") }
|
435
435
|
|
436
436
|
describe "when the given location is in the activity" do
|
@@ -445,7 +445,7 @@ describe Friends::Activity do
|
|
445
445
|
end
|
446
446
|
|
447
447
|
describe "#includes_friend?" do
|
448
|
-
subject { activity.includes_friend?(friend
|
448
|
+
subject { activity.includes_friend?(friend) }
|
449
449
|
|
450
450
|
describe "when the given friend is in the activity" do
|
451
451
|
let(:friend) { friend1 }
|
@@ -458,36 +458,36 @@ describe Friends::Activity do
|
|
458
458
|
end
|
459
459
|
end
|
460
460
|
|
461
|
-
describe "#
|
462
|
-
subject { activity.
|
461
|
+
describe "#tags" do
|
462
|
+
subject { activity.tags }
|
463
463
|
|
464
|
-
describe "when the activity has no
|
464
|
+
describe "when the activity has no tags" do
|
465
465
|
let(:activity) { Friends::Activity.new(str: "Enormous ball pit!") }
|
466
466
|
it { subject.must_be :empty? }
|
467
467
|
end
|
468
468
|
|
469
|
-
describe "when the activity has
|
470
|
-
let(:activity) { Friends::Activity.new(str: "Party!
|
471
|
-
it { subject.must_equal Set.new(["
|
469
|
+
describe "when the activity has tags" do
|
470
|
+
let(:activity) { Friends::Activity.new(str: "Party! @fun @crazy @fun") }
|
471
|
+
it { subject.must_equal Set.new(["@fun", "@crazy"]) }
|
472
472
|
end
|
473
473
|
end
|
474
474
|
|
475
|
-
describe "#
|
476
|
-
subject { activity.
|
477
|
-
let(:activity) { Friends::Activity.new(str: "Enormous ball pit!
|
475
|
+
describe "#includes_tag?" do
|
476
|
+
subject { activity.includes_tag?(tag) }
|
477
|
+
let(:activity) { Friends::Activity.new(str: "Enormous ball pit! @fun") }
|
478
478
|
|
479
|
-
describe "when the given
|
480
|
-
let(:
|
479
|
+
describe "when the given tag is not in the activity" do
|
480
|
+
let(:tag) { "@garbage" }
|
481
481
|
it { subject.must_equal false }
|
482
482
|
end
|
483
483
|
|
484
|
-
describe "when the given word is in the activity but not as a
|
485
|
-
let(:
|
484
|
+
describe "when the given word is in the activity but not as a tag" do
|
485
|
+
let(:tag) { "@ball" }
|
486
486
|
it { subject.must_equal false }
|
487
487
|
end
|
488
488
|
|
489
|
-
describe "when the given
|
490
|
-
let(:
|
489
|
+
describe "when the given tag is in the activity" do
|
490
|
+
let(:tag) { "@fun" }
|
491
491
|
it { subject.must_equal true }
|
492
492
|
end
|
493
493
|
end
|
data/test/friend_spec.rb
CHANGED
@@ -81,35 +81,35 @@ describe Friends::Friend do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
describe "#
|
85
|
-
subject { friend.
|
84
|
+
describe "#add_tag" do
|
85
|
+
subject { friend.add_tag("@college") }
|
86
86
|
|
87
87
|
it "adds the nickname" do
|
88
88
|
subject
|
89
|
-
friend.
|
89
|
+
friend.tags.must_include("@college")
|
90
90
|
end
|
91
91
|
|
92
92
|
it "does not keep duplicates" do
|
93
93
|
# Add the same nickname twice. Do not use `subject` because it's memoized.
|
94
|
-
friend.
|
95
|
-
friend.
|
94
|
+
friend.add_tag("@college")
|
95
|
+
friend.add_tag("@college")
|
96
96
|
|
97
|
-
friend.
|
97
|
+
friend.tags.must_equal ["@college"]
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
describe "
|
102
|
-
subject { friend.
|
101
|
+
describe "@remove_tag" do
|
102
|
+
subject { friend.remove_tag("@school") }
|
103
103
|
|
104
|
-
describe "when the
|
104
|
+
describe "when the tag is present" do
|
105
105
|
let(:friend) do
|
106
|
-
Friends::Friend.new(name: friend_name,
|
106
|
+
Friends::Friend.new(name: friend_name, tags_str: "@school @work")
|
107
107
|
end
|
108
108
|
|
109
109
|
it "removes the nickname" do
|
110
|
-
friend.instance_variable_get(:@
|
110
|
+
friend.instance_variable_get(:@tags).must_equal ["@school", "@work"]
|
111
111
|
subject
|
112
|
-
friend.instance_variable_get(:@
|
112
|
+
friend.instance_variable_get(:@tags).must_equal ["@work"]
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
data/test/introvert_spec.rb
CHANGED
@@ -38,7 +38,7 @@ describe Friends::Introvert do
|
|
38
38
|
let(:friend_names) { ["George Washington Carver", "Betsy Ross"] }
|
39
39
|
let(:friends) do
|
40
40
|
friend_names.map do |name|
|
41
|
-
Friends::Friend.new(name: name,
|
41
|
+
Friends::Friend.new(name: name, tags_str: "@test")
|
42
42
|
end
|
43
43
|
end
|
44
44
|
let(:activities) do
|
@@ -146,15 +146,15 @@ describe Friends::Introvert do
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
-
describe "when a
|
149
|
+
describe "when a tag has been passed" do
|
150
150
|
let(:location_name) { nil }
|
151
|
-
let(:tagged) { "
|
151
|
+
let(:tagged) { "@superhero" }
|
152
152
|
let(:verbose) { false }
|
153
153
|
let(:friends) do
|
154
154
|
[
|
155
155
|
Friends::Friend.new(name: "Mark Watney"),
|
156
|
-
Friends::Friend.new(name: "Aquaman",
|
157
|
-
Friends::Friend.new(name: "Shark-Boy",
|
156
|
+
Friends::Friend.new(name: "Aquaman", tags_str: "@superhero"),
|
157
|
+
Friends::Friend.new(name: "Shark-Boy", tags_str: "@superhero"),
|
158
158
|
Friends::Friend.new(name: "Ms. Nowhere")
|
159
159
|
]
|
160
160
|
end
|
@@ -268,35 +268,35 @@ describe Friends::Introvert do
|
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
271
|
-
describe "#
|
272
|
-
subject { introvert.
|
271
|
+
describe "#list_tags" do
|
272
|
+
subject { introvert.list_tags(from: from) }
|
273
273
|
|
274
274
|
let(:activities) do
|
275
275
|
[
|
276
|
-
Friends::Activity.new(str: "Lunch in the park.
|
277
|
-
Friends::Activity.new(str: "Fancy dinner.
|
276
|
+
Friends::Activity.new(str: "Lunch in the park. @picnic @food"),
|
277
|
+
Friends::Activity.new(str: "Fancy dinner. @food @swanky")
|
278
278
|
]
|
279
279
|
end
|
280
280
|
|
281
281
|
let(:friends) do
|
282
282
|
[
|
283
|
-
Friends::Friend.new(name: "Grace Hopper",
|
284
|
-
Friends::Friend.new(name: "James Bond",
|
283
|
+
Friends::Friend.new(name: "Grace Hopper", tags_str: "@coder @navy"),
|
284
|
+
Friends::Friend.new(name: "James Bond", tags_str: "@cool @swanky")
|
285
285
|
]
|
286
286
|
end
|
287
287
|
|
288
288
|
describe "when from flag is nil" do
|
289
289
|
let(:from) { nil }
|
290
|
-
it "lists all
|
290
|
+
it "lists all tags in sorted order" do
|
291
291
|
stub_activities(activities) do
|
292
292
|
stub_friends(friends) do
|
293
293
|
subject.must_equal [
|
294
|
-
"
|
295
|
-
"
|
296
|
-
"
|
297
|
-
"
|
298
|
-
"
|
299
|
-
"
|
294
|
+
"@coder",
|
295
|
+
"@cool",
|
296
|
+
"@food",
|
297
|
+
"@navy",
|
298
|
+
"@picnic",
|
299
|
+
"@swanky"
|
300
300
|
]
|
301
301
|
end
|
302
302
|
end
|
@@ -305,10 +305,10 @@ describe Friends::Introvert do
|
|
305
305
|
|
306
306
|
describe 'when from flag is "activities"' do
|
307
307
|
let(:from) { "activities" }
|
308
|
-
it "lists all activity
|
308
|
+
it "lists all activity tags in sorted order" do
|
309
309
|
stub_activities(activities) do
|
310
310
|
stub_friends(friends) do
|
311
|
-
subject.must_equal ["
|
311
|
+
subject.must_equal ["@food", "@picnic", "@swanky"]
|
312
312
|
end
|
313
313
|
end
|
314
314
|
end
|
@@ -316,10 +316,10 @@ describe Friends::Introvert do
|
|
316
316
|
|
317
317
|
describe 'when from flag is "friends"' do
|
318
318
|
let(:from) { "friends" }
|
319
|
-
it "lists all friend
|
319
|
+
it "lists all friend tags in sorted order" do
|
320
320
|
stub_activities(activities) do
|
321
321
|
stub_friends(friends) do
|
322
|
-
subject.must_equal ["
|
322
|
+
subject.must_equal ["@coder", "@cool", "@navy", "@swanky"]
|
323
323
|
end
|
324
324
|
end
|
325
325
|
end
|
@@ -497,7 +497,7 @@ describe Friends::Introvert do
|
|
497
497
|
end
|
498
498
|
end
|
499
499
|
|
500
|
-
describe "when not filtering by a
|
500
|
+
describe "when not filtering by a tag" do
|
501
501
|
let(:tagged) { nil }
|
502
502
|
|
503
503
|
it "lists the activities" do
|
@@ -507,17 +507,17 @@ describe Friends::Introvert do
|
|
507
507
|
end
|
508
508
|
end
|
509
509
|
|
510
|
-
describe "when filtering by a
|
510
|
+
describe "when filtering by a tag" do
|
511
511
|
let(:activities) do
|
512
512
|
[
|
513
|
-
Friends::Activity.new(str: "Tennis after work.
|
514
|
-
Friends::Activity.new(str: "Wimbledon!
|
515
|
-
Friends::Activity.new(str: "Drinks after work.
|
513
|
+
Friends::Activity.new(str: "Tennis after work. @exercise @tennis"),
|
514
|
+
Friends::Activity.new(str: "Wimbledon! @tennis"),
|
515
|
+
Friends::Activity.new(str: "Drinks after work. @beer")
|
516
516
|
]
|
517
517
|
end
|
518
518
|
|
519
|
-
describe "when the
|
520
|
-
let(:tagged) { "
|
519
|
+
describe "when the tag ('@tag') is not used at all" do
|
520
|
+
let(:tagged) { "@garbage" }
|
521
521
|
it "returns no results" do
|
522
522
|
stub_activities(activities) do
|
523
523
|
subject.must_equal []
|
@@ -525,18 +525,18 @@ describe Friends::Introvert do
|
|
525
525
|
end
|
526
526
|
end
|
527
527
|
|
528
|
-
describe "when the
|
529
|
-
let(:tagged) { "
|
530
|
-
it "returns the activity with that
|
528
|
+
describe "when the tag ('@tag') is used once" do
|
529
|
+
let(:tagged) { "@beer" }
|
530
|
+
it "returns the activity with that tag" do
|
531
531
|
stub_activities(activities) do
|
532
532
|
subject.must_equal [activities.last.to_s]
|
533
533
|
end
|
534
534
|
end
|
535
535
|
end
|
536
536
|
|
537
|
-
describe "when the
|
538
|
-
let(:tagged) { "
|
539
|
-
it "returns the activities with that
|
537
|
+
describe "when the tag ('@tag') is used multiple times" do
|
538
|
+
let(:tagged) { "@tennis" }
|
539
|
+
it "returns the activities with that tag" do
|
540
540
|
stub_activities(activities) do
|
541
541
|
subject.must_equal activities[0..1].map(&:to_s)
|
542
542
|
end
|
@@ -685,9 +685,9 @@ describe Friends::Introvert do
|
|
685
685
|
end
|
686
686
|
end
|
687
687
|
|
688
|
-
describe "#
|
688
|
+
describe "#add_tag" do
|
689
689
|
subject do
|
690
|
-
introvert.
|
690
|
+
introvert.add_tag(name: friend_names.first, tag: "@school")
|
691
691
|
end
|
692
692
|
|
693
693
|
it "returns the modified friend" do
|
@@ -697,13 +697,13 @@ describe Friends::Introvert do
|
|
697
697
|
end
|
698
698
|
end
|
699
699
|
|
700
|
-
describe "#
|
700
|
+
describe "#remove_tag" do
|
701
701
|
subject do
|
702
|
-
introvert.
|
702
|
+
introvert.remove_tag(name: "Jeff", tag: "@school")
|
703
703
|
end
|
704
704
|
|
705
705
|
it "returns the modified friend" do
|
706
|
-
friend = Friends::Friend.new(name: "Jeff",
|
706
|
+
friend = Friends::Friend.new(name: "Jeff", tags_str: "@school")
|
707
707
|
stub_friends([friend]) do
|
708
708
|
subject.must_equal friend
|
709
709
|
end
|
@@ -820,18 +820,18 @@ describe Friends::Introvert do
|
|
820
820
|
|
821
821
|
let(:activities) do
|
822
822
|
[
|
823
|
-
#
|
823
|
+
# In a location
|
824
824
|
Friends::Activity.new(
|
825
825
|
str: "2016-01-01: \
|
826
826
|
At _The Eiffel Tower_ with **George Washington Carver**."
|
827
827
|
),
|
828
828
|
|
829
|
-
#
|
829
|
+
# Tagged
|
830
830
|
Friends::Activity.new(
|
831
|
-
str: "2016-01-01: Called **George Washington Carver**.
|
831
|
+
str: "2016-01-01: Called **George Washington Carver**. @phone"
|
832
832
|
),
|
833
833
|
|
834
|
-
#
|
834
|
+
# With a friend
|
835
835
|
Friends::Activity.new(
|
836
836
|
str: "2016-01-01: Hung out with **Betsy Ross**."
|
837
837
|
)
|
@@ -894,10 +894,10 @@ describe Friends::Introvert do
|
|
894
894
|
end
|
895
895
|
end
|
896
896
|
|
897
|
-
describe "Filtering by
|
898
|
-
let(:tagged) { "
|
897
|
+
describe "Filtering by tag" do
|
898
|
+
let(:tagged) { "@phone" }
|
899
899
|
|
900
|
-
it "graphs
|
900
|
+
it "graphs tagged activities" do
|
901
901
|
stub_activities(activities) do
|
902
902
|
subject.must_equal("Jan 2016" => 1)
|
903
903
|
end
|
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.
|
4
|
+
version: '0.24'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Evelyn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|