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 +4 -4
- data/NEWS.md +13 -0
- data/README.md +10 -14
- data/lib/date_parser.rb +30 -6
- data/lib/date_parser/natural_date_parsing.rb +31 -10
- data/lib/date_parser/utils.rb +9 -0
- data/lib/spec/date_parser_spec.rb +96 -229
- data/lib/spec/natural_date_parsing_spec.rb +260 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49515560a749346476e3439e00f22696efe24e6c
|
4
|
+
data.tar.gz: 5b62496f4a460f5de51309ed666248013bffc00e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
4
|
+
text.
|
5
5
|
|
6
6
|
# Installation
|
7
7
|
```
|
8
8
|
$ gem install date_parser
|
9
9
|
```
|
10
10
|
|
11
|
-
#
|
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
|
-
#
|
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)
|
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
|
-
#
|
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
|
-
#
|
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]
|
62
|
-
nil_date = opts[:nil_date]
|
63
|
-
parse_single_years = opts[:parse_single_years]
|
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
|
-
#
|
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
|
-
#
|
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,
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
|
data/lib/date_parser/utils.rb
CHANGED
@@ -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
|
-
|
4
|
-
## rspec lib/spec/date_parser_spec.rb
|
5
|
-
|
6
|
-
describe NaturalDateParsing do
|
3
|
+
describe DateParser do
|
7
4
|
|
8
5
|
#########################################################
|
9
6
|
##
|
10
|
-
##
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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 "
|
60
|
-
text = "
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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 "
|
68
|
-
expect(
|
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 "
|
73
|
-
text = "
|
74
|
-
creation_date = Date.parse("July
|
75
|
-
answer = [Date.parse("July
|
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
|
78
|
-
expect(
|
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 "
|
83
|
-
text = "
|
84
|
-
creation_date = Date.parse("
|
85
|
-
|
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
|
88
|
-
expect(
|
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 "
|
93
|
-
text = "
|
94
|
-
creation_date =
|
95
|
-
answer = [Date.
|
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
|
98
|
-
expect(
|
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 "
|
103
|
-
text = "
|
104
|
-
creation_date = Date.parse("
|
105
|
-
answer = [
|
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 "
|
108
|
-
expect(
|
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 "
|
113
|
-
text = "
|
114
|
-
creation_date =
|
115
|
-
answer = [Date.parse("January 1,
|
116
|
-
|
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 "
|
119
|
-
expect(
|
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
|
-
##
|
87
|
+
## Edge Cases
|
142
88
|
##
|
143
89
|
|
144
|
-
describe ".
|
145
|
-
|
146
|
-
|
147
|
-
|
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(
|
96
|
+
expect(DateParser::parse(text)).to eql(answer)
|
235
97
|
end
|
236
98
|
end
|
237
99
|
|
238
|
-
context "
|
239
|
-
text = "
|
240
|
-
|
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(
|
105
|
+
expect(DateParser::parse(text)).to eql(answer)
|
247
106
|
end
|
248
107
|
end
|
249
108
|
|
250
|
-
context "
|
251
|
-
text = "
|
252
|
-
|
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(
|
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
|
-
##
|
121
|
+
## Type Testing
|
271
122
|
##
|
272
123
|
|
124
|
+
#########################
|
125
|
+
## Negative Tests
|
126
|
+
##
|
273
127
|
describe ".parse" do
|
274
|
-
context "
|
128
|
+
context "Passing an int for creation_date" do
|
275
129
|
text = "2012-02-12"
|
276
|
-
|
130
|
+
creation_date = 12
|
277
131
|
|
278
|
-
it "
|
279
|
-
expect
|
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 "
|
284
|
-
text = "
|
285
|
-
|
137
|
+
context "Passing a String for creation_date" do
|
138
|
+
text = "2012-02-12"
|
139
|
+
creation_date = "Test"
|
286
140
|
|
287
|
-
it "
|
288
|
-
expect
|
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 "
|
293
|
-
text = "
|
294
|
-
|
146
|
+
context "Passing a Time for creation_date" do
|
147
|
+
text = "2012-02-12"
|
148
|
+
creation_date = Time.at(0)
|
295
149
|
|
296
|
-
it "
|
297
|
-
expect
|
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.
|
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-
|
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
|
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:
|
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
|