friends 0.26 → 0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/CODE_OF_CONDUCT.md +53 -29
- data/README.md +5 -4
- data/RELEASING.md +5 -4
- data/bin/friends +19 -11
- data/friends.gemspec +4 -4
- data/lib/friends/activity.rb +1 -2
- data/lib/friends/friend.rb +2 -2
- data/lib/friends/introvert.rb +62 -98
- data/lib/friends/location.rb +1 -1
- data/lib/friends/version.rb +1 -1
- data/test/activity_spec.rb +4 -0
- data/test/introvert_spec.rb +28 -2
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f518378eebb4f86c3a576648152ed462ed01618b
|
4
|
+
data.tar.gz: 76c7d599c00fd30eb91034c07f699b9f9b23986e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c46eadf9adfbf48498f84eed1fe6dd7b7edc7563ad7ec66250465719a5653ebe44553d8639edda26abe14e5afa8d383e2784852a884f61bdb8f4b70bb99b3893
|
7
|
+
data.tar.gz: 522058cf6e6b06d9d9fa8fffe24c7d7aeda87fe448a3349bfffe8627b637bfec96fb2ba70526c0fb4c6d37c61ce83a17cc9de4702555d8eb3a4319d89c55fade
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v0.27](https://github.com/JacobEvelyn/friends/tree/v0.27) (2016-06-22)
|
4
|
+
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.26...v0.27)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Allow tags to be added and removed from friends without quotes [\#148](https://github.com/JacobEvelyn/friends/issues/148)
|
9
|
+
- Allow multi-word locations to be added without quotes [\#147](https://github.com/JacobEvelyn/friends/issues/147)
|
10
|
+
- Speed up initialization [\#143](https://github.com/JacobEvelyn/friends/issues/143)
|
11
|
+
- `friends update` can skip reading the friends.md file [\#137](https://github.com/JacobEvelyn/friends/issues/137)
|
12
|
+
- Add Gemnasium badge to README [\#130](https://github.com/JacobEvelyn/friends/issues/130)
|
13
|
+
|
14
|
+
**Fixed bugs:**
|
15
|
+
|
16
|
+
- Commands that find a friend fail on exact text matches when there's more than one fuzzy match [\#149](https://github.com/JacobEvelyn/friends/issues/149)
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Small improvements to UX for some commands [\#150](https://github.com/JacobEvelyn/friends/pull/150) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
21
|
+
- Bump development dependencies [\#146](https://github.com/JacobEvelyn/friends/pull/146) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
22
|
+
- Skips reading the `friends.md` file on update [\#145](https://github.com/JacobEvelyn/friends/pull/145) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
23
|
+
- Simplify code and improve performance [\#144](https://github.com/JacobEvelyn/friends/pull/144) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
24
|
+
- Add Gemnasium integration with README badge [\#142](https://github.com/JacobEvelyn/friends/pull/142) ([JacobEvelyn](https://github.com/JacobEvelyn))
|
25
|
+
|
3
26
|
## [v0.26](https://github.com/JacobEvelyn/friends/tree/v0.26) (2016-05-23)
|
4
27
|
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.25...v0.26)
|
5
28
|
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -1,24 +1,41 @@
|
|
1
|
-
# Contributor Code of Conduct
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
2
|
|
3
|
-
|
4
|
-
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
-
contribute through reporting issues, posting feature requests, updating
|
6
|
-
documentation, submitting pull requests or patches, and other activities.
|
3
|
+
## Our Pledge
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
12
22
|
|
13
23
|
Examples of unacceptable behavior by participants include:
|
14
24
|
|
15
|
-
* The use of sexualized language or imagery
|
16
|
-
|
17
|
-
* Trolling
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
18
28
|
* Public or private harassment
|
19
|
-
* Publishing
|
20
|
-
|
21
|
-
* Other
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
22
39
|
|
23
40
|
Project maintainers have the right and responsibility to remove, edit, or
|
24
41
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
@@ -26,25 +43,32 @@ that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
26
43
|
permanently any contributor for other behaviors that they deem inappropriate,
|
27
44
|
threatening, offensive, or harmful.
|
28
45
|
|
29
|
-
|
30
|
-
fairly and consistently applying these principles to every aspect of managing
|
31
|
-
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
-
Conduct may be permanently removed from the project team.
|
46
|
+
## Scope
|
33
47
|
|
34
48
|
This Code of Conduct applies both within project spaces and in public spaces
|
35
|
-
when an individual is representing the project or its community.
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
36
56
|
|
37
57
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
-
reported by contacting
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
58
|
+
reported by contacting the project team at jacobevelyn@gmail.com. The project team
|
59
|
+
will review and investigate all complaints, and will respond in a way that it deems
|
60
|
+
appropriate to the circumstances. The project team is obligated to maintain
|
61
|
+
confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
43
67
|
|
68
|
+
## Attribution
|
44
69
|
|
45
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
46
|
-
|
47
|
-
[http://contributor-covenant.org/version/1/3/0/][version]
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
48
72
|
|
49
73
|
[homepage]: http://contributor-covenant.org
|
50
|
-
[version]: http://contributor-covenant.org/version/1/
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
[![Gem Version](https://badge.fury.io/rb/friends.svg)](https://badge.fury.io/rb/friends) [![
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/friends.svg)](https://badge.fury.io/rb/friends) [![Dependency Status](https://gemnasium.com/badges/github.com/JacobEvelyn/friends.svg)](https://gemnasium.com/github.com/JacobEvelyn/friends)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/JacobEvelyn/friends/badges/gpa.svg)](https://codeclimate.com/github/JacobEvelyn/friends) [![Test Coverage](https://codeclimate.com/github/JacobEvelyn/friends/badges/coverage.svg)](https://codeclimate.com/github/JacobEvelyn/friends) [![Build Status](https://travis-ci.org/JacobEvelyn/friends.svg?branch=master)](https://travis-ci.org/JacobEvelyn/friends) [![Inline docs](http://inch-ci.org/github/JacobEvelyn/friends.png)](http://inch-ci.org/github/JacobEvelyn/friends) [![ghit.me](https://ghit.me/badge.svg?repo=JacobEvelyn/friends)](https://ghit.me/repo/JacobEvelyn/friends)
|
2
3
|
|
3
|
-
#
|
4
|
+
# `friends`
|
4
5
|
|
5
6
|
Spend time with the people you care about. Introvert-tested.
|
6
7
|
Extrovert-approved.
|
@@ -270,7 +271,7 @@ Friend added: "Grace Hopper"
|
|
270
271
|
#### `add tag`
|
271
272
|
|
272
273
|
```bash
|
273
|
-
$ friends add tag
|
274
|
+
$ friends add tag Grace Hopper science
|
274
275
|
Tag added to friend: "Grace Hopper @science"
|
275
276
|
```
|
276
277
|
|
@@ -568,7 +569,7 @@ Paris
|
|
568
569
|
Removes a specific tag from a friend:
|
569
570
|
|
570
571
|
```bash
|
571
|
-
$ friends remove tag
|
572
|
+
$ friends remove tag Grace Hopper fun
|
572
573
|
Tag removed from friend: "Grace Hopper (a.k.a. Amazing Grace) @OtherTag"
|
573
574
|
```
|
574
575
|
|
data/RELEASING.md
CHANGED
@@ -8,7 +8,8 @@ These are steps for the maintainer to take to release a new version of this gem.
|
|
8
8
|
3. Add a tag (`git tag -am "vX.X" vX.X`).
|
9
9
|
4. `git push && git push --tags`
|
10
10
|
5. `CHANGELOG_GITHUB_TOKEN=... github_changelog_generator`
|
11
|
-
6. `
|
12
|
-
7. `git
|
13
|
-
8. `
|
14
|
-
9.
|
11
|
+
6. Confirm the `CHANGELOG` looks good with `git diff`
|
12
|
+
7. `git add -A && git commit -m 'Update CHANGELOG for vX.X'`
|
13
|
+
8. `git push`
|
14
|
+
9. `gem build friends.gemspec && gem push *.gem && rm *.gem`
|
15
|
+
10. Celebrate!
|
data/bin/friends
CHANGED
@@ -63,14 +63,18 @@ command :update do |update|
|
|
63
63
|
Semverse::Version.coerce(Friends::VERSION)
|
64
64
|
`gem update friends && gem cleanup friends`
|
65
65
|
if $?.success?
|
66
|
-
|
66
|
+
@message = Paint[
|
67
|
+
"Updated to friends #{remote_version}", :bold, :green
|
68
|
+
]
|
67
69
|
else
|
68
|
-
|
70
|
+
@message = Paint[
|
69
71
|
"Error updating to friends version #{remote_version}", :bold, :red
|
70
72
|
]
|
71
73
|
end
|
72
74
|
else
|
73
|
-
|
75
|
+
@message = Paint[
|
76
|
+
"Already up-to-date (#{Friends::VERSION})", :bold, :green
|
77
|
+
]
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
@@ -250,7 +254,7 @@ command :add do |add|
|
|
250
254
|
add.arg_name "LOCATION"
|
251
255
|
add.command :location do |add_location|
|
252
256
|
add_location.action do |_, _, args|
|
253
|
-
location = @introvert.add_location(name: args.
|
257
|
+
location = @introvert.add_location(name: args.join(" "))
|
254
258
|
@message = "Location added: \"#{location.name}\""
|
255
259
|
@dirty = true # Mark the file for cleaning.
|
256
260
|
end
|
@@ -271,8 +275,8 @@ command :add do |add|
|
|
271
275
|
add.command :tag do |add_tag|
|
272
276
|
add_tag.action do |_, _, args|
|
273
277
|
friend = @introvert.add_tag(
|
274
|
-
name: args.
|
275
|
-
tag: Tag.convert_to_tag(args
|
278
|
+
name: args[0..-2].join(" "),
|
279
|
+
tag: Tag.convert_to_tag(args.last)
|
276
280
|
)
|
277
281
|
@message = "Tag added to friend: \"#{friend}\""
|
278
282
|
@dirty = true # Mark the file for cleaning.
|
@@ -310,8 +314,8 @@ command :remove do |remove|
|
|
310
314
|
remove.command :tag do |remove_tag|
|
311
315
|
remove_tag.action do |_, _, args|
|
312
316
|
friend = @introvert.remove_tag(
|
313
|
-
name: args.
|
314
|
-
tag: Tag.convert_to_tag(args
|
317
|
+
name: args[0..-2].join(" "),
|
318
|
+
tag: Tag.convert_to_tag(args.last)
|
315
319
|
)
|
316
320
|
@message = "Tag removed from friend: \"#{friend}\""
|
317
321
|
@dirty = true # Mark the file for cleaning.
|
@@ -429,15 +433,19 @@ command :rename do |rename|
|
|
429
433
|
end
|
430
434
|
|
431
435
|
# Before each command, clean up all arguments and create the global Introvert.
|
432
|
-
pre do |global_options,
|
436
|
+
pre do |global_options, cmd, options|
|
433
437
|
@debug_mode = global_options[:debug]
|
434
438
|
|
435
439
|
final_options = global_options.merge!(options).select do |key, _|
|
436
440
|
[:filename].include? key
|
437
441
|
end
|
438
442
|
|
439
|
-
|
440
|
-
|
443
|
+
# If we're updating the friends program we don't need to read the friends file
|
444
|
+
# but we don't skip this block entirely because we might still want to enable
|
445
|
+
# debug mode.
|
446
|
+
@introvert = Friends::Introvert.new(final_options) unless cmd.name == :update
|
447
|
+
|
448
|
+
true # Continue executing the command.
|
441
449
|
end
|
442
450
|
|
443
451
|
post do |global_options|
|
data/friends.gemspec
CHANGED
@@ -25,14 +25,14 @@ 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.
|
28
|
+
spec.add_dependency "memoist", "~> 0.14"
|
29
29
|
spec.add_dependency "paint", "~> 1.0"
|
30
30
|
spec.add_dependency "semverse", "~> 1.2"
|
31
31
|
|
32
32
|
spec.add_development_dependency "bundler", "~> 1.6"
|
33
|
-
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.
|
33
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.5"
|
34
34
|
spec.add_development_dependency "minitest", "~> 5.5"
|
35
|
-
spec.add_development_dependency "overcommit", "~> 0.
|
36
|
-
spec.add_development_dependency "rake", "~>
|
35
|
+
spec.add_development_dependency "overcommit", "~> 0.34"
|
36
|
+
spec.add_development_dependency "rake", "~> 11.2"
|
37
37
|
spec.add_development_dependency "rubocop", "~> 0.40"
|
38
38
|
end
|
data/lib/friends/activity.rb
CHANGED
@@ -37,7 +37,7 @@ module Friends
|
|
37
37
|
date_s, _, description = str.partition(DATE_PARTITION)
|
38
38
|
|
39
39
|
# rubocop:disable Lint/AssignmentInCondition
|
40
|
-
if time = Chronic.parse(date_s)
|
40
|
+
if time = (date_s =~ /^\d{4}-\d{2}-\d{2}$/ ? Time : Chronic).parse(date_s)
|
41
41
|
# rubocop:enable Lint/AssignmentInCondition
|
42
42
|
@date = time.to_date
|
43
43
|
@description = description
|
@@ -211,7 +211,6 @@ module Friends
|
|
211
211
|
end
|
212
212
|
|
213
213
|
# Now, we compute the likelihood of each friend in the possible-match set.
|
214
|
-
introvert.set_friend_n_activities!
|
215
214
|
introvert.set_likelihood_score!(
|
216
215
|
matches: matched_friends,
|
217
216
|
possible_matches: possible_matched_friends
|
data/lib/friends/friend.rb
CHANGED
@@ -103,7 +103,7 @@ module Friends
|
|
103
103
|
# and is set by the Introvert as needed.
|
104
104
|
attr_writer :n_activities
|
105
105
|
def n_activities
|
106
|
-
@n_activities
|
106
|
+
defined?(@n_activities) ? @n_activities : 0
|
107
107
|
end
|
108
108
|
|
109
109
|
# The likelihood_score that an activity description that matches part of
|
@@ -113,7 +113,7 @@ module Friends
|
|
113
113
|
# introvert#set_likelihood_score! methods.
|
114
114
|
attr_writer :likelihood_score
|
115
115
|
def likelihood_score
|
116
|
-
@likelihood_score
|
116
|
+
defined?(@likelihood_score) ? @likelihood_score : 0
|
117
117
|
end
|
118
118
|
|
119
119
|
# @return [Array] a list of all regexes to match the name in a string
|
data/lib/friends/introvert.rb
CHANGED
@@ -49,15 +49,11 @@ module Friends
|
|
49
49
|
# @raise [FriendsError] when a friend with that name is already in the file
|
50
50
|
# @return [Friend] the added friend
|
51
51
|
def add_friend(name:)
|
52
|
-
if
|
53
|
-
raise FriendsError, "Friend named #{name} already exists"
|
52
|
+
if @friends.any? { |friend| friend.name == name }
|
53
|
+
raise FriendsError, "Friend named \"#{name}\" already exists"
|
54
54
|
end
|
55
55
|
|
56
|
-
|
57
|
-
friend = Friend.deserialize(name)
|
58
|
-
rescue Serializable::SerializationError => e
|
59
|
-
raise FriendsError, e
|
60
|
-
end
|
56
|
+
friend = Friend.deserialize(name)
|
61
57
|
|
62
58
|
@friends << friend
|
63
59
|
|
@@ -68,11 +64,7 @@ module Friends
|
|
68
64
|
# @param serialization [String] the serialized activity
|
69
65
|
# @return [Activity] the added activity
|
70
66
|
def add_activity(serialization:)
|
71
|
-
|
72
|
-
activity = Activity.deserialize(serialization)
|
73
|
-
rescue Serializable::SerializationError => e
|
74
|
-
raise FriendsError, e
|
75
|
-
end
|
67
|
+
activity = Activity.deserialize(serialization)
|
76
68
|
|
77
69
|
activity.highlight_description(introvert: self) if activity.description
|
78
70
|
@activities.unshift(activity)
|
@@ -89,11 +81,7 @@ module Friends
|
|
89
81
|
raise FriendsError, "Location \"#{name}\" already exists"
|
90
82
|
end
|
91
83
|
|
92
|
-
|
93
|
-
location = Location.deserialize(name)
|
94
|
-
rescue Serializable::SerializationError => e
|
95
|
-
raise FriendsError, e
|
96
|
-
end
|
84
|
+
location = Location.deserialize(name)
|
97
85
|
|
98
86
|
@locations << location
|
99
87
|
|
@@ -107,8 +95,8 @@ module Friends
|
|
107
95
|
# @raise [FriendsError] if 0 or 2+ locations match the given location name
|
108
96
|
# @return [Friend] the modified friend
|
109
97
|
def set_location(name:, location_name:)
|
110
|
-
friend =
|
111
|
-
location =
|
98
|
+
friend = thing_with_name_in(:friend, name)
|
99
|
+
location = thing_with_name_in(:location, location_name)
|
112
100
|
friend.location_name = location.name
|
113
101
|
friend
|
114
102
|
end
|
@@ -119,7 +107,7 @@ module Friends
|
|
119
107
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
120
108
|
# @return [Friend] the existing friend
|
121
109
|
def rename_friend(old_name:, new_name:)
|
122
|
-
friend =
|
110
|
+
friend = thing_with_name_in(:friend, old_name)
|
123
111
|
@activities.each do |activity|
|
124
112
|
activity.update_friend_name(old_name: friend.name, new_name: new_name)
|
125
113
|
end
|
@@ -133,7 +121,7 @@ module Friends
|
|
133
121
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
134
122
|
# @return [Location] the existing location
|
135
123
|
def rename_location(old_name:, new_name:)
|
136
|
-
loc =
|
124
|
+
loc = thing_with_name_in(:location, old_name)
|
137
125
|
|
138
126
|
# Update locations in activities.
|
139
127
|
@activities.each do |activity|
|
@@ -155,7 +143,7 @@ module Friends
|
|
155
143
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
156
144
|
# @return [Friend] the existing friend
|
157
145
|
def add_nickname(name:, nickname:)
|
158
|
-
friend =
|
146
|
+
friend = thing_with_name_in(:friend, name)
|
159
147
|
friend.add_nickname(nickname)
|
160
148
|
friend
|
161
149
|
end
|
@@ -166,7 +154,7 @@ module Friends
|
|
166
154
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
167
155
|
# @return [Friend] the existing friend
|
168
156
|
def add_tag(name:, tag:)
|
169
|
-
friend =
|
157
|
+
friend = thing_with_name_in(:friend, name)
|
170
158
|
friend.add_tag(tag)
|
171
159
|
friend
|
172
160
|
end
|
@@ -178,7 +166,7 @@ module Friends
|
|
178
166
|
# @raise [FriendsError] if the friend does not have the given nickname
|
179
167
|
# @return [Friend] the existing friend
|
180
168
|
def remove_tag(name:, tag:)
|
181
|
-
friend =
|
169
|
+
friend = thing_with_name_in(:friend, name)
|
182
170
|
friend.remove_tag(tag)
|
183
171
|
friend
|
184
172
|
end
|
@@ -190,7 +178,7 @@ module Friends
|
|
190
178
|
# @raise [FriendsError] if the friend does not have the given nickname
|
191
179
|
# @return [Friend] the existing friend
|
192
180
|
def remove_nickname(name:, nickname:)
|
193
|
-
friend =
|
181
|
+
friend = thing_with_name_in(:friend, name)
|
194
182
|
friend.remove_nickname(nickname)
|
195
183
|
friend
|
196
184
|
end
|
@@ -208,7 +196,7 @@ module Friends
|
|
208
196
|
|
209
197
|
# Filter by location if a name is passed.
|
210
198
|
if location_name
|
211
|
-
location =
|
199
|
+
location = thing_with_name_in(:location, location_name)
|
212
200
|
fs = fs.select { |friend| friend.location_name == location.name }
|
213
201
|
end
|
214
202
|
|
@@ -244,9 +232,12 @@ module Friends
|
|
244
232
|
# @param tagged [String] the name of a tag to filter by (of the form:
|
245
233
|
# "@tag"), or nil for unfiltered
|
246
234
|
# @return [Array] a list of all activity text values
|
235
|
+
# @raise [ArgumentError] if limit is present but limit < 1
|
247
236
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
248
237
|
# is ambiguous
|
249
238
|
def list_activities(limit:, with:, location_name:, tagged:)
|
239
|
+
raise ArgumentError, "Limit must be positive" if limit && limit < 1
|
240
|
+
|
250
241
|
acts = filtered_activities(
|
251
242
|
with: with,
|
252
243
|
location_name: location_name,
|
@@ -338,8 +329,6 @@ module Friends
|
|
338
329
|
# for unfiltered
|
339
330
|
# @return [Hash{String => Array<String>}]
|
340
331
|
def suggest(location_name:)
|
341
|
-
set_friend_n_activities! # Set n_activities for all friends.
|
342
|
-
|
343
332
|
# Filter our friends by location if necessary.
|
344
333
|
fs = @friends
|
345
334
|
fs = fs.select { |f| f.location_name == location_name } if location_name
|
@@ -369,11 +358,6 @@ module Friends
|
|
369
358
|
# Methods below this are only used internally and are not tested. #
|
370
359
|
###################################################################
|
371
360
|
|
372
|
-
# Sets the n_activities field on each friend.
|
373
|
-
def set_friend_n_activities!
|
374
|
-
set_n_activities!(:friend)
|
375
|
-
end
|
376
|
-
|
377
361
|
# Get a regex friend map.
|
378
362
|
#
|
379
363
|
# The returned hash uses the following format:
|
@@ -480,13 +464,13 @@ module Friends
|
|
480
464
|
|
481
465
|
# Filter by friend name if argument is passed.
|
482
466
|
unless with.nil?
|
483
|
-
friend =
|
467
|
+
friend = thing_with_name_in(:friend, with)
|
484
468
|
acts = acts.select { |act| act.includes_friend?(friend) }
|
485
469
|
end
|
486
470
|
|
487
471
|
# Filter by location name if argument is passed.
|
488
472
|
unless location_name.nil?
|
489
|
-
location =
|
473
|
+
location = thing_with_name_in(:location, location_name)
|
490
474
|
acts = acts.select { |act| act.includes_location?(location) }
|
491
475
|
end
|
492
476
|
|
@@ -501,16 +485,14 @@ module Friends
|
|
501
485
|
# @param type [Symbol] one of: [:friend, :location]
|
502
486
|
# @param limit [Integer] the number of favorite things to return
|
503
487
|
# @return [Array] a list of the favorite things' names and activity counts
|
488
|
+
# @raise [ArgumentError] if type is not one of: [:friend, :location]
|
489
|
+
# @raise [ArgumentError] if limit is < 1
|
504
490
|
def list_favorite_things(type, limit:)
|
505
491
|
unless [:friend, :location].include? type
|
506
|
-
raise
|
492
|
+
raise ArgumentError, "Type must be either :friend or :location"
|
507
493
|
end
|
508
494
|
|
509
|
-
if limit < 1
|
510
|
-
raise FriendsError, "Favorites limit must be positive"
|
511
|
-
end
|
512
|
-
|
513
|
-
send("set_n_activities!", type) # Set n_activities for all things.
|
495
|
+
raise ArgumentError, "Favorites limit must be positive" if limit < 1
|
514
496
|
|
515
497
|
# Sort the results, with the most favorite thing first.
|
516
498
|
results = instance_variable_get("@#{type}s").sort_by do |thing|
|
@@ -531,9 +513,10 @@ module Friends
|
|
531
513
|
|
532
514
|
# Sets the n_activities field on each thing.
|
533
515
|
# @param type [Symbol] one of: [:friend, :location]
|
516
|
+
# @raise [ArgumentError] if `type` is not one of: [:friend, :location]
|
534
517
|
def set_n_activities!(type)
|
535
518
|
unless [:friend, :location].include? type
|
536
|
-
raise
|
519
|
+
raise ArgumentError, "Type must be either :friend or :location"
|
537
520
|
end
|
538
521
|
|
539
522
|
# Construct a hash of location name to frequency of appearance.
|
@@ -546,8 +529,16 @@ module Friends
|
|
546
529
|
|
547
530
|
# Remove names that are not in the locations list.
|
548
531
|
freq_table.each do |name, count|
|
549
|
-
|
550
|
-
|
532
|
+
things = instance_variable_get("@#{type}s").select do |thing|
|
533
|
+
thing.name == name
|
534
|
+
end
|
535
|
+
|
536
|
+
# Do nothing if no matches found.
|
537
|
+
if things.size == 1
|
538
|
+
things.first.n_activities = count
|
539
|
+
elsif things.size > 1
|
540
|
+
raise FriendsError, "More than one #{type} named \"#{name}\""
|
541
|
+
end
|
551
542
|
end
|
552
543
|
end
|
553
544
|
|
@@ -569,6 +560,9 @@ module Friends
|
|
569
560
|
# Parse the line and update the parsing state.
|
570
561
|
state = parse_line!(line, line_num: line_num, state: state)
|
571
562
|
end
|
563
|
+
|
564
|
+
set_n_activities!(:friend)
|
565
|
+
set_n_activities!(:location)
|
572
566
|
end
|
573
567
|
|
574
568
|
# Parse the given line, adding to the various internal data structures as
|
@@ -599,7 +593,7 @@ module Friends
|
|
599
593
|
|
600
594
|
begin
|
601
595
|
instance_variable_get("@#{stage.id}") << stage.klass.deserialize(line)
|
602
|
-
rescue
|
596
|
+
rescue => e
|
603
597
|
bad_line(e, line_num)
|
604
598
|
end
|
605
599
|
|
@@ -615,67 +609,37 @@ module Friends
|
|
615
609
|
ParsingStage.new(:locations, Location)
|
616
610
|
].freeze
|
617
611
|
|
618
|
-
# @param
|
619
|
-
# @
|
620
|
-
#
|
621
|
-
|
622
|
-
results = @friends.select { |friend| friend.name == name }
|
623
|
-
|
624
|
-
case results.size
|
625
|
-
when 0 then nil
|
626
|
-
when 1 then results.first
|
627
|
-
else raise FriendsError, "More than one friend named #{name}"
|
628
|
-
end
|
629
|
-
end
|
630
|
-
|
631
|
-
# @param text [String] the name (or substring) of the friend to search for
|
632
|
-
# @return [Friend] the friend that matches
|
612
|
+
# @param type [Symbol] one of: [:friend, :location]
|
613
|
+
# @param text [String] the name (or substring) of the friend or location to
|
614
|
+
# search for
|
615
|
+
# @return [Friend/Location] the friend or location that matches
|
633
616
|
# @raise [FriendsError] if 0 or 2+ friends match the given text
|
634
|
-
def
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
return friends.first
|
642
|
-
when 0 then raise FriendsError, "No friend found for \"#{text}\""
|
643
|
-
else
|
644
|
-
raise FriendsError,
|
645
|
-
"More than one friend found for \"#{text}\": "\
|
646
|
-
"#{friends.map(&:name).join(', ')}"
|
617
|
+
def thing_with_name_in(type, text)
|
618
|
+
things = instance_variable_get("@#{type}s").select do |thing|
|
619
|
+
if type == :friend
|
620
|
+
thing.regexes_for_name.any? { |regex| regex.match(text) }
|
621
|
+
else
|
622
|
+
thing.regex_for_name.match(text)
|
623
|
+
end
|
647
624
|
end
|
648
|
-
end
|
649
625
|
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
626
|
+
# If there's more than one match with fuzzy regexes but exactly one thing
|
627
|
+
# with that exact name, match it.
|
628
|
+
if things.size > 1
|
629
|
+
exact_things = things.select do |thing|
|
630
|
+
thing.name.casecmp(text) == 0 # We ignore case for an "exact" match.
|
631
|
+
end
|
655
632
|
|
656
|
-
|
657
|
-
when 0 then nil
|
658
|
-
when 1 then results.first
|
659
|
-
else raise FriendsError, "More than one location named #{name}"
|
633
|
+
things = exact_things if exact_things.size == 1
|
660
634
|
end
|
661
|
-
end
|
662
|
-
|
663
|
-
# @param text [String] the name (or substring) of the location to search for
|
664
|
-
# @return [Location] the location that matches
|
665
|
-
# @raise [FriendsError] if 0 or 2+ location match the given text
|
666
|
-
def location_with_name_in(text)
|
667
|
-
regex = Regexp.new(text, Regexp::IGNORECASE)
|
668
|
-
locations = @locations.select { |location| location.name.match(regex) }
|
669
635
|
|
670
|
-
case
|
671
|
-
when 1
|
672
|
-
|
673
|
-
return locations.first
|
674
|
-
when 0 then raise FriendsError, "No location found for \"#{text}\""
|
636
|
+
case things.size
|
637
|
+
when 1 then things.first # If exactly one thing matches, use that thing.
|
638
|
+
when 0 then raise FriendsError, "No #{type} found for \"#{text}\""
|
675
639
|
else
|
676
640
|
raise FriendsError,
|
677
|
-
"More than one
|
678
|
-
"#{
|
641
|
+
"More than one #{type} found for \"#{text}\": "\
|
642
|
+
"#{things.map(&:name).join(', ')}"
|
679
643
|
end
|
680
644
|
end
|
681
645
|
|
data/lib/friends/location.rb
CHANGED
data/lib/friends/version.rb
CHANGED
data/test/activity_spec.rb
CHANGED
@@ -125,6 +125,7 @@ describe Friends::Activity do
|
|
125
125
|
def stub_friends(val)
|
126
126
|
old_val = introvert.instance_variable_get(:@friends)
|
127
127
|
introvert.instance_variable_set(:@friends, val)
|
128
|
+
introvert.send(:set_n_activities!, :friend)
|
128
129
|
yield
|
129
130
|
introvert.instance_variable_set(:@friends, old_val)
|
130
131
|
end
|
@@ -132,6 +133,8 @@ describe Friends::Activity do
|
|
132
133
|
def stub_activities(val)
|
133
134
|
old_val = introvert.instance_variable_get(:@activities)
|
134
135
|
introvert.instance_variable_set(:@activities, val)
|
136
|
+
introvert.send(:set_n_activities!, :friend)
|
137
|
+
introvert.send(:set_n_activities!, :location)
|
135
138
|
yield
|
136
139
|
introvert.instance_variable_set(:@activities, old_val)
|
137
140
|
end
|
@@ -139,6 +142,7 @@ describe Friends::Activity do
|
|
139
142
|
def stub_locations(val)
|
140
143
|
old_val = introvert.instance_variable_get(:@locations)
|
141
144
|
introvert.instance_variable_set(:@locations, val)
|
145
|
+
introvert.send(:set_n_activities!, :location)
|
142
146
|
yield
|
143
147
|
introvert.instance_variable_set(:@locations, old_val)
|
144
148
|
end
|
data/test/introvert_spec.rb
CHANGED
@@ -14,6 +14,7 @@ describe Friends::Introvert do
|
|
14
14
|
def stub_friends(val)
|
15
15
|
old_val = introvert.instance_variable_get(:@friends)
|
16
16
|
introvert.instance_variable_set(:@friends, val)
|
17
|
+
introvert.send(:set_n_activities!, :friend)
|
17
18
|
yield
|
18
19
|
introvert.instance_variable_set(:@friends, old_val)
|
19
20
|
end
|
@@ -21,6 +22,8 @@ describe Friends::Introvert do
|
|
21
22
|
def stub_activities(val)
|
22
23
|
old_val = introvert.instance_variable_get(:@activities)
|
23
24
|
introvert.instance_variable_set(:@activities, val)
|
25
|
+
introvert.send(:set_n_activities!, :friend)
|
26
|
+
introvert.send(:set_n_activities!, :location)
|
24
27
|
yield
|
25
28
|
introvert.instance_variable_set(:@activities, old_val)
|
26
29
|
end
|
@@ -28,6 +31,7 @@ describe Friends::Introvert do
|
|
28
31
|
def stub_locations(val)
|
29
32
|
old_val = introvert.instance_variable_get(:@locations)
|
30
33
|
introvert.instance_variable_set(:@locations, val)
|
34
|
+
introvert.send(:set_n_activities!, :location)
|
31
35
|
yield
|
32
36
|
introvert.instance_variable_set(:@locations, old_val)
|
33
37
|
end
|
@@ -79,7 +83,7 @@ describe Friends::Introvert do
|
|
79
83
|
subject { introvert.clean }
|
80
84
|
|
81
85
|
# Delete the file that is created each time.
|
82
|
-
after { File.delete(filename) if File.
|
86
|
+
after { File.delete(filename) if File.exist?(filename) }
|
83
87
|
|
84
88
|
it "writes cleaned file" do
|
85
89
|
sorted_friends = friends.sort
|
@@ -394,7 +398,7 @@ describe Friends::Introvert do
|
|
394
398
|
let(:with) { "george" }
|
395
399
|
|
396
400
|
describe "when there is more than one friend match" do
|
397
|
-
let(:friend_names) { ["George Washington Carver", "
|
401
|
+
let(:friend_names) { ["George Washington Carver", "George Harrison"] }
|
398
402
|
|
399
403
|
it "raises an error" do
|
400
404
|
stub_friends(friends) do
|
@@ -695,6 +699,28 @@ describe Friends::Introvert do
|
|
695
699
|
subject.must_equal friends.first
|
696
700
|
end
|
697
701
|
end
|
702
|
+
|
703
|
+
describe "when more than one friend name matches" do
|
704
|
+
let(:friend_names) { ["George Washington Carver", "George Washington"] }
|
705
|
+
|
706
|
+
describe "when one friend name matches exactly" do
|
707
|
+
it "returns the modified friend" do
|
708
|
+
stub_friends(friends) do
|
709
|
+
subject.must_equal friends.first
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
describe "when no friend name matches exactly" do
|
715
|
+
it "raises an error" do
|
716
|
+
proc do
|
717
|
+
stub_friends(friends) do
|
718
|
+
introvert.add_tag(name: "George", tag: "@school")
|
719
|
+
end
|
720
|
+
end.must_raise Friends::FriendsError
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
698
724
|
end
|
699
725
|
|
700
726
|
describe "#remove_tag" do
|
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.27'
|
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-
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
47
|
+
version: '0.14'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0.
|
54
|
+
version: '0.14'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: paint
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0.
|
103
|
+
version: '0.5'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
110
|
+
version: '0.5'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: minitest
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,28 +128,28 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0.
|
131
|
+
version: '0.34'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0.
|
138
|
+
version: '0.34'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: rake
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '11.2'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '11.2'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: rubocop
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|