date_parser 0.1.1 → 0.1.3

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: 83fcce6dfc6821ee2701b10b33bb9cead5aa05e7
4
- data.tar.gz: 47922dd354451a884c45e02f0fd818f359aef78c
3
+ metadata.gz: 49515560a749346476e3439e00f22696efe24e6c
4
+ data.tar.gz: 5b62496f4a460f5de51309ed666248013bffc00e
5
5
  SHA512:
6
- metadata.gz: 405f093a43e736aef635c60ca99655f891a42c9308d4da053e3a7aaa9cd9a8edabb93f2c1fa590141f87d289e80a348ab620468a35ef1433eeb16ef7819cd130
7
- data.tar.gz: 4ce37b863c5901b1f4ddaa0bd68792f40f64cd3649e715d64dd7af49a6e6884088348487a3b76763b80f22380d2473a3eb1c2340105b553a77702e830604ef6d
6
+ metadata.gz: 04d19e1cb3d309af0e6a840392fbf888770db7badd423c5bfdb1887a8d34717b37e974f7a3cf01500cabb0a338fb77faf36c7453be253b71acde2d28905fbd39
7
+ data.tar.gz: c246d93f41261c4417eeb49b7b6544ddb1c8f8b70bc7d2892ac341292fecc86e44ece6ee4f507b7aa0c16126c29a79dd907f057edc6e97115142019c2d553c82
data/NEWS.md CHANGED
@@ -1,3 +1,16 @@
1
+ # DateParser 0.1.3
2
+ * New internal checks to avoid ambiguous behavior.
3
+ + Notably: creation_date is enforced to be a descendent of the Date class.
4
+ * New tests to ensure that the program fails when unexpected types are passed in.
5
+
6
+ # DateParser 0.1.2
7
+ * New option: `parse_ambiguous_dates` flag, which determines whether or not some
8
+ looser phrases are considered dates.
9
+ * Documentation fixes and format improvements.
10
+ * Added more test cases to cover options in `parse`.
11
+ * Restructured test files.
12
+ * `parse` option defaults now work in all cases.
13
+
1
14
  # DateParser 0.1.1
2
15
  * Critical bug fix - Helper files now sent with the gem.
3
16
 
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # DateParser
2
2
 
3
3
  DateParser is a simple, fast, effective way of parsing dates from natural language
4
- text in a flexible way.
4
+ text.
5
5
 
6
6
  # Installation
7
7
  ```
8
8
  $ gem install date_parser
9
9
  ```
10
10
 
11
- # Usage
11
+ # Examples
12
12
  ```ruby
13
13
  require 'date_parser'
14
14
 
@@ -35,15 +35,6 @@ DateParser::parse(text, creation_date).to_s
35
35
  #=> [#<Date: 1994-01-11 ((2449364j,0s,0n),+0s,2299161j)>]
36
36
 
37
37
 
38
- text = "The first time I asked someone on a date, I was in Iowa, it was a " +
39
- "winterly mid-month January, we were to go to finding nemo, I was 9, and " +
40
- "although she was interested, her parents said no."
41
- creation_date = Date.parse("July 6, 2016")
42
-
43
- DateParser::parse(text, creation_date).to_s
44
- #=> [#<Date: 2016-01-01 ((2457389j,0s,0n),+0s,2299161j)>]
45
-
46
-
47
38
  text = "7-24-2015"
48
39
  DateParser::parse(text).to_s
49
40
  #=> [#<Date: 2015-07-24 ((2457228j,0s,0n),+0s,2299161j)>]
@@ -97,10 +88,12 @@ DateParser::parse("No dates here",
97
88
  #=> [#<Date: 2016-01-01 ((2457389j,0s,0n),+0s,2299161j)>]
98
89
  ```
99
90
 
100
- # Examples
91
+ # Usage
101
92
 
102
93
  DateParser has just one function: `parse(txt, creation_date, opts)`, which
103
- always returns an array with Date elements parsed from the text.
94
+ always returns an array with Date elements parsed from the text. If DateParser
95
+ can't find any dates, it'll return an empty array (or an array containing just
96
+ the `nil_date`, if you define that!)
104
97
 
105
98
  `parse` is case-insensitive, robust to crazy punctuation and spacing, and will
106
99
  try to interpret dates in the strictest possible way before trying to find
@@ -119,7 +112,10 @@ to the `creation_date`.
119
112
  * `unique`: (boolean) Return only unique dates in the output array.
120
113
  * `nil_date`: (Date) If no dates are found, instead of returning an empty array,
121
114
  return an array containing only `nil_date`.
122
- * `parse_single_years`: (boolean) Should the parser interpret integers as years?
115
+ * `parse_single_years`: (boolean) Interpret integers as years.
116
+ * `parse_ambiguous_dates`: (boolean) Some phrases are not necessarily dates depending
117
+ on context. For example "1st" may not refer to the 1st of a month.
118
+ This option toggles whether or not those phrases are considered dates. Defaults to true.
123
119
 
124
120
  # Requests or Bugs?
