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
@@ -7,6 +7,15 @@ clean_describe "remove tag" do
|
|
7
7
|
|
8
8
|
let(:content) { CONTENT }
|
9
9
|
|
10
|
+
describe "when friend name and tag are blank" do
|
11
|
+
let(:friend_name) { nil }
|
12
|
+
let(:tag) { nil }
|
13
|
+
|
14
|
+
it "prints an error message" do
|
15
|
+
stderr_only 'Error: No friend found for ""'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
10
19
|
describe "when friend name has no matches" do
|
11
20
|
let(:friend_name) { "Garbage" }
|
12
21
|
let(:tag) { "science" }
|
data/test/commands/stats_spec.rb
CHANGED
data/test/default_file_spec.rb
CHANGED
@@ -4,7 +4,7 @@ require "./test/helper"
|
|
4
4
|
|
5
5
|
# Since this touches the ~/friends.md file instead of a temp
|
6
6
|
# one, we only want to run it on our CI servers.
|
7
|
-
if ENV["
|
7
|
+
if ENV["CI"] == "true"
|
8
8
|
describe "default filename behavior" do
|
9
9
|
let(:filename) { File.expand_path("~/friends.md") }
|
10
10
|
|
data/test/helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
if ENV["
|
3
|
+
if ENV["CI"] == "true" && ENV["CODE_COVERAGE"] == "true"
|
4
4
|
require "simplecov"
|
5
5
|
require "codecov"
|
6
6
|
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
@@ -48,6 +48,7 @@ CONTENT = <<-FILE
|
|
48
48
|
### Locations:
|
49
49
|
- Atlantis
|
50
50
|
- Martha's Vineyard
|
51
|
+
- New York City (a.k.a. NYC a.k.a. NY)
|
51
52
|
- Paris
|
52
53
|
FILE
|
53
54
|
|
@@ -77,6 +78,7 @@ SCRAMBLED_CONTENT = <<-FILE
|
|
77
78
|
- Paris
|
78
79
|
- Atlantis
|
79
80
|
- Martha's Vineyard
|
81
|
+
- New York City (a.k.a. NYC a.k.a. NY)
|
80
82
|
FILE
|
81
83
|
|
82
84
|
# Define these methods so they can be referenced in the methods below. They'll be overridden in
|
@@ -119,6 +121,17 @@ def stderr_only(expected)
|
|
119
121
|
value(subject[:status]).must_be :>, 0
|
120
122
|
end
|
121
123
|
|
124
|
+
def stdout_only_regexes(regexes)
|
125
|
+
puts subject[:stderr] unless subject[:stderr] == ""
|
126
|
+
lines = subject[:stdout].split("\n")
|
127
|
+
regexes.each_with_index do |regex, index|
|
128
|
+
value(lines[index]).must_match regex
|
129
|
+
end
|
130
|
+
assert_nil(lines[regexes.size])
|
131
|
+
value(subject[:stderr]).must_equal ""
|
132
|
+
value(subject[:status]).must_equal 0
|
133
|
+
end
|
134
|
+
|
122
135
|
def file_equals(expected)
|
123
136
|
subject
|
124
137
|
value(File.read(filename)).must_equal expected
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: friends
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.55'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Evelyn
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|
@@ -120,10 +120,10 @@ files:
|
|
120
120
|
- ".github/FUNDING.yml"
|
121
121
|
- ".github/ISSUE_TEMPLATE.md"
|
122
122
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
123
|
+
- ".github/workflows/main.yml"
|
123
124
|
- ".gitignore"
|
124
125
|
- ".overcommit.yml"
|
125
126
|
- ".rubocop.yml"
|
126
|
-
- ".travis.yml"
|
127
127
|
- CHANGELOG.md
|
128
128
|
- CODE_OF_CONDUCT.md
|
129
129
|
- Gemfile
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/friends/version.rb
|
164
164
|
- test/add_event_helper.rb
|
165
165
|
- test/commands/add/activity_spec.rb
|
166
|
+
- test/commands/add/alias_spec.rb
|
166
167
|
- test/commands/add/friend_spec.rb
|
167
168
|
- test/commands/add/location_spec.rb
|
168
169
|
- test/commands/add/nickname_spec.rb
|
@@ -173,12 +174,11 @@ files:
|
|
173
174
|
- test/commands/graph_spec.rb
|
174
175
|
- test/commands/help_spec.rb
|
175
176
|
- test/commands/list/activities_spec.rb
|
176
|
-
- test/commands/list/favorite/friends_spec.rb
|
177
|
-
- test/commands/list/favorite/locations_spec.rb
|
178
177
|
- test/commands/list/friends_spec.rb
|
179
178
|
- test/commands/list/locations_spec.rb
|
180
179
|
- test/commands/list/notes_spec.rb
|
181
180
|
- test/commands/list/tags_spec.rb
|
181
|
+
- test/commands/remove/alias_spec.rb
|
182
182
|
- test/commands/remove/nickname_spec.rb
|
183
183
|
- test/commands/remove/tag_spec.rb
|
184
184
|
- test/commands/rename/friend_spec.rb
|
@@ -212,13 +212,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
212
|
- !ruby/object:Gem::Version
|
213
213
|
version: '0'
|
214
214
|
requirements: []
|
215
|
-
rubygems_version: 3.
|
216
|
-
signing_key:
|
215
|
+
rubygems_version: 3.1.4
|
216
|
+
signing_key:
|
217
217
|
specification_version: 4
|
218
218
|
summary: Spend time with the people you care about.
|
219
219
|
test_files:
|
220
220
|
- test/add_event_helper.rb
|
221
221
|
- test/commands/add/activity_spec.rb
|
222
|
+
- test/commands/add/alias_spec.rb
|
222
223
|
- test/commands/add/friend_spec.rb
|
223
224
|
- test/commands/add/location_spec.rb
|
224
225
|
- test/commands/add/nickname_spec.rb
|
@@ -229,12 +230,11 @@ test_files:
|
|
229
230
|
- test/commands/graph_spec.rb
|
230
231
|
- test/commands/help_spec.rb
|
231
232
|
- test/commands/list/activities_spec.rb
|
232
|
-
- test/commands/list/favorite/friends_spec.rb
|
233
|
-
- test/commands/list/favorite/locations_spec.rb
|
234
233
|
- test/commands/list/friends_spec.rb
|
235
234
|
- test/commands/list/locations_spec.rb
|
236
235
|
- test/commands/list/notes_spec.rb
|
237
236
|
- test/commands/list/tags_spec.rb
|
237
|
+
- test/commands/remove/alias_spec.rb
|
238
238
|
- test/commands/remove/nickname_spec.rb
|
239
239
|
- test/commands/remove/tag_spec.rb
|
240
240
|
- test/commands/rename/friend_spec.rb
|
data/.travis.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 2.3
|
4
|
-
- 2.4
|
5
|
-
- 2.5
|
6
|
-
- 2.6 # 2.7 is tested below
|
7
|
-
gemfile: Gemfile.old # The latest Ruby version uses Gemfile below
|
8
|
-
script:
|
9
|
-
- bundle exec rake test
|
10
|
-
matrix:
|
11
|
-
include:
|
12
|
-
- rvm: 2.7
|
13
|
-
gemfile: Gemfile
|
14
|
-
script:
|
15
|
-
- bundle exec rake test
|
16
|
-
- gem install --no-document rubocop && rubocop
|
17
|
-
env:
|
18
|
-
- CODE_COVERAGE=true
|
19
|
-
branches:
|
20
|
-
only:
|
21
|
-
- master # Always run on the master branch
|
22
|
-
notifications:
|
23
|
-
email: false
|
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "./test/helper"
|
4
|
-
|
5
|
-
clean_describe "list favorite friends" do
|
6
|
-
subject { run_cmd("list favorite friends") }
|
7
|
-
|
8
|
-
describe "when file does not exist" do
|
9
|
-
let(:content) { nil }
|
10
|
-
|
11
|
-
it "prints a no-data message" do
|
12
|
-
stdout_only "Your favorite friends:"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "when file is empty" do
|
17
|
-
let(:content) { "" }
|
18
|
-
|
19
|
-
it "prints a no-data message" do
|
20
|
-
stdout_only "Your favorite friends:"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "when file has content" do
|
25
|
-
let(:content) do
|
26
|
-
<<-FILE
|
27
|
-
### Activities:
|
28
|
-
- 2017-01-01: Did some math with **Grace Hopper**.
|
29
|
-
- 2015-11-01: **Grace Hopper** and I went to _Martha's Vineyard_. George had to cancel at the last minute.
|
30
|
-
- 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
|
31
|
-
- 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
|
32
|
-
- 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
|
33
|
-
|
34
|
-
### Friends:
|
35
|
-
- George Washington Carver
|
36
|
-
- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
|
37
|
-
- Marie Curie [Atlantis] @science
|
38
|
-
FILE
|
39
|
-
end
|
40
|
-
|
41
|
-
it "lists friends in order of decreasing activity" do
|
42
|
-
stdout_only <<-OUTPUT
|
43
|
-
Your favorite friends:
|
44
|
-
1. Grace Hopper (3 activities)
|
45
|
-
2. George Washington Carver (2)
|
46
|
-
3. Marie Curie (1)
|
47
|
-
OUTPUT
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "when friends are tied for the same number of activities" do
|
51
|
-
let(:content) do
|
52
|
-
<<-FILE
|
53
|
-
### Activities:
|
54
|
-
- 2017-01-01: Did something with **Friend A**.
|
55
|
-
- 2017-01-01: Did something with **Friend A**.
|
56
|
-
- 2017-01-01: Did something with **Friend B**.
|
57
|
-
- 2017-01-01: Did something with **Friend B**.
|
58
|
-
- 2017-01-01: Did something with **Friend C**.
|
59
|
-
- 2017-01-01: Did something with **Friend D**.
|
60
|
-
- 2017-01-01: Did something with **Friend E**.
|
61
|
-
- 2017-01-01: Did something with **Friend F**.
|
62
|
-
- 2017-01-01: Did something with **Friend G**.
|
63
|
-
- 2017-01-01: Did something with **Friend H**.
|
64
|
-
- 2017-01-01: Did something with **Friend I**.
|
65
|
-
- 2017-01-01: Did something with **Friend J**.
|
66
|
-
|
67
|
-
### Friends:
|
68
|
-
- Friend A
|
69
|
-
- Friend B
|
70
|
-
- Friend C
|
71
|
-
- Friend D
|
72
|
-
- Friend E
|
73
|
-
- Friend F
|
74
|
-
- Friend G
|
75
|
-
- Friend H
|
76
|
-
- Friend I
|
77
|
-
- Friend J
|
78
|
-
FILE
|
79
|
-
end
|
80
|
-
|
81
|
-
it "uses tied ranks" do
|
82
|
-
value(subject[:stderr]).must_equal ""
|
83
|
-
value(subject[:status]).must_equal 0
|
84
|
-
|
85
|
-
lines = subject[:stdout].split("\n")
|
86
|
-
value(lines[1]).must_match(/1\. Friend (A|B)/)
|
87
|
-
value(lines[2]).must_match(/1\. Friend (A|B)/)
|
88
|
-
value(lines[3]).must_include "3. Friend"
|
89
|
-
end
|
90
|
-
|
91
|
-
it "only uses the word 'activities' for the first item, even when a tie" do
|
92
|
-
value(subject[:stderr]).must_equal ""
|
93
|
-
value(subject[:status]).must_equal 0
|
94
|
-
|
95
|
-
lines = subject[:stdout].split("\n")
|
96
|
-
value(lines[1]).must_include "activities"
|
97
|
-
value(lines[2]).wont_include "activities"
|
98
|
-
end
|
99
|
-
|
100
|
-
it "indents based on the highest rank number, not the number of friends" do
|
101
|
-
value(subject[:stderr]).must_equal ""
|
102
|
-
value(subject[:status]).must_equal 0
|
103
|
-
|
104
|
-
# Since there are 10 friends, a naive implementation would pad our output
|
105
|
-
# assuming the (numerically) highest rank is "10." but since the highest
|
106
|
-
# rank is a tie, we never display a double-digit rank, so we don't need to
|
107
|
-
# pad our output for double digits.
|
108
|
-
lines = subject[:stdout].split("\n")
|
109
|
-
value(lines.last).must_include "3. Friend"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
@@ -1,149 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "./test/helper"
|
4
|
-
|
5
|
-
clean_describe "list favorite locations" do
|
6
|
-
subject { run_cmd("list favorite locations") }
|
7
|
-
|
8
|
-
describe "when file does not exist" do
|
9
|
-
let(:content) { nil }
|
10
|
-
|
11
|
-
it "prints a no-data message" do
|
12
|
-
stdout_only "Your favorite locations:"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "when file is empty" do
|
17
|
-
let(:content) { "" }
|
18
|
-
|
19
|
-
it "prints a no-data message" do
|
20
|
-
stdout_only "Your favorite locations:"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "when file has content" do
|
25
|
-
let(:content) do
|
26
|
-
<<-FILE
|
27
|
-
### Activities:
|
28
|
-
- 2017-01-01: **Grace Hopper** and I went to _Martha's Vineyard_ for breakfast.
|
29
|
-
- 2015-11-01: **Grace Hopper** and I went to _Martha's Vineyard_. George had to cancel at the last minute.
|
30
|
-
- 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
|
31
|
-
- 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
|
32
|
-
- 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
|
33
|
-
|
34
|
-
### Friends:
|
35
|
-
- George Washington Carver
|
36
|
-
- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
|
37
|
-
- Marie Curie [Atlantis] @science
|
38
|
-
|
39
|
-
### Locations:
|
40
|
-
- Atlantis
|
41
|
-
- Martha's Vineyard
|
42
|
-
- Paris
|
43
|
-
FILE
|
44
|
-
end
|
45
|
-
|
46
|
-
it "lists locations in order of decreasing activity" do
|
47
|
-
stdout_only <<-OUTPUT
|
48
|
-
Your favorite locations:
|
49
|
-
1. Martha's Vineyard (2 activities)
|
50
|
-
2. Paris (1)
|
51
|
-
3. Atlantis (0)
|
52
|
-
OUTPUT
|
53
|
-
end
|
54
|
-
|
55
|
-
describe "when locations are tied for the same number of activities" do
|
56
|
-
let(:content) do
|
57
|
-
<<-FILE
|
58
|
-
### Activities:
|
59
|
-
- 2017-01-01: Did something in _Location A_.
|
60
|
-
- 2017-01-01: Did something in _Location A_.
|
61
|
-
- 2017-01-01: Did something in _Location B_.
|
62
|
-
- 2017-01-01: Did something in _Location B_.
|
63
|
-
- 2017-01-01: Did something in _Location C_.
|
64
|
-
- 2017-01-01: Did something in _Location D_.
|
65
|
-
- 2017-01-01: Did something in _Location E_.
|
66
|
-
- 2017-01-01: Did something in _Location F_.
|
67
|
-
- 2017-01-01: Did something in _Location G_.
|
68
|
-
- 2017-01-01: Did something in _Location H_.
|
69
|
-
- 2017-01-01: Did something in _Location I_.
|
70
|
-
- 2017-01-01: Did something in _Location J_.
|
71
|
-
|
72
|
-
### Locations:
|
73
|
-
- Location A
|
74
|
-
- Location B
|
75
|
-
- Location C
|
76
|
-
- Location D
|
77
|
-
- Location E
|
78
|
-
- Location F
|
79
|
-
- Location G
|
80
|
-
- Location H
|
81
|
-
- Location I
|
82
|
-
- Location J
|
83
|
-
FILE
|
84
|
-
end
|
85
|
-
|
86
|
-
it "uses tied ranks" do
|
87
|
-
value(subject[:stderr]).must_equal ""
|
88
|
-
value(subject[:status]).must_equal 0
|
89
|
-
|
90
|
-
lines = subject[:stdout].split("\n")
|
91
|
-
value(lines[1]).must_match(/1\. Location (A|B)/)
|
92
|
-
value(lines[2]).must_match(/1\. Location (A|B)/)
|
93
|
-
value(lines[3]).must_include "3. Location"
|
94
|
-
end
|
95
|
-
|
96
|
-
it "only uses the word 'activities' for the first item, even when a tie" do
|
97
|
-
value(subject[:stderr]).must_equal ""
|
98
|
-
value(subject[:status]).must_equal 0
|
99
|
-
|
100
|
-
lines = subject[:stdout].split("\n")
|
101
|
-
value(lines[1]).must_include "activities"
|
102
|
-
value(lines[2]).wont_include "activities"
|
103
|
-
end
|
104
|
-
|
105
|
-
it "indents based on the highest rank number, not the number of locations" do
|
106
|
-
value(subject[:stderr]).must_equal ""
|
107
|
-
value(subject[:status]).must_equal 0
|
108
|
-
|
109
|
-
# Since there are 10 friends, a naive implementation would pad our output
|
110
|
-
# assuming the (numerically) highest rank is "10." but since the highest
|
111
|
-
# rank is a tie, we never display a double-digit rank, so we don't need to
|
112
|
-
# pad our output for double digits.
|
113
|
-
lines = subject[:stdout].split("\n")
|
114
|
-
value(lines.last).must_include "3. Location"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
describe "when implied locations are set" do
|
119
|
-
let(:content) do
|
120
|
-
<<-FILE
|
121
|
-
### Activities:
|
122
|
-
- 2015-01-30: Went to a museum with **George Washington Carver**.
|
123
|
-
- 2015-01-29: Moved to _Paris_.
|
124
|
-
- 2015-01-01: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
|
125
|
-
- 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying @food
|
126
|
-
- 2014-12-30: Went to _Atlantis_.
|
127
|
-
- 2014-12-29: Talked to **George Washington Carver** on the phone for an hour.
|
128
|
-
|
129
|
-
### Friends:
|
130
|
-
- George Washington Carver
|
131
|
-
- Marie Curie [Atlantis] @science
|
132
|
-
- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
|
133
|
-
|
134
|
-
### Locations:
|
135
|
-
- Atlantis
|
136
|
-
- Paris
|
137
|
-
FILE
|
138
|
-
end
|
139
|
-
|
140
|
-
it "lists locations in order of decreasing activity" do
|
141
|
-
stdout_only <<-OUTPUT
|
142
|
-
Your favorite locations:
|
143
|
-
1. Paris (3 activities)
|
144
|
-
2. Atlantis (2)
|
145
|
-
OUTPUT
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|