friends 0.35 → 0.36
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +20 -0
- data/README.md +103 -6
- data/bin/friends +12 -16
- data/lib/friends/commands/add.rb +5 -17
- data/lib/friends/commands/edit.rb +13 -2
- data/lib/friends/commands/list.rb +4 -4
- data/lib/friends/commands/remove.rb +2 -4
- data/lib/friends/commands/rename.rb +2 -4
- data/lib/friends/commands/set.rb +1 -2
- data/lib/friends/commands/stats.rb +1 -7
- data/lib/friends/commands/suggest.rb +1 -8
- data/lib/friends/commands/update.rb +12 -13
- data/lib/friends/event.rb +2 -2
- data/lib/friends/introvert.rb +122 -110
- data/lib/friends/version.rb +1 -1
- data/test/commands/clean_spec.rb +88 -1
- data/test/commands/edit_spec.rb +125 -17
- data/test/commands/rename/friend_spec.rb +7 -0
- data/test/commands/rename/location_spec.rb +8 -0
- data/test/commands/set/location_spec.rb +2 -2
- data/test/editor +15 -0
- data/test/helper.rb +2 -2
- metadata +4 -2
@@ -8,13 +8,6 @@ command :suggest do |suggest|
|
|
8
8
|
type: Stripped
|
9
9
|
|
10
10
|
suggest.action do |_, options|
|
11
|
-
|
12
|
-
|
13
|
-
puts "Distant friend: "\
|
14
|
-
"#{Paint[suggestions[:distant].sample || 'None found', :bold, :magenta]}"
|
15
|
-
puts "Moderate friend: "\
|
16
|
-
"#{Paint[suggestions[:moderate].sample || 'None found', :bold, :magenta]}"
|
17
|
-
puts "Close friend: "\
|
18
|
-
"#{Paint[suggestions[:close].sample || 'None found', :bold, :magenta]}"
|
11
|
+
@introvert.suggest(location_name: options[:in])
|
19
12
|
end
|
20
13
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
desc "Updates the `friends` program"
|
4
4
|
command :update do |update|
|
5
|
-
update.action do
|
5
|
+
update.action do |global_options|
|
6
6
|
# rubocop:disable Lint/AssignmentInCondition
|
7
7
|
if match = `gem search friends`.match(/^friends\s\(([^\)]+)\)$/)
|
8
8
|
# rubocop:enable Lint/AssignmentInCondition
|
@@ -10,19 +10,18 @@ command :update do |update|
|
|
10
10
|
if Semverse::Version.coerce(remote_version) >
|
11
11
|
Semverse::Version.coerce(Friends::VERSION)
|
12
12
|
`gem update friends && gem cleanup friends`
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
13
|
+
|
14
|
+
unless global_options[:quiet]
|
15
|
+
if $?.success?
|
16
|
+
puts Paint["Updated to friends #{remote_version}", :bold, :green]
|
17
|
+
else
|
18
|
+
puts Paint["Error updating to friends version #{remote_version}", :bold, :red]
|
19
|
+
end
|
20
|
+
end
|
22
21
|
else
|
23
|
-
|
24
|
-
"Already up-to-date (#{Friends::VERSION})", :bold, :green
|
25
|
-
|
22
|
+
unless global_options[:quiet]
|
23
|
+
puts Paint["Already up-to-date (#{Friends::VERSION})", :bold, :green]
|
24
|
+
end
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
data/lib/friends/event.rb
CHANGED
@@ -156,13 +156,13 @@ module Friends
|
|
156
156
|
# Find the names of all friends in this description.
|
157
157
|
# @return [Array] list of all friend names in the description
|
158
158
|
def friend_names
|
159
|
-
@
|
159
|
+
@description.scan(/(?<=\*\*)\w[^\*]*(?=\*\*)/).uniq
|
160
160
|
end
|
161
161
|
|
162
162
|
# Find the names of all locations in this description.
|
163
163
|
# @return [Array] list of all location names in the description
|
164
164
|
def location_names
|
165
|
-
@
|
165
|
+
@description.scan(/(?<=_)\w[^_]*(?=_)/).uniq
|
166
166
|
end
|
167
167
|
|
168
168
|
private
|
data/lib/friends/introvert.rb
CHANGED
@@ -15,15 +15,16 @@ require "friends/friends_error"
|
|
15
15
|
|
16
16
|
module Friends
|
17
17
|
class Introvert
|
18
|
-
DEFAULT_FILENAME = "./friends.md".freeze
|
19
18
|
ACTIVITIES_HEADER = "### Activities:".freeze
|
20
19
|
NOTES_HEADER = "### Notes:".freeze
|
21
20
|
FRIENDS_HEADER = "### Friends:".freeze
|
22
21
|
LOCATIONS_HEADER = "### Locations:".freeze
|
23
22
|
|
24
23
|
# @param filename [String] the name of the friends Markdown file
|
25
|
-
|
24
|
+
# @param quiet [Boolean] true iff we should suppress all STDOUT output
|
25
|
+
def initialize(filename:, quiet:)
|
26
26
|
@filename = filename
|
27
|
+
@quiet = quiet
|
27
28
|
|
28
29
|
# Read in the input file. It's easier to do this now and optimize later
|
29
30
|
# than try to overly be clever about what we read and write.
|
@@ -31,7 +32,25 @@ module Friends
|
|
31
32
|
end
|
32
33
|
|
33
34
|
# Write out the friends file with cleaned/sorted data.
|
34
|
-
|
35
|
+
# @param clean_command [Boolean] true iff the command the user
|
36
|
+
# executed is `friends clean`; false if this is called as the
|
37
|
+
# result of another command
|
38
|
+
def clean(clean_command:)
|
39
|
+
friend_names = Set.new(@friends.map(&:name))
|
40
|
+
location_names = Set.new(@locations.map(&:name))
|
41
|
+
|
42
|
+
# Iterate through all events and add missing friends and
|
43
|
+
# locations.
|
44
|
+
(@activities + @notes).each do |event|
|
45
|
+
event.friend_names.each do |name|
|
46
|
+
add_friend(name: name) unless friend_names.include? name
|
47
|
+
end
|
48
|
+
|
49
|
+
event.location_names.each do |name|
|
50
|
+
add_location(name: name) unless location_names.include? name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
35
54
|
File.open(@filename, "w") do |file|
|
36
55
|
file.puts(ACTIVITIES_HEADER)
|
37
56
|
stable_sort(@activities).each { |act| file.puts(act.serialize) }
|
@@ -46,13 +65,14 @@ module Friends
|
|
46
65
|
@locations.sort.each { |location| file.puts(location.serialize) }
|
47
66
|
end
|
48
67
|
|
49
|
-
|
68
|
+
# This is a special-case piece of code that lets us print a message that
|
69
|
+
# includes the filename when `friends clean` is called.
|
70
|
+
safe_puts "File cleaned: \"#{@filename}\"" if clean_command
|
50
71
|
end
|
51
72
|
|
52
73
|
# Add a friend.
|
53
74
|
# @param name [String] the name of the friend to add
|
54
75
|
# @raise [FriendsError] when a friend with that name is already in the file
|
55
|
-
# @return [Friend] the added friend
|
56
76
|
def add_friend(name:)
|
57
77
|
if @friends.any? { |friend| friend.name == name }
|
58
78
|
raise FriendsError, "Friend named \"#{name}\" already exists"
|
@@ -62,32 +82,45 @@ module Friends
|
|
62
82
|
|
63
83
|
@friends << friend
|
64
84
|
|
65
|
-
|
85
|
+
safe_puts "Friend added: \"#{friend.name}\""
|
66
86
|
end
|
67
87
|
|
68
88
|
# Add an activity.
|
69
89
|
# @param serialization [String] the serialized activity
|
70
|
-
# @return [Activity] the added activity
|
71
90
|
def add_activity(serialization:)
|
72
91
|
Activity.deserialize(serialization).tap do |activity|
|
73
|
-
|
92
|
+
# If there's no description, prompt the user for one.
|
93
|
+
if activity.description.nil? || activity.description.empty?
|
94
|
+
activity.description = Readline.readline(activity.to_s)
|
95
|
+
end
|
96
|
+
|
97
|
+
activity.highlight_description(introvert: self)
|
98
|
+
|
74
99
|
@activities.unshift(activity)
|
100
|
+
|
101
|
+
safe_puts "Activity added: \"#{activity}\""
|
75
102
|
end
|
76
103
|
end
|
77
104
|
|
78
105
|
# Add a note.
|
79
106
|
# @param serialization [String] the serialized note
|
80
|
-
# @return [Note] the added note
|
81
107
|
def add_note(serialization:)
|
82
108
|
Note.deserialize(serialization).tap do |note|
|
83
|
-
|
109
|
+
# If there's no description, prompt the user for one.
|
110
|
+
if note.description.nil? || note.description.empty?
|
111
|
+
note.description = Readline.readline(note.to_s)
|
112
|
+
end
|
113
|
+
|
114
|
+
note.highlight_description(introvert: self)
|
115
|
+
|
84
116
|
@notes.unshift(note)
|
117
|
+
|
118
|
+
safe_puts "Note added: \"#{note}\""
|
85
119
|
end
|
86
120
|
end
|
87
121
|
|
88
122
|
# Add a location.
|
89
123
|
# @param name [String] the serialized location
|
90
|
-
# @return [Location] the added location
|
91
124
|
# @raise [FriendsError] if a location with that name already exists
|
92
125
|
def add_location(name:)
|
93
126
|
if @locations.any? { |location| location.name == name }
|
@@ -98,7 +131,7 @@ module Friends
|
|
98
131
|
|
99
132
|
@locations << location
|
100
133
|
|
101
|
-
location # Return the added location.
|
134
|
+
safe_puts "Location added: \"#{location.name}\"" # Return the added location.
|
102
135
|
end
|
103
136
|
|
104
137
|
# Set a friend's location.
|
@@ -106,39 +139,38 @@ module Friends
|
|
106
139
|
# @param location_name [String] the name of an existing location
|
107
140
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
108
141
|
# @raise [FriendsError] if 0 or 2+ locations match the given location name
|
109
|
-
# @return [Friend] the modified friend
|
110
142
|
def set_location(name:, location_name:)
|
111
143
|
friend = thing_with_name_in(:friend, name)
|
112
144
|
location = thing_with_name_in(:location, location_name)
|
113
145
|
friend.location_name = location.name
|
114
|
-
|
146
|
+
|
147
|
+
safe_puts "#{friend.name}'s location set to: \"#{location.name}\""
|
115
148
|
end
|
116
149
|
|
117
150
|
# Rename an existing friend.
|
118
151
|
# @param old_name [String] the name of the friend
|
119
152
|
# @param new_name [String] the new name of the friend
|
120
153
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
121
|
-
# @return [Friend] the existing friend
|
122
154
|
def rename_friend(old_name:, new_name:)
|
123
155
|
friend = thing_with_name_in(:friend, old_name)
|
124
|
-
@activities.each do |
|
125
|
-
|
156
|
+
(@activities + @notes).each do |event|
|
157
|
+
event.update_friend_name(old_name: friend.name, new_name: new_name)
|
126
158
|
end
|
127
159
|
friend.name = new_name
|
128
|
-
|
160
|
+
|
161
|
+
safe_puts "Name changed: \"#{friend}\""
|
129
162
|
end
|
130
163
|
|
131
164
|
# Rename an existing location.
|
132
165
|
# @param old_name [String] the name of the location
|
133
166
|
# @param new_name [String] the new name of the location
|
134
167
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
135
|
-
# @return [Location] the existing location
|
136
168
|
def rename_location(old_name:, new_name:)
|
137
169
|
loc = thing_with_name_in(:location, old_name)
|
138
170
|
|
139
|
-
# Update locations in activities.
|
140
|
-
@activities.each do |
|
141
|
-
|
171
|
+
# Update locations in activities and notes.
|
172
|
+
(@activities + @notes).each do |event|
|
173
|
+
event.update_location_name(old_name: loc.name, new_name: new_name)
|
142
174
|
end
|
143
175
|
|
144
176
|
# Update locations of friends.
|
@@ -147,29 +179,30 @@ module Friends
|
|
147
179
|
end
|
148
180
|
|
149
181
|
loc.name = new_name # Update location itself.
|
150
|
-
|
182
|
+
|
183
|
+
safe_puts "Location renamed: \"#{loc.name}\""
|
151
184
|
end
|
152
185
|
|
153
186
|
# Add a nickname to an existing friend.
|
154
187
|
# @param name [String] the name of the friend
|
155
188
|
# @param nickname [String] the nickname to add to the friend
|
156
189
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
157
|
-
# @return [Friend] the existing friend
|
158
190
|
def add_nickname(name:, nickname:)
|
159
191
|
friend = thing_with_name_in(:friend, name)
|
160
192
|
friend.add_nickname(nickname)
|
161
|
-
|
193
|
+
|
194
|
+
safe_puts "Nickname added: \"#{friend}\""
|
162
195
|
end
|
163
196
|
|
164
197
|
# Add a tag to an existing friend.
|
165
198
|
# @param name [String] the name of the friend
|
166
199
|
# @param tag [String] the tag to add to the friend, of the form: "@tag"
|
167
200
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
168
|
-
# @return [Friend] the existing friend
|
169
201
|
def add_tag(name:, tag:)
|
170
202
|
friend = thing_with_name_in(:friend, name)
|
171
203
|
friend.add_tag(tag)
|
172
|
-
|
204
|
+
|
205
|
+
safe_puts "Tag added to friend: \"#{friend}\""
|
173
206
|
end
|
174
207
|
|
175
208
|
# Remove a tag from an existing friend.
|
@@ -177,11 +210,11 @@ module Friends
|
|
177
210
|
# @param tag [String] the tag to remove from the friend, of the form: "@tag"
|
178
211
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
179
212
|
# @raise [FriendsError] if the friend does not have the given nickname
|
180
|
-
# @return [Friend] the existing friend
|
181
213
|
def remove_tag(name:, tag:)
|
182
214
|
friend = thing_with_name_in(:friend, name)
|
183
215
|
friend.remove_tag(tag)
|
184
|
-
|
216
|
+
|
217
|
+
safe_puts "Tag removed from friend: \"#{friend}\""
|
185
218
|
end
|
186
219
|
|
187
220
|
# Remove a nickname from an existing friend.
|
@@ -189,11 +222,11 @@ module Friends
|
|
189
222
|
# @param nickname [String] the nickname to remove from the friend
|
190
223
|
# @raise [FriendsError] if 0 or 2+ friends match the given name
|
191
224
|
# @raise [FriendsError] if the friend does not have the given nickname
|
192
|
-
# @return [Friend] the existing friend
|
193
225
|
def remove_nickname(name:, nickname:)
|
194
226
|
friend = thing_with_name_in(:friend, name)
|
195
227
|
friend.remove_nickname(nickname)
|
196
|
-
|
228
|
+
|
229
|
+
safe_puts "Nickname removed: \"#{friend}\""
|
197
230
|
end
|
198
231
|
|
199
232
|
# List all friend names in the friends file.
|
@@ -203,7 +236,6 @@ module Friends
|
|
203
236
|
# unfiltered
|
204
237
|
# @param verbose [Boolean] true iff we should output friend names with
|
205
238
|
# nicknames, locations, and tags; false for names only
|
206
|
-
# @return [Array] a list of all friend names
|
207
239
|
def list_friends(location_name:, tagged:, verbose:)
|
208
240
|
fs = @friends
|
209
241
|
|
@@ -220,69 +252,41 @@ module Friends
|
|
220
252
|
end
|
221
253
|
end
|
222
254
|
|
223
|
-
verbose ? fs.map(&:to_s) : fs.map(&:name)
|
255
|
+
safe_puts(verbose ? fs.map(&:to_s) : fs.map(&:name))
|
224
256
|
end
|
225
257
|
|
226
258
|
# List your favorite friends.
|
227
259
|
# @param limit [Integer] the number of favorite friends to return
|
228
|
-
# @return [Array] a list of the favorite friends' names and activity
|
229
|
-
# counts
|
230
260
|
def list_favorite_friends(limit:)
|
231
261
|
list_favorite_things(:friend, limit: limit)
|
232
262
|
end
|
233
263
|
|
234
264
|
# List your favorite friends.
|
235
265
|
# @param limit [Integer] the number of favorite locations to return
|
236
|
-
# @return [Array] a list of the favorite locations' names and activity
|
237
|
-
# counts
|
238
266
|
def list_favorite_locations(limit:)
|
239
267
|
list_favorite_things(:location, limit: limit)
|
240
268
|
end
|
241
269
|
|
242
270
|
# See `list_events` for all of the parameters we can pass.
|
243
|
-
# @return [Array] a list of all activities' text values
|
244
271
|
def list_activities(**args)
|
245
272
|
list_events(events: @activities, **args)
|
246
273
|
end
|
247
274
|
|
248
275
|
# See `list_events` for all of the parameters we can pass.
|
249
|
-
# @return [Array] a list of all notes' text values
|
250
276
|
def list_notes(**args)
|
251
277
|
list_events(events: @notes, **args)
|
252
278
|
end
|
253
279
|
|
254
280
|
# List all location names in the friends file.
|
255
|
-
# @return [Array] a list of all location names
|
256
281
|
def list_locations
|
257
|
-
@locations.map(&:name)
|
282
|
+
safe_puts @locations.map(&:name)
|
258
283
|
end
|
259
284
|
|
260
285
|
# @param from [Array] containing any of: ["activities", "friends", "notes"]
|
261
286
|
# If not empty, limits the tags returned to only those from either
|
262
287
|
# activities, notes, or friends.
|
263
|
-
# @return [Array] a sorted list of all tags in activity descriptions
|
264
288
|
def list_tags(from:)
|
265
|
-
|
266
|
-
|
267
|
-
if from.empty? || from.include?("activities")
|
268
|
-
@activities.each_with_object(output) do |activity, set|
|
269
|
-
set.merge(activity.tags)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
if from.empty? || from.include?("notes")
|
274
|
-
@notes.each_with_object(output) do |note, set|
|
275
|
-
set.merge(note.tags)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
if from.empty? || from.include?("friends")
|
280
|
-
@friends.each_with_object(output) do |friend, set|
|
281
|
-
set.merge(friend.tags)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
output.sort_by(&:downcase)
|
289
|
+
safe_puts tags(from: from).sort_by(&:downcase)
|
286
290
|
end
|
287
291
|
|
288
292
|
# Find data points for graphing activities over time.
|
@@ -305,7 +309,6 @@ module Friends
|
|
305
309
|
# unfiltered
|
306
310
|
# @param since_date [Date] a date on or after which to find activities, or nil for unfiltered
|
307
311
|
# @param until_date [Date] a date before or on which to find activities, or nil for unfiltered
|
308
|
-
# @return [Hash{String => Integer}]
|
309
312
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
310
313
|
# is ambiguous
|
311
314
|
def graph(with:, location_name:, tagged:, since_date:, until_date:)
|
@@ -350,7 +353,6 @@ module Friends
|
|
350
353
|
#
|
351
354
|
# @param location_name [String] the name of a location to filter by, or nil
|
352
355
|
# for unfiltered
|
353
|
-
# @return [Hash{String => Array<String>}]
|
354
356
|
def suggest(location_name:)
|
355
357
|
# Filter our friends by location if necessary.
|
356
358
|
fs = @friends
|
@@ -359,22 +361,25 @@ module Friends
|
|
359
361
|
# Sort our friends, with the least favorite friend first.
|
360
362
|
sorted_friends = fs.sort_by(&:n_activities)
|
361
363
|
|
362
|
-
output = Hash.new { |h, k| h[k] = [] }
|
363
|
-
|
364
364
|
# Set initial value in case there are no friends and the while loop is
|
365
365
|
# never entered.
|
366
|
-
|
366
|
+
distant_friend_names = []
|
367
367
|
|
368
368
|
# First, get not-so-good friends.
|
369
369
|
while !sorted_friends.empty? && sorted_friends.first.n_activities < 2
|
370
|
-
|
370
|
+
distant_friend_names << sorted_friends.shift.name
|
371
371
|
end
|
372
372
|
|
373
|
-
|
374
|
-
|
375
|
-
|
373
|
+
moderate_friend_names = sorted_friends.slice!(0, sorted_friends.size * 3 / 4).
|
374
|
+
map!(&:name)
|
375
|
+
close_friend_names = sorted_friends.map!(&:name)
|
376
376
|
|
377
|
-
|
377
|
+
safe_puts "Distant friend: "\
|
378
|
+
"#{Paint[distant_friend_names.sample || 'None found', :bold, :magenta]}"
|
379
|
+
safe_puts "Moderate friend: "\
|
380
|
+
"#{Paint[moderate_friend_names.sample || 'None found', :bold, :magenta]}"
|
381
|
+
safe_puts "Close friend: "\
|
382
|
+
"#{Paint[close_friend_names.sample || 'None found', :bold, :magenta]}"
|
378
383
|
end
|
379
384
|
|
380
385
|
###################################################################
|
@@ -452,41 +457,50 @@ module Friends
|
|
452
457
|
end
|
453
458
|
end
|
454
459
|
|
455
|
-
|
456
|
-
|
457
|
-
@friends.size
|
458
|
-
|
460
|
+
def stats
|
461
|
+
safe_puts "Total activities: #{@activities.size}"
|
462
|
+
safe_puts "Total friends: #{@friends.size}"
|
463
|
+
safe_puts "Total locations: #{@locations.size}"
|
464
|
+
safe_puts "Total notes: #{@notes.size}"
|
465
|
+
safe_puts "Total tags: #{tags.size}"
|
459
466
|
|
460
|
-
|
461
|
-
def total_activities
|
462
|
-
@activities.size
|
463
|
-
end
|
467
|
+
events = @activities + @notes
|
464
468
|
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
+
elapsed_days = if events.size < 2
|
470
|
+
0
|
471
|
+
else
|
472
|
+
sorted_events = events.sort
|
473
|
+
(sorted_events.first.date - sorted_events.last.date).to_i
|
474
|
+
end
|
469
475
|
|
470
|
-
|
471
|
-
def total_notes
|
472
|
-
@notes.size
|
476
|
+
safe_puts "Total time elapsed: #{elapsed_days} day#{'s' if elapsed_days != 1}"
|
473
477
|
end
|
474
478
|
|
475
|
-
|
476
|
-
def total_tags
|
477
|
-
list_tags(from: []).size
|
478
|
-
end
|
479
|
+
private
|
479
480
|
|
480
|
-
#
|
481
|
-
#
|
482
|
-
def
|
483
|
-
|
484
|
-
return 0 if events.size < 2
|
485
|
-
sorted_events = events.sort
|
486
|
-
(sorted_events.first.date - sorted_events.last.date).to_i
|
481
|
+
# Print the message unless we're in `quiet` mode.
|
482
|
+
# @param str [String] a message to print
|
483
|
+
def safe_puts(str)
|
484
|
+
puts str unless @quiet
|
487
485
|
end
|
488
486
|
|
489
|
-
|
487
|
+
# @param from [Array] containing any of: ["activities", "friends", "notes"]
|
488
|
+
# If not empty, limits the tags returned to only those from either
|
489
|
+
# activities, notes, or friends.
|
490
|
+
# @return [Set] the set of tags present in the given things
|
491
|
+
def tags(from: [])
|
492
|
+
Set.new.tap do |output|
|
493
|
+
if from.empty? || from.include?("activities")
|
494
|
+
@activities.each { |activity| output.merge(activity.tags) }
|
495
|
+
end
|
496
|
+
|
497
|
+
@notes.each { |note| output.merge(note.tags) } if from.empty? || from.include?("notes")
|
498
|
+
|
499
|
+
if from.empty? || from.include?("friends")
|
500
|
+
@friends.each { |friend| output.merge(friend.tags) }
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
490
504
|
|
491
505
|
# List all event details.
|
492
506
|
# @param events [Array<Event>] the base events to list, either @activities or @notes
|
@@ -500,7 +514,6 @@ module Friends
|
|
500
514
|
# unfiltered
|
501
515
|
# @param since_date [Date] a date on or after which to find events, or nil for unfiltered
|
502
516
|
# @param until_date [Date] a date before or on which to find events, or nil for unfiltered
|
503
|
-
# @return [Array] a list of all event (activity or note) text values
|
504
517
|
# @raise [ArgumentError] if limit is present but limit < 1
|
505
518
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
506
519
|
# is ambiguous
|
@@ -519,7 +532,7 @@ module Friends
|
|
519
532
|
# If we need to, trim the list.
|
520
533
|
events = events.take(limit) unless limit.nil?
|
521
534
|
|
522
|
-
events.map(&:to_s)
|
535
|
+
safe_puts events.map(&:to_s)
|
523
536
|
end
|
524
537
|
|
525
538
|
# @param arr [Array] an unsorted array
|
@@ -538,7 +551,7 @@ module Friends
|
|
538
551
|
# unfiltered
|
539
552
|
# @param since_date [Date] a date on or after which to find activities, or nil for unfiltered
|
540
553
|
# @param until_date [Date] a date before or on which to find activities, or nil for unfiltered
|
541
|
-
# @return [Array] an array of activities
|
554
|
+
# @return [Array] an array of activities or notes
|
542
555
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
543
556
|
# is ambiguous
|
544
557
|
def filtered_events(events:, with:, location_name:, tagged:, since_date:, until_date:)
|
@@ -572,7 +585,6 @@ module Friends
|
|
572
585
|
|
573
586
|
# @param type [Symbol] one of: [:friend, :location]
|
574
587
|
# @param limit [Integer] the number of favorite things to return
|
575
|
-
# @return [Array] a list of the favorite things' names and activity counts
|
576
588
|
# @raise [ArgumentError] if type is not one of: [:friend, :location]
|
577
589
|
# @raise [ArgumentError] if limit is < 1
|
578
590
|
def list_favorite_things(type, limit:)
|
@@ -589,12 +601,12 @@ module Friends
|
|
589
601
|
|
590
602
|
if results.size == 1
|
591
603
|
favorite = results.first
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
604
|
+
safe_puts "Your favorite #{type} is "\
|
605
|
+
"#{favorite.name} "\
|
606
|
+
"(#{favorite.n_activities} "\
|
607
|
+
"#{favorite.n_activities == 1 ? 'activity' : 'activities'})"
|
596
608
|
else
|
597
|
-
|
609
|
+
safe_puts "Your favorite #{type}s:"
|
598
610
|
|
599
611
|
max_str_size = results.map(&:name).map(&:size).max
|
600
612
|
|
@@ -621,7 +633,7 @@ module Friends
|
|
621
633
|
# elements, which may be too large if the last element in the list is a tie.
|
622
634
|
num_str_size = data.last.first.to_s.size + 1 unless data.empty?
|
623
635
|
data.each do |ranking, str|
|
624
|
-
|
636
|
+
safe_puts "#{"#{ranking}.".ljust(num_str_size)} #{str}"
|
625
637
|
end
|
626
638
|
end
|
627
639
|
end
|