125
121
  Leave an issue on this Github page! I'll most likely get back to you within 24
data/lib/date_parser.rb CHANGED
@@ -17,14 +17,24 @@ module DateParser
17
17
  # ==== Attributes
18
18
  #
19
19
  # * +txt+ - The text to parse.
20
+ #
20
21
  # * +creation_date+ - A Date object of when the text was created or released.
21
- # Defaults to nil, but if provided can make returned dates more accurate.
22
+ # Defaults to nil, but if provided can make returned dates more accurate.
23
+ # This is intentionally checked to be a Date object, as other data types
24
+ # may cause unforeseen behavior.
22
25
  #
23
26
  # ==== Options
24
27
  #
25
28
  # * +:unique+ - Return only unique Date objects. Defaults to false
29
+ #
26
30
  # * +:nil_date+ - A date to return if no dates are parsed. Defaults to nil.
27
- # * +:parse_single_years+ - Should we parse single ints as years? Defaults to false.
31
+ #
32
+ # * +:parse_single_years+ - Parse single ints as years. Defaults to false.
33
+ #
34
+ # * +:parse_ambiguous_dates+ - Some phrases are not necessarily dates depending
35
+ # on context. For example "1st" may not refer to
36
+ # the 1st of a month. This option toggles whether or not those
37
+ # phrases are considered dates. Defaults to true.
28
38
  #
29
39
  # ==== Examples
30
40
  #
@@ -57,14 +67,28 @@ module DateParser
57
67
  # DateParser::parse("No dates here", nil, nil_date: Date.parse("Jan 1 2012"))
58
68
  # #=> [#<Date: 2012-01-01 ((2455928j,0s,0n),+0s,2299161j)>]
59
69
  #
70
+ # creation_date = Date.parse("July 15, 2016")
71
+ # DateParser::parse("He was 1st!", creation_date)
72
+ # #=> [#<Date: 2016-07-01 ((2457571j,0s,0n),+0s,2299161j)>]
73
+ #
74
+ # DateParser::parse("He was 1st!", creation_date, parse_ambiguous_dates: false)
75
+ # #=> []
76
+ #
60
77
  def DateParser.parse(txt, creation_date = nil, opts = {})
61
- unique = opts[:unique] || false
62
- nil_date = opts[:nil_date] || nil
63
- parse_single_years = opts[:parse_single_years] || false
78
+ unique = opts[:unique].nil? ? false : opts[:unique]
79
+ nil_date = opts[:nil_date].nil? ? nil : opts[:nil_date]
80
+ parse_single_years = opts[:parse_single_years].nil? ? false : opts[:parse_single_years]
81
+ parse_ambiguous_dates = opts[:parse_ambiguous_dates].nil? ? true : opts[:parse_ambiguous_dates]
82
+
83
+ if ! Utils::descended_from?(creation_date, Date)
84
+ raise ArgumentError, "creation_date must be a descendent of the Date class." +
85
+ "Otherwise, ambiguous behavior may result."
86
+ end
64
87
 
65
88
  interpreted_dates = NaturalDateParsing::interpret_date(txt,
66
89
  creation_date,
67
- parse_single_years)
90
+ parse_single_years,
91
+ parse_ambiguous_dates)
68
92
 
69
93
  if unique
70
94
  interpreted_dates.uniq!
@@ -77,10 +77,17 @@ module NaturalDateParsing
77
77
  # ==== Attributes
78
78
  #
79
79
  # * +txt+ - The text to parse.
80
+ #
80
81
  # * +creation_date+ - A Date object of when the text was created or released.
81
- # Defaults to nil, but if provided can make returned dates more accurate.
82
+ # Defaults to nil, but if provided can make returned dates more accurate.
83
+ #
82
84
  # * +parse_single_years+ - A boolean. If true, we interpret single numbers as
83
- # years. This is a very broad assumption, and so defaults to false.
85
+ # years. This is a very broad assumption, and so defaults to false.
86
+ #
87
+ # * +parse_ambiguous_dates+ - Some phrases are not necessarily dates depending
88
+ # on context. For example "1st" may not refer to
89
+ # the 1st of a month. This option toggles whether or not those
90
+ # phrases are considered dates. Defaults to true.
84
91
  #
85
92
  # ==== Examples
86
93
  #
@@ -102,7 +109,8 @@ module NaturalDateParsing
102
109
  def NaturalDateParsing.interpret_date(
103
110
  txt,
104
111
  creation_date = nil,
105
- parse_single_years = false
112
+ parse_single_years = false,
113
+ parse_ambiguous_dates = true
106
114
  )
107
115
  possible_dates = []
108
116
  txt = Utils::clean_str(txt)
@@ -149,7 +157,10 @@ module NaturalDateParsing
149
157
  while (i <= words.length - 1) do
150
158
  subset_words = words[i]
151
159
 
152
- proposed_date = parse_one_word(subset_words, creation_date, parse_single_years)
160
+ proposed_date = parse_one_word(subset_words,
161
+ creation_date,
162
+ parse_single_years,
163
+ parse_ambiguous_dates)
153
164
 
