friends 0.22 → 0.23
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/CHANGELOG.md +12 -0
- data/Gemfile +2 -0
- data/README.md +35 -8
- data/Rakefile +2 -0
- data/bin/friends +26 -9
- data/friends.gemspec +3 -2
- data/lib/friends.rb +2 -0
- data/lib/friends/activity.rb +8 -4
- data/lib/friends/friend.rb +3 -2
- data/lib/friends/friends_error.rb +2 -0
- data/lib/friends/graph.rb +60 -0
- data/lib/friends/introvert.rb +71 -51
- data/lib/friends/location.rb +2 -1
- data/lib/friends/regex_builder.rb +9 -8
- data/lib/friends/serializable.rb +2 -0
- data/lib/friends/version.rb +2 -1
- data/test/activity_spec.rb +2 -0
- data/test/friend_spec.rb +2 -0
- data/test/graph_spec.rb +92 -0
- data/test/helper.rb +2 -0
- data/test/introvert_spec.rb +63 -40
- data/test/location_spec.rb +2 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 560b5f5b4af9d8762ecb97f2a0ffdbb0cd8be02e
|
4
|
+
data.tar.gz: 39338ddbdffe9c8c712bed9e5078d0cfc5c8877a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2349672e223cec6d4f08df3ffce8209b8190540eb51862c72354d9a36144c813232bc18327a8d04c0da0d62ad1101f1a0931858f029e8e9cf1c94ea433c7ae0
|
7
|
+
data.tar.gz: 3c833ed0d247ea59064335482a182b9ffbb094b172e5388370161baba6992e0f7f125d41fb967628b14e581b252039e17c7fbb3cac9a800fc0c9cf6945983e37
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v0.23](https://github.com/JacobEvelyn/friends/tree/v0.23) (2016-05-16)
|
4
|
+
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.22...v0.23)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- Change `graph` to use `--with`, `--tagged`, and `--in` flags [\#124](https://github.com/JacobEvelyn/friends/issues/124)
|
9
|
+
- Add `graph` command for locations [\#109](https://github.com/JacobEvelyn/friends/issues/109)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Allow graph to be filtered by friend, location and hashtag [\#129](https://github.com/JacobEvelyn/friends/pull/129) ([andypearson](https://github.com/andypearson))
|
14
|
+
|
3
15
|
## [v0.22](https://github.com/JacobEvelyn/friends/tree/v0.22) (2016-05-14)
|
4
16
|
[Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.21...v0.22)
|
5
17
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -318,24 +318,51 @@ Opening "./friends.md" in atom
|
|
318
318
|
|
319
319
|
#### `graph`
|
320
320
|
|
321
|
-
Graphs (in color!) your
|
321
|
+
Graphs (in color!) your activities over time:
|
322
322
|
|
323
323
|
```bash
|
324
|
-
$ friends graph
|
324
|
+
$ friends graph
|
325
|
+
Nov 2014 |███
|
326
|
+
Dec 2014 |██
|
327
|
+
Jan 2015 |███████
|
328
|
+
Feb 2015 |█████
|
329
|
+
```
|
330
|
+
|
331
|
+
Or graph only activities with a certain friend:
|
332
|
+
|
333
|
+
```bash
|
334
|
+
$ friends graph --with George
|
325
335
|
Nov 2014 |█
|
326
336
|
Dec 2014 |
|
327
337
|
Jan 2015 |█████
|
328
338
|
Feb 2015 |███
|
329
339
|
```
|
330
340
|
|
331
|
-
Or
|
341
|
+
Or graph only activities with a certain hashtag:
|
332
342
|
|
333
343
|
```bash
|
334
|
-
$ friends graph
|
335
|
-
Nov 2014
|
336
|
-
Dec 2014
|
337
|
-
Jan 2015
|
338
|
-
Feb 2015
|
344
|
+
$ friends graph --tagged food
|
345
|
+
Nov 2014 |█
|
346
|
+
Dec 2014 |
|
347
|
+
Jan 2015 |
|
348
|
+
Feb 2015 |███
|
349
|
+
```
|
350
|
+
|
351
|
+
Or graph only activities in a certain location:
|
352
|
+
|
353
|
+
```bash
|
354
|
+
$ friends graph --in Paris
|
355
|
+
Nov 2014 |█
|
356
|
+
Dec 2014 |
|
357
|
+
Jan 2015 |
|
358
|
+
Feb 2015 |█
|
359
|
+
```
|
360
|
+
|
361
|
+
And you can use multiple of these flags together:
|
362
|
+
|
363
|
+
```bash
|
364
|
+
$ friends graph --in Paris --tagged food --with George
|
365
|
+
Nov 2014 |█
|
339
366
|
```
|
340
367
|
|
341
368
|
#### `help`
|
data/Rakefile
CHANGED
data/bin/friends
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "gli"
|
4
5
|
require "paint"
|
@@ -27,7 +28,7 @@ class Hashtag
|
|
27
28
|
# See: https://github.com/davetron5000/gli/issues/241
|
28
29
|
def self.convert_to_hashtag(str)
|
29
30
|
str = str.strip
|
30
|
-
str.
|
31
|
+
!str.empty? && str[0] == "#" ? str : "##{str}"
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
@@ -35,10 +36,8 @@ accept(Hashtag) do |value|
|
|
35
36
|
Hashtag.convert_to_hashtag(value)
|
36
37
|
end
|
37
38
|
|
38
|
-
class Stripped
|
39
|
-
accept(Stripped)
|
40
|
-
value.strip
|
41
|
-
end
|
39
|
+
class Stripped; end
|
40
|
+
accept(Stripped, &:strip)
|
42
41
|
|
43
42
|
switch [:quiet],
|
44
43
|
negatable: false,
|
@@ -320,10 +319,24 @@ command :remove do |remove|
|
|
320
319
|
end
|
321
320
|
end
|
322
321
|
|
323
|
-
desc "Graph
|
324
|
-
arg_name "NAME (default: none)"
|
322
|
+
desc "Graph activities over time"
|
325
323
|
command :graph do |graph|
|
326
|
-
graph.
|
324
|
+
graph.flag [:with],
|
325
|
+
arg_name: "NAME",
|
326
|
+
desc: "Graph activities with the given friend",
|
327
|
+
type: Stripped
|
328
|
+
|
329
|
+
graph.flag [:in],
|
330
|
+
arg_name: "LOCATION",
|
331
|
+
desc: "Graph activities in the given location",
|
332
|
+
type: Stripped
|
333
|
+
|
334
|
+
graph.flag [:tagged],
|
335
|
+
arg_name: "HASHTAG",
|
336
|
+
desc: "Graph activities with the given hashtag",
|
337
|
+
type: Hashtag
|
338
|
+
|
339
|
+
graph.action do |_, options|
|
327
340
|
# This math is taken from Minitest's Pride plugin (the PrideLOL class).
|
328
341
|
PI_3 = Math::PI / 3
|
329
342
|
|
@@ -336,7 +349,11 @@ command :graph do |graph|
|
|
336
349
|
[r, g, b].map { |c| c * 51 }
|
337
350
|
end
|
338
351
|
|
339
|
-
data = @introvert.graph(
|
352
|
+
data = @introvert.graph(
|
353
|
+
with: options[:with],
|
354
|
+
location_name: options[:in],
|
355
|
+
tagged: options[:tagged]
|
356
|
+
)
|
340
357
|
|
341
358
|
data.each do |month, count|
|
342
359
|
print "#{month} |"
|
data/friends.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
lib = File.expand_path("../lib", __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "friends/version"
|
@@ -33,5 +34,5 @@ Gem::Specification.new do |spec|
|
|
33
34
|
spec.add_development_dependency "minitest", "~> 5.5"
|
34
35
|
spec.add_development_dependency "overcommit", "~> 0.30"
|
35
36
|
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
37
|
+
spec.add_development_dependency "rubocop", "~> 0.40"
|
37
38
|
end
|
data/lib/friends.rb
CHANGED
data/lib/friends/activity.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# Activity represents an activity you've done with one or more Friends.
|
3
4
|
|
4
5
|
require "chronic"
|
@@ -12,8 +13,8 @@ module Friends
|
|
12
13
|
extend Serializable
|
13
14
|
extend Memoist
|
14
15
|
|
15
|
-
SERIALIZATION_PREFIX = "- "
|
16
|
-
DATE_PARTITION = ": "
|
16
|
+
SERIALIZATION_PREFIX = "- "
|
17
|
+
DATE_PARTITION = ": "
|
17
18
|
|
18
19
|
# @return [Regexp] the regex for capturing groups in deserialization
|
19
20
|
def self.deserialization_regex
|
@@ -97,7 +98,7 @@ module Friends
|
|
97
98
|
# @return [String] if name found in description
|
98
99
|
# @return [nil] if no change was made
|
99
100
|
def update_friend_name(old_name:, new_name:)
|
100
|
-
@description.gsub
|
101
|
+
@description = @description.gsub(
|
101
102
|
Regexp.new("(?<=\\*\\*)#{old_name}(?=\\*\\*)"),
|
102
103
|
new_name
|
103
104
|
)
|
@@ -109,7 +110,10 @@ module Friends
|
|
109
110
|
# @return [String] if name found in description
|
110
111
|
# @return [nil] if no change was made
|
111
112
|
def update_location_name(old_name:, new_name:)
|
112
|
-
@description.gsub
|
113
|
+
@description = @description.gsub(
|
114
|
+
Regexp.new("(?<=_)#{old_name}(?=_)"),
|
115
|
+
new_name
|
116
|
+
)
|
113
117
|
end
|
114
118
|
|
115
119
|
# @param location [Location] the location to test
|
data/lib/friends/friend.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# Friend represents a friend. You know, a real-life friend!
|
3
4
|
|
4
5
|
require "friends"
|
@@ -9,8 +10,8 @@ module Friends
|
|
9
10
|
class Friend
|
10
11
|
extend Serializable
|
11
12
|
|
12
|
-
SERIALIZATION_PREFIX = "- "
|
13
|
-
NICKNAME_PREFIX = "a.k.a. "
|
13
|
+
SERIALIZATION_PREFIX = "- "
|
14
|
+
NICKNAME_PREFIX = "a.k.a. "
|
14
15
|
|
15
16
|
# @return [Regexp] the regex for capturing groups in deserialization
|
16
17
|
def self.deserialization_regex
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Graphs activities by month
|
3
|
+
|
4
|
+
module Friends
|
5
|
+
class Graph
|
6
|
+
DATE_FORMAT = "%b %Y"
|
7
|
+
|
8
|
+
# @param start_date [Date] the first month of the graph
|
9
|
+
# @param end_date [Date] the last month of the graph
|
10
|
+
# @param activities [Array<Friends::Activity>] a list of activities to graph
|
11
|
+
def initialize(start_date:, end_date:, activities:)
|
12
|
+
self.start_date = start_date
|
13
|
+
self.end_date = end_date
|
14
|
+
self.activities = activities
|
15
|
+
end
|
16
|
+
|
17
|
+
# Render the graph as a hash in the format:
|
18
|
+
#
|
19
|
+
# {
|
20
|
+
# "Jan 2015" => 3, # The number of activities during each month.
|
21
|
+
# "Feb 2015" => 0,
|
22
|
+
# "Mar 2015" => 9
|
23
|
+
# }
|
24
|
+
#
|
25
|
+
# @return [Hash{String => Integer}]
|
26
|
+
def to_h
|
27
|
+
empty_graph.tap do |graph|
|
28
|
+
activities.each do |activity|
|
29
|
+
graph[format_date(activity.date)] += 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_accessor :start_date, :end_date, :activities
|
37
|
+
|
38
|
+
# Render an empty graph as a hash in the format:
|
39
|
+
#
|
40
|
+
# {
|
41
|
+
# "Jan 2015" => 0,
|
42
|
+
# "Feb 2015" => 0,
|
43
|
+
# "Mar 2015" => 0
|
44
|
+
# }
|
45
|
+
#
|
46
|
+
# @return [Hash{String => Integer}]
|
47
|
+
def empty_graph
|
48
|
+
Hash[(start_date..end_date).map do |date|
|
49
|
+
[format_date(date), 0]
|
50
|
+
end]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Format a date for use in the graph label
|
54
|
+
# @param date [Date] the date to format
|
55
|
+
# @return [String]
|
56
|
+
def format_date(date)
|
57
|
+
date.strftime(DATE_FORMAT)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/friends/introvert.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# Introvert is the internal handler for the friends script. It is designed to be
|
3
4
|
# able to be used directly within another Ruby program, without needing to call
|
4
5
|
# the command-line script explicitly.
|
5
6
|
|
6
7
|
require "friends/activity"
|
7
8
|
require "friends/friend"
|
9
|
+
require "friends/graph"
|
8
10
|
require "friends/location"
|
9
11
|
require "friends/friends_error"
|
10
12
|
|
11
13
|
module Friends
|
12
14
|
class Introvert
|
13
|
-
DEFAULT_FILENAME = "./friends.md"
|
14
|
-
ACTIVITIES_HEADER = "### Activities:"
|
15
|
-
FRIENDS_HEADER = "### Friends:"
|
16
|
-
LOCATIONS_HEADER = "### Locations:"
|
17
|
-
GRAPH_DATE_FORMAT = "%b %Y".freeze # Used as the param for date.strftime().
|
15
|
+
DEFAULT_FILENAME = "./friends.md"
|
16
|
+
ACTIVITIES_HEADER = "### Activities:"
|
17
|
+
FRIENDS_HEADER = "### Friends:"
|
18
|
+
LOCATIONS_HEADER = "### Locations:"
|
18
19
|
|
19
20
|
# @param filename [String] the name of the friends Markdown file
|
20
21
|
def initialize(filename: DEFAULT_FILENAME)
|
@@ -241,26 +242,14 @@ module Friends
|
|
241
242
|
# @param tagged [String] the name of a hashtag to filter by, or nil for
|
242
243
|
# unfiltered
|
243
244
|
# @return [Array] a list of all activity text values
|
244
|
-
# @raise [FriendsError] if
|
245
|
+
# @raise [FriendsError] if friend, location or hashtag cannot be found or
|
246
|
+
# is ambiguous
|
245
247
|
def list_activities(limit:, with:, location_name:, tagged:)
|
246
|
-
acts =
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
acts = acts.select { |act| act.includes_friend?(friend: friend) }
|
252
|
-
end
|
253
|
-
|
254
|
-
# Filter by location name if argument is passed.
|
255
|
-
unless location_name.nil?
|
256
|
-
location = location_with_name_in(location_name)
|
257
|
-
acts = acts.select { |act| act.includes_location?(location: location) }
|
258
|
-
end
|
259
|
-
|
260
|
-
# Filter by tag if argument is passed.
|
261
|
-
unless tagged.nil?
|
262
|
-
acts = acts.select { |act| act.includes_hashtag?(hashtag: tagged) }
|
263
|
-
end
|
248
|
+
acts = filtered_activities(
|
249
|
+
with: with,
|
250
|
+
location_name: location_name,
|
251
|
+
tagged: tagged
|
252
|
+
)
|
264
253
|
|
265
254
|
# If we need to, trim the list.
|
266
255
|
acts = acts.take(limit) unless limit.nil?
|
@@ -297,7 +286,7 @@ module Friends
|
|
297
286
|
end
|
298
287
|
|
299
288
|
# Find data points for graphing activities over time.
|
300
|
-
# Optionally filter by
|
289
|
+
# Optionally filter by friend, location and hashtag
|
301
290
|
#
|
302
291
|
# The returned hash uses the following format:
|
303
292
|
# {
|
@@ -308,32 +297,30 @@ module Friends
|
|
308
297
|
# The keys of the hash are all of the months (inclusive) between the first
|
309
298
|
# and last month in which activities have been recorded.
|
310
299
|
#
|
311
|
-
# @param
|
312
|
-
#
|
313
|
-
# @
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
end
|
336
|
-
act_table
|
300
|
+
# @param with [String] the name of a friend to filter by, or nil for
|
301
|
+
# unfiltered
|
302
|
+
# @param location_name [String] the name of a location to filter by, or nil
|
303
|
+
# for unfiltered
|
304
|
+
# @param tagged [String] the name of a hashtag to filter by, or nil for
|
305
|
+
# unfiltered
|
306
|
+
# @return [Hash{String => Integer}]
|
307
|
+
# @raise [FriendsError] if friend, location or hashtag cannot be found or
|
308
|
+
# is ambiguous
|
309
|
+
def graph(with:, location_name:, tagged:)
|
310
|
+
# There is no point trying to graph no activities
|
311
|
+
return {} if @activities.empty?
|
312
|
+
|
313
|
+
activities_to_graph = filtered_activities(
|
314
|
+
with: with,
|
315
|
+
location_name: location_name,
|
316
|
+
tagged: tagged
|
317
|
+
)
|
318
|
+
|
319
|
+
Graph.new(
|
320
|
+
start_date: @activities.last.date,
|
321
|
+
end_date: @activities.first.date,
|
322
|
+
activities: activities_to_graph
|
323
|
+
).to_h
|
337
324
|
end
|
338
325
|
|
339
326
|
# Suggest friends to do something with.
|
@@ -476,6 +463,39 @@ module Friends
|
|
476
463
|
|
477
464
|
private
|
478
465
|
|
466
|
+
# Filter activities by friend, location and hashtag
|
467
|
+
# @param with [String] the name of a friend to filter by, or nil for
|
468
|
+
# unfiltered
|
469
|
+
# @param location_name [String] the name of a location to filter by, or nil
|
470
|
+
# for unfiltered
|
471
|
+
# @param tagged [String] the name of a hashtag to filter by, or nil for
|
472
|
+
# unfiltered
|
473
|
+
# @return [Array] an array of activities
|
474
|
+
# @raise [FriendsError] if friend, location or hashtag cannot be found or
|
475
|
+
# is ambiguous
|
476
|
+
def filtered_activities(with:, location_name:, tagged:)
|
477
|
+
acts = @activities
|
478
|
+
|
479
|
+
# Filter by friend name if argument is passed.
|
480
|
+
unless with.nil?
|
481
|
+
friend = friend_with_name_in(with)
|
482
|
+
acts = acts.select { |act| act.includes_friend?(friend: friend) }
|
483
|
+
end
|
484
|
+
|
485
|
+
# Filter by location name if argument is passed.
|
486
|
+
unless location_name.nil?
|
487
|
+
location = location_with_name_in(location_name)
|
488
|
+
acts = acts.select { |act| act.includes_location?(location: location) }
|
489
|
+
end
|
490
|
+
|
491
|
+
# Filter by tag if argument is passed.
|
492
|
+
unless tagged.nil?
|
493
|
+
acts = acts.select { |act| act.includes_hashtag?(hashtag: tagged) }
|
494
|
+
end
|
495
|
+
|
496
|
+
acts
|
497
|
+
end
|
498
|
+
|
479
499
|
# @param type [Symbol] one of: [:friend, :location]
|
480
500
|
# @param limit [Integer] the number of favorite things to return
|
481
501
|
# @return [Array] a list of the favorite things' names and activity counts
|
data/lib/friends/location.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# Location represents a location in the world.
|
3
4
|
|
4
5
|
require "friends/regex_builder"
|
@@ -8,7 +9,7 @@ module Friends
|
|
8
9
|
class Location
|
9
10
|
extend Serializable
|
10
11
|
|
11
|
-
SERIALIZATION_PREFIX = "- "
|
12
|
+
SERIALIZATION_PREFIX = "- "
|
12
13
|
|
13
14
|
# @return [Regexp] the regex for capturing groups in deserialization
|
14
15
|
def self.deserialization_regex
|
@@ -1,30 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# RegexpBuilder is an internal class that helps us build regexes to find things.
|
3
4
|
|
4
5
|
module Friends
|
5
6
|
class RegexBuilder
|
6
7
|
# We don't want to match strings that are "escaped" with a leading
|
7
8
|
# backslash.
|
8
|
-
NO_LEADING_BACKSLASH = "(?<!\\\\)"
|
9
|
+
NO_LEADING_BACKSLASH = "(?<!\\\\)"
|
9
10
|
|
10
11
|
# We don't want to match strings that are directly touching double asterisks
|
11
12
|
# as these are treated as sacred by our program.
|
12
|
-
NO_LEADING_ASTERISKS = "(?<!\\*\\*)"
|
13
|
-
NO_TRAILING_ASTERISKS = "(?!\\*\\*)"
|
13
|
+
NO_LEADING_ASTERISKS = "(?<!\\*\\*)"
|
14
|
+
NO_TRAILING_ASTERISKS = "(?!\\*\\*)"
|
14
15
|
|
15
16
|
# We don't want to match strings that are directly touching underscores
|
16
17
|
# as these are treated as sacred by our program.
|
17
|
-
NO_LEADING_UNDERSCORES = "(?<!_)"
|
18
|
-
NO_TRAILING_UNDERSCORES = "(?!_)"
|
18
|
+
NO_LEADING_UNDERSCORES = "(?<!_)"
|
19
|
+
NO_TRAILING_UNDERSCORES = "(?!_)"
|
19
20
|
|
20
21
|
# We don't want to match strings that are part of other words.
|
21
|
-
NO_LEADING_ALPHABETICALS = "(?<![A-z])"
|
22
|
-
NO_TRAILING_ALPHABETICALS = "(?![A-z])"
|
22
|
+
NO_LEADING_ALPHABETICALS = "(?<![A-z])"
|
23
|
+
NO_TRAILING_ALPHABETICALS = "(?![A-z])"
|
23
24
|
|
24
25
|
# We ignore case within the regex as opposed to globally to allow consumers
|
25
26
|
# of this API the ability to pass in strings that turn off this modifier
|
26
27
|
# with the "(?-i)" string.
|
27
|
-
IGNORE_CASE = "(?i)"
|
28
|
+
IGNORE_CASE = "(?i)"
|
28
29
|
|
29
30
|
def self.regex(str)
|
30
31
|
Regexp.new(
|
data/lib/friends/serializable.rb
CHANGED
data/lib/friends/version.rb
CHANGED
data/test/activity_spec.rb
CHANGED
data/test/friend_spec.rb
CHANGED
data/test/graph_spec.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "./test/helper"
|
3
|
+
|
4
|
+
describe Friends::Graph do
|
5
|
+
subject do
|
6
|
+
Friends::Graph.new(
|
7
|
+
start_date: start_date,
|
8
|
+
end_date: end_date,
|
9
|
+
activities: activities
|
10
|
+
).to_h
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:start_date) { Date.new(2016, 1, 1) }
|
14
|
+
let(:end_date) { Date.new(2016, 2, 1) }
|
15
|
+
let(:activities) do
|
16
|
+
[
|
17
|
+
Friends::Activity.new(
|
18
|
+
str: "2016-02-01: Relaxing."
|
19
|
+
),
|
20
|
+
|
21
|
+
Friends::Activity.new(
|
22
|
+
str: "2016-01-01: Running."
|
23
|
+
)
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "graphs activities by month" do
|
28
|
+
subject.must_equal(
|
29
|
+
"Jan 2016" => 1,
|
30
|
+
"Feb 2016" => 1
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "there is a gap between activities" do
|
35
|
+
let(:end_date) { Date.new(2016, 3, 1) }
|
36
|
+
|
37
|
+
let(:activities) do
|
38
|
+
[
|
39
|
+
Friends::Activity.new(
|
40
|
+
str: "2016-03-01: Relaxing."
|
41
|
+
),
|
42
|
+
|
43
|
+
Friends::Activity.new(
|
44
|
+
str: "2016-01-01: Running."
|
45
|
+
)
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "includes the month with no activities" do
|
50
|
+
subject.must_equal(
|
51
|
+
"Jan 2016" => 1,
|
52
|
+
"Feb 2016" => 0,
|
53
|
+
"Mar 2016" => 1
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "graph starts before the first activity" do
|
59
|
+
let(:start_date) { Date.new(2015, 12, 1) }
|
60
|
+
|
61
|
+
it "graphs activities by month" do
|
62
|
+
subject.must_equal(
|
63
|
+
"Dec 2015" => 0,
|
64
|
+
"Jan 2016" => 1,
|
65
|
+
"Feb 2016" => 1
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "graph ends after the last activity" do
|
71
|
+
let(:end_date) { Date.new(2016, 3, 1) }
|
72
|
+
|
73
|
+
it "graphs activities by month" do
|
74
|
+
subject.must_equal(
|
75
|
+
"Jan 2016" => 1,
|
76
|
+
"Feb 2016" => 1,
|
77
|
+
"Mar 2016" => 0
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "there are no activities" do
|
83
|
+
let(:activities) { [] }
|
84
|
+
|
85
|
+
it "graphs activities by month" do
|
86
|
+
subject.must_equal(
|
87
|
+
"Jan 2016" => 0,
|
88
|
+
"Feb 2016" => 0
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/test/helper.rb
CHANGED
data/test/introvert_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "./test/helper"
|
2
4
|
|
3
5
|
describe Friends::Introvert do
|
@@ -804,82 +806,103 @@ describe Friends::Introvert do
|
|
804
806
|
end
|
805
807
|
|
806
808
|
describe "#graph" do
|
807
|
-
subject
|
809
|
+
subject do
|
810
|
+
introvert.graph(
|
811
|
+
with: with,
|
812
|
+
location_name: location_name,
|
813
|
+
tagged: tagged
|
814
|
+
)
|
815
|
+
end
|
816
|
+
|
817
|
+
let(:with) { nil }
|
818
|
+
let(:location_name) { nil }
|
819
|
+
let(:tagged) { nil }
|
808
820
|
|
809
821
|
let(:activities) do
|
810
822
|
[
|
823
|
+
# With a friend
|
811
824
|
Friends::Activity.new(
|
812
|
-
str: "2016-
|
825
|
+
str: "2016-01-01: \
|
826
|
+
At _The Eiffel Tower_ with **George Washington Carver**."
|
813
827
|
),
|
814
828
|
|
815
|
-
#
|
816
|
-
# the next activity, so we can test that we correctly return data for
|
817
|
-
# months in the range with no activities.
|
829
|
+
# In a location
|
818
830
|
Friends::Activity.new(
|
819
|
-
str: "2016-
|
831
|
+
str: "2016-01-01: Called **George Washington Carver**. #phone"
|
820
832
|
),
|
821
833
|
|
822
|
-
#
|
834
|
+
# Tagged with a hashtag
|
823
835
|
Friends::Activity.new(
|
824
|
-
str: "2016-01-01:
|
836
|
+
str: "2016-01-01: Hung out with **Betsy Ross**."
|
825
837
|
)
|
826
838
|
]
|
827
839
|
end
|
828
840
|
|
829
|
-
|
830
|
-
|
841
|
+
it "graphs activities by month" do
|
842
|
+
stub_activities(activities) do
|
843
|
+
subject.must_equal("Jan 2016" => 3)
|
844
|
+
end
|
845
|
+
end
|
831
846
|
|
832
|
-
|
833
|
-
|
847
|
+
describe "No activities" do
|
848
|
+
it "returns an empty graph" do
|
849
|
+
subject.must_equal({})
|
834
850
|
end
|
835
851
|
end
|
836
852
|
|
837
|
-
describe "
|
838
|
-
let(:
|
853
|
+
describe "Filtering by friend" do
|
854
|
+
let(:with) { "Betsy Ross" }
|
839
855
|
|
840
|
-
it "
|
856
|
+
it "graphs activities with a friend" do
|
841
857
|
stub_friends(friends) do
|
842
|
-
|
858
|
+
stub_activities(activities) do
|
859
|
+
subject.must_equal("Jan 2016" => 1)
|
860
|
+
end
|
843
861
|
end
|
844
862
|
end
|
845
|
-
end
|
846
863
|
|
847
|
-
|
848
|
-
|
864
|
+
describe "when the friend does not exist" do
|
865
|
+
let(:with) { "Oscar the Grouch" }
|
849
866
|
|
850
|
-
|
851
|
-
stub_friends(friends) do
|
867
|
+
it "raises an error" do
|
852
868
|
stub_activities(activities) do
|
853
|
-
subject.
|
854
|
-
{
|
855
|
-
"Jan 2016" => 1,
|
856
|
-
"Feb 2016" => 1,
|
857
|
-
"Mar 2016" => 0,
|
858
|
-
"Apr 2016" => 1
|
859
|
-
}
|
860
|
-
)
|
869
|
+
proc { subject }.must_raise Friends::FriendsError
|
861
870
|
end
|
862
871
|
end
|
863
872
|
end
|
864
873
|
end
|
865
874
|
|
866
|
-
describe "
|
867
|
-
let(:
|
875
|
+
describe "Filtering by location" do
|
876
|
+
let(:location_name) { "The Eiffel Tower" }
|
868
877
|
|
869
|
-
it "
|
870
|
-
|
878
|
+
it "graphs activities in a location" do
|
879
|
+
stub_locations(locations) do
|
871
880
|
stub_activities(activities) do
|
872
|
-
subject.must_equal(
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
881
|
+
subject.must_equal("Jan 2016" => 1)
|
882
|
+
end
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
describe "when the location does not exist" do
|
887
|
+
let(:location_name) { "Nowhere" }
|
888
|
+
|
889
|
+
it "raises an error" do
|
890
|
+
stub_activities(activities) do
|
891
|
+
proc { subject }.must_raise Friends::FriendsError
|
879
892
|
end
|
880
893
|
end
|
881
894
|
end
|
882
895
|
end
|
896
|
+
|
897
|
+
describe "Filtering by hashtag" do
|
898
|
+
let(:tagged) { "#phone" }
|
899
|
+
|
900
|
+
it "graphs activities tagged with a hashtag" do
|
901
|
+
stub_activities(activities) do
|
902
|
+
subject.must_equal("Jan 2016" => 1)
|
903
|
+
end
|
904
|
+
end
|
905
|
+
end
|
883
906
|
end
|
884
907
|
|
885
908
|
describe "#total_friends" do
|
data/test/location_spec.rb
CHANGED
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.23'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Evelyn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|
@@ -156,14 +156,14 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0.
|
159
|
+
version: '0.40'
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0.
|
166
|
+
version: '0.40'
|
167
167
|
description: Spend time with the people you care about. Introvert-tested. Extrovert-approved.
|
168
168
|
email:
|
169
169
|
- jacobevelyn@gmail.com
|
@@ -192,6 +192,7 @@ files:
|
|
192
192
|
- lib/friends/activity.rb
|
193
193
|
- lib/friends/friend.rb
|
194
194
|
- lib/friends/friends_error.rb
|
195
|
+
- lib/friends/graph.rb
|
195
196
|
- lib/friends/introvert.rb
|
196
197
|
- lib/friends/location.rb
|
197
198
|
- lib/friends/regex_builder.rb
|
@@ -199,6 +200,7 @@ files:
|
|
199
200
|
- lib/friends/version.rb
|
200
201
|
- test/activity_spec.rb
|
201
202
|
- test/friend_spec.rb
|
203
|
+
- test/graph_spec.rb
|
202
204
|
- test/helper.rb
|
203
205
|
- test/introvert_spec.rb
|
204
206
|
- test/location_spec.rb
|
@@ -230,6 +232,7 @@ summary: Spend time with the people you care about.
|
|
230
232
|
test_files:
|
231
233
|
- test/activity_spec.rb
|
232
234
|
- test/friend_spec.rb
|
235
|
+
- test/graph_spec.rb
|
233
236
|
- test/helper.rb
|
234
237
|
- test/introvert_spec.rb
|
235
238
|
- test/location_spec.rb
|