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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -4
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +2 -0
  5. data/CHANGELOG.md +13 -0
  6. data/README.md +35 -5
  7. data/Rakefile +1 -1
  8. data/bin/friends +7 -379
  9. data/friends.gemspec +3 -1
  10. data/lib/friends/activity.rb +4 -4
  11. data/lib/friends/commands/add.rb +64 -0
  12. data/lib/friends/commands/clean.rb +9 -0
  13. data/lib/friends/commands/edit.rb +12 -0
  14. data/lib/friends/commands/graph.rb +56 -0
  15. data/lib/friends/commands/list.rb +143 -0
  16. data/lib/friends/commands/remove.rb +27 -0
  17. data/lib/friends/commands/rename.rb +30 -0
  18. data/lib/friends/commands/set.rb +14 -0
  19. data/lib/friends/commands/stats.rb +11 -0
  20. data/lib/friends/commands/suggest.rb +20 -0
  21. data/lib/friends/commands/update.rb +29 -0
  22. data/lib/friends/graph.rb +7 -7
  23. data/lib/friends/introvert.rb +23 -18
  24. data/lib/friends/version.rb +1 -1
  25. data/test/commands/add/activity_spec.rb +379 -0
  26. data/test/commands/add/friend_spec.rb +30 -0
  27. data/test/commands/add/location_spec.rb +30 -0
  28. data/test/commands/add/nickname_spec.rb +50 -0
  29. data/test/commands/add/tag_spec.rb +65 -0
  30. data/test/commands/clean_spec.rb +39 -0
  31. data/test/commands/graph_spec.rb +147 -0
  32. data/test/commands/help_spec.rb +45 -0
  33. data/test/commands/list/activities_spec.rb +136 -0
  34. data/test/commands/list/favorite/friends_spec.rb +77 -0
  35. data/test/commands/list/favorite/locations_spec.rb +82 -0
  36. data/test/commands/list/friends_spec.rb +76 -0
  37. data/test/commands/list/locations_spec.rb +35 -0
  38. data/test/commands/list/tags_spec.rb +58 -0
  39. data/test/commands/remove/nickname_spec.rb +63 -0
  40. data/test/commands/remove/tag_spec.rb +64 -0
  41. data/test/commands/rename/friend_spec.rb +55 -0
  42. data/test/commands/rename/location_spec.rb +43 -0
  43. data/test/commands/set/location_spec.rb +54 -0
  44. data/test/commands/stats_spec.rb +41 -0
  45. data/test/commands/suggest_spec.rb +86 -0
  46. data/test/commands/update_spec.rb +13 -0
  47. data/test/helper.rb +114 -0
  48. metadata +89 -15
  49. data/test/activity_spec.rb +0 -597
  50. data/test/friend_spec.rb +0 -241
  51. data/test/graph_spec.rb +0 -92
  52. data/test/introvert_spec.rb +0 -969
  53. data/test/location_spec.rb +0 -60