154
165
  if(! proposed_date.nil?)
155
166
  possible_dates << proposed_date
@@ -184,15 +195,23 @@ module NaturalDateParsing
184
195
  # ==== Attributes
185
196
  #
186
197
  # * +word+ - A String, preferably consisting of a single word.
198
+ #
187
199
  # * +creation_date+ - A Date object of when the text was created or released.
188
- # Defaults to nil, but if provided can make returned dates more accurate.
200
+ # Defaults to nil, but if provided can make returned dates more accurate.
201
+ #
189
202
  # * +parse_single_years+ - A boolean. If true, we interpret single numbers as
190
- # years. This is a very broad assumption, and so defaults to false.
203
+ # years. This is a very broad assumption, and so defaults to false.
204
+ #
205
+ # * +parse_ambiguous_dates+ - Some phrases are not necessarily dates depending
206
+ # on context. For example "1st" may not refer to
207
+ # the 1st of a month. This option toggles whether or not those
208
+ # phrases are considered dates. Defaults to true.
191
209
  #
192
210
  def NaturalDateParsing.parse_one_word(
193
211
  word,
194
212
  creation_date = nil,
195
- parse_single_years = false
213
+ parse_single_years = false,
214
+ parse_ambiguous_dates = true
196
215
  )
197
216
 
198
217
  if SINGLE_DAYS.include? word
@@ -243,7 +262,7 @@ module NaturalDateParsing
243
262
  end
244
263
 
245
264
  # Parsing strings like "23rd"
246
- if SUFFIXED_NUMERIC_DAY.include? word
265
+ if (SUFFIXED_NUMERIC_DAY.include? word) && parse_ambiguous_dates
247
266
  return numeric_single_day(word, creation_date)
248
267
  end
249
268
 
@@ -274,8 +293,9 @@ module NaturalDateParsing
274
293
  # ==== Attributes
275
294
  #
276
295
  # * +words+ - An array of two words, downcased and stripped.
296
+ #
277
297
  # * +creation_date+ - A Date object of when the text was created or released.
278
- # Defaults to nil, but if provided can make returned dates more accurate.
298
+ # Defaults to nil, but if provided can make returned dates more accurate.
279
299
  #
280
300
  def NaturalDateParsing.parse_two_words(words, creation_date = nil)
281
301
 
@@ -295,8 +315,9 @@ module NaturalDateParsing
295
315
  # ==== Attributes
296
316
  #
297
317
  # * +words+ - An array of three words, downcased and stripped.
318
+ #
298
319
  # * +creation_date+ - A Date object of when the text was created or released.
299
- # Defaults to nil, but if provided can make returned dates more accurate.
320
+ # Defaults to nil, but if provided can make returned dates more accurate.
300
321
  #
301
322
  def NaturalDateParsing.parse_three_words(words, creation_date = nil)
302
323
 
@@ -31,6 +31,9 @@ module Utils
31
31
  end
32
32
 
33
33
  # Performs delete_at for a range of integers
34
+ #
35
+ # Assumes that the integers in range are contiguous, and sorted in ascending
36
+ # order.
34
37
  def Utils.delete_at_indices(array, range)
35
38
  first_val = range.first
36
39
  for _ in range do
@@ -39,4 +42,10 @@ module Utils
39
42
 
40
43
  return array
41
44
  end
45
+
46
+ # Checks to see if an object is descended from an ancestor (or is the ancestor)
47
+ # nil_accepted is a flag that checks
48
+ def Utils.descended_from?(obj, ancestor, nil_accepted = true)
49
+ return obj.nil? ? nil_accepted : obj.class.ancestors.include?(ancestor)
50
+ end
42
51
  end
@@ -1,300 +1,167 @@
1
1
  require_relative "../date_parser"
2
2
 
3
- ## Run this file with this command:
4
- ## rspec lib/spec/date_parser_spec.rb
5
-
6
- describe NaturalDateParsing do
3
+ describe DateParser do
7
4
 
8
5
  #########################################################
9
6
  ##
10
- ## Basic Mechanics Testing
7
+ ## Options Testing
11
8
  ##
12
-
13
- before do
14
-
15
- @date = "April 6th, 2014"
16
- @text = "Remember to meet me on April 6th, 2014, alright?"
17
- @paragraph = "April 6th, 2014 isn't good for me. We should meet instead on\n" +
18
- "February 4th, 2013. Or even March 31st, 2017. No rush."
19
-
20
- @parsed_date = [Date.parse("April 6th, 2014")]
21
- @parsed_date_paragraph = [
22
- Date.parse("April 6th, 2014"),
23
- Date.parse("February 4th, 2013"),
24
- Date.parse("March 31st, 2017")
25
- ]
26
- end
27
-
28
- describe ".interpret_date" do
29
- context "given 'April 6th, 2014'" do
30
- it "returns Sun, 06 Apr 2014 as a date object" do
31
- expect(NaturalDateParsing::interpret_date(@date)).to eql(@parsed_date)
32
- end
33
- end
34
9
 
