friends 0.51 → 0.55
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +1 -1
- data/.github/PULL_REQUEST_TEMPLATE.md +2 -2
- data/.github/workflows/main.yml +36 -0
- data/CHANGELOG.md +67 -4
- data/Gemfile +2 -2
- data/README.md +108 -50
- data/RELEASING.md +1 -1
- data/bin/friends +2 -2
- data/lib/friends/commands/add.rb +12 -3
- data/lib/friends/commands/list.rb +33 -20
- data/lib/friends/commands/remove.rb +9 -0
- data/lib/friends/introvert.rb +112 -64
- data/lib/friends/location.rb +39 -7
- data/lib/friends/version.rb +1 -1
- data/test/commands/add/alias_spec.rb +74 -0
- data/test/commands/add/nickname_spec.rb +9 -0
- data/test/commands/add/tag_spec.rb +9 -0
- data/test/commands/edit_spec.rb +1 -0
- data/test/commands/list/friends_spec.rb +101 -7
- data/test/commands/list/locations_spec.rb +104 -2
- data/test/commands/remove/alias_spec.rb +68 -0
- data/test/commands/remove/tag_spec.rb +9 -0
- data/test/commands/stats_spec.rb +1 -1
- data/test/default_file_spec.rb +1 -1
- data/test/helper.rb +14 -1
- metadata +10 -10
- data/.travis.yml +0 -23
- data/test/commands/list/favorite/friends_spec.rb +0 -113
- data/test/commands/list/favorite/locations_spec.rb +0 -149
data/RELEASING.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
These are steps for the maintainer to take to release a new version of this gem.
|
4
4
|
|
5
|
-
1. On the `
|
5
|
+
1. On the `main` branch, update the `VERSION` constant in
|
6
6
|
`lib/friends/version.rb`.
|
7
7
|
2. Commit the change (`git add -A && git commit -m 'Bump to vX.X'`).
|
8
8
|
3. Add a tag (`git tag -am "vX.X" vX.X`).
|
data/bin/friends
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
if ENV["
|
4
|
+
if ENV["CI"] == "true" && ENV["CODE_COVERAGE"] == "true"
|
5
5
|
require "simplecov"
|
6
6
|
SimpleCov.print_error_status = false
|
7
7
|
SimpleCov.formatter = SimpleCov::Formatter::SimpleFormatter
|
@@ -34,7 +34,7 @@ class Tag
|
|
34
34
|
# conversions for arguments.
|
35
35
|
# See: https://github.com/davetron5000/gli/issues/241
|
36
36
|
def self.convert_to_tag(str)
|
37
|
-
str = str.strip
|
37
|
+
str = str.to_s.strip
|
38
38
|
!str.empty? && str[0] == "@" ? str : "@#{str}"
|
39
39
|
end
|
40
40
|
end
|
data/lib/friends/commands/add.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
desc "Adds a friend (or nickname), activity, note, or location"
|
3
|
+
desc "Adds a friend (or nickname), activity, note, or location (or alias)"
|
4
4
|
command :add do |add|
|
5
5
|
add.desc "Adds a friend"
|
6
6
|
add.arg_name "NAME"
|
@@ -35,7 +35,16 @@ command :add do |add|
|
|
35
35
|
add.arg_name "NAME NICKNAME"
|
36
36
|
add.command :nickname do |add_nickname|
|
37
37
|
add_nickname.action do |_, _, args|
|
38
|
-
@introvert.add_nickname(name: args.first.strip, nickname: args[1].strip)
|
38
|
+
@introvert.add_nickname(name: args.first.to_s.strip, nickname: args[1].to_s.strip)
|
39
|
+
@dirty = true # Mark the file for cleaning.
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
add.desc "Adds an alias to a location"
|
44
|
+
add.arg_name "LOCATION ALIAS"
|
45
|
+
add.command :alias do |add_alias|
|
46
|
+
add_alias.action do |_, _, args|
|
47
|
+
@introvert.add_alias(name: args.first.to_s.strip, nickname: args[1].to_s.strip)
|
39
48
|
@dirty = true # Mark the file for cleaning.
|
40
49
|
end
|
41
50
|
end
|
@@ -46,7 +55,7 @@ command :add do |add|
|
|
46
55
|
add_tag.action do |_, _, args|
|
47
56
|
@introvert.add_tag(
|
48
57
|
name: args[0..-2].join(" "),
|
49
|
-
tag: Tag.convert_to_tag(args.last.strip)
|
58
|
+
tag: Tag.convert_to_tag(args.last.to_s.strip)
|
50
59
|
)
|
51
60
|
@dirty = true # Mark the file for cleaning.
|
52
61
|
end
|
@@ -19,11 +19,23 @@ command :list do |list|
|
|
19
19
|
negatable: false,
|
20
20
|
desc: "Output friend nicknames, locations, and tags"
|
21
21
|
|
22
|
+
list_friends.flag :sort,
|
23
|
+
default_value: "alphabetical",
|
24
|
+
arg_name: "ATTRIBUTE",
|
25
|
+
must_match: %w[alphabetical n-activities recency],
|
26
|
+
desc: "Sort output by one of: alphabetical, n-activities, recency"
|
27
|
+
|
28
|
+
list_friends.switch :reverse,
|
29
|
+
negatable: false,
|
30
|
+
desc: "Reverse the sort order"
|
31
|
+
|
22
32
|
list_friends.action do |_, options|
|
23
33
|
@introvert.list_friends(
|
24
34
|
location_name: options[:in],
|
25
35
|
tagged: options[:tagged],
|
26
|
-
verbose: options[:verbose]
|
36
|
+
verbose: options[:verbose],
|
37
|
+
sort: options[:sort],
|
38
|
+
reverse: options[:reverse]
|
27
39
|
)
|
28
40
|
end
|
29
41
|
end
|
@@ -73,8 +85,26 @@ command :list do |list|
|
|
73
85
|
|
74
86
|
list.desc "List all locations"
|
75
87
|
list.command :locations do |list_locations|
|
76
|
-
list_locations.
|
77
|
-
|
88
|
+
list_locations.switch [:verbose],
|
89
|
+
negatable: false,
|
90
|
+
desc: "Output location aliases"
|
91
|
+
|
92
|
+
list_locations.flag :sort,
|
93
|
+
default_value: "alphabetical",
|
94
|
+
arg_name: "ATTRIBUTE",
|
95
|
+
must_match: %w[alphabetical n-activities recency],
|
96
|
+
desc: "Sort output by one of: alphabetical, n-activities, recency"
|
97
|
+
|
98
|
+
list_locations.switch :reverse,
|
99
|
+
negatable: false,
|
100
|
+
desc: "Reverse the sort order"
|
101
|
+
|
102
|
+
list_locations.action do |_, options|
|
103
|
+
@introvert.list_locations(
|
104
|
+
verbose: options[:verbose],
|
105
|
+
sort: options[:sort],
|
106
|
+
reverse: options[:reverse]
|
107
|
+
)
|
78
108
|
end
|
79
109
|
end
|
80
110
|
|
@@ -89,21 +119,4 @@ command :list do |list|
|
|
89
119
|
@introvert.list_tags(from: options[:from])
|
90
120
|
end
|
91
121
|
end
|
92
|
-
|
93
|
-
list.desc "List favorite friends and locations"
|
94
|
-
list.command :favorite do |list_favorite|
|
95
|
-
list_favorite.desc "List favorite friends"
|
96
|
-
list_favorite.command :friends do |list_favorite_friends|
|
97
|
-
list_favorite_friends.action do
|
98
|
-
@introvert.list_favorite_friends
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
list_favorite.desc "List favorite locations"
|
103
|
-
list_favorite.command :locations do |list_favorite_locations|
|
104
|
-
list_favorite_locations.action do
|
105
|
-
@introvert.list_favorite_locations
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
122
|
end
|
@@ -11,6 +11,15 @@ command :remove do |remove|
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
remove.desc "Removes an alias from a location"
|
15
|
+
remove.arg_name "LOCATION ALIAS"
|
16
|
+
remove.command :alias do |remove_alias|
|
17
|
+
remove_alias.action do |_, _, args|
|
18
|
+
@introvert.remove_alias(name: args.first.to_s.strip, nickname: args[1].to_s.strip)
|
19
|
+
@dirty = true # Mark the file for cleaning.
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
remove.desc "Removes a tag from a friend"
|
15
24
|
remove.arg_name "NAME @TAG"
|
16
25
|
remove.command :tag do |remove_tag|
|
data/lib/friends/introvert.rb
CHANGED
@@ -203,6 +203,7 @@ module Friends
|
|
203
203
|
# @param nickname [String] the nickname to add to the friend
|
204
204
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
205
205
|
def add_nickname(name:, nickname:)
|
206
|
+
raise FriendsError, "Expected \"[Friend Name]\" \"[Nickname]\"" if name.empty?
|
206
207
|
raise FriendsError, "Nickname cannot be blank" if nickname.empty?
|
207
208
|
|
208
209
|
friend = thing_with_name_in(:friend, name)
|
@@ -211,11 +212,37 @@ module Friends
|
|
211
212
|
@output << "Nickname added: \"#{friend}\""
|
212
213
|
end
|
213
214
|
|
215
|
+
# Add an alias to an existing location.
|
216
|
+
# @param name [String] the name of the location
|
217
|
+
# @param nickname [String] the alias to add to the location
|
218
|
+
# @raise [FriendsError] if 0 or 2+ locations match the given name
|
219
|
+
# @raise [FriendsError] if the alias is already taken
|
220
|
+
def add_alias(name:, nickname:)
|
221
|
+
raise FriendsError, "Expected \"[Location Name]\" \"[Alias]\"" if name.empty?
|
222
|
+
raise FriendsError, "Alias cannot be blank" if nickname.empty?
|
223
|
+
|
224
|
+
collision = @locations.find do |loc|
|
225
|
+
loc.name.casecmp(nickname).zero? || loc.aliases.any? { |a| a.casecmp(nickname).zero? }
|
226
|
+
end
|
227
|
+
|
228
|
+
if collision
|
229
|
+
raise FriendsError,
|
230
|
+
"The location alias \"#{nickname}\" is already taken by "\
|
231
|
+
"\"#{collision}\""
|
232
|
+
end
|
233
|
+
|
234
|
+
location = thing_with_name_in(:location, name)
|
235
|
+
location.add_alias(nickname)
|
236
|
+
|
237
|
+
@output << "Alias added: \"#{location}\""
|
238
|
+
end
|
239
|
+
|
214
240
|
# Add a tag to an existing friend.
|
215
241
|
# @param name [String] the name of the friend
|
216
242
|
# @param tag [String] the tag to add to the friend, of the form: "@tag"
|
217
243
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
218
244
|
def add_tag(name:, tag:)
|
245
|
+
raise FriendsError, "Expected \"[Friend Name]\" \"[Tag]\"" if name.empty?
|
219
246
|
raise FriendsError, "Tag cannot be blank" if tag == "@"
|
220
247
|
|
221
248
|
friend = thing_with_name_in(:friend, name)
|
@@ -248,6 +275,21 @@ module Friends
|
|
248
275
|
@output << "Nickname removed: \"#{friend}\""
|
249
276
|
end
|
250
277
|
|
278
|
+
# Remove an alias from an existing location.
|
279
|
+
# @param name [String] the name of the location
|
280
|
+
# @param nickname [String] the alias to remove from the location
|
281
|
+
# @raise [FriendsError] if 0 or 2+ locations match the given name
|
282
|
+
# @raise [FriendsError] if the location does not have the given alias
|
283
|
+
def remove_alias(name:, nickname:)
|
284
|
+
raise FriendsError, "Expected \"[Location Name]\" \"[Alias]\"" if name.empty?
|
285
|
+
raise FriendsError, "Alias cannot be blank" if nickname.empty?
|
286
|
+
|
287
|
+
location = thing_with_name_in(:location, name)
|
288
|
+
location.remove_alias(nickname)
|
289
|
+
|
290
|
+
@output << "Alias removed: \"#{location}\""
|
291
|
+
end
|
292
|
+
|
251
293
|
# List all friend names in the friends file.
|
252
294
|
# @param location_name [String] the name of a location to filter by, or nil
|
253
295
|
# for unfiltered
|
@@ -255,7 +297,11 @@ module Friends
|
|
255
297
|
# unfiltered
|
256
298
|
# @param verbose [Boolean] true iff we should output friend names with
|
257
299
|
# nicknames, locations, and tags; false for names only
|
258
|
-
|
300
|
+
# @param sort [String] one of:
|
301
|
+
# ["alphabetical", "n-activities", "recency"]
|
302
|
+
# @param reverse [Boolean] true iff we should reverse the sorted order of
|
303
|
+
# our output
|
304
|
+
def list_friends(location_name:, tagged:, verbose:, sort:, reverse:)
|
259
305
|
fs = @friends
|
260
306
|
|
261
307
|
# Filter by location if a name is passed.
|
@@ -271,18 +317,11 @@ module Friends
|
|
271
317
|
end
|
272
318
|
end
|
273
319
|
|
274
|
-
(
|
320
|
+
list_things(type: :friend, arr: fs, verbose: verbose, sort: sort, reverse: reverse)
|
275
321
|
end
|
276
322
|
|
277
|
-
|
278
|
-
|
279
|
-
list_favorite_things(:friend)
|
280
|
-
end
|
281
|
-
|
282
|
-
# List your favorite friends.
|
283
|
-
def list_favorite_locations
|
284
|
-
list_favorite_things(:location)
|
285
|
-
end
|
323
|
+
NA_STR = "N/A"
|
324
|
+
private_constant :NA_STR
|
286
325
|
|
287
326
|
# See `list_events` for all of the parameters we can pass.
|
288
327
|
def list_activities(**args)
|
@@ -295,8 +334,14 @@ module Friends
|
|
295
334
|
end
|
296
335
|
|
297
336
|
# List all location names in the friends file.
|
298
|
-
|
299
|
-
|
337
|
+
# @param verbose [Boolean] true iff we should output location names with
|
338
|
+
# aliases; false for names only
|
339
|
+
# @param sort [String] one of:
|
340
|
+
# ["alphabetical", "n-activities", "recency"]
|
341
|
+
# @param reverse [Boolean] true iff we should reverse the sorted order of
|
342
|
+
# our output
|
343
|
+
def list_locations(verbose:, sort:, reverse:)
|
344
|
+
list_things(type: :location, verbose: verbose, sort: sort, reverse: reverse)
|
300
345
|
end
|
301
346
|
|
302
347
|
# @param from [Array] containing any of: ["activities", "friends", "notes"]
|
@@ -427,16 +472,16 @@ module Friends
|
|
427
472
|
#
|
428
473
|
# The returned hash uses the following format:
|
429
474
|
# {
|
430
|
-
# /regex/ =>
|
475
|
+
# /regex/ => location
|
431
476
|
# }
|
432
477
|
#
|
433
478
|
# This hash is sorted (because Ruby's hashes are ordered) by decreasing
|
434
479
|
# regex key length, so the key /Paris, France/ appears before /Paris/.
|
435
480
|
#
|
436
|
-
# @return [Hash{Regexp =>
|
481
|
+
# @return [Hash{Regexp => location}]
|
437
482
|
def regex_location_map
|
438
483
|
@locations.each_with_object({}) do |location, hash|
|
439
|
-
hash[
|
484
|
+
location.regexes_for_name.each { |regex| hash[regex] = location }
|
440
485
|
end.sort_by { |k, _| -k.to_s.size }.to_h
|
441
486
|
end
|
442
487
|
|
@@ -495,6 +540,49 @@ module Friends
|
|
495
540
|
|
496
541
|
private
|
497
542
|
|
543
|
+
# List either friends or activities
|
544
|
+
# @param arr [Array<Friend|Activity>] a filtered list to print
|
545
|
+
# @param verbose [Boolean] true iff we should output names with
|
546
|
+
# aliases/nicknames/etc.; false for names only
|
547
|
+
# @param sort [String] one of:
|
548
|
+
# ["alphabetical", "n-activities", "recency"]
|
549
|
+
# @param reverse [Boolean] true iff we should reverse the sorted order of
|
550
|
+
# our output
|
551
|
+
def list_things(type:, arr: instance_variable_get("@#{type}s"), verbose:, sort:, reverse:)
|
552
|
+
case sort
|
553
|
+
when "alphabetical"
|
554
|
+
arr = stable_sort(arr) # In case the input file was not already sorted.
|
555
|
+
when "n-activities"
|
556
|
+
arr = stable_sort_by(arr) { |thing| -thing.n_activities }
|
557
|
+
when "recency"
|
558
|
+
today = Date.today
|
559
|
+
|
560
|
+
most_recent_activity_by_thing = @activities.each_with_object({}) do |activity, output|
|
561
|
+
activity.send("#{type}_names").each do |thing_name|
|
562
|
+
output[thing_name] = (today - activity.date).to_i unless output.key?(thing_name)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
arr = stable_sort_by(arr) do |thing|
|
567
|
+
most_recent_activity_by_thing[thing.name] || -Float::INFINITY
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
(reverse ? arr.reverse : arr).each do |thing|
|
572
|
+
case sort
|
573
|
+
when "n-activities"
|
574
|
+
prefix = "#{Paint[thing.n_activities, :bold, :red]} "\
|
575
|
+
"activit#{thing.n_activities == 1 ? 'y' : 'ies'}: "
|
576
|
+
when "recency"
|
577
|
+
n_days = most_recent_activity_by_thing[thing.name] || NA_STR
|
578
|
+
prefix = "#{Paint[n_days, :bold, :red]} "\
|
579
|
+
"day#{'s' unless n_days == 1} ago: "
|
580
|
+
end
|
581
|
+
|
582
|
+
@output << "#{prefix}#{verbose ? thing.to_s : thing.name}"
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
498
586
|
# @param from [Array] containing any of: ["activities", "friends", "notes"]
|
499
587
|
# If not empty, limits the tags returned to only those from either
|
500
588
|
# activities, notes, or friends.
|
@@ -544,6 +632,13 @@ module Friends
|
|
544
632
|
arr.sort_by.with_index { |x, idx| [x, idx] }
|
545
633
|
end
|
546
634
|
|
635
|
+
# @param arr [Array] an unsorted array
|
636
|
+
# @param &block [block] used to return a value for each element's sort position
|
637
|
+
# @return [Array] a stably-sorted array
|
638
|
+
def stable_sort_by(arr)
|
639
|
+
arr.sort_by.with_index { |x, idx| [yield(x), idx] }
|
640
|
+
end
|
641
|
+
|
547
642
|
# Filter activities by friend, location and tag
|
548
643
|
# @param events [Array<Event>] the base events to list, either @activities or @notes
|
549
644
|
# @param with [Array<String>] the names of friends to filter by, or empty for
|
@@ -586,49 +681,6 @@ module Friends
|
|
586
681
|
events
|
587
682
|
end
|
588
683
|
|
589
|
-
# @param type [Symbol] one of: [:friend, :location]
|
590
|
-
# @raise [ArgumentError] if type is not one of: [:friend, :location]
|
591
|
-
def list_favorite_things(type)
|
592
|
-
unless [:friend, :location].include? type
|
593
|
-
raise ArgumentError, "Type must be either :friend or :location"
|
594
|
-
end
|
595
|
-
|
596
|
-
# Sort the results, with the most favorite thing first.
|
597
|
-
results = instance_variable_get("@#{type}s").sort_by do |thing|
|
598
|
-
-thing.n_activities
|
599
|
-
end
|
600
|
-
|
601
|
-
@output << "Your favorite #{type}s:"
|
602
|
-
|
603
|
-
max_str_size = results.map(&:name).map(&:size).max
|
604
|
-
|
605
|
-
grouped_results = results.group_by(&:n_activities)
|
606
|
-
|
607
|
-
rank = 1
|
608
|
-
first = true
|
609
|
-
data = grouped_results.each.with_object([]) do |(n_activities, things), arr|
|
610
|
-
things.each do |thing|
|
611
|
-
name = thing.name.ljust(max_str_size)
|
612
|
-
if first
|
613
|
-
label = n_activities == 1 ? " activity" : " activities"
|
614
|
-
first = false
|
615
|
-
end
|
616
|
-
str = "#{name} (#{n_activities}#{label})"
|
617
|
-
|
618
|
-
arr << [rank, str]
|
619
|
-
end
|
620
|
-
rank += things.size
|
621
|
-
end
|
622
|
-
|
623
|
-
# We need to use `data.last.first` instead of `rank` to determine the size
|
624
|
-
# of the numbering prefix because `rank` will simply be the size of all
|
625
|
-
# elements, which may be too large if the last element in the list is a tie.
|
626
|
-
num_str_size = data.last.first.to_s.size + 1 unless data.empty?
|
627
|
-
data.each do |ranking, str|
|
628
|
-
@output << "#{"#{ranking}.".ljust(num_str_size)} #{str}"
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
684
|
# Sets the n_activities field on each thing.
|
633
685
|
# @param type [Symbol] one of: [:friend, :location]
|
634
686
|
# @raise [ArgumentError] if `type` is not one of: [:friend, :location]
|
@@ -749,11 +801,7 @@ module Friends
|
|
749
801
|
# @raise [FriendsError] if 0 or 2+ friends match the given text
|
750
802
|
def thing_with_name_in(type, text)
|
751
803
|
things = instance_variable_get("@#{type}s").select do |thing|
|
752
|
-
|
753
|
-
thing.regexes_for_name.any? { |regex| regex.match(text) }
|
754
|
-
else
|
755
|
-
thing.regex_for_name.match(text)
|
756
|
-
end
|
804
|
+
thing.regexes_for_name.any? { |regex| regex.match(text) }
|
757
805
|
end
|
758
806
|
|
759
807
|
# If there's more than one match with fuzzy regexes but exactly one thing
|
data/lib/friends/location.rb
CHANGED
@@ -10,11 +10,12 @@ module Friends
|
|
10
10
|
extend Serializable
|
11
11
|
|
12
12
|
SERIALIZATION_PREFIX = "- "
|
13
|
+
ALIAS_PREFIX = "a.k.a. "
|
13
14
|
|
14
15
|
# @return [Regexp] the regex for capturing groups in deserialization
|
15
16
|
def self.deserialization_regex
|
16
17
|
# Note: this regex must be on one line because whitespace is important
|
17
|
-
/(#{SERIALIZATION_PREFIX})?(?<name>.+)
|
18
|
+
/(#{SERIALIZATION_PREFIX})?(?<name>[^\(]*[^\(\s])(\s+\(#{ALIAS_PREFIX}(?<alias_str>.+)\))?/
|
18
19
|
end
|
19
20
|
|
20
21
|
# @return [Regexp] the string of what we expected during deserialization
|
@@ -23,21 +24,52 @@ module Friends
|
|
23
24
|
end
|
24
25
|
|
25
26
|
# @param name [String] the name of the location
|
26
|
-
def initialize(name:)
|
27
|
+
def initialize(name:, alias_str: nil)
|
27
28
|
@name = name
|
29
|
+
@aliases = alias_str&.split(" #{ALIAS_PREFIX}") || []
|
28
30
|
end
|
29
31
|
|
30
32
|
attr_accessor :name
|
33
|
+
attr_reader :aliases
|
31
34
|
|
32
35
|
# @return [String] the file serialization text for the location
|
33
36
|
def serialize
|
34
|
-
"#{SERIALIZATION_PREFIX}#{
|
37
|
+
Paint.unpaint("#{SERIALIZATION_PREFIX}#{self}")
|
35
38
|
end
|
36
39
|
|
37
|
-
# @return [
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
# @return [String] a string representing the location's name and aliases
|
41
|
+
def to_s
|
42
|
+
unless @aliases.empty?
|
43
|
+
alias_str = " (" +
|
44
|
+
@aliases.map do |nickname|
|
45
|
+
"#{ALIAS_PREFIX}#{Paint[nickname, :bold, :yellow]}"
|
46
|
+
end.join(" ") + ")"
|
47
|
+
end
|
48
|
+
|
49
|
+
"#{Paint[@name, :bold]}#{alias_str}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add an alias, ignoring duplicates.
|
53
|
+
# @param nickname [String] the alias to add
|
54
|
+
def add_alias(nickname)
|
55
|
+
@aliases << nickname
|
56
|
+
@aliases.uniq!
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param nickname [String] the alias to remove
|
60
|
+
# @raise [FriendsError] if the location does not have the given alias
|
61
|
+
def remove_alias(nickname)
|
62
|
+
unless @aliases.include? nickname
|
63
|
+
raise FriendsError, "Alias \"#{nickname}\" not found for \"#{name}\""
|
64
|
+
end
|
65
|
+
|
66
|
+
@aliases.delete(nickname)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Array] a list of all regexes to match the name in a string
|
70
|
+
# NOTE: Only full names and aliases
|
71
|
+
def regexes_for_name
|
72
|
+
[name, *@aliases].map { |str| Friends::RegexBuilder.regex(str) }
|
41
73
|
end
|
42
74
|
|
43
75
|
# The number of activities this location is in. This is for internal use
|