friends 0.13 → 0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 844eb360bcc04aed352a8b3c3371117afb18f564
4
- data.tar.gz: db2feb8fbf5a15232b6b5923218dc8d7cff4ded1
3
+ metadata.gz: 1fd5cb3c9a9b913b0772d731f872709820e5fa12
4
+ data.tar.gz: 99b28c2a79ae11aea5b49e75f328ed03433f94dd
5
5
  SHA512:
6
- metadata.gz: c3eb0061ba85b5dcc7eb1fa9f7d0dc1c711834b4b128b37d789252b5293b290e95de4553f55cb57a585dee1cf077e87c7b2d8fa6e5806f7ed8520227287e3e9a
7
- data.tar.gz: cac077cacd2c4a0309b5614e1952dd65b55f0c22b7d23ed619cda4c6637f282284c0c236ff1a16ed83a4fd9ecc3bcfe434755f3c46f87c241fd8073990deda7d
6
+ metadata.gz: b8aba3f30dfc6de57c2d98a79b8fa3e131458b199c25e3bfff960ec0011069040844a90580848b10e255fb869ab2843e0ab941daa85c390e69e3ba74dbe650ce
7
+ data.tar.gz: f9491efb85eed54694805e080c2e00ab5893687d60d78bc643cdccae64cc3081139ea5333e8a9d5d99ba0861e9c3b5586a59156f81b6766d2facbc1ca9eeee65
@@ -1,5 +1,19 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.15](https://github.com/JacobEvelyn/friends/tree/v0.15) (2016-03-11)
4
+ [Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.14...v0.15)
5
+
6
+ ## [v0.14](https://github.com/JacobEvelyn/friends/tree/v0.14) (2016-03-11)
7
+ [Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.13...v0.14)
8
+
9
+ **Implemented enhancements:**
10
+
11
+ - Allow dates in natural-language formats [\#65](https://github.com/JacobEvelyn/friends/issues/65)
12
+
13
+ **Merged pull requests:**
14
+
15
+ - Allow natural-language dates [\#82](https://github.com/JacobEvelyn/friends/pull/82) ([JacobEvelyn](https://github.com/JacobEvelyn))
16
+
3
17
  ## [v0.13](https://github.com/JacobEvelyn/friends/tree/v0.13) (2016-01-21)
4
18
  [Full Changelog](https://github.com/JacobEvelyn/friends/compare/v0.12...v0.13)
5
19
 
@@ -208,4 +222,4 @@
208
222
  ## [v0.0.1](https://github.com/JacobEvelyn/friends/tree/v0.0.1) (2014-12-11)
209
223
 
210
224
 
211
- \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
225
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/README.md CHANGED
@@ -51,7 +51,7 @@ Activity added: "2015-01-04: Got lunch with Grace Hopper and George Washington C
51
51
 
52
52
  You can of course specify a date for the activity:
53
53
  ```
54
- $ friends add activity "2014-12-31: Celebrated the new year with Marie."
54
+ $ friends add activity "Yesterday: Celebrated the new year with Marie."
55
55
  Activity added: "2014-12-31: Celebrated the new year with Marie Curie."
56
56
  ```
57
57
  Or get an **interactive prompt** by just typing `friends add activity`, with or without a date specified:
@@ -59,6 +59,11 @@ Or get an **interactive prompt** by just typing `friends add activity`, with or
59
59
  $ friends add activity 2015-11-01
60
60
  2015-11-01: <type description here>
61
61
  ```
62
+ **Natural-language dates** work just fine:
63
+ ```
64
+ $ friends add activity 'last Monday'
65
+ 2016-03-07: <type description here>
66
+ ```
62
67
  You can escape the names of friends you don't want `friends` to match with a backslash:
63
68
  ```
64
69
  $ friends add activity "2015-11-01: Grace and I went to \Marie's Diner. \George had to cancel at the last minute."
@@ -131,7 +131,7 @@ command :add do |add|
131
131
  activity = @introvert.add_activity(serialization: args.first)
132
132
 
133
133
  # If there's no description, prompt the user for one.
134
- if !activity.description
134
+ if activity.description.nil? || activity.description.empty?
135
135
  activity.description = Readline.readline(activity.display_text)
136
136
  activity.highlight_friends(introvert: @introvert)
137
137
  end
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  # We need Ruby 2.0's keyword arguments and default UTF-8 encoding.
23
23
  spec.required_ruby_version = ">= 2.1"
24
24
 
25
+ spec.add_dependency "chronic", "~> 0.10"
25
26
  spec.add_dependency "gli", "~> 2.12"
26
27
  spec.add_dependency "memoist", "~> 0.11"
27
28
  spec.add_dependency "paint", "~> 1.0"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # Activity represents an activity you've done with one or more Friends.
3
3
 
4
+ require "chronic"
4
5
  require "memoist"
5
6
  require "paint"
6
7
 
@@ -12,13 +13,11 @@ module Friends
12
13
  extend Memoist
13
14
 
14
15
  SERIALIZATION_PREFIX = "- ".freeze
16
+ DATE_PARTITION = ": ".freeze
15
17
 
16
18
  # @return [Regexp] the regex for capturing groups in deserialization
17
19
  def self.deserialization_regex
18
- # Note: this regex must be on one line because whitespace is important
19
- # rubocop:disable Metrics/LineLength
20
- /(#{SERIALIZATION_PREFIX})?((?<date_s>\d{4}-\d\d-\d\d)(:\s)?)?(?<description>.+)?/
21
- # rubocop:enable Metrics/LineLength
20
+ /(#{SERIALIZATION_PREFIX})?(?<str>.+)?/
22
21
  end
23
22
 
24
23
  # @return [Regexp] the string of what we expected during deserialization
@@ -26,12 +25,23 @@ module Friends
26
25
  "[YYYY-MM-DD]: [Activity]"
27
26
  end
28
27
 
29
- # @param date_s [String] the activity's date, parsed using Date.parse()
30
- # @param description [String] the activity's description
28
+ # @param str [String] the text of the activity, of one of the formats:
29
+ # "<date>: <description>"
30
+ # "<date>" (Program will prompt for description.)
31
+ # "<description>" (The current date will be used by default.)
31
32
  # @return [Activity] the new activity
32
- def initialize(date_s: Date.today.to_s, description: nil)
33
- @date = Date.parse(date_s)
34
- @description = description
33
+ def initialize(str: "")
34
+ # Partition lets us parse "Today" and "Today: I awoke." identically.
35
+ date_s, _, description = str.partition(DATE_PARTITION)
36
+
37
+ if time = Chronic.parse(date_s)
38
+ @date = time.to_date
39
+ @description = description
40
+ else
41
+ # If the user didn't input a date, we fall back to the current date.
42
+ @date = Date.today
43
+ @description = str # Use str in case DATE_PARTITION occurred naturally.
44
+ end
35
45
  end
36
46
 
37
47
  attr_reader :date
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Friends
3
- VERSION = "0.13".freeze
3
+ VERSION = "0.15".freeze
4
4
  end
@@ -1,18 +1,37 @@
1
1
  require "./test/helper"
2
2
 
3
3
  describe Friends::Activity do
4
- let(:date) { Date.today }
4
+ let(:date) { Date.today - 1 }
5
5
  let(:date_s) { date.to_s }
6
6
  let(:friend1) { Friends::Friend.new(name: "Elizabeth Cady Stanton") }
7
7
  let(:friend2) { Friends::Friend.new(name: "John Cage") }
8
8
  let(:description) { "Lunch with **#{friend1.name}** and **#{friend2.name}**" }
9
+ let(:partition) { Friends::Activity::DATE_PARTITION }
9
10
  let(:activity) do
10
- Friends::Activity.new(date_s: date_s, description: description)
11
+ Friends::Activity.new(str: "#{date_s}#{partition}#{description}")
11
12
  end
12
13
 
13
14
  describe ".deserialize" do
14
15
  subject { Friends::Activity.deserialize(serialized_str) }
15
16
 
17
+ describe "when serialized string is empty" do
18
+ let(:serialized_str) { "" }
19
+
20
+ it "defaults date to today and sets no description" do
21
+ today = Date.today - 7
22
+
23
+ # We stub out Date.today to guarantee that it is always the same even
24
+ # when the date changes in the middle of the test's execution. To ensure
25
+ # this technique actually works, we move our reference time backward by
26
+ # a week.
27
+ Date.stub(:today, today) do
28
+ new_activity = subject
29
+ new_activity.date.must_equal today
30
+ new_activity.description.must_equal ""
31
+ end
32
+ end
33
+ end
34
+
16
35
  describe "when string is well-formed" do
17
36
  let(:serialized_str) { "#{date_s}: #{description}" }
18
37
 
@@ -23,23 +42,45 @@ describe Friends::Activity do
23
42
  end
24
43
  end
25
44
 
45
+ describe "when date is written in natural language" do
46
+ let(:serialized_str) { "Yesterday: #{description}" }
47
+
48
+ it "creates an activity with the correct date and description" do
49
+ now = Time.now + 604800
50
+
51
+ # Chronic uses Time.now for parsing, so we stub this to prevent racy
52
+ # behavior when the date changes in the middle of test execution. To
53
+ # ensure this technique actually works, we move our reference time
54
+ # backward by a week.
55
+ Time.stub(:now, now) do
56
+ new_activity = subject
57
+ new_activity.date.must_equal (now.to_date - 1)
58
+ new_activity.description.must_equal description
59
+ end
60
+ end
61
+ end
62
+
26
63
  describe "when no date is present" do
27
64
  let(:serialized_str) { description }
28
65
 
29
66
  it "defaults to today" do
30
- today = Date.today
67
+ today = Date.today - 7
31
68
 
32
69
  # We stub out Date.today to guarantee that it is always the same even
33
- # when the date changes in the middle of the test's execution.
70
+ # when the date changes in the middle of the test's execution. To ensure
71
+ # this technique actually works, we move our reference time backward by
72
+ # a week.
34
73
  Date.stub(:today, today) { subject.date.must_equal today }
35
74
  end
36
75
  end
37
76
 
38
77
  describe "when no description is present" do
39
- let(:serialized_str) { "" }
78
+ let(:serialized_str) { date_s }
40
79
 
41
- it "sets no description in deserialization" do
42
- subject.description.must_equal nil
80
+ it "leaves description blank" do
81
+ new_activity = subject
82
+ new_activity.date.must_equal date
83
+ new_activity.description.must_equal ""
43
84
  end
44
85
  end
45
86
  end
@@ -249,17 +290,14 @@ describe Friends::Activity do
249
290
  # better friend than Elizabeth Cady Stanton.
250
291
  old_activities = [
251
292
  Friends::Activity.new(
252
- date_s: date_s,
253
- description: "Picnic with **Elizabeth Cady Stanton** and "\
254
- "**John Cage**."
293
+ str: "#{date_s}#{partition}Picnic with "\
294
+ "**Elizabeth Cady Stanton** and **John Cage**."
255
295
  ),
256
296
  Friends::Activity.new(
257
- date_s: date_s,
258
- description: "Got lunch with with **Elizabeth II**."
297
+ str: "#{date_s}#{partition}Got lunch with **Elizabeth II**."
259
298
  ),
260
299
  Friends::Activity.new(
261
- date_s: date_s,
262
- description: "Ice skated with **Elizabeth II**."
300
+ str: "#{date_s}#{partition}Ice skated with **Elizabeth II**."
263
301
  )
264
302
  ]
265
303
 
@@ -282,8 +320,7 @@ describe Friends::Activity do
282
320
 
283
321
  # Give a past activity to Elizabeth II.
284
322
  old_activity = Friends::Activity.new(
285
- date_s: date_s,
286
- description: "Do something with **Elizabeth II**."
323
+ str: "#{date_s}#{partition}Do something with **Elizabeth II**."
287
324
  )
288
325
 
289
326
  stub_activities([old_activity]) { subject }
@@ -339,10 +376,8 @@ describe Friends::Activity do
339
376
 
340
377
  describe "#<=>" do
341
378
  it "sorts by reverse-date" do
342
- yesterday = (Date.today - 1).to_s
343
- tomorrow = (Date.today + 1).to_s
344
- past_act = Friends::Activity.new(date_s: yesterday, description: "Dummy")
345
- future_act = Friends::Activity.new(date_s: tomorrow, description: "Dummy")
379
+ past_act = Friends::Activity.new(str: "Yesterday: Dummy")
380
+ future_act = Friends::Activity.new(str: "Tomorrow: Dummy")
346
381
  [past_act, future_act].sort.must_equal [future_act, past_act]
347
382
  end
348
383
  end
@@ -31,13 +31,10 @@ describe Friends::Introvert do
31
31
  let(:activities) do
32
32
  [
33
33
  Friends::Activity.new(
34
- date_s: Date.today.to_s,
35
- description: "Lunch with **#{friend_names.first}** and "\
36
- "**#{friend_names.last}**."
34
+ str: "Lunch w/ **#{friend_names.first}** and **#{friend_names.last}**."
37
35
  ),
38
36
  Friends::Activity.new(
39
- date_s: (Date.today - 1).to_s,
40
- description: "Called **#{friend_names.last}**."
37
+ str: "Yesterday: Called **#{friend_names.last}**."
41
38
  )
42
39
  ]
43
40
  end
@@ -413,22 +410,19 @@ describe Friends::Introvert do
413
410
  let(:activities) do
414
411
  [
415
412
  Friends::Activity.new(
416
- date_s: Date.today.to_s,
417
- description: "Lunch with **George Washington Carver**."
413
+ str: "Lunch with **George Washington Carver**."
418
414
  ),
419
415
 
420
416
  # Create another activity with a gap of over a month between it and
421
417
  # the next activity, so we can test that we correctly return data for
422
418
  # months in the range with no activities.
423
419
  Friends::Activity.new(
424
- date_s: (Date.today - 70).to_s,
425
- description: "Called **George Washington Carver**."
420
+ str: "70 days ago: Called **George Washington Carver**."
426
421
  ),
427
422
 
428
423
  # Create an activity that doesn't involve our friend name.
429
424
  Friends::Activity.new(
430
- date_s: (Date.today - 150).to_s,
431
- description: "Called **Betsy Ross** on the phone."
425
+ str: "150 days ago: Called **Betsy Ross** on the phone."
432
426
  )
433
427
  ]
434
428
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friends
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.13'
4
+ version: '0.15'
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-01-21 00:00:00.000000000 Z
11
+ date: 2016-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chronic
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.10'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: gli
15
29
  requirement: !ruby/object:Gem::Requirement