35
- context "given a sentence containing April 6th, 2014" do
36
- it "returns Sun, 06 Apr 2014 as a date object" do
37
- expect(NaturalDateParsing::interpret_date(@text)).to eql(@parsed_date)
38
- end
39
- end
40
-
41
- context "given a paragraph containing several dates" do
42
- it "returns a list of all dates mentioned in the paragraph" do
43
- expect(NaturalDateParsing::interpret_date(@paragraph)).to eql(@parsed_date_paragraph)
44
- end
45
- end
46
- end
47
- end
48
-
49
-
50
- describe NaturalDateParsing do
51
-
52
- #########################################################
53
- ##
54
- ## Edge Cases. More Colloquial Language. More complicated phrases.
55
- ##
56
-
57
- describe ".interpret_date" do
10
+ # * +:parse_single_years+ - Parse single ints as years. Defaults to false.
11
+ #
12
+ # * +:parse_ambiguous_dates+ - Some phrases are not necessarily dates depending
13
+ # on context. For example "1st" may not refer to
14
+ # the 1st of a month. This option toggles whether or not those
15
+ # phrases are considered dates. Defaults to true.
16
+ describe ".parse" do
58
17
 
59
- context "Given a longer sentence containing a date" do
60
- text = "La Puerta del Conde (The Count's Gate) is the site in Santo" +
61
- "Domingo, Dominican Republic where Francisco del Rosario Sánchez, one of the" +
62
- "Dominican Founding Fathers, proclaimed Dominican independence and raised the" +
63
- "first Dominican Flag, on February 27, 1844."
64
- creation_date = nil
65
- answer = [Date.parse("February 27, 1844")]
18
+ context "Not using unique option" do
19
+ text = "Sunday, Sunday, Sunday!"
20
+ creation_date = Date.parse("July 15, 2016")
21
+ answer = [Date.parse("July 17, 2016"),
22
+ Date.parse("July 17, 2016"),
23
+ Date.parse("July 17, 2016")]
66
24
 
67
- it "captures the single date" do
68
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
25
+ it "correctly gets repeated dates" do
26
+ expect(DateParser::parse(text, creation_date, unique: false)).to eql(answer)
69
27
  end
70
28
  end
71
29
 
72
- context "Colloquial use of date 1" do
73
- text = "We should go on the 4th if we can."
74
- creation_date = Date.parse("July 1st 2016")
75
- answer = [Date.parse("July 4th, 2016")]
30
+ context "Using unique option" do
31
+ text = "Sunday, Sunday, Sunday!"
32
+ creation_date = Date.parse("July 15, 2016")
33
+ answer = [Date.parse("July 17, 2016")]
76
34
 
77
- it "correctly uses the creation_date parameter" do
78
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
35
+ it "correctly gets only unique dates" do
36
+ expect(DateParser::parse(text, creation_date, unique: true)).to eql(answer)
79
37
  end
80
38
  end
81
39
 
82
- context "Correct use of XX/XX format 1" do
83
- text = "Newsflash: things happen on 02/12!"
84
- creation_date = Date.parse("January 1st, 1994")
85
- answer = [Date.parse("February 12, 1994")]
40
+ context "Using nil date option" do
41
+ text = "No dates"
42
+ creation_date = Date.parse("July 15, 2016")
43
+ nil_date = Date.parse("July 17, 2016")
44
+ answer = [Date.parse("July 17, 2016")]
86
45
 
87
- it "correctly grabs the date" do
88
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
46
+ it "correctly returns the nil_date" do
47
+ expect(DateParser::parse(text, creation_date, nil_date: nil_date)).to eql(answer)
89
48
  end
90
49
  end
91
50
 
92
- context "Given yesterday" do
93
- text = "Yesterday was certainly a day."
94
- creation_date = nil
95
- answer = [Date.today - 1]
51
+ context "Using the parse_single_years option" do
52
+ text = "2000"
53
+ creation_date = Date.parse("July 15, 2016")
54
+ answer = [Date.parse("January 1, 2000")]
96
55
 
97
- it "correctly grabs the date" do
98
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
56
+ it "correctly parses ints as years" do
57
+ expect(DateParser::parse(text, creation_date, parse_single_years: true)).to eql(answer)
99
58
  end
100
59
  end
101
60
 
102
- context "Given yesterday with a creation_date date" do
103
- text = "Yesterday was certainly a day."
104
- creation_date = Date.parse("January 12, 1994")
105
- answer = [Date.parse("January 11, 1994")]
61
+ context "Setting the parse_ambiguous_dates option to false" do
62
+ text = "He was 1st!"
63
+ creation_date = Date.parse("July 15, 2016")
64
+ answer = []
106
65
 
107
- it "correctly grabs the date" do
108
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
66
+ it "ignores ambiguous phrases" do
67
+ expect(DateParser::parse(text, creation_date, parse_ambiguous_dates: false)).to eql(answer)
109
68
  end
110
69
  end
111
70
 
