friends 0.23 → 0.24
Sign up to get free protection for your applications and to get access to all the features.
- 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
|