friends 0.26 → 0.27
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 +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
|
-
[](https://badge.fury.io/rb/friends) [](https://badge.fury.io/rb/friends) [](https://gemnasium.com/github.com/JacobEvelyn/friends)
|
2
|
+
[](https://codeclimate.com/github/JacobEvelyn/friends) [](https://codeclimate.com/github/JacobEvelyn/friends) [](https://travis-ci.org/JacobEvelyn/friends) [](http://inch-ci.org/github/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
|