112
- context "Single year is correctly parsed" do
113
- text = "In 1492 Columbus sailed the ocean blue."
114
- creation_date = nil
115
- answer = [Date.parse("January 1, 1492")]
116
- parse_single_years = true
71
+ context "Setting unique and parse_single_years" do
72
+ text = "12 20 32 402 20"
73
+ creation_date = Date.parse("July 15, 2016")
74
+ answer = [Date.parse("January 1, 12"),
75
+ Date.parse("January 1, 20"),
76
+ Date.parse("January 1, 32"),
77
+ Date.parse("January 1, 402")]
117
78
 
118
- it "correctly grabs the date" do
119
- expect(NaturalDateParsing::interpret_date(text, creation_date, parse_single_years)).to eql(answer)
79
+ it "Returns unique dates and parses ints as years." do
80
+ expect(DateParser::parse(text, creation_date, unique: true, parse_single_years: true)).to eql(answer)
120
81
  end
121
82
  end
122
-
123
- context "Correctly parses month and day in middle of sentence" do
124
- text = "Something something something march 4 something something"
125
- creation_date = Date.parse("Jan 1, 2004")
126
- answer = [Date.parse("March 4, 2004")]
127
-
128
- it "correctly grabs the date" do
129
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
130
- end
131
- end
132
-
133
83
  end
134
- end
135
-
136
-
137
- describe NaturalDateParsing do
138
84
 
139
85
  #########################################################
140
86
  ##
141
- ## Colloquial Language samples from volunteers
87
+ ## Edge Cases
142
88
  ##
143
89
 
144
- describe ".interpret_date" do
145
-
146
- context "Colloquial example 1" do
147
- text = "Charlie Chaplin and Jason Earles (Hannah Montana's brother) were " +
148
- "alive at the same time for eight months in 1977"
149
- creation_date = Date.parse("July 6, 2016")
150
- answer = [Date.parse("January 1, 1977")]
151
- parse_single_years = true
152
-
153
- it "correctly grabs the date" do
154
- expect(NaturalDateParsing::interpret_date(text, creation_date, parse_single_years)).to eql(answer)
155
- end
156
- end
157
-
158
- ## Stopping this test for right now. Hard to tell which April.
159
- ## Ambiguous in the general case.
160
- #context "Colloquial example 2" do
161
- # text = "For a job I started this April, I had to parse dates of various " +
162
- # "formats, such as MM-DD-YY, MM/YYYY, and YY-MM-DD. It was infuriating, " +
163
- # "and what I assume you to be doing reminds me of this."
164
- # creation_date = Date.parse("July 6, 2016")
165
- # answer = [Date.parse("April 1, 2016")] ## Reconsider
166
- #
167
- # it "correctly grabs the date" do
168
- # expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
169
- # end
170
- #end
171
-
172
- context "Colloquial example 3" do
173
- text = "August 25, 2013, I met So-and-So"
174
- creation_date = Date.parse("July 6, 2016")
175
- answer = [Date.parse("August 25, 2013")]
176
-
177
- it "correctly grabs the date" do
178
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
179
- end
180
- end
181
-
182
- context "Colloquial example 4" do
183
- text = "Quincy Jones (producer of Thriller) and Michael Caine (veteran " +
184
- "British actor) were both born on the same day and the same hour on March " +
185
- "14, 1933. They are still friends to this day."
186
- creation_date = Date.parse("July 6, 2016")
187
- answer = [Date.parse("March 14, 1933")]
188
-
189
- it "correctly grabs the date" do
190
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
191
- end
192
- end
193
-
194
- context "Colloquial example 5" do
195
- text = "Two days ago (July 4, 2016) was the 190th death anniversary of " +
196
- "the second and third US Presidents: John Adams and Thomas Jefferson, who died 5 hours apart."
197
- creation_date = Date.parse("July 6, 2016")
198
- answer = [Date.parse("July 4, 2016")]
199
-
200
- it "correctly grabs the date" do
201
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
202
- end
203
- end
204
-
205
- context "Colloquial example 6" do
206
- text = "On October 3rd So-and-So asked me what day it was"
207
- creation_date = Date.parse("July 6, 2016")
208
- answer = [Date.parse("October 3, 2016")]
209
-
210
- it "correctly grabs the date" do
211
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
212
- end
213
- end
214
-
215
- context "Colloquial example 7" do
216
- text = "Henry and Hanke created a calendar that causes each day to fall " +
217
- "on the same day of the week every year. They recommend its " +
218
- "implementation on January 1, 2018, a Monday."
219
- creation_date = Date.parse("July 6, 2016")
220
- answer = [Date.parse("January 1, 2018"),
221
- Date.parse("July 11, 2016")] # Reconsider
222
-
223
- it "correctly grabs the date" do
224
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
225
- end
226
- end
227
-
228
- context "Colloquial example 8" do
229
- text = "Beyoncé Giselle Knowles-Carter was born on September 4, 1981."
230
- creation_date = Date.parse("July 6, 2016")
231
- answer = [Date.parse("September 4, 1981")]
90
+ describe ".parse" do
91
+ context "Parse fully numeric date" do
92
+ text = "2012-02-12"
93
+ answer = [Date.parse("2012-02-12")]
232
94
 
