friends 0.28 → 0.29

Sign up to get free protection for your applications and to get access to all the features.
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