friends 0.16 → 0.17
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/CONTRIBUTING.md +2 -1
- data/README.md +59 -2
- data/bin/friends +74 -18
- data/friends.md +9 -4
- data/lib/friends/activity.rb +101 -42
- data/lib/friends/friend.rb +15 -39
- data/lib/friends/introvert.rb +229 -71
- data/lib/friends/location.rb +49 -0
- data/lib/friends/regex_builder.rb +38 -0
- data/lib/friends/version.rb +1 -1
- data/test/activity_spec.rb +89 -18
- data/test/friend_spec.rb +2 -13
- data/test/introvert_spec.rb +330 -56
- data/test/location_spec.rb +58 -0
- metadata +6 -2
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Location represents a location in the world.
|
3
|
+
|
4
|
+
require "friends/regex_builder"
|
5
|
+
require "friends/serializable"
|
6
|
+
|
7
|
+
module Friends
|
8
|
+
class Location
|
9
|
+
extend Serializable
|
10
|
+
|
11
|
+
SERIALIZATION_PREFIX = "- ".freeze
|
12
|
+
|
13
|
+
# @return [Regexp] the regex for capturing groups in deserialization
|
14
|
+
def self.deserialization_regex
|
15
|
+
# Note: this regex must be on one line because whitespace is important
|
16
|
+
/(#{SERIALIZATION_PREFIX})?(?<name>.+)/
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Regexp] the string of what we expected during deserialization
|
20
|
+
def self.deserialization_expectation
|
21
|
+
"[Location Name]"
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param name [String] the name of the location
|
25
|
+
def initialize(name:)
|
26
|
+
@name = name
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :name
|
30
|
+
|
31
|
+
# @return [String] the file serialization text for the location
|
32
|
+
def serialize
|
33
|
+
"#{SERIALIZATION_PREFIX}#{@name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Regexp] the regex used to match this location's name in an
|
37
|
+
# activity description
|
38
|
+
def regex_for_name
|
39
|
+
Friends::RegexBuilder.regex(@name)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Default sorting for an array of locations is alphabetical.
|
45
|
+
def <=>(other)
|
46
|
+
name <=> other.name
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# RegexpBuilder is an internal class that helps us build regexes to find things.
|
3
|
+
|
4
|
+
module Friends
|
5
|
+
class RegexBuilder
|
6
|
+
# We don't want to match strings that are "escaped" with a leading
|
7
|
+
# backslash.
|
8
|
+
NO_LEADING_BACKSLASH = "(?<!\\\\)".freeze
|
9
|
+
|
10
|
+
# We don't want to match strings that are directly touching double asterisks
|
11
|
+
# as these are treated as sacred by our program.
|
12
|
+
NO_LEADING_ASTERISKS = "(?<!\\*\\*)".freeze
|
13
|
+
NO_TRAILING_ASTERISKS = "(?!\\*\\*)".freeze
|
14
|
+
|
15
|
+
# We don't want to match strings that are directly touching underscores
|
16
|
+
# as these are treated as sacred by our program.
|
17
|
+
NO_LEADING_UNDERSCORES = "(?<!_)".freeze
|
18
|
+
NO_TRAILING_UNDERSCORES = "(?!_)".freeze
|
19
|
+
|
20
|
+
# We don't want to match strings that are part of other words.
|
21
|
+
NO_LEADING_ALPHABETICALS = "(?<![A-z])".freeze
|
22
|
+
NO_TRAILING_ALPHABETICALS = "(?![A-z])".freeze
|
23
|
+
|
24
|
+
def self.regex(str)
|
25
|
+
Regexp.new(
|
26
|
+
NO_LEADING_BACKSLASH +
|
27
|
+
NO_LEADING_ASTERISKS +
|
28
|
+
NO_LEADING_UNDERSCORES +
|
29
|
+
NO_LEADING_ALPHABETICALS +
|
30
|
+
str +
|
31
|
+
NO_TRAILING_ALPHABETICALS +
|
32
|
+
NO_TRAILING_UNDERSCORES +
|
33
|
+
NO_TRAILING_ASTERISKS,
|
34
|
+
Regexp::IGNORECASE
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/friends/version.rb
CHANGED
data/test/activity_spec.rb
CHANGED
@@ -5,7 +5,10 @@ describe Friends::Activity do
|
|
5
5
|
let(:date_s) { date.to_s }
|
6
6
|
let(:friend1) { Friends::Friend.new(name: "Elizabeth Cady Stanton") }
|
7
7
|
let(:friend2) { Friends::Friend.new(name: "John Cage") }
|
8
|
-
let(:description)
|
8
|
+
let(:description) do
|
9
|
+
"Lunch with **#{friend1.name}** and **#{friend2.name}** on _The Moon_ "\
|
10
|
+
"after hanging out in _Atlantis_."
|
11
|
+
end
|
9
12
|
let(:partition) { Friends::Activity::DATE_PARTITION }
|
10
13
|
let(:activity) do
|
11
14
|
Friends::Activity.new(str: "#{date_s}#{partition}#{description}")
|
@@ -99,7 +102,9 @@ describe Friends::Activity do
|
|
99
102
|
subject.
|
100
103
|
must_equal "#{Paint[date_s, :bold]}: "\
|
101
104
|
"Lunch with #{Paint[friend1.name, :bold, :magenta]} and "\
|
102
|
-
"#{Paint[friend2.name, :bold, :magenta]}"
|
105
|
+
"#{Paint[friend2.name, :bold, :magenta]} on "\
|
106
|
+
"#{Paint['The Moon', :bold, :yellow]} after hanging out in "\
|
107
|
+
"#{Paint['Atlantis', :bold, :yellow]}."
|
103
108
|
end
|
104
109
|
end
|
105
110
|
|
@@ -113,7 +118,7 @@ describe Friends::Activity do
|
|
113
118
|
end
|
114
119
|
end
|
115
120
|
|
116
|
-
describe "#
|
121
|
+
describe "#highlight_description" do
|
117
122
|
# Add helpers to set internal states for friends and activities.
|
118
123
|
def stub_friends(val)
|
119
124
|
old_val = introvert.instance_variable_get(:@friends)
|
@@ -129,16 +134,34 @@ describe Friends::Activity do
|
|
129
134
|
introvert.instance_variable_set(:@activities, old_val)
|
130
135
|
end
|
131
136
|
|
137
|
+
def stub_locations(val)
|
138
|
+
old_val = introvert.instance_variable_get(:@locations)
|
139
|
+
introvert.instance_variable_set(:@locations, val)
|
140
|
+
yield
|
141
|
+
introvert.instance_variable_set(:@locations, old_val)
|
142
|
+
end
|
143
|
+
|
144
|
+
let(:locations) do
|
145
|
+
[
|
146
|
+
Friends::Location.new(name: "Atlantis"),
|
147
|
+
Friends::Location.new(name: "The Moon")
|
148
|
+
]
|
149
|
+
end
|
132
150
|
let(:friends) { [friend1, friend2] }
|
133
151
|
let(:introvert) { Friends::Introvert.new }
|
134
152
|
subject do
|
135
|
-
stub_friends(friends)
|
153
|
+
stub_friends(friends) do
|
154
|
+
stub_locations(locations) do
|
155
|
+
activity.highlight_description(introvert: introvert)
|
156
|
+
end
|
157
|
+
end
|
136
158
|
end
|
137
159
|
|
138
|
-
it "finds all friends" do
|
160
|
+
it "finds all friends and locations" do
|
139
161
|
subject
|
140
|
-
activity.description.
|
141
|
-
|
162
|
+
activity.description.must_equal "Lunch with **#{friend1.name}** and "\
|
163
|
+
"**#{friend2.name}** on _The Moon_ "\
|
164
|
+
"after hanging out in _Atlantis_."
|
142
165
|
end
|
143
166
|
|
144
167
|
describe "when description has first names" do
|
@@ -332,23 +355,32 @@ describe Friends::Activity do
|
|
332
355
|
end
|
333
356
|
end
|
334
357
|
|
358
|
+
describe "#includes_location?" do
|
359
|
+
subject { activity.includes_location?(location: loc) }
|
360
|
+
let(:loc) { Friends::Location.new(name: "Atlantis") }
|
361
|
+
|
362
|
+
describe "when the given location is in the activity" do
|
363
|
+
let(:activity) { Friends::Activity.new(str: "Explored _#{loc.name}_") }
|
364
|
+
it { subject.must_equal true }
|
365
|
+
end
|
366
|
+
|
367
|
+
describe "when the given location is not in the activity" do
|
368
|
+
let(:activity) { Friends::Activity.new(str: "Explored _Elsewhere_") }
|
369
|
+
it { subject.must_equal false }
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
335
373
|
describe "#includes_friend?" do
|
336
374
|
subject { activity.includes_friend?(friend: friend) }
|
337
375
|
|
338
376
|
describe "when the given friend is in the activity" do
|
339
377
|
let(:friend) { friend1 }
|
340
|
-
|
341
|
-
it "returns true" do
|
342
|
-
subject.must_equal true
|
343
|
-
end
|
378
|
+
it { subject.must_equal true }
|
344
379
|
end
|
345
380
|
|
346
381
|
describe "when the given friend is not in the activity" do
|
347
382
|
let(:friend) { Friends::Friend.new(name: "Claude Debussy") }
|
348
|
-
|
349
|
-
it "returns false" do
|
350
|
-
subject.must_equal false
|
351
|
-
end
|
383
|
+
it { subject.must_equal false }
|
352
384
|
end
|
353
385
|
end
|
354
386
|
|
@@ -382,10 +414,13 @@ describe Friends::Activity do
|
|
382
414
|
end
|
383
415
|
end
|
384
416
|
|
385
|
-
describe "#
|
417
|
+
describe "#update_friend_name" do
|
386
418
|
let(:description) { "Lunch with **John Candy**." }
|
387
419
|
subject do
|
388
|
-
activity.
|
420
|
+
activity.update_friend_name(
|
421
|
+
old_name: "John Candy",
|
422
|
+
new_name: "John Cleese"
|
423
|
+
)
|
389
424
|
end
|
390
425
|
|
391
426
|
it "renames the given friend in the description" do
|
@@ -403,7 +438,7 @@ describe Friends::Activity do
|
|
403
438
|
describe "when the description contains the complete old name" do
|
404
439
|
let(:description) { "Coffee with **John** at John's Studio." }
|
405
440
|
subject do
|
406
|
-
activity.
|
441
|
+
activity.update_friend_name(old_name: "John", new_name: "Joe")
|
407
442
|
end
|
408
443
|
|
409
444
|
it "only replaces the actual name" do
|
@@ -411,4 +446,40 @@ describe Friends::Activity do
|
|
411
446
|
end
|
412
447
|
end
|
413
448
|
end
|
449
|
+
|
450
|
+
describe "#update_location_name" do
|
451
|
+
let(:description) { "Lunch in _Paris_." }
|
452
|
+
subject do
|
453
|
+
activity.update_location_name(
|
454
|
+
old_name: "Paris",
|
455
|
+
new_name: "Paris, France"
|
456
|
+
)
|
457
|
+
end
|
458
|
+
|
459
|
+
it "renames the given friend in the description" do
|
460
|
+
subject.must_equal "Lunch in _Paris, France_."
|
461
|
+
end
|
462
|
+
|
463
|
+
describe "when the description contains a fragment of the old name" do
|
464
|
+
let(:description) { "Lunch in _Paris_ at the Parisian Café." }
|
465
|
+
|
466
|
+
it "only replaces the name" do
|
467
|
+
subject.must_equal "Lunch in _Paris, France_ at the Parisian Café."
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe "when the description contains the complete old name" do
|
472
|
+
let(:description) { "Lunch in _Paris_ at The Paris Café." }
|
473
|
+
subject do
|
474
|
+
activity.update_location_name(
|
475
|
+
old_name: "Paris",
|
476
|
+
new_name: "Paris, France"
|
477
|
+
)
|
478
|
+
end
|
479
|
+
|
480
|
+
it "only replaces the actual name" do
|
481
|
+
subject.must_equal "Lunch in _Paris, France_ at The Paris Café."
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
414
485
|
end
|
data/test/friend_spec.rb
CHANGED
@@ -30,15 +30,6 @@ describe Friends::Friend do
|
|
30
30
|
it { subject.name.must_equal friend_name }
|
31
31
|
end
|
32
32
|
|
33
|
-
describe "#rename" do
|
34
|
-
subject { friend }
|
35
|
-
|
36
|
-
it "renames the friend" do
|
37
|
-
friend.rename("Ada Lovelace")
|
38
|
-
subject.name.must_equal "Ada Lovelace"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
33
|
describe "#serialize" do
|
43
34
|
subject { friend.serialize }
|
44
35
|
|
@@ -118,10 +109,8 @@ describe Friends::Friend do
|
|
118
109
|
subject { friend.regexes_for_name }
|
119
110
|
|
120
111
|
it "generates appropriate regexes" do
|
121
|
-
subject.must_equal
|
122
|
-
|
123
|
-
/(?<!\\)(?<!\*\*)(?<![A-z])Jacob(?![A-z])(?!\*\*)/i
|
124
|
-
]
|
112
|
+
subject.any? { |r| r =~ friend_name }.must_equal true
|
113
|
+
subject.any? { |r| r =~ friend_name.partition(" ").first }.must_equal true
|
125
114
|
end
|
126
115
|
end
|
127
116
|
|
data/test/introvert_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Friends::Introvert do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
# Add helpers to set internal states for friends
|
11
|
+
# Add helpers to set internal states for friends/locations/activities.
|
12
12
|
def stub_friends(val)
|
13
13
|
old_val = introvert.instance_variable_get(:@friends)
|
14
14
|
introvert.instance_variable_set(:@friends, val)
|
@@ -23,6 +23,13 @@ describe Friends::Introvert do
|
|
23
23
|
introvert.instance_variable_set(:@activities, old_val)
|
24
24
|
end
|
25
25
|
|
26
|
+
def stub_locations(val)
|
27
|
+
old_val = introvert.instance_variable_get(:@locations)
|
28
|
+
introvert.instance_variable_set(:@locations, val)
|
29
|
+
yield
|
30
|
+
introvert.instance_variable_set(:@locations, old_val)
|
31
|
+
end
|
32
|
+
|
26
33
|
let(:filename) { "test/tmp/friends.md" }
|
27
34
|
let(:args) { { filename: filename } }
|
28
35
|
let(:introvert) { Friends::Introvert.new(args) }
|
@@ -38,6 +45,12 @@ describe Friends::Introvert do
|
|
38
45
|
)
|
39
46
|
]
|
40
47
|
end
|
48
|
+
let(:locations) do
|
49
|
+
[
|
50
|
+
Friends::Location.new(name: "The Eiffel Tower"),
|
51
|
+
Friends::Location.new(name: "Atlantis")
|
52
|
+
]
|
53
|
+
end
|
41
54
|
|
42
55
|
describe "#new" do
|
43
56
|
it "accepts all arguments" do
|
@@ -67,22 +80,28 @@ describe Friends::Introvert do
|
|
67
80
|
unsorted_friends = sorted_friends.reverse
|
68
81
|
sorted_activities = activities.sort
|
69
82
|
unsorted_activities = sorted_activities.reverse
|
83
|
+
sorted_locations = locations.sort
|
84
|
+
unsorted_locations = sorted_locations.reverse
|
70
85
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
serialized_descriptions = sorted_activities.map(&:serialize)
|
75
|
-
descriptions_output = serialized_descriptions.join("\n")
|
86
|
+
serialized_friends = sorted_friends.map(&:serialize).join("\n")
|
87
|
+
serialized_activities = sorted_activities.map(&:serialize).join("\n")
|
88
|
+
serialized_locations = sorted_locations.map(&:serialize).join("\n")
|
76
89
|
|
77
90
|
expected_output =
|
78
|
-
"#{Friends::Introvert::ACTIVITIES_HEADER}\n
|
79
|
-
"#{
|
91
|
+
"#{Friends::Introvert::ACTIVITIES_HEADER}\n"\
|
92
|
+
"#{serialized_activities}\n\n"\
|
93
|
+
"#{Friends::Introvert::FRIENDS_HEADER}\n"\
|
94
|
+
"#{serialized_friends}\n\n"\
|
95
|
+
"#{Friends::Introvert::LOCATIONS_HEADER}\n"\
|
96
|
+
"#{serialized_locations}\n"
|
80
97
|
|
81
98
|
# Read the input as unsorted, and make sure we get sorted output.
|
82
99
|
stub_friends(unsorted_friends) do
|
83
100
|
stub_activities(unsorted_activities) do
|
84
|
-
|
85
|
-
|
101
|
+
stub_locations(unsorted_locations) do
|
102
|
+
subject
|
103
|
+
File.read(filename).must_equal expected_output
|
104
|
+
end
|
86
105
|
end
|
87
106
|
end
|
88
107
|
end
|
@@ -91,11 +110,35 @@ describe Friends::Introvert do
|
|
91
110
|
end
|
92
111
|
|
93
112
|
describe "#list_friends" do
|
94
|
-
subject { introvert.list_friends }
|
113
|
+
subject { introvert.list_friends(location_name: location_name) }
|
95
114
|
|
96
|
-
|
97
|
-
|
98
|
-
|
115
|
+
describe "when no location name has been passed" do
|
116
|
+
let(:location_name) { nil }
|
117
|
+
|
118
|
+
it "lists the names of friends" do
|
119
|
+
stub_friends(friends) do
|
120
|
+
subject.must_equal friend_names
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "when a location name has been passed" do
|
126
|
+
let(:location_name) { "Atlantis" }
|
127
|
+
let(:friends) do
|
128
|
+
[
|
129
|
+
Friends::Friend.new(name: "Mark Watney", location_name: "Mars"),
|
130
|
+
Friends::Friend.new(name: "Aquaman", location_name: "Atlantis"),
|
131
|
+
Friends::Friend.new(name: "Shark-Boy", location_name: "Atlantis"),
|
132
|
+
Friends::Friend.new(name: "Ms. Nowhere")
|
133
|
+
]
|
134
|
+
end
|
135
|
+
|
136
|
+
it "lists the names of friends" do
|
137
|
+
stub_friends(friends) do
|
138
|
+
stub_locations(locations) do
|
139
|
+
subject.must_equal ["Aquaman", "Shark-Boy"]
|
140
|
+
end
|
141
|
+
end
|
99
142
|
end
|
100
143
|
end
|
101
144
|
end
|
@@ -104,14 +147,12 @@ describe Friends::Introvert do
|
|
104
147
|
let(:new_friend_name) { "Jacob Evelyn" }
|
105
148
|
subject { introvert.add_friend(name: new_friend_name) }
|
106
149
|
|
107
|
-
# Delete the file that is created each time.
|
108
|
-
after { File.delete(filename) if File.exists?(filename) }
|
109
|
-
|
110
150
|
describe "when there is no existing friend with that name" do
|
111
151
|
it "adds the given friend" do
|
112
152
|
stub_friends(friends) do
|
113
153
|
subject
|
114
|
-
introvert.list_friends.
|
154
|
+
introvert.list_friends(location_name: nil).
|
155
|
+
must_include new_friend_name
|
115
156
|
end
|
116
157
|
end
|
117
158
|
|
@@ -133,10 +174,57 @@ describe Friends::Introvert do
|
|
133
174
|
end
|
134
175
|
end
|
135
176
|
|
177
|
+
describe "#add_location" do
|
178
|
+
let(:new_location_name) { "Peru" }
|
179
|
+
subject { introvert.add_location(name: new_location_name) }
|
180
|
+
|
181
|
+
describe "when there is no existing location with that name" do
|
182
|
+
it "adds the given location" do
|
183
|
+
stub_locations(locations) do
|
184
|
+
subject
|
185
|
+
introvert.list_locations.must_include new_location_name
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns the location added" do
|
190
|
+
stub_locations(locations) do
|
191
|
+
subject.name.must_equal new_location_name
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "when there is an existing location with that name" do
|
197
|
+
let(:new_location_name) { locations.first.name }
|
198
|
+
|
199
|
+
it "raises an error" do
|
200
|
+
stub_locations(locations) do
|
201
|
+
proc { subject }.must_raise Friends::FriendsError
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "#list_locations" do
|
208
|
+
subject { introvert.list_locations }
|
209
|
+
|
210
|
+
it "lists all locations" do
|
211
|
+
stub_locations(locations) do
|
212
|
+
subject.must_equal locations.map(&:name)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
136
217
|
describe "#list_activities" do
|
137
|
-
subject
|
218
|
+
subject do
|
219
|
+
introvert.list_activities(
|
220
|
+
limit: limit,
|
221
|
+
with: with,
|
222
|
+
location_name: location_name
|
223
|
+
)
|
224
|
+
end
|
138
225
|
let(:limit) { nil }
|
139
226
|
let(:with) { nil }
|
227
|
+
let(:location_name) { nil }
|
140
228
|
|
141
229
|
describe "when the limit is lower than the number of activities" do
|
142
230
|
let(:limit) { 1 }
|
@@ -226,6 +314,74 @@ describe Friends::Introvert do
|
|
226
314
|
end
|
227
315
|
end
|
228
316
|
end
|
317
|
+
|
318
|
+
describe "when not filtering by a location" do
|
319
|
+
let(:location_name) { nil }
|
320
|
+
|
321
|
+
it "lists the activities" do
|
322
|
+
stub_activities(activities) do
|
323
|
+
subject.must_equal activities.map(&:display_text)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "when filtering by part of a location name" do
|
329
|
+
let(:location_name) { "City" }
|
330
|
+
|
331
|
+
describe "when there is more than one location match" do
|
332
|
+
let(:locations) do
|
333
|
+
[
|
334
|
+
Friends::Location.new(name: "New York City"),
|
335
|
+
Friends::Location.new(name: "Kansas City")
|
336
|
+
]
|
337
|
+
end
|
338
|
+
|
339
|
+
it "raises an error" do
|
340
|
+
stub_friends(friends) do
|
341
|
+
stub_locations(locations) do
|
342
|
+
stub_activities(activities) do
|
343
|
+
proc { subject }.must_raise Friends::FriendsError
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
describe "when there are no location matches" do
|
351
|
+
let(:locations) { [Friends::Location.new(name: "Atantis")] }
|
352
|
+
|
353
|
+
it "raises an error" do
|
354
|
+
stub_friends(friends) do
|
355
|
+
stub_locations(locations) do
|
356
|
+
stub_activities(activities) do
|
357
|
+
proc { subject }.must_raise Friends::FriendsError
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe "when there is exactly one location match" do
|
365
|
+
let(:location_name) { "Atlantis" }
|
366
|
+
let(:activities) do
|
367
|
+
[
|
368
|
+
Friends::Activity.new(str: "Swimming near _Atlantis_."),
|
369
|
+
Friends::Activity.new(str: "Swimming somewhere else.")
|
370
|
+
]
|
371
|
+
end
|
372
|
+
|
373
|
+
it "filters the activities by that location" do
|
374
|
+
stub_friends(friends) do
|
375
|
+
stub_locations(locations) do
|
376
|
+
stub_activities(activities) do
|
377
|
+
# Only one activity has that friend.
|
378
|
+
subject.must_equal activities[0..0].map(&:display_text)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
229
385
|
end
|
230
386
|
|
231
387
|
describe "#add_activity" do
|
@@ -233,9 +389,6 @@ describe Friends::Introvert do
|
|
233
389
|
let(:activity_description) { "Snorkeling with **Betsy Ross**." }
|
234
390
|
subject { introvert.add_activity(serialization: activity_serialization) }
|
235
391
|
|
236
|
-
# Delete the file that is created each time.
|
237
|
-
after { File.delete(filename) if File.exists?(filename) }
|
238
|
-
|
239
392
|
it "adds the given activity" do
|
240
393
|
stub_friends(friends) do
|
241
394
|
subject
|
@@ -293,14 +446,101 @@ describe Friends::Introvert do
|
|
293
446
|
end
|
294
447
|
end
|
295
448
|
|
449
|
+
describe "#rename_location" do
|
450
|
+
subject do
|
451
|
+
introvert.rename_location(old_name: old_name, new_name: new_name)
|
452
|
+
end
|
453
|
+
let(:old_name) { "Paris" }
|
454
|
+
let(:new_name) { "Paris, France" }
|
455
|
+
|
456
|
+
let(:activities) do
|
457
|
+
[
|
458
|
+
Friends::Activity.new(str: "Dining in _Paris_."),
|
459
|
+
Friends::Activity.new(str: "Falling in love in _Paris_."),
|
460
|
+
Friends::Activity.new(str: "Swimming near _Atlantis_.")
|
461
|
+
]
|
462
|
+
end
|
463
|
+
let(:locations) do
|
464
|
+
[
|
465
|
+
Friends::Location.new(name: "Paris"),
|
466
|
+
Friends::Location.new(name: "Atlantis")
|
467
|
+
]
|
468
|
+
end
|
469
|
+
|
470
|
+
it "replaces old name within activities to the new name" do
|
471
|
+
stub_locations(locations) do
|
472
|
+
stub_activities(activities) do
|
473
|
+
subject
|
474
|
+
introvert.activities.map do |activity|
|
475
|
+
activity.description.include? new_name
|
476
|
+
end.must_equal [true, true, false]
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
describe "when there are friends at the location" do
|
482
|
+
let(:friends) do
|
483
|
+
[
|
484
|
+
Friends::Friend.new(name: "Jacques Cousteau", location_name: "Paris"),
|
485
|
+
Friends::Friend.new(name: "Marie Antoinette", location_name: "Paris"),
|
486
|
+
Friends::Friend.new(name: "Julius Caesar", location_name: "Rome")
|
487
|
+
]
|
488
|
+
end
|
489
|
+
|
490
|
+
it "updates their locations" do
|
491
|
+
stub_locations(locations) do
|
492
|
+
stub_friends(friends) do
|
493
|
+
subject
|
494
|
+
introvert.friends.map do |friend|
|
495
|
+
friend.location_name == new_name
|
496
|
+
end.must_equal [true, true, false]
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
describe "when given names with leading and trailing spaces" do
|
503
|
+
let(:new_name) { " Paris, France " }
|
504
|
+
let(:old_name) { " Paris " }
|
505
|
+
subject do
|
506
|
+
introvert.rename_location(old_name: old_name, new_name: new_name)
|
507
|
+
end
|
508
|
+
|
509
|
+
it "correctly strips the spaces" do
|
510
|
+
stub_locations(locations) do
|
511
|
+
stub_activities(activities) do
|
512
|
+
subject
|
513
|
+
introvert.activities.map do |activity|
|
514
|
+
activity.description.include? new_name
|
515
|
+
end.must_equal [true, true, false]
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
describe "#set_location" do
|
523
|
+
subject do
|
524
|
+
introvert.set_location(
|
525
|
+
name: friend_names.first,
|
526
|
+
location_name: locations.first.name
|
527
|
+
)
|
528
|
+
end
|
529
|
+
|
530
|
+
it "returns the modified friend" do
|
531
|
+
stub_friends(friends) do
|
532
|
+
stub_locations(locations) do
|
533
|
+
subject.must_equal friends.first
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
296
539
|
describe "#add_nickname" do
|
297
540
|
subject do
|
298
541
|
introvert.add_nickname(name: friend_names.first, nickname: "The Dude")
|
299
542
|
end
|
300
543
|
|
301
|
-
# Delete the file that is created each time.
|
302
|
-
after { File.delete(filename) if File.exists?(filename) }
|
303
|
-
|
304
544
|
it "returns the modified friend" do
|
305
545
|
stub_friends(friends) do
|
306
546
|
subject.must_equal friends.first
|
@@ -313,9 +553,6 @@ describe Friends::Introvert do
|
|
313
553
|
introvert.remove_nickname(name: "Jeff", nickname: "The Dude")
|
314
554
|
end
|
315
555
|
|
316
|
-
# Delete the file that is created each time.
|
317
|
-
after { File.delete(filename) if File.exists?(filename) }
|
318
|
-
|
319
556
|
it "returns the modified friend" do
|
320
557
|
friend = Friends::Friend.new(name: "Jeff",
|
321
558
|
nickname_str: "a.k.a. The Dude")
|
@@ -357,28 +594,61 @@ describe Friends::Introvert do
|
|
357
594
|
end
|
358
595
|
|
359
596
|
describe "#suggest" do
|
360
|
-
subject { introvert.suggest }
|
597
|
+
subject { introvert.suggest(location_name: location_name) }
|
361
598
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
599
|
+
describe "when no location name is passed" do
|
600
|
+
let(:location_name) { nil }
|
601
|
+
|
602
|
+
it "returns distant, moderate, and close friends" do
|
603
|
+
stub_friends(friends) do
|
604
|
+
stub_activities(activities) do
|
605
|
+
subject.must_equal(
|
606
|
+
distant: ["George Washington Carver"],
|
607
|
+
moderate: [],
|
608
|
+
close: ["Betsy Ross"]
|
609
|
+
)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
it "doesn't choke when there are no friends" do
|
615
|
+
stub_friends([]) do
|
616
|
+
stub_activities([]) do
|
617
|
+
subject.must_equal(
|
618
|
+
distant: [],
|
619
|
+
moderate: [],
|
620
|
+
close: []
|
621
|
+
)
|
622
|
+
end
|
370
623
|
end
|
371
624
|
end
|
372
625
|
end
|
373
626
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
627
|
+
describe "when a location name is passed" do
|
628
|
+
let(:location_name) { "USA" }
|
629
|
+
|
630
|
+
it "returns distant, moderate, and close friends" do
|
631
|
+
friends.first.location_name = location_name
|
632
|
+
stub_friends(friends) do
|
633
|
+
stub_activities(activities) do
|
634
|
+
subject.must_equal(
|
635
|
+
distant: ["George Washington Carver"],
|
636
|
+
moderate: [],
|
637
|
+
close: []
|
638
|
+
)
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
it "doesn't choke when there are no friends" do
|
644
|
+
stub_friends([]) do
|
645
|
+
stub_activities([]) do
|
646
|
+
subject.must_equal(
|
647
|
+
distant: [],
|
648
|
+
moderate: [],
|
649
|
+
close: []
|
650
|
+
)
|
651
|
+
end
|
382
652
|
end
|
383
653
|
end
|
384
654
|
end
|
@@ -431,12 +701,14 @@ describe Friends::Introvert do
|
|
431
701
|
it "returns a hash of months and frequencies" do
|
432
702
|
stub_friends(friends) do
|
433
703
|
stub_activities(activities) do
|
434
|
-
subject.must_equal(
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
704
|
+
subject.must_equal(
|
705
|
+
{
|
706
|
+
"Jan 2016" => 1,
|
707
|
+
"Feb 2016" => 1,
|
708
|
+
"Mar 2016" => 0,
|
709
|
+
"Apr 2016" => 1
|
710
|
+
}
|
711
|
+
)
|
440
712
|
end
|
441
713
|
end
|
442
714
|
end
|
@@ -448,11 +720,13 @@ describe Friends::Introvert do
|
|
448
720
|
it "returns a hash of months and frequencies" do
|
449
721
|
stub_friends(friends) do
|
450
722
|
stub_activities(activities) do
|
451
|
-
subject.must_equal(
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
723
|
+
subject.must_equal(
|
724
|
+
{
|
725
|
+
"Feb 2016" => 1,
|
726
|
+
"Mar 2016" => 0,
|
727
|
+
"Apr 2016" => 1
|
728
|
+
}
|
729
|
+
)
|
456
730
|
end
|
457
731
|
end
|
458
732
|
end
|