233
95
  it "correctly grabs the date" do
234
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
96
+ expect(DateParser::parse(text)).to eql(answer)
235
97
  end
236
98
  end
237
99
 
238
- context "Colloquial example 9" do
239
- text = "The first time I asked someone on a date, I was in Iowa, it was a " +
240
- "winterly mid-month January, we were to go to finding nemo, I was 9, and " +
241
- "although she was interested, her parents said no."
242
- creation_date = Date.parse("July 6, 2016")
243
- answer = [Date.parse("January 1st, 2016")]
100
+ context "Parse American fully numeric date" do
101
+ text = "7-24-2015"
102
+ answer = [Date.parse("July 24, 2015")]
244
103
 
245
104
  it "correctly grabs the date" do
246
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
105
+ expect(DateParser::parse(text)).to eql(answer)
247
106
  end
248
107
  end
249
108
 
250
- context "Colloquial example 10" do
251
- text = "You ate 10 dates from a crate of dates that were picked on June " +
252
- "8th from a date tree that was cultivated one score and three years ago. " +
253
- "Good luck parsing through the antics of my semantics."
254
- creation_date = Date.parse("July 6, 2016")
255
- answer = [Date.parse("June 8, 2016")]
109
+ context "Parse International Standard fully numeric date" do
110
+ text = "24-07-2015"
111
+ answer = [Date.parse("24-07-2015")]
256
112
 
257
113
  it "correctly grabs the date" do
258
- expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
114
+ expect(DateParser::parse(text)).to eql(answer)
259
115
  end
260
116
  end
261
-
262
117
  end
263
- end
264
-
265
-
266
- describe DateParser do
267
118
 
268
119
  #########################################################
269
120
  ##
270
- ## More Edge Cases looking at specific features.
121
+ ## Type Testing
271
122
  ##
272
123
 
124
+ #########################
125
+ ## Negative Tests
126
+ ##
273
127
  describe ".parse" do
274
- context "Parse fully numeric date" do
128
+ context "Passing an int for creation_date" do
275
129
  text = "2012-02-12"
276
- answer = [Date.parse("2012-02-12")]
130
+ creation_date = 12
277
131
 
278
- it "correctly grabs the date" do
279
- expect(DateParser::parse(text)).to eql(answer)
132
+ it "Raises an exception" do
133
+ expect { DateParser::parse(text, creation_date) }.to raise_exception(ArgumentError)
280
134
  end
281
135
  end
282
136
 
283
- context "Parse American fully numeric date" do
284
- text = "7-24-2015"
285
- answer = [Date.parse("July 24, 2015")]
137
+ context "Passing a String for creation_date" do
138
+ text = "2012-02-12"
139
+ creation_date = "Test"
286
140
 
287
- it "correctly grabs the date" do
288
- expect(DateParser::parse(text)).to eql(answer)
141
+ it "Raises an exception" do
142
+ expect { DateParser::parse(text, creation_date) }.to raise_exception(ArgumentError)
289
143
  end
290
144
  end
291
145
 
292
- context "Parse International Standard fully numeric date" do
293
- text = "24-07-2015"
294
- answer = [Date.parse("24-07-2015")]
146
+ context "Passing a Time for creation_date" do
147
+ text = "2012-02-12"
148
+ creation_date = Time.at(0)
295
149
 
296
- it "correctly grabs the date" do
297
- expect(DateParser::parse(text)).to eql(answer)
150
+ it "Raises an exception" do
151
+ expect { DateParser::parse(text, creation_date) }.to raise_exception(ArgumentError)
152
+ end
153
+ end
154
+
155
+ #########################
156
+ ## Positive Tests
157
+ ##
158
+ context "Passing in a DateTime object for creation_date" do
159
+ text = "Something something something march 4 something something"
160
+ creation_date = DateTime.parse("Jan 1, 2004")
161
+ answer = [Date.parse("March 4, 2004")]
162
+
163
+ it "Does not raise an exception, and produces the correct answer" do
164
+ expect(DateParser::parse(text, creation_date)).to eql(answer)
298
165
  end
299
166
  end
300
167
  end