@@ -0,0 +1,77 @@
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
+ it "prints a no-data message" do
10
+ stdout_only "Your favorite friends:"
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "prints a no-data message" do
18
+ stdout_only "Your favorite friends:"
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ let(:content) do
24
+ <<-FILE
25
+ ### Activities:
26
+ - 2017-01-01: Did some math with **Grace Hopper**.
27
+ - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
28
+ - 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
29
+ - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
30
+ - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
31
+
32
+ ### Friends:
33
+ - George Washington Carver
34
+ - Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
35
+ - Marie Curie [Atlantis] @science
36
+ FILE
37
+ end
38
+
39
+ it "lists friends in order of decreasing activity" do
40
+ stdout_only <<-OUTPUT
41
+ Your favorite friends:
42
+ 1. Grace Hopper (3 activities)
43
+ 2. George Washington Carver (2)
44
+ 3. Marie Curie (1)
45
+ OUTPUT
46
+ end
47
+
48
+ describe "--limit" do
49
+ subject { run_cmd("list favorite friends --limit #{limit}") }
50
+
51
+ describe "when limit is less than 1" do
52
+ let(:limit) { 0 }
53
+ it "prints an error message" do
54
+ stderr_only "Error: Favorites limit must be positive"
55
+ end
56
+ end
57
+
58
+ describe "when limit is 1" do
59
+ let(:limit) { 1 }
60
+ it "outputs as a best friend" do
61
+ stdout_only "Your best friend is Grace Hopper (3 activities)"
62
+ end
63
+ end
64
+
65
+ describe "when limit is greater than 1" do
66
+ let(:limit) { 2 }
67
+ it "limits output to the number specified" do
68
+ stdout_only <<-OUTPUT
69
+ Your favorite friends:
70
+ 1. Grace Hopper (3 activities)
71
+ 2. George Washington Carver (2)
72
+ OUTPUT
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,82 @@
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
+ it "prints a no-data message" do
10
+ stdout_only "Your favorite locations:"
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "prints a no-data message" do
18
+ stdout_only "Your favorite locations:"
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ let(:content) do
24
+ <<-FILE
25
+ ### Activities:
26
+ - 2017-01-01: **Grace Hopper** and I went to _Marie's Diner_ for breakfast.
27
+ - 2015-11-01: **Grace Hopper** and I went to _Marie's Diner_. George had to cancel at the last minute. @food
28
+ - 2015-01-04: Got lunch with **Grace Hopper** and **George Washington Carver**. @food
29
+ - 2014-12-31: Celebrated the new year in _Paris_ with **Marie Curie**. @partying
30
+ - 2014-11-15: Talked to **George Washington Carver** on the phone for an hour.
31
+
32
+ ### Friends:
33
+ - George Washington Carver
34
+ - Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
35
+ - Marie Curie [Atlantis] @science
36
+
37
+ ### Locations:
38
+ - Atlantis
39
+ - Marie's Diner
40
+ - Paris
41
+ FILE
42
+ end
43
+
44
+ it "lists locations in order of decreasing activity" do
45
+ stdout_only <<-OUTPUT
46
+ Your favorite locations:
47
+ 1. Marie's Diner (2 activities)
48
+ 2. Paris (1)
49
+ 3. Atlantis (0)
50
+ OUTPUT
51
+ end
52
+
53
+ describe "--limit" do
54
+ subject { run_cmd("list favorite locations --limit #{limit}") }
55
+
56
+ describe "when limit is less than 1" do
57
+ let(:limit) { 0 }
58
+ it "prints an error message" do
59
+ stderr_only "Error: Favorites limit must be positive"
60
+ end
61
+ end
62
+
63
+ describe "when limit is 1" do
64
+ let(:limit) { 1 }
65
+ it "outputs as a favorite location" do
66
+ stdout_only "Your favorite location is Marie's Diner (2 activities)"
67
+ end
68
+ end
69
+
70
+ describe "when limit is greater than 1" do
71
+ let(:limit) { 2 }
72
+ it "limits output to the number specified" do
73
+ stdout_only <<-OUTPUT
74
+ Your favorite locations:
75
+ 1. Marie's Diner (2 activities)
76
+ 2. Paris (1)
77
+ OUTPUT
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "list friends" do
6
+ subject { run_cmd("list friends") }
7
+
8
+ describe "when file does not exist" do
9
+ it "does not list anything" do
10
+ stdout_only ""
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "does not list anything" do
18
+ stdout_only ""
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ # Use scrambled content to differentiate between output that is sorted and output that
24
+ # only reads from the (usually-sorted) file.
25
+ let(:content) { SCRAMBLED_CONTENT }
26
+
27
+ it "lists friends in file order" do
28
+ stdout_only <<-OUTPUT
29
+ George Washington Carver
30
+ Marie Curie
31
+ Grace Hopper
32
+ OUTPUT
33
+ end
34
+
35
+ describe "--verbose" do
36
+ subject { run_cmd("list friends --verbose") }
37
+
38
+ it "lists friends in file order with details" do
39
+ stdout_only <<-OUTPUT
40
+ George Washington Carver
41
+ Marie Curie [Atlantis] @science
42
+ Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science
43
+ OUTPUT
44
+ end
45
+ end
46
+
47
+ describe "--in" do
48
+ subject { run_cmd("list friends --in #{location_name}") }
49
+
50
+ describe "when location does not exist" do
51
+ let(:location_name) { "Garbage" }
52
+ it "prints an error message" do
53
+ stderr_only 'Error: No location found for "Garbage"'
54
+ end
55
+ end
56
+
57
+ describe "when location exists" do
58
+ let(:location_name) { "paris" }
59
+ it "matches location case-insensitively" do
60
+ stdout_only "Grace Hopper"
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "--tagged" do
66
+ subject { run_cmd("list friends --tagged science") }
67
+
68
+ it "matches tag case-sensitively" do
69
+ stdout_only <<-OUTPUT
70
+ Marie Curie
71
+ Grace Hopper
72
+ OUTPUT
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "list locations" do
6
+ subject { run_cmd("list locations") }
7
+
8
+ describe "when file does not exist" do
9
+ it "does not list anything" do
10
+ stdout_only ""
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "does not list anything" do
18
+ stdout_only ""
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ # Use scrambled content to differentiate between output that is sorted and output that
24
+ # only reads from the (usually-sorted) file.
25
+ let(:content) { SCRAMBLED_CONTENT }
26
+
27
+ it "lists locations in file order" do
28
+ stdout_only <<-OUTPUT
29
+ Paris
30
+ Atlantis
31
+ Marie's Diner
32
+ OUTPUT
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "list tags" do
6
+ subject { run_cmd("list tags") }
7
+
8
+ describe "when file does not exist" do
9
+ it "does not list anything" do
10
+ stdout_only ""
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "does not list anything" do
18
+ stdout_only ""
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ # Use scrambled content to differentiate between output that is sorted and output that
24
+ # only reads from the (usually-sorted) file.
25
+ let(:content) { SCRAMBLED_CONTENT }
26
+
27
+ it "lists unique tags" do
28
+ stdout_only <<-OUTPUT
29
+ @food
30
+ @navy
31
+ @partying
32
+ @science
33
+ OUTPUT
34
+ end
35
+
36
+ describe "--from activities" do
37
+ subject { run_cmd("list tags --from activities") }
38
+
39
+ it "lists unique tags from activities" do
40
+ stdout_only <<-OUTPUT
41
+ @food
42
+ @partying
43
+ OUTPUT
44
+ end
45
+ end
46
+
47
+ describe "--from friends" do
48
+ subject { run_cmd("list tags --from friends") }
49
+
50
+ it "lists unique tags from friends" do
51
+ stdout_only <<-OUTPUT
52
+ @navy
53
+ @science
54
+ OUTPUT
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "remove nickname" do
6
+ subject { run_cmd("remove nickname #{friend_name} #{nickname}") }
7
+
8
+ let(:content) { CONTENT }
9
+
10
+ describe "when friend name has no matches" do
11
+ let(:friend_name) { "Garbage" }
12
+ let(:nickname) { "'Amazing Grace'" }
13
+
14
+ it "prints an error message" do
15
+ stderr_only 'Error: No friend found for "Garbage"'
16
+ end
17
+ end
18
+
19
+ describe "when friend name has more than one match" do
20
+ let(:friend_name) { "George" }
21
+ let(:nickname) { "'Amazing Grace'" }
22
+ before { run_cmd("add friend George Harrison") }
23
+
24
+ it "prints an error message" do
25
+ stderr_only 'Error: More than one friend found for "George": '\
26
+ "George Harrison, George Washington Carver"
27
+ end
28
+ end
29
+
30
+ describe "when friend name has one match" do
31
+ let(:friend_name) { "Grace" }
32
+
33
+ describe "when nickname is not present on friend" do
34
+ let(:nickname) { "Gracie" }
35
+ it "prints an error message" do
36
+ stderr_only 'Error: Nickname "Gracie" not found for "Grace Hopper"'
37
+ end
38
+ end
39
+
40
+ describe "when nickname is present on friend" do
41
+ let(:nickname) { "'Amazing Grace'" }
42
+
43
+ it "removes nickname from friend" do
44
+ line_changed(
45
+ "- Grace Hopper (a.k.a. The Admiral a.k.a. Amazing Grace) [Paris] @navy @science",
46
+ "- Grace Hopper (a.k.a. The Admiral) [Paris] @navy @science"
47
+ )
48
+ end
49
+
50
+ it "removes parenthetical from file when friend has no more nicknames" do
51
+ run_cmd("remove nickname #{friend_name} 'The Admiral'")
52
+ line_changed(
53
+ "- Grace Hopper (a.k.a. Amazing Grace) [Paris] @navy @science",
54
+ "- Grace Hopper [Paris] @navy @science"
55
+ )
56
+ end
57
+
58
+ it "prints an output message" do
59
+ stdout_only 'Nickname removed: "Grace Hopper (a.k.a. The Admiral) [Paris] @navy @science"'
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "remove tag" do
6
+ subject { run_cmd("remove tag #{friend_name} #{tag}") }
7
+
8
+ let(:content) { CONTENT }
9
+
10
+ describe "when friend name has no matches" do
11
+ let(:friend_name) { "Garbage" }
12
+ let(:tag) { "science" }
13
+
14
+ it "prints an error message" do
15
+ stderr_only 'Error: No friend found for "Garbage"'
16
+ end
17
+ end
18
+
19
+ describe "when friend name has more than one match" do
20
+ let(:friend_name) { "George" }
21
+ let(:tag) { "science" }
22
+ before { run_cmd("add friend George Harrison") }
23
+
24
+ it "prints an error message" do
25
+ stderr_only 'Error: More than one friend found for "George": '\
26
+ "George Harrison, George Washington Carver"
27
+ end
28
+ end
29
+
30
+ describe "when friend name has one match" do
31
+ let(:friend_name) { "Marie" }
32
+
33
+ describe "when tag is not present on friend" do
34
+ let(:tag) { "garbage" }
35
+ it "prints an error message" do
36
+ stderr_only 'Error: Tag "@garbage" not found for "Marie Curie"'
37
+ end
38
+ end
39
+
40
+ describe "when tag is present on friend" do
41
+ let(:tag) { "science" }
42
+
43
+ it "removes tag from friend" do
44
+ line_changed "- Marie Curie [Atlantis] @science", "- Marie Curie [Atlantis]"
45
+ end
46
+
47
+ it "prints an output message" do
48
+ stdout_only 'Tag removed from friend: "Marie Curie [Atlantis]"'
49
+ end
50
+
51
+ describe "when tag is passed with @" do
52
+ let(:tag) { "@science" }
53
+
54
+ it "adds tag to friend" do
55
+ line_changed "- Marie Curie [Atlantis] @science", "- Marie Curie [Atlantis]"
56
+ end
57
+
58
+ it "prints an output message" do
59
+ stdout_only 'Tag removed from friend: "Marie Curie [Atlantis]"'
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end