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,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "add friend" do
6
+ subject { run_cmd("add friend #{friend_name}") }
7
+
8
+ let(:content) { CONTENT }
9
+
10
+ describe "when there is an existing friend with that name" do
11
+ let(:friend_name) { "George Washington Carver" }
12
+
13
+ it "prints an error message" do
14
+ stderr_only 'Error: Friend named "George Washington Carver" already exists'
15
+ end
16
+ end
17
+
18
+ describe "when there is no existing friend with that name" do
19
+ # This also tests that we can use multi-word names without quotes.
20
+ let(:friend_name) { "George Washington" }
21
+
22
+ it "adds friend" do
23
+ line_added "- George Washington"
24
+ end
25
+
26
+ it "prints an output message" do
27
+ stdout_only 'Friend added: "George Washington"'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "add location" do
6
+ subject { run_cmd("add location #{location_name}") }
7
+
8
+ let(:content) { CONTENT }
9
+
10
+ describe "when there is an existing location with that name" do
11
+ let(:location_name) { "Paris" }
12
+
13
+ it "prints an error message" do
14
+ stderr_only 'Error: Location "Paris" already exists'
15
+ end
16
+ end
17
+
18
+ describe "when there is no existing location with that name" do
19
+ # This also tests that we can use multi-word names without quotes.
20
+ let(:location_name) { "New England" }
21
+
22
+ it "adds location" do
23
+ line_added "- New England"
24
+ end
25
+
26
+ it "prints an output message" do
27
+ stdout_only 'Location added: "New England"'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "add nickname" do
6
+ subject { run_cmd("add 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) { "Georgie" }
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) { "Georgie" }
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) { "George" }
32
+ let(:nickname) { "Georgie" }
33
+
34
+ it "adds nickname to friend" do
35
+ line_changed "- George Washington Carver", "- George Washington Carver (a.k.a. Georgie)"
36
+ end
37
+
38
+ it "updates parenthetical in file when friend has existing nicknames" do
39
+ run_cmd("add nickname #{friend_name} 'Mr. Peanut'")
40
+ line_changed(
41
+ "- George Washington Carver (a.k.a. Mr. Peanut)",
42
+ "- George Washington Carver (a.k.a. Mr. Peanut a.k.a. Georgie)"
43
+ )
44
+ end
45
+
46
+ it "prints an output message" do
47
+ stdout_only 'Nickname added: "George Washington Carver (a.k.a. Georgie)"'
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "add tag" do
6
+ subject { run_cmd("add 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) { "school" }
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) { "school" }
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) { "George" }
32
+ let(:tag) { "school" }
33
+
34
+ it "adds tag to friend" do
35
+ line_changed "- George Washington Carver", "- George Washington Carver @school"
36
+ end
37
+
38
+ it "prints an output message" do
39
+ stdout_only 'Tag added to friend: "George Washington Carver @school"'
40
+ end
41
+
42
+ describe "when tag is passed with @" do
43
+ let(:tag) { "@school" }
44
+
45
+ it "adds tag to friend" do
46
+ line_changed "- George Washington Carver", "- George Washington Carver @school"
47
+ end
48
+
49
+ it "prints an output message" do
50
+ stdout_only 'Tag added to friend: "George Washington Carver @school"'
51
+ end
52
+ end
53
+
54
+ describe "when friend already has tags" do
55
+ let(:friend_name) { "Marie" }
56
+
57
+ it "allows for multiple tags" do
58
+ line_changed(
59
+ "- Marie Curie [Atlantis] @science",
60
+ "- Marie Curie [Atlantis] @science @school"
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "clean" do
6
+ subject { run_cmd("clean") }
7
+
8
+ it "outputs a message" do
9
+ stdout_only "File cleaned: \"#{filename}\""
10
+ end
11
+
12
+ describe "when file does not exist" do
13
+ it "does not create the file" do
14
+ File.exist?(filename).must_equal false
15
+ end
16
+ end
17
+
18
+ describe "when file is empty" do
19
+ let(:content) { "" }
20
+
21
+ it "adds the file structure" do
22
+ file_equals <<-FILE
23
+ ### Activities:
24
+
25
+ ### Friends:
26
+
27
+ ### Locations:
28
+ FILE
29
+ end
30
+ end
31
+
32
+ describe "when file has content" do
33
+ let(:content) { SCRAMBLED_CONTENT }
34
+
35
+ it "writes the file with contents sorted" do
36
+ file_equals CONTENT
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "graph" do
6
+ subject { run_cmd("graph") }
7
+
8
+ describe "when file does not exist" do
9
+ it "prints no output" do
10
+ stdout_only ""
11
+ end
12
+ end
13
+
14
+ describe "when file is empty" do
15
+ let(:content) { "" }
16
+
17
+ it "prints no output" do
18
+ stdout_only ""
19
+ end
20
+ end
21
+
22
+ describe "when file has content" do
23
+ let(:content) { CONTENT } # Content must be sorted to avoid errors.
24
+
25
+ it "graphs all activities" do
26
+ stdout_only <<-OUTPUT
27
+ Nov 2014 |█
28
+ Dec 2014 |█
29
+ Jan 2015 |█
30
+ Feb 2015 |
31
+ Mar 2015 |
32
+ Apr 2015 |
33
+ May 2015 |
34
+ Jun 2015 |
35
+ Jul 2015 |
36
+ Aug 2015 |
37
+ Sep 2015 |
38
+ Oct 2015 |
39
+ Nov 2015 |█
40
+ OUTPUT
41
+ end
42
+
43
+ describe "--in" do
44
+ subject { run_cmd("graph --in #{location_name}") }
45
+
46
+ describe "when location does not exist" do
47
+ let(:location_name) { "Garbage" }
48
+ it "prints an error message" do
49
+ stderr_only 'Error: No location found for "Garbage"'
50
+ end
51
+ end
52
+
53
+ describe "when location exists" do
54
+ let(:location_name) { "paris" }
55
+ it "matches location case-insensitively" do
56
+ stdout_only <<-OUTPUT
57
+ Dec 2014 |█
58
+ OUTPUT
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "--with" do
64
+ subject { run_cmd("graph --with #{friend_name}") }
65
+
66
+ describe "when friend does not exist" do
67
+ let(:friend_name) { "Garbage" }
68
+ it "prints an error message" do
69
+ stderr_only 'Error: No friend found for "Garbage"'
70
+ end
71
+ end
72
+
73
+ describe "when friend name matches more than one friend" do
74
+ let(:friend_name) { "george" }
75
+ before { run_cmd("add friend George Harrison") }
76
+ it "prints an error message" do
77
+ stderr_only 'Error: More than one friend found for "george": '\
78
+ "George Harrison, George Washington Carver"
79
+ end
80
+ end
81
+
82
+ describe "when friend name matches one friend" do
83
+ let(:friend_name) { "george" }
84
+
85
+ it "matches friend case-insensitively" do
86
+ stdout_only <<-OUTPUT
87
+ Nov 2014 |█
88
+ Dec 2014 |
89
+ Jan 2015 |█
90
+ OUTPUT
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "--tagged" do
96
+ subject { run_cmd("graph --tagged food") }
97
+
98
+ it "matches tag case-sensitively" do
99
+ stdout_only <<-OUTPUT
100
+ Jan 2015 |█
101
+ Feb 2015 |
102
+ Mar 2015 |
103
+ Apr 2015 |
104
+ May 2015 |
105
+ Jun 2015 |
106
+ Jul 2015 |
107
+ Aug 2015 |
108
+ Sep 2015 |
109
+ Oct 2015 |
110
+ Nov 2015 |█
111
+ OUTPUT
112
+ end
113
+ end
114
+
115
+ describe "--since" do
116
+ subject { run_cmd("graph --since 'January 4th 2015'") }
117
+
118
+ it "graphs activities on and after the specified date" do
119
+ stdout_only <<-OUTPUT
120
+ Jan 2015 |█
121
+ Feb 2015 |
122
+ Mar 2015 |
123
+ Apr 2015 |
124
+ May 2015 |
125
+ Jun 2015 |
126
+ Jul 2015 |
127
+ Aug 2015 |
128
+ Sep 2015 |
129
+ Oct 2015 |
130
+ Nov 2015 |█
131
+ OUTPUT
132
+ end
133
+ end
134
+
135
+ describe "--after" do
136
+ subject { run_cmd("graph --until 'January 4th 2015'") }
137
+
138
+ it "graphs activities before and on the specified date" do
139
+ stdout_only <<-OUTPUT
140
+ Nov 2014 |█
141
+ Dec 2014 |█
142
+ Jan 2015 |█
143
+ OUTPUT
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "help" do
6
+ subject { run_cmd("help") }
7
+
8
+ describe "with no subcommand passed" do
9
+ it "prints overall help message" do
10
+ subject[:stderr].must_equal ""
11
+ subject[:status].must_equal 0
12
+ [
13
+ "NAME",
14
+ "SYNOPSIS",
15
+ "VERSION",
16
+ "GLOBAL OPTIONS",
17
+ "COMMANDS"
18
+ ].all? { |msg| subject[:stdout].include? msg }.must_equal true
19
+ end
20
+ end
21
+
22
+ describe "with a subcommand passed" do
23
+ subject { run_cmd("help graph") }
24
+
25
+ it "prints subcommand help message" do
26
+ subject[:stderr].must_equal ""
27
+ subject[:status].must_equal 0
28
+ [
29
+ "NAME",
30
+ "SYNOPSIS",
31
+ "COMMAND OPTIONS"
32
+ ].all? { |msg| subject[:stdout].include? msg }.must_equal true
33
+ end
34
+ end
35
+
36
+ describe "with an invalid subcommand passed" do
37
+ subject { run_cmd("help garbage") }
38
+
39
+ # FIXME uncomment!!!
40
+ # Waiting for: https://github.com/davetron5000/gli/issues/255
41
+ # it "prints an error message" do
42
+ # stderr_only "error: Unknown command 'garbage'. Use 'friends help' for a list of commands."
43
+ # end
44
+ end
45
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./test/helper"
4
+
5
+ clean_describe "list activities" do
6
+ subject { run_cmd("list activities") }
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 activities in file order" do
28
+ stdout_only <<-OUTPUT
29
+ 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
30
+ 2015-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute. @food
31
+ 2014-11-15: Talked to George Washington Carver on the phone for an hour.
32
+ 2014-12-31: Celebrated the new year in Paris with Marie Curie. @partying
33
+ OUTPUT
34
+ end
35
+
36
+ describe "--limit" do
37
+ subject { run_cmd("list activities --limit #{limit}") }
38
+
39
+ describe "when limit is less than 1" do
40
+ let(:limit) { 0 }
41
+ it "prints an error message" do
42
+ stderr_only "Error: Limit must be positive"
43
+ end
44
+ end
45
+
46
+ describe "when limit is 1 or greater" do
47
+ let(:limit) { 2 }
48
+ it "limits output to the number specified" do
49
+ stdout_only <<-OUTPUT
50
+ 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
51
+ 2015-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute. @food
52
+ OUTPUT
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "--in" do
58
+ subject { run_cmd("list activities --in #{location_name}") }
59
+
60
+ describe "when location does not exist" do
61
+ let(:location_name) { "Garbage" }
62
+ it "prints an error message" do
63
+ stderr_only 'Error: No location found for "Garbage"'
64
+ end
65
+ end
66
+
67
+ describe "when location exists" do
68
+ let(:location_name) { "paris" }
69
+ it "matches location case-insensitively" do
70
+ stdout_only "2014-12-31: Celebrated the new year in Paris with Marie Curie. @partying"
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "--with" do
76
+ subject { run_cmd("list activities --with #{friend_name}") }
77
+
78
+ describe "when friend does not exist" do
79
+ let(:friend_name) { "Garbage" }
80
+ it "prints an error message" do
81
+ stderr_only 'Error: No friend found for "Garbage"'
82
+ end
83
+ end
84
+
85
+ describe "when friend name matches more than one friend" do
86
+ let(:friend_name) { "george" }
87
+ before { run_cmd("add friend George Harrison") }
88
+ it "prints an error message" do
89
+ stderr_only 'Error: More than one friend found for "george": '\
90
+ "George Harrison, George Washington Carver"
91
+ end
92
+ end
93
+
94
+ describe "when friend name matches one friend" do
95
+ let(:friend_name) { "marie" }
96
+ it "matches friend case-insensitively" do
97
+ stdout_only "2014-12-31: Celebrated the new year in Paris with Marie Curie. @partying"
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "--tagged" do
103
+ subject { run_cmd("list activities --tagged food") }
104
+
105
+ it "matches tag case-sensitively" do
106
+ stdout_only <<-OUTPUT
107
+ 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
108
+ 2015-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute. @food
109
+ OUTPUT
110
+ end
111
+ end
112
+
113
+ describe "--since" do
114
+ subject { run_cmd("list activities --since 'January 4th 2015'") }
115
+
116
+ it "lists activities on and after the specified date" do
117
+ stdout_only <<-OUTPUT
118
+ 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
119
+ 2015-11-01: Grace Hopper and I went to Marie's Diner. George had to cancel at the last minute. @food
120
+ OUTPUT
121
+ end
122
+ end
123
+
124
+ describe "--after" do
125
+ subject { run_cmd("list activities --until 'January 4th 2015'") }
126
+
127
+ it "lists activities before and on the specified date" do
128
+ stdout_only <<-OUTPUT
129
+ 2015-01-04: Got lunch with Grace Hopper and George Washington Carver. @food
130
+ 2014-11-15: Talked to George Washington Carver on the phone for an hour.
131
+ 2014-12-31: Celebrated the new year in Paris with Marie Curie. @partying
132
+ OUTPUT
133
+ end
134
+ end
135
+ end
136
+ end