@@ -0,0 +1,260 @@
1
+ require_relative "../date_parser"
2
+
3
+ describe NaturalDateParsing do
4
+
5
+ #########################################################
6
+ ##
7
+ ## Basic Mechanics Testing
8
+ ##
9
+
10
+ before do
11
+
12
+ @date = "April 6th, 2014"
13
+ @text = "Remember to meet me on April 6th, 2014, alright?"
14
+ @paragraph = "April 6th, 2014 isn't good for me. We should meet instead on\n" +
15
+ "February 4th, 2013. Or even March 31st, 2017. No rush."
16
+
17
+ @parsed_date = [Date.parse("April 6th, 2014")]
18
+ @parsed_date_paragraph = [
19
+ Date.parse("April 6th, 2014"),
20
+ Date.parse("February 4th, 2013"),
21
+ Date.parse("March 31st, 2017")
22
+ ]
23
+ end
24
+
25
+ describe ".interpret_date" do
26
+ context "given 'April 6th, 2014'" do
27
+ it "returns Sun, 06 Apr 2014 as a date object" do
28
+ expect(NaturalDateParsing::interpret_date(@date)).to eql(@parsed_date)
29
+ end
30
+ end
31
+
32
+ context "given a sentence containing April 6th, 2014" do
33
+ it "returns Sun, 06 Apr 2014 as a date object" do
34
+ expect(NaturalDateParsing::interpret_date(@text)).to eql(@parsed_date)
35
+ end
36
+ end
37
+
38
+ context "given a paragraph containing several dates" do
39
+ it "returns a list of all dates mentioned in the paragraph" do
40
+ expect(NaturalDateParsing::interpret_date(@paragraph)).to eql(@parsed_date_paragraph)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ describe NaturalDateParsing do
48
+
49
+ #########################################################
50
+ ##
51
+ ## Edge Cases. More Colloquial Language. More complicated phrases.
52
+ ##
53
+
54
+ describe ".interpret_date" do
55
+
56
+ context "Given a longer sentence containing a date" do
57
+ text = "La Puerta del Conde (The Count's Gate) is the site in Santo" +
58
+ "Domingo, Dominican Republic where Francisco del Rosario Sánchez, one of the" +
59
+ "Dominican Founding Fathers, proclaimed Dominican independence and raised the" +
60
+ "first Dominican Flag, on February 27, 1844."
61
+ creation_date = nil
62
+ answer = [Date.parse("February 27, 1844")]
63
+
64
+ it "captures the single date" do
65
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
66
+ end
67
+ end
68
+
69
+ context "Colloquial use of date 1" do
70
+ text = "We should go on the 4th if we can."
71
+ creation_date = Date.parse("July 1st 2016")
72
+ answer = [Date.parse("July 4th, 2016")]
73
+
74
+ it "correctly uses the creation_date parameter" do
75
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
76
+ end
77
+ end
78
+
79
+ context "Correct use of XX/XX format 1" do
80
+ text = "Newsflash: things happen on 02/12!"
81
+ creation_date = Date.parse("January 1st, 1994")
82
+ answer = [Date.parse("February 12, 1994")]
83
+
84
+ it "correctly grabs the date" do
85
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
86
+ end
87
+ end
88
+
89
+ context "Given yesterday" do
90
+ text = "Yesterday was certainly a day."
91
+ creation_date = nil
92
+ answer = [Date.today - 1]
93
+
94
+ it "correctly grabs the date" do
95
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
96
+ end
97
+ end
98
+
99
+ context "Given yesterday with a creation_date date" do
100
+ text = "Yesterday was certainly a day."
101
+ creation_date = Date.parse("January 12, 1994")
102
+ answer = [Date.parse("January 11, 1994")]
103
+
104
+ it "correctly grabs the date" do
105
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
106
+ end
107
+ end
108
+
109
+ context "Single year is correctly parsed" do
110
+ text = "In 1492 Columbus sailed the ocean blue."
111
+ creation_date = nil
112
+ answer = [Date.parse("January 1, 1492")]
113
+ parse_single_years = true
114
+
115
+ it "correctly grabs the date" do
116
+ expect(NaturalDateParsing::interpret_date(text, creation_date, parse_single_years)).to eql(answer)
117
+ end
118
+ end
119
+
120
+ context "Correctly parses month and day in middle of sentence" do
121
+ text = "Something something something march 4 something something"
122
+ creation_date = Date.parse("Jan 1, 2004")
123
+ answer = [Date.parse("March 4, 2004")]
124
+
125
+ it "correctly grabs the date" do
126
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
127
+ end
128
+ end
129
+
130
+ end
131
+ end
132
+
133
+
134
+ describe NaturalDateParsing do
135
+
136
+ #########################################################
137
+ ##
138
+ ## Colloquial Language samples from volunteers
139
+ ##
140
+
141
+ describe ".interpret_date" do
142
+
143
+ context "Colloquial example 1" do
144
+ text = "Charlie Chaplin and Jason Earles (Hannah Montana's brother) were " +
145
+ "alive at the same time for eight months in 1977"
146
+ creation_date = Date.parse("July 6, 2016")
147
+ answer = [Date.parse("January 1, 1977")]
148
+ parse_single_years = true
149
+
150
+ it "correctly grabs the date" do
151
+ expect(NaturalDateParsing::interpret_date(text, creation_date, parse_single_years)).to eql(answer)
152
+ end
153
+ end
154
+
155
+ ## Stopping this test for right now. Hard to tell which April.
156
+ ## Ambiguous in the general case.
157
+ #context "Colloquial example 2" do
158
+ # text = "For a job I started this April, I had to parse dates of various " +
159
+ # "formats, such as MM-DD-YY, MM/YYYY, and YY-MM-DD. It was infuriating, " +
160
+ # "and what I assume you to be doing reminds me of this."
161
+ # creation_date = Date.parse("July 6, 2016")
162
+ # answer = [Date.parse("April 1, 2016")] ## Reconsider
163
+ #
164
+ # it "correctly grabs the date" do
165
+ # expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
166
+ # end
167
+ #end
168
+
169
+ context "Colloquial example 3" do
170
+ text = "August 25, 2013, I met So-and-So"
171
+ creation_date = Date.parse("July 6, 2016")
172
+ answer = [Date.parse("August 25, 2013")]
173
+
174
+ it "correctly grabs the date" do
175
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
176
+ end
177
+ end
178
+
179
+ context "Colloquial example 4" do
180
+ text = "Quincy Jones (producer of Thriller) and Michael Caine (veteran " +
181
+ "British actor) were both born on the same day and the same hour on March " +
182
+ "14, 1933. They are still friends to this day."
183
+ creation_date = Date.parse("July 6, 2016")
184
+ answer = [Date.parse("March 14, 1933")]
185
+
186
+ it "correctly grabs the date" do
187
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
188
+ end
189
+ end
190
+
191
+ context "Colloquial example 5" do
192
+ text = "Two days ago (July 4, 2016) was the 190th death anniversary of " +
193
+ "the second and third US Presidents: John Adams and Thomas Jefferson, who died 5 hours apart."
194
+ creation_date = Date.parse("July 6, 2016")
195
+ answer = [Date.parse("July 4, 2016")]
196
+
197
+ it "correctly grabs the date" do
198
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
199
+ end
200
+ end
201
+
202
+ context "Colloquial example 6" do
203
+ text = "On October 3rd So-and-So asked me what day it was"
204
+ creation_date = Date.parse("July 6, 2016")
205
+ answer = [Date.parse("October 3, 2016")]
206
+
207
+ it "correctly grabs the date" do
208
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
209
+ end
210
+ end
211
+
212
+ context "Colloquial example 7" do
213
+ text = "Henry and Hanke created a calendar that causes each day to fall " +
214
+ "on the same day of the week every year. They recommend its " +
215
+ "implementation on January 1, 2018, a Monday."
216
+ creation_date = Date.parse("July 6, 2016")
217
+ answer = [Date.parse("January 1, 2018"),
218
+ Date.parse("July 11, 2016")] # Reconsider
219
+
220
+ it "correctly grabs the date" do
221
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
222
+ end
223
+ end
224
+
225
+ context "Colloquial example 8" do
226
+ text = "Beyoncé Giselle Knowles-Carter was born on September 4, 1981."
227
+ creation_date = Date.parse("July 6, 2016")
228
+ answer = [Date.parse("September 4, 1981")]
229
+
230
+ it "correctly grabs the date" do
231
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
232
+ end
233
+ end
234
+
235
+ context "Colloquial example 9" do
236
+ text = "The first time I asked someone on a date, I was in Iowa, it was a " +
237
+ "winterly mid-month January, we were to go to finding nemo, I was 9, and " +
238
+ "although she was interested, her parents said no."
239
+ creation_date = Date.parse("July 6, 2016")
240
+ answer = [Date.parse("January 1st, 2016")]
241
+
242
+ it "correctly grabs the date" do
243
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
244
+ end
245
+ end
246
+
247
+ context "Colloquial example 10" do
248
+ text = "You ate 10 dates from a crate of dates that were picked on June " +
249
+ "8th from a date tree that was cultivated one score and three years ago. " +
250
+ "Good luck parsing through the antics of my semantics."
251
+ creation_date = Date.parse("July 6, 2016")
252
+ answer = [Date.parse("June 8, 2016")]
253
+
254
+ it "correctly grabs the date" do
255
+ expect(NaturalDateParsing::interpret_date(text, creation_date)).to eql(answer)
256
+ end
257
+ end
258
+
259
+ end
260
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: date_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Kwon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-26 00:00:00.000000000 Z
11
+ date: 2016-09-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: DateParser is a simple, fast, and effective way to parse dates from natural
14
- language text in a robust way.
14
+ language text.
15
15
  email: rynkwn@gmail.com
16
16
  executables: []
17
17
  extensions: []
@@ -26,6 +26,7 @@ files:
26
26
  - lib/date_parser/natural_date_parsing.rb
27
27
  - lib/date_parser/utils.rb
28
28
  - lib/spec/date_parser_spec.rb
29
+ - lib/spec/natural_date_parsing_spec.rb
29
30
  homepage: https://github.com/rynkwn/DateParser
30
31
  licenses:
31
32
  - MIT
@@ -49,6 +50,7 @@ rubyforge_project:
49
50
  rubygems_version: 2.5.1
50
51
  signing_key:
51
52
  specification_version: 4
52
- summary: Quickly parse natural language into dates robustly.
53
+ summary: Robust natural language parsing for dates.
53
54
  test_files:
54
55
  - lib/spec/date_parser_spec.rb
56
+ - lib/spec/natural_date_parsing_spec.rb