friends 0.28 → 0.29
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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +2 -0
- data/CHANGELOG.md +13 -0
- data/README.md +35 -5
- data/Rakefile +1 -1
- data/bin/friends +7 -379
- data/friends.gemspec +3 -1
- data/lib/friends/activity.rb +4 -4
- data/lib/friends/commands/add.rb +64 -0
- data/lib/friends/commands/clean.rb +9 -0
- data/lib/friends/commands/edit.rb +12 -0
- data/lib/friends/commands/graph.rb +56 -0
- data/lib/friends/commands/list.rb +143 -0
- data/lib/friends/commands/remove.rb +27 -0
- data/lib/friends/commands/rename.rb +30 -0
- data/lib/friends/commands/set.rb +14 -0
- data/lib/friends/commands/stats.rb +11 -0
- data/lib/friends/commands/suggest.rb +20 -0
- data/lib/friends/commands/update.rb +29 -0
- data/lib/friends/graph.rb +7 -7
- data/lib/friends/introvert.rb +23 -18
- data/lib/friends/version.rb +1 -1
- data/test/commands/add/activity_spec.rb +379 -0
- data/test/commands/add/friend_spec.rb +30 -0
- data/test/commands/add/location_spec.rb +30 -0
- data/test/commands/add/nickname_spec.rb +50 -0
- data/test/commands/add/tag_spec.rb +65 -0
- data/test/commands/clean_spec.rb +39 -0
- data/test/commands/graph_spec.rb +147 -0
- data/test/commands/help_spec.rb +45 -0
- data/test/commands/list/activities_spec.rb +136 -0
- data/test/commands/list/favorite/friends_spec.rb +77 -0
- data/test/commands/list/favorite/locations_spec.rb +82 -0
- data/test/commands/list/friends_spec.rb +76 -0
- data/test/commands/list/locations_spec.rb +35 -0
- data/test/commands/list/tags_spec.rb +58 -0
- data/test/commands/remove/nickname_spec.rb +63 -0
- data/test/commands/remove/tag_spec.rb +64 -0
- data/test/commands/rename/friend_spec.rb +55 -0
- data/test/commands/rename/location_spec.rb +43 -0
- data/test/commands/set/location_spec.rb +54 -0
- data/test/commands/stats_spec.rb +41 -0
- data/test/commands/suggest_spec.rb +86 -0
- data/test/commands/update_spec.rb +13 -0
- data/test/helper.rb +114 -0
- metadata +89 -15
- data/test/activity_spec.rb +0 -597
- data/test/friend_spec.rb +0 -241
- data/test/graph_spec.rb +0 -92
- data/test/introvert_spec.rb +0 -969
- data/test/location_spec.rb +0 -60
data/lib/friends/graph.rb
CHANGED
@@ -5,13 +5,13 @@ module Friends
|
|
5
5
|
class Graph
|
6
6
|
DATE_FORMAT = "%b %Y"
|
7
7
|
|
8
|
-
# @param start_date [Date] the first month of the graph
|
9
|
-
# @param end_date [Date] the last month of the graph
|
10
8
|
# @param activities [Array<Friends::Activity>] a list of activities to graph
|
11
|
-
def initialize(
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def initialize(activities:)
|
10
|
+
@activities = activities
|
11
|
+
unless @activities.empty?
|
12
|
+
@start_date = @activities.last.date
|
13
|
+
@end_date = @activities.first.date
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
17
|
# Render the graph as a hash in the format:
|
@@ -45,7 +45,7 @@ module Friends
|
|
45
45
|
#
|
46
46
|
# @return [Hash{String => Integer}]
|
47
47
|
def empty_graph
|
48
|
-
Hash[(start_date..end_date).map do |date|
|
48
|
+
Hash[(start_date && end_date ? (start_date..end_date) : []).map do |date|
|
49
49
|
[format_date(date), 0]
|
50
50
|
end]
|
51
51
|
end
|
data/lib/friends/introvert.rb
CHANGED
@@ -231,17 +231,21 @@ module Friends
|
|
231
231
|
# for unfiltered
|
232
232
|
# @param tagged [String] the name of a tag to filter by (of the form:
|
233
233
|
# "@tag"), or nil for unfiltered
|
234
|
+
# @param since_date [Date] a date on or after which to find activities, or nil for unfiltered
|
235
|
+
# @param until_date [Date] a date before or on which to find activities, or nil for unfiltered
|
234
236
|
# @return [Array] a list of all activity text values
|
235
237
|
# @raise [ArgumentError] if limit is present but limit < 1
|
236
238
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
237
239
|
# is ambiguous
|
238
|
-
def list_activities(limit:, with:, location_name:, tagged:)
|
240
|
+
def list_activities(limit:, with:, location_name:, tagged:, since_date:, until_date:)
|
239
241
|
raise ArgumentError, "Limit must be positive" if limit && limit < 1
|
240
242
|
|
241
243
|
acts = filtered_activities(
|
242
244
|
with: with,
|
243
245
|
location_name: location_name,
|
244
|
-
tagged: tagged
|
246
|
+
tagged: tagged,
|
247
|
+
since_date: since_date,
|
248
|
+
until_date: until_date
|
245
249
|
)
|
246
250
|
|
247
251
|
# If we need to, trim the list.
|
@@ -296,24 +300,21 @@ module Friends
|
|
296
300
|
# for unfiltered
|
297
301
|
# @param tagged [String] the name of a tag to filter by (of the form:
|
298
302
|
# "@tag"), or nil for unfiltered
|
303
|
+
# @param since_date [Date] a date on or after which to find activities, or nil for unfiltered
|
304
|
+
# @param until_date [Date] a date before or on which to find activities, or nil for unfiltered
|
299
305
|
# @return [Hash{String => Integer}]
|
300
306
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
301
307
|
# is ambiguous
|
302
|
-
def graph(with:, location_name:, tagged:)
|
303
|
-
# There is no point trying to graph no activities
|
304
|
-
return {} if @activities.empty?
|
305
|
-
|
308
|
+
def graph(with:, location_name:, tagged:, since_date:, until_date:)
|
306
309
|
activities_to_graph = filtered_activities(
|
307
310
|
with: with,
|
308
311
|
location_name: location_name,
|
309
|
-
tagged: tagged
|
312
|
+
tagged: tagged,
|
313
|
+
since_date: since_date,
|
314
|
+
until_date: until_date
|
310
315
|
)
|
311
316
|
|
312
|
-
Graph.new(
|
313
|
-
start_date: @activities.last.date,
|
314
|
-
end_date: @activities.first.date,
|
315
|
-
activities: activities_to_graph
|
316
|
-
).to_h
|
317
|
+
Graph.new(activities: activities_to_graph).to_h
|
317
318
|
end
|
318
319
|
|
319
320
|
# Suggest friends to do something with.
|
@@ -456,10 +457,12 @@ module Friends
|
|
456
457
|
# for unfiltered
|
457
458
|
# @param tagged [String] the name of a tag to filter by, or nil for
|
458
459
|
# unfiltered
|
460
|
+
# @param since_date [Date] a date on or after which to find activities, or nil for unfiltered
|
461
|
+
# @param until_date [Date] a date before or on which to find activities, or nil for unfiltered
|
459
462
|
# @return [Array] an array of activities
|
460
463
|
# @raise [FriendsError] if friend, location or tag cannot be found or
|
461
464
|
# is ambiguous
|
462
|
-
def filtered_activities(with:, location_name:, tagged:)
|
465
|
+
def filtered_activities(with:, location_name:, tagged:, since_date:, until_date:)
|
463
466
|
acts = @activities
|
464
467
|
|
465
468
|
# Filter by friend name if argument is passed.
|
@@ -475,9 +478,11 @@ module Friends
|
|
475
478
|
end
|
476
479
|
|
477
480
|
# Filter by tag if argument is passed.
|
478
|
-
unless tagged.nil?
|
479
|
-
|
480
|
-
|
481
|
+
acts = acts.select { |act| act.includes_tag?(tagged) } unless tagged.nil?
|
482
|
+
|
483
|
+
# Filter by date if arguments are passed.
|
484
|
+
acts = acts.select { |act| act.date >= since_date } unless since_date.nil?
|
485
|
+
acts = acts.select { |act| act.date <= until_date } unless until_date.nil?
|
481
486
|
|
482
487
|
acts
|
483
488
|
end
|
@@ -503,7 +508,7 @@ module Friends
|
|
503
508
|
results.map.with_index(0) do |thing, index|
|
504
509
|
name = thing.name.ljust(max_str_size)
|
505
510
|
n = thing.n_activities
|
506
|
-
if index
|
511
|
+
if index.zero?
|
507
512
|
label = n == 1 ? " activity" : " activities"
|
508
513
|
end
|
509
514
|
parenthetical = "(#{n}#{label})"
|
@@ -627,7 +632,7 @@ module Friends
|
|
627
632
|
# with that exact name, match it.
|
628
633
|
if things.size > 1
|
629
634
|
exact_things = things.select do |thing|
|
630
|
-
thing.name.casecmp(text)
|
635
|
+
thing.name.casecmp(text).zero? # We ignore case for an "exact" match.
|
631
636
|
end
|
632
637
|
|
633
638
|
things = exact_things if exact_things.size == 1
|
data/lib/friends/version.rb
CHANGED
@@ -0,0 +1,379 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "./test/helper"
|
4
|
+
|
5
|
+
def date_parsing_specs(test_stdout: true)
|
6
|
+
describe "date parsing" do
|
7
|
+
let(:description) { "Test." }
|
8
|
+
|
9
|
+
describe "when date is in YYYY-MM-DD" do
|
10
|
+
let(:date) { "2017-01-01" }
|
11
|
+
|
12
|
+
it { line_added "- #{date}: #{description}" }
|
13
|
+
it { stdout_only "Activity added: \"#{date}: #{description}\"" } if test_stdout
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when date is in MM-DD-YYYY" do
|
17
|
+
let(:date) { "01-02-2017" }
|
18
|
+
|
19
|
+
it { line_added "- 2017-01-02: #{description}" }
|
20
|
+
it { stdout_only "Activity added: \"2017-01-02: #{description}\"" } if test_stdout
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when date is invalid" do
|
24
|
+
let(:date) { "2017-02-30" }
|
25
|
+
|
26
|
+
it { line_added "- 2017-03-02: #{description}" }
|
27
|
+
it { stdout_only "Activity added: \"2017-03-02: #{description}\"" } if test_stdout
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "when date is natural language" do
|
31
|
+
let(:date) { "February 23rd, 2017" }
|
32
|
+
|
33
|
+
it { line_added "- 2017-02-23: #{description}" }
|
34
|
+
it { stdout_only "Activity added: \"2017-02-23: #{description}\"" } if test_stdout
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def description_parsing_specs(test_stdout: true)
|
40
|
+
describe "description parsing" do
|
41
|
+
let(:date) { Date.today.strftime }
|
42
|
+
|
43
|
+
describe "when description includes a friend's full name (case insensitive)" do
|
44
|
+
let(:description) { "Lunch with grace hopper." }
|
45
|
+
|
46
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**." }
|
47
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper.\"" } if test_stdout
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when description includes a friend's first name (case insensitive)" do
|
51
|
+
let(:description) { "Lunch with grace." }
|
52
|
+
|
53
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**." }
|
54
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper.\"" } if test_stdout
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "when description has a friend's first name and last initial (case insensitive)" do
|
58
|
+
describe "when followed by no period" do
|
59
|
+
let(:description) { "Lunch with grace h" }
|
60
|
+
|
61
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**" }
|
62
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper\"" } if test_stdout
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "when followed by a period at the end of a sentence" do
|
66
|
+
let(:description) { "Met grace h. So fun!" }
|
67
|
+
|
68
|
+
it { line_added "- #{date}: Met **Grace Hopper**. So fun!" }
|
69
|
+
it { stdout_only "Activity added: \"#{date}: Met Grace Hopper. So fun!\"" } if test_stdout
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "when followed by a period at the end of the description" do
|
73
|
+
let(:description) { "Lunch with grace h." }
|
74
|
+
|
75
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**." }
|
76
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper.\"" } if test_stdout
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "when followed by a period in the middle of a sentence" do
|
80
|
+
let(:description) { "Met grace h. at 12." }
|
81
|
+
|
82
|
+
it { line_added "- #{date}: Met **Grace Hopper** at 12." }
|
83
|
+
it { stdout_only "Activity added: \"#{date}: Met Grace Hopper at 12.\"" } if test_stdout
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "when description includes a friend's nickname (case insensitive)" do
|
88
|
+
let(:description) { "Lunch with the admiral." }
|
89
|
+
|
90
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**." }
|
91
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper.\"" } if test_stdout
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "when description includes a friend's nickname which contains a name" do
|
95
|
+
let(:description) { "Lunch with Amazing Grace." }
|
96
|
+
|
97
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper**." }
|
98
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace Hopper.\"" } if test_stdout
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "when description includes a friend's name at the beginning of a word" do
|
102
|
+
# Capitalization reduces chance of a false positive.
|
103
|
+
let(:description) { "Gracefully strolled." }
|
104
|
+
|
105
|
+
it { line_added "- #{date}: Gracefully strolled." }
|
106
|
+
it { stdout_only "Activity added: \"#{date}: Gracefully strolled.\"" } if test_stdout
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "when description includes a friend's name at the end of a word" do
|
110
|
+
# Capitalization reduces chance of a false positive.
|
111
|
+
let(:description) { "The service was a disGrace." }
|
112
|
+
|
113
|
+
it { line_added "- #{date}: The service was a disGrace." }
|
114
|
+
it { stdout_only "Activity added: \"#{date}: The service was a disGrace.\"" } if test_stdout
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "when description includes a friend's name in the middle of a word" do
|
118
|
+
# Capitalization reduces chance of a false positive.
|
119
|
+
let(:description) { "The service was disGraceful." }
|
120
|
+
|
121
|
+
it { line_added "- #{date}: The service was disGraceful." }
|
122
|
+
it { stdout_only "Activity added: \"#{date}: The service was disGraceful.\"" } if test_stdout
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "when a friend's name is escaped with a backslash" do
|
126
|
+
# We have to use four backslashes here because of Ruby's backslash escaping; when this
|
127
|
+
# goes through all of the layers of this test it emerges on the other side as a single one.
|
128
|
+
let(:description) { "Dinner with \\\\Grace Kelly." }
|
129
|
+
|
130
|
+
it { line_added "- #{date}: Dinner with Grace Kelly." }
|
131
|
+
it { stdout_only "Activity added: \"#{date}: Dinner with Grace Kelly.\"" } if test_stdout
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "hyphenated name edge cases" do
|
135
|
+
describe "when one name precedes another before a hyphen" do
|
136
|
+
let(:description) { "Shopped w/ Mary-Kate." }
|
137
|
+
|
138
|
+
# Make sure "Mary" is a closer friend than "Mary-Kate" so we know our
|
139
|
+
# test result isn't due to chance.
|
140
|
+
let(:content) do
|
141
|
+
<<-FILE
|
142
|
+
### Activities:
|
143
|
+
- 2017-01-01: Singing with **Mary Poppins**.
|
144
|
+
|
145
|
+
### Friends:
|
146
|
+
- Mary Poppins
|
147
|
+
- Mary-Kate Olsen
|
148
|
+
|
149
|
+
### Locations:
|
150
|
+
FILE
|
151
|
+
end
|
152
|
+
|
153
|
+
it { line_added "- #{date}: Shopped w/ **Mary-Kate Olsen**." }
|
154
|
+
it { stdout_only "Activity added: \"#{date}: Shopped w/ Mary-Kate Olsen.\"" } if test_stdout
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "when one name follows another after a hyphen" do
|
158
|
+
let(:description) { "Shopped w/ Mary-Kate." }
|
159
|
+
|
160
|
+
# Make sure "Kate" is a closer friend than "Mary-Kate" so we know our
|
161
|
+
# test result isn't due to chance.
|
162
|
+
let(:content) do
|
163
|
+
<<-FILE
|
164
|
+
### Activities:
|
165
|
+
- 2017-01-01: Improv with **Kate Winslet**.
|
166
|
+
|
167
|
+
### Friends:
|
168
|
+
- Kate Winslet
|
169
|
+
- Mary-Kate Olsen
|
170
|
+
|
171
|
+
### Locations:
|
172
|
+
FILE
|
173
|
+
end
|
174
|
+
|
175
|
+
it { line_added "- #{date}: Shopped w/ **Mary-Kate Olsen**." }
|
176
|
+
it { stdout_only "Activity added: \"#{date}: Shopped w/ Mary-Kate Olsen.\"" } if test_stdout
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "when one name is contained within another via hyphens" do
|
180
|
+
let(:description) { "Met Mary-Jo-Kate." }
|
181
|
+
|
182
|
+
# Make sure "Jo" is a closer friend than "Mary-Jo-Kate" so we know our
|
183
|
+
# test result isn't due to chance.
|
184
|
+
let(:content) do
|
185
|
+
<<-FILE
|
186
|
+
### Activities:
|
187
|
+
- 2017-01-01: Singing with **Jo Stafford**.
|
188
|
+
|
189
|
+
### Friends:
|
190
|
+
- Jo Stafford
|
191
|
+
- Mary-Jo-Kate Olsen
|
192
|
+
|
193
|
+
### Locations:
|
194
|
+
FILE
|
195
|
+
end
|
196
|
+
|
197
|
+
it { line_added "- #{date}: Met **Mary-Jo-Kate Olsen**." }
|
198
|
+
it { stdout_only "Activity added: \"#{date}: Met Mary-Jo-Kate Olsen.\"" } if test_stdout
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "when description has a friend's name with leading asterisks" do
|
203
|
+
let(:description) { "Lunch with **Grace Hopper." }
|
204
|
+
|
205
|
+
it { line_added "- #{date}: Lunch with **Grace Hopper." }
|
206
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with **Grace Hopper.\"" } if test_stdout
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "when description has a friend's name with trailing asterisks" do
|
210
|
+
# Note: We can't guarantee that "Grace Hopper**" doesn't match because the "Grace" isn't
|
211
|
+
# surrounded by asterisks.
|
212
|
+
let(:description) { "Lunch with Grace**." }
|
213
|
+
|
214
|
+
it { line_added "- #{date}: Lunch with Grace**." }
|
215
|
+
it { stdout_only "Activity added: \"#{date}: Lunch with Grace**.\"" } if test_stdout
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "when description has a friend's name multiple times" do
|
219
|
+
let(:description) { "Grace! Grace!!!" }
|
220
|
+
|
221
|
+
it { line_added "- #{date}: **Grace Hopper**! **Grace Hopper**!!!" }
|
222
|
+
it { stdout_only "Activity added: \"#{date}: Grace Hopper! Grace Hopper!!!\"" } if test_stdout
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "when description has a name with multiple friend matches" do
|
226
|
+
describe "when there is useful context from past activities" do
|
227
|
+
let(:description) { "Met John + Elizabeth." }
|
228
|
+
|
229
|
+
# Create a past activity in which Elizabeth Cady Stanton did something
|
230
|
+
# with John Cage. Then, create past activities to make Elizabeth II a
|
231
|
+
# better friend than Elizabeth Cady Stanton.
|
232
|
+
let(:content) do
|
233
|
+
<<-FILE
|
234
|
+
### Activities:
|
235
|
+
- 2017-01-05: Picnic with **Elizabeth Cady Stanton** and **John Cage**.
|
236
|
+
- 2017-01-04: Got lunch with **Elizabeth II**.
|
237
|
+
- 2017-01-03: Ice skated with **Elizabeth II**.
|
238
|
+
|
239
|
+
### Friends:
|
240
|
+
- Elizabeth Cady Stanton
|
241
|
+
- Elizabeth II
|
242
|
+
- John Cage
|
243
|
+
|
244
|
+
### Locations:
|
245
|
+
FILE
|
246
|
+
end
|
247
|
+
|
248
|
+
# Elizabeth II is the better friend, but historical activities have
|
249
|
+
# had Elizabeth Cady Stanton and John Cage together. Thus, we should
|
250
|
+
# interpret "Elizabeth" as Elizabeth Cady Stanton.
|
251
|
+
it { line_added "- #{date}: Met **John Cage** + **Elizabeth Cady Stanton**." }
|
252
|
+
if test_stdout
|
253
|
+
it { stdout_only "Activity added: \"#{date}: Met John Cage + Elizabeth Cady Stanton.\"" }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "when there is no useful context from past activities" do
|
258
|
+
let(:description) { "Dinner with John and Elizabeth." }
|
259
|
+
|
260
|
+
# Create a past activity in which Elizabeth Cady Stanton did something
|
261
|
+
# with John Cage. Then, create past activities to make Elizabeth II a
|
262
|
+
# better friend than Elizabeth Cady Stanton.
|
263
|
+
let(:content) do
|
264
|
+
<<-FILE
|
265
|
+
### Activities:
|
266
|
+
- 2017-01-03: Ice skated with **Elizabeth II**.
|
267
|
+
|
268
|
+
### Friends:
|
269
|
+
- Elizabeth Cady Stanton
|
270
|
+
- Elizabeth II
|
271
|
+
- John Cage
|
272
|
+
|
273
|
+
### Locations:
|
274
|
+
FILE
|
275
|
+
end
|
276
|
+
|
277
|
+
# Pick the "Elizabeth" with more activities.
|
278
|
+
it { line_added "- #{date}: Dinner with **John Cage** and **Elizabeth II**." }
|
279
|
+
if test_stdout
|
280
|
+
it { stdout_only "Activity added: \"#{date}: Dinner with John Cage and Elizabeth II.\"" }
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "when description contains a location name (case insensitive)" do
|
286
|
+
let(:description) { "Lunch at a cafe in paris." }
|
287
|
+
|
288
|
+
it { line_added "- #{date}: Lunch at a cafe in _Paris_." }
|
289
|
+
it { stdout_only "Activity added: \"#{date}: Lunch at a cafe in Paris.\"" } if test_stdout
|
290
|
+
end
|
291
|
+
|
292
|
+
describe "when description contains both names and locations" do
|
293
|
+
let(:description) { "Grace and I went to Atlantis and then Paris for lunch with George." }
|
294
|
+
|
295
|
+
it do
|
296
|
+
line_added "- #{date}: **Grace Hopper** and I went to _Atlantis_ and then _Paris_ for "\
|
297
|
+
"lunch with **George Washington Carver**."
|
298
|
+
end
|
299
|
+
if test_stdout
|
300
|
+
it do
|
301
|
+
stdout_only "Activity added: \"#{date}: Grace Hopper and I went to Atlantis and then "\
|
302
|
+
"Paris for lunch with George Washington Carver.\""
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
clean_describe "add activity" do
|
310
|
+
let(:content) { CONTENT }
|
311
|
+
|
312
|
+
describe "date ordering" do
|
313
|
+
let(:content) do
|
314
|
+
<<-FILE
|
315
|
+
### Activities:
|
316
|
+
- 2017-01-01: Activity 1.
|
317
|
+
|
318
|
+
### Friends:
|
319
|
+
|
320
|
+
### Locations:
|
321
|
+
FILE
|
322
|
+
end
|
323
|
+
|
324
|
+
subject do
|
325
|
+
run_cmd("add activity 2017-01-01: Activity 2.")
|
326
|
+
run_cmd("add activity 2017-01-01: Activity 3.")
|
327
|
+
run_cmd("add activity 2017-01-01: Activity 4.")
|
328
|
+
end
|
329
|
+
|
330
|
+
it "orders dates by insertion time" do
|
331
|
+
subject
|
332
|
+
File.read(filename).must_equal <<-FILE
|
333
|
+
### Activities:
|
334
|
+
- 2017-01-01: Activity 4.
|
335
|
+
- 2017-01-01: Activity 3.
|
336
|
+
- 2017-01-01: Activity 2.
|
337
|
+
- 2017-01-01: Activity 1.
|
338
|
+
|
339
|
+
### Friends:
|
340
|
+
|
341
|
+
### Locations:
|
342
|
+
FILE
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
describe "when given a date and a description in the command" do
|
347
|
+
subject { run_cmd("add activity #{date}: #{description}") }
|
348
|
+
|
349
|
+
date_parsing_specs
|
350
|
+
description_parsing_specs
|
351
|
+
end
|
352
|
+
|
353
|
+
describe "when given only a date in the command" do
|
354
|
+
subject { run_cmd("add activity #{date}", stdin_data: description) }
|
355
|
+
|
356
|
+
# We don't try to test the STDOUT here because our command prompt produces other STDOUT that's
|
357
|
+
# hard to test.
|
358
|
+
date_parsing_specs(test_stdout: false)
|
359
|
+
description_parsing_specs(test_stdout: false)
|
360
|
+
end
|
361
|
+
|
362
|
+
describe "when given only a description in the command" do
|
363
|
+
subject { run_cmd("add activity #{description}") }
|
364
|
+
|
365
|
+
# We don't test date parsing since in this case the date is always inferred to be today.
|
366
|
+
|
367
|
+
description_parsing_specs
|
368
|
+
end
|
369
|
+
|
370
|
+
describe "when given neither a date nor a description in the command" do
|
371
|
+
subject { run_cmd("add activity", stdin_data: description) }
|
372
|
+
|
373
|
+
# We don't test date parsing since in this case the date is always inferred to be today.
|
374
|
+
|
375
|
+
# We don't try to test the STDOUT here because our command prompt produces other STDOUT that's
|
376
|
+
# hard to test.
|
377
|
+
description_parsing_specs(test_stdout: false)
|
378
|
+
end
|
379
|
+
end
|