friends 0.13 → 0.15

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