time_pup 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e6853e36eb663fcd250e211152181b56f540f137
4
+ data.tar.gz: 9babb3d3625d59a0dd1668282617f951e6ac485a
5
+ SHA512:
6
+ metadata.gz: e4a71b79772ad63d1717ac7387e3e00ce97f05bf72f97d7433dee85fc1190342072789395af00b49d21b435d77137e6c591d1d024d154cc21b65c6242939ddd8
7
+ data.tar.gz: e7a45f81fc0c4a9ef59125f9be5ef1a2cb695b1ab8ca6a2461a56a7bec0a823f0a51879721bd16347f4efe8b28ce60d31e8723c0135b17781d23b56edc8a56d8
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in time_pup.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Siyelo Software
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # TimePup
2
+
3
+ A simple natural language date time parser extracted from [hound.cc](http://www.hound.cc). It is perfect for parsing the local part of an email address.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'time_pup'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install time_pup
18
+
19
+ ## Usage
20
+
21
+ TimePup.parse( 'tomorrow', timezone = UTC )
22
+
23
+ The time is always returned in UTC, it is just adjusted based on the time zone provided e.g:
24
+
25
+ * TimePup.parse( '8am' ) #=> 8 AM UTC
26
+ * TimePup.parse( '8am', 'Harare' ) #=> 6 AM UTC
27
+
28
+ ### Examples
29
+
30
+ **From now**
31
+
32
+ > 2minutes <br/>
33
+ > 3hours <br/>
34
+ > 1day <br/>
35
+ > 2weeks <br/>
36
+ > 3month <br/>
37
+
38
+ **Composite**
39
+
40
+ > 1day2hours <br/>
41
+
42
+ **Weekdays**
43
+
44
+ > friday <br/>
45
+ > monday9am <br/>
46
+ > nexttuesday <br/>
47
+ > nextweek <br/>
48
+
49
+ **Handy**
50
+
51
+ > tomorrow <br/>
52
+ > tomorrow1030am <br/>
53
+ > endofday <br/>
54
+
55
+ **Actual Date**
56
+
57
+ > 04july <br/>
58
+ > aug-10 <br/>
59
+ > 16sept1030am <br/>
60
+
61
+ **Actual Time**
62
+
63
+ > 1030 <br/>
64
+ > 22 <br/>
65
+ > 1030am <br/>
66
+
67
+ **Abbreviations**
68
+
69
+ > 2m <br/>
70
+ > 5d <br/>
71
+ > 1mo <br/>
72
+
73
+ ## Contributing
74
+
75
+ 1. Fork it
76
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
77
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
78
+ 4. Push to the branch (`git push origin my-new-feature`)
79
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/time_pup.rb ADDED
@@ -0,0 +1,24 @@
1
+ require "time_pup/version"
2
+
3
+ module TimePup
4
+ require 'active_support/core_ext/numeric/time'
5
+ require 'active_support/core_ext/integer/time'
6
+ require 'active_support/values/time_zone'
7
+ require 'active_support/time_with_zone'
8
+ require 'active_support/core_ext/time/calculations'
9
+ require 'active_support/core_ext/date_time/calculations'
10
+ require 'active_support/core_ext/date/calculations'
11
+ require 'active_support/core_ext/date_time/zones'
12
+
13
+ require 'time_pup/adverb_parser'
14
+ require 'time_pup/time_parser'
15
+ require 'time_pup/incremental_time'
16
+ require 'time_pup/date_time_parser'
17
+
18
+ def self.parse(time, timezone = 'UTC')
19
+ TimePup::AdverbParser.parse(time, timezone) ||
20
+ TimePup::DateTimeParser.parse(time, timezone) ||
21
+ TimePup::IncrementalTime.parse(time) ||
22
+ TimePup::TimeParser.parse(time, timezone)
23
+ end
24
+ end
@@ -0,0 +1,104 @@
1
+ module TimePup
2
+ class AdverbParser
3
+ STARTOFDAY = 8
4
+ ENDOFDAY = 17
5
+ DAYSOFWEEK = [:monday, :tuesday, :wednesday,
6
+ :thursday, :friday, :saturday, :sunday]
7
+ MATCHERS = {
8
+ tomorrow: /tomorrow/,
9
+ endofday: /endofday/,
10
+ endofmonth: /endofmonth/,
11
+ nextmonday: /nextmonday/,
12
+ monday: /monday/,
13
+ nexttuesday: /nexttuesday/,
14
+ tuesday: /tuesday/,
15
+ nextwednesday: /nextwednesday/,
16
+ wednesday: /wednesday/,
17
+ nextthursday: /nextthursday/,
18
+ thursday: /thursday/,
19
+ nextfriday: /nextfriday/,
20
+ friday: /friday/,
21
+ nextsaturday: /nextsaturday/,
22
+ saturday: /saturday/,
23
+ nextsunday: /nextsunday/,
24
+ sunday: /sunday/,
25
+ nextweek: /nextweek/
26
+ }
27
+
28
+ class << self
29
+ def parse(parsable, zone = 'UTC')
30
+ matches = match_key_words(parsable)
31
+ unless matches.empty?
32
+ time = parse_time(parsable, matches.first)
33
+ if time
34
+ hour = time.hour
35
+ min = time.min
36
+ end
37
+
38
+ match = self.send(matches.first)
39
+ return utc_offset(match, zone, hour, min)
40
+ end
41
+ end
42
+
43
+ def parse_time(parsable, matcher)
44
+ parsable_parts = parsable.partition(matcher)
45
+ time_part = nil
46
+ [0, 2].each do |index|
47
+ parsed_time = TimePup::TimeParser.parse(parsable_parts[index])
48
+ time_part = parsed_time if parsed_time
49
+ end
50
+
51
+ time_part
52
+ end
53
+
54
+ def match_key_words(time)
55
+ MATCHERS.keys.inject([]) do
56
+ |result, m| result << time.scan(MATCHERS[m])
57
+ end.flatten
58
+ end
59
+
60
+ def tomorrow
61
+ 1.day.from_now.utc.change hour: STARTOFDAY
62
+ end
63
+
64
+ def endofday
65
+ Time.now.utc.change hour: ENDOFDAY
66
+ end
67
+
68
+ def endofmonth
69
+ Time.now.end_of_month.utc.change hour: STARTOFDAY
70
+ end
71
+
72
+ def nextweek
73
+ Time.now.next_week.utc.change hour: STARTOFDAY
74
+ end
75
+
76
+ DAYSOFWEEK.each do |d|
77
+ define_method d do
78
+ date_of_next(d.to_s)
79
+ end
80
+ end
81
+
82
+ DAYSOFWEEK.each do |d|
83
+ define_method "next#{d}" do
84
+ date_of_next(d.to_s)
85
+ end
86
+ end
87
+
88
+ def date_of_next(day)
89
+ date = DateTime.parse(day).to_time
90
+ delta = date > Date.today ? 0 : 7
91
+ (date + delta.days).change hour: STARTOFDAY
92
+ end
93
+
94
+ private
95
+
96
+ def utc_offset(utc_time, zone, hour, min)
97
+ tz_time = utc_time.in_time_zone(ActiveSupport::TimeZone[zone])
98
+ tz_time = tz_time.change hour: hour || utc_time.hour
99
+ tz_time = tz_time.change min: min || 0
100
+ tz_time.utc
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,24 @@
1
+ module TimePup
2
+ class DateTimeParser
3
+ MONTHS = /jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/i
4
+ TIME = /\d{1,4}[a|p]m/i
5
+
6
+ def self.parse(parsable, timezone = 'UTC')
7
+ return nil unless parsable.match(MONTHS)
8
+ date = DateTime.parse(parsable).to_time
9
+ date = date.in_time_zone(ActiveSupport::TimeZone[timezone])
10
+ time = find_time(parsable)
11
+ if time
12
+ date.change(hour: time.hour, min: time.min).utc
13
+ else
14
+ date.change(hour: 8).utc
15
+ end
16
+ end
17
+
18
+ private
19
+ def self.find_time(parsable)
20
+ time_part = parsable.slice(TIME)
21
+ TimePup::TimeParser.parse(time_part) if time_part
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ module TimePup
2
+ # Parses time with the following keywords;
3
+ # year y
4
+ # month mo
5
+ # week w
6
+ # day d
7
+ # hour h
8
+ # minute m
9
+
10
+ class IncrementalTime
11
+ MATCHERS = {
12
+ years: /(\d{1,2})ye?a?r?s?/,
13
+ months: /(\d{1,2})mo[a-zA-Z]*/,
14
+ weeks: /(\d{1,2})we?e?k?s?/,
15
+ days: /(\d{1,2}(\.\d{1,2})?)da?y?s?/,
16
+ hours: /(\d{1,2}(\.\d{1,2})?)ho?u?r?s?/,
17
+ minutes: /(\d{1,2})(?!(mo|mar))m[a-zA-Z]*/
18
+ }
19
+
20
+ class << self
21
+ def parse(time)
22
+ increment = match_and_return_time(time.downcase)
23
+ increment == 0.seconds ? nil : increment.from_now
24
+ end
25
+
26
+ def match_and_return_time(time)
27
+ MATCHERS.keys.inject(0.seconds) do |result, m|
28
+ result += scan_increments(time, m)
29
+ end
30
+ end
31
+
32
+ def scan_increments(time, unit)
33
+ increments = time.scan MATCHERS[unit]
34
+ if increments.empty?
35
+ 0.seconds
36
+ else
37
+ if unit == :hours || unit == :days
38
+ increments.first[0].to_f.send(unit.to_sym)
39
+ else
40
+ increments.first[0].to_i.send(unit.to_sym)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,48 @@
1
+ module TimePup
2
+ class TimeParser
3
+ MATCHERS = {
4
+ twelve_hour_with_period: /\d{1,4}[a|p]m/i,
5
+ twenty_four_hour_with_minutes: /[0-2]{,1}\d[0-5]\d/,
6
+ twenty_four_hour_without_minutes: /\d\d{,1}/,
7
+ }
8
+ AM_PM = /[a|p]m/i
9
+
10
+ class << self
11
+ def parse(parsable, zone = 'UTC')
12
+ matches = match_key_words(parsable)
13
+ if matches.empty?
14
+ return nil
15
+ else
16
+ time_part = matches.first
17
+ case time_part.length
18
+ when 1..2
19
+ time_part = time_part + ':00'
20
+ when 3..4
21
+ unless time_part.match(AM_PM)
22
+ time_part = time_part.insert(-3,':')
23
+ end
24
+ when 5..6
25
+ time_part = time_part.insert(-5,':')
26
+ end
27
+
28
+ return set_time_in_future(time_part, zone)
29
+ end
30
+ end
31
+
32
+ def match_key_words(time)
33
+ MATCHERS.keys.inject([]) { |result, m| result << time.scan(MATCHERS[m]) }.flatten
34
+ end
35
+
36
+ def set_time_in_future(time_part, zone)
37
+ time = DateTime.parse(time_part)
38
+ time_for_today = DateTime.now.to_time.in_time_zone(ActiveSupport::TimeZone[zone])
39
+ time_for_today = time_for_today.change(hour: time.hour, min: time.min).utc
40
+ if time_for_today < DateTime.now.to_time.utc
41
+ time_for_today + 1.day
42
+ else
43
+ time_for_today
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module TimePup
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1 @@
1
+ require 'time_pup'
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe TimePup::AdverbParser do
4
+ it "should return the reminder time" do
5
+ time = "tomorrow"
6
+ TimePup::AdverbParser.parse(time).should == 1.day.from_now.utc.change(hour: 8)
7
+ end
8
+
9
+ it "should offset the time based on the timezone" do
10
+ time = "tomorrow"
11
+ TimePup::AdverbParser.parse(time, 'Harare').should == 1.day.from_now.utc.change(hour: 6) # 6am UTC = 8am Harare
12
+ end
13
+
14
+ it "should default to 'UTC' if given time zone is not valid" do
15
+ time = "tomorrow"
16
+ TimePup::AdverbParser.parse(time, 'THISisntAtimezone').should == 1.day.from_now.utc.change(hour: 8)
17
+ end
18
+
19
+ it "should handle timezone > GMT+8" do
20
+ time = "tomorrow"
21
+ # Today 11pm UTC == Tomorrow 8am IRKT
22
+ TimePup::AdverbParser.parse(time, 'Irkutsk').should == Time.now.utc.change(hour: 23)
23
+ end
24
+
25
+ it "should return 8am the next day" do
26
+ time = "tomorrow"
27
+ TimePup::AdverbParser.parse(time) == 1.day.from_now.utc.change(hour: 8)
28
+ end
29
+
30
+ it "should return the next day (mon tues ect)" do
31
+ time = "nextmonday"
32
+ send_at = TimePup::AdverbParser.parse(time)
33
+ send_at.wday.should == 1
34
+ send_at.hour.should == 8
35
+ end
36
+
37
+ it "should return the next day (mon tues ect)" do
38
+ time = "tuesday"
39
+ send_at = TimePup::AdverbParser.parse(time)
40
+ send_at.wday.should == 2
41
+ send_at.hour.should == 8
42
+ end
43
+
44
+ it "should return 8am the next day" do
45
+ time = "endofday"
46
+ TimePup::AdverbParser.parse(time).should == Time.now.utc.change(hour: 17)
47
+ end
48
+
49
+ it "should return 8am the last day of the month" do
50
+ time = "endofmonth"
51
+ t = Time.now.utc
52
+ resulting_time = (t.change month: t.month + 1, day: 1, hour: 8) - 1.day
53
+ TimePup::AdverbParser.parse(time).should == resulting_time
54
+ end
55
+
56
+ it "should return nil if not parseable" do
57
+ time = 'eeee10am'
58
+ TimePup::AdverbParser.parse(time).should == nil
59
+ end
60
+
61
+ it "should parse trailing 12-hour time with period" do
62
+ time = "tomorrow10am"
63
+ TimePup::AdverbParser.parse(time).should == 1.day.from_now.utc.change(hour: 10)
64
+ end
65
+
66
+ it "should parse leading 12-hour time with period" do
67
+ time = "10pmtomorrow"
68
+ TimePup::AdverbParser.parse(time).should == 1.day.from_now.utc.change(hour: 22)
69
+ end
70
+
71
+ it "should parse 12-hour time with minutes and period" do
72
+ time = "1030amtomorrow"
73
+ TimePup::AdverbParser.parse(time).should == 1.day.from_now.utc.change(hour: 10, min:30)
74
+ end
75
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe TimePup::DateTimeParser do
4
+
5
+ it "barfs on bad local parts" do
6
+ TimePup::DateTimeParser.parse('pimpin').should be_nil
7
+ end
8
+
9
+ it "parses day month combinations (defaulting to UTC)" do
10
+ TimePup::DateTimeParser.parse('31Mar').should == DateTime.parse('31 Mar 08:00')
11
+ TimePup::DateTimeParser.parse('3July').should == DateTime.parse('3 July 08:00')
12
+ end
13
+
14
+ it "parses day month time combinations (defaulting to UTC)" do
15
+ TimePup::DateTimeParser.parse('31Mar1030am').should == DateTime.parse('31 Mar 10:30')
16
+ TimePup::DateTimeParser.parse('3July10pm').should == DateTime.parse('3 July 22:00')
17
+ TimePup::DateTimeParser.parse('10pm3July2013').should == DateTime.parse('3 July 2013 22:00')
18
+ end
19
+
20
+ it "returns as UTC with the hour equal to 8am in given timezone" do
21
+ TimePup::DateTimeParser.parse('1Nov', 'Harare').should == DateTime.parse('1Nov 06:00')
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe TimePup::IncrementalTime do
4
+ def incremental_time(time)
5
+ TimePup::IncrementalTime.parse(time).to_i
6
+ end
7
+
8
+ it "should detect the minutes" do
9
+ incremental_time("2minutes").should == 2.minutes.from_now.to_i
10
+ end
11
+
12
+ it "should detect the minutes (m) (complex)" do
13
+ incremental_time("5m").should == 5.minutes.from_now.to_i
14
+ end
15
+
16
+ it "should detect the minutes(mi) (complex)" do
17
+ incremental_time("5mi").should == 5.minutes.from_now.to_i
18
+ end
19
+
20
+ it "should detect the minutes(min) (complex)" do
21
+ incremental_time("5min").should == 5.minutes.from_now.to_i
22
+ end
23
+
24
+ it "should detect the hours" do
25
+ incremental_time("2hours").should == 2.hours.from_now.to_i
26
+ end
27
+
28
+ it "should detect the hours (complex)" do
29
+ incremental_time("5h").should == 5.hours.from_now.to_i
30
+ end
31
+
32
+ it "should detect the days" do
33
+ incremental_time("2days").should == 2.days.from_now.to_i
34
+ end
35
+
36
+ it "should detect the days (complex)" do
37
+ incremental_time("5d").should == 5.days.from_now.to_i
38
+ end
39
+
40
+ it "should detect the weeks" do
41
+ incremental_time("2weeks").should == 2.weeks.from_now.to_i
42
+ end
43
+
44
+ it "should detect the weeks (complex)" do
45
+ incremental_time("5w").should == 5.weeks.from_now.to_i
46
+ end
47
+
48
+ it "should detect the months" do
49
+ incremental_time("2months").should == 2.months.from_now.to_i || 2.months.from_now.to_i + 1
50
+ end
51
+
52
+ it "should detect the months (complex)" do
53
+ incremental_time("5mo").should == 5.months.from_now.to_i
54
+ end
55
+
56
+ it "should detect the years" do
57
+ incremental_time("2years").should == 2.years.from_now.to_i
58
+ end
59
+
60
+ it "should detect the years (complex)" do
61
+ incremental_time("5y").should == 5.years.from_now.to_i
62
+ end
63
+
64
+ context 'combinations' do
65
+ let(:duration) { (2.years + 3.months + 12.days + 23.hours + 1.minute).from_now.to_i }
66
+ it "should detect everything" do
67
+ incremental_time("2years3months12days23hours1minute").to_i.
68
+ should == duration
69
+ end
70
+
71
+ it "should work with composite times" do
72
+ incremental_time("2y3mo12d23h1m").to_i.
73
+ should == duration
74
+ end
75
+
76
+ it "should work with a mixture of composite and non times" do
77
+ incremental_time("2years3mo12days23h1min").to_i.
78
+ should == duration
79
+ end
80
+ end
81
+
82
+ # if today is 30th day in a month of 31 days (and next month has 30 days)
83
+ # then Time.now + 1.day + 1.month != Time.now + 1.month + 1.day
84
+ # i.e.:
85
+ # 30 March + 1.day == 31 March
86
+ # 31 March + 1.month = 30 April
87
+ # -------------------------------
88
+ # 30 March + 1.month == 30 April
89
+ # 30 April + 1.day == 31 April
90
+
91
+ it "should match increments in decending order (years to minutes) regardless of email order" do
92
+ Time.stub(:now).and_return Time.parse '30-03-2011'
93
+ incremental_time("1d1mo1y").to_i.
94
+ should == Time.parse('31-04-2012').to_i
95
+ end
96
+
97
+ it "should return nil if unparseable" do
98
+ TimePup::IncrementalTime.parse("jiosj").should be_nil
99
+ end
100
+
101
+ it "should not try parse Mar / March as minutes" do
102
+ TimePup::IncrementalTime.parse("31mar").should be_nil
103
+ TimePup::IncrementalTime.parse("31march").should be_nil
104
+ end
105
+
106
+ it "should downcase email before parsing" do
107
+ incremental_time("5Min").should == 5.minutes.from_now.to_i
108
+ end
109
+
110
+ it "can parse decimals for days" do
111
+ incremental_time('1.5d').should == (1.5).days.from_now.to_i
112
+ end
113
+
114
+ it "can parse decimals for days" do
115
+ incremental_time('3.5h').should == (3.5).hours.from_now.to_i
116
+ end
117
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe TimePup::TimeParser do
4
+ it "should return the reminder time - 12 hour format with period" do
5
+ time = "10am"
6
+ TimePup::TimeParser.parse(time).hour.should == 10
7
+ TimePup::TimeParser.parse(time).min.should == 00
8
+ time = "10pm"
9
+ TimePup::TimeParser.parse(time).hour.should == 22
10
+ TimePup::TimeParser.parse(time).min.should == 00
11
+ time = "9pm"
12
+ TimePup::TimeParser.parse(time).hour.should == 21
13
+ TimePup::TimeParser.parse(time).min.should == 00
14
+ end
15
+
16
+ it "should return the reminder time - 12 hour format with period and minutes" do
17
+ time = "1030am"
18
+ TimePup::TimeParser.parse(time).hour.should == 10
19
+ TimePup::TimeParser.parse(time).min.should == 30
20
+ time = "1030pm"
21
+ TimePup::TimeParser.parse(time).hour.should == 22
22
+ TimePup::TimeParser.parse(time).min.should == 30
23
+ time = "930pm"
24
+ TimePup::TimeParser.parse(time).hour.should == 21
25
+ TimePup::TimeParser.parse(time).min.should == 30
26
+ end
27
+
28
+ it "should return the reminder time - 24 hour format" do
29
+ time = "22"
30
+ TimePup::TimeParser.parse(time).hour.should == 22
31
+ TimePup::TimeParser.parse(time).min.should == 00
32
+ time = "10"
33
+ TimePup::TimeParser.parse(time).hour.should == 10
34
+ TimePup::TimeParser.parse(time).min.should == 00
35
+ time = "9"
36
+ TimePup::TimeParser.parse(time).hour.should == 9
37
+ TimePup::TimeParser.parse(time).min.should == 00
38
+ end
39
+
40
+ it "should return the reminder time - 24 hour format with minutes" do
41
+ time = "2230"
42
+ TimePup::TimeParser.parse(time).hour.should == 22
43
+ TimePup::TimeParser.parse(time).min.should == 30
44
+ time = "1030"
45
+ TimePup::TimeParser.parse(time).hour.should == 10
46
+ TimePup::TimeParser.parse(time).min.should == 30
47
+ time = "930"
48
+ TimePup::TimeParser.parse(time).hour.should == 9
49
+ TimePup::TimeParser.parse(time).min.should == 30
50
+ end
51
+
52
+ it "should set the time in the future" do
53
+ time = (Time.now.utc.hour - 1).to_s
54
+ TimePup::TimeParser.parse("#{time}am").day.should == Time.now.utc.day + 1
55
+ end
56
+
57
+ it "should adjust the UTC time based on the given time zone" do
58
+ time = '10am'
59
+ TimePup::TimeParser.parse(time, 'Harare').hour.should == 8 #10am CAT == 8am UTC
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe TimePup do
4
+ it "parses adverb addresses (defaulting to 8am)" do
5
+ Time.zone = "Harare"
6
+ TimePup.parse('tomorrow').should == (Time.now.utc + 1.day).change(hour: 8)
7
+ end
8
+
9
+ it "parses incremental addresses" do
10
+ TimePup.parse('2d').to_i.should == (Time.now + 2.days).to_i
11
+ end
12
+
13
+ it "parses calendar addresses w/o times: defaults to 8am" do
14
+ TimePup.parse('12May2014').should == DateTime.parse('12May2014 08:00')
15
+ end
16
+
17
+ it "parses full month names" do
18
+ TimePup.parse('12November2013').should == DateTime.parse('12Nov2013 08:00')
19
+ end
20
+
21
+ it "parses adverbs and times" do
22
+ TimePup.parse('tomorrow1030pm').should == (Time.now.utc + 1.day).change(hour: 22, min: 30)
23
+ end
24
+
25
+ it "parses times" do
26
+ TimePup.parse('1030pm').should == (Time.now.utc).change(hour: 22, min: 30)
27
+ end
28
+
29
+ it "returns nil or barfs on bad local parts" do
30
+ lambda do
31
+ TimePup.parse('99Apr999 aa:00')
32
+ end.should raise_exception ArgumentError
33
+ TimePup.parse('pimping').should be_nil
34
+ end
35
+
36
+ end
data/time_pup.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'time_pup/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "time_pup"
8
+ gem.version = TimePup::VERSION
9
+ gem.authors = ["Sachin Ranchod"]
10
+ gem.email = ["sachin.ranchod@gmail.com"]
11
+ gem.description = %q{A simple natural language date time parser extracted from hound.cc. Perfect for parsing the local part of an email address}
12
+ gem.summary = %q{Parses time from now (1day2h), weekdays (mon9am), actual dates (15sep2013), actual time (1030) and more. See hound.cc/how-to for examples. }
13
+ gem.homepage = "http://www.hound.cc"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency "rspec"
21
+ gem.add_development_dependency "debugger"
22
+ gem.add_dependency "activesupport", "~> 3.2"
23
+ gem.add_dependency "tzinfo"
24
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_pup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sachin Ranchod
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: debugger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: tzinfo
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A simple natural language date time parser extracted from hound.cc. Perfect
70
+ for parsing the local part of an email address
71
+ email:
72
+ - sachin.ranchod@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - .travis.yml
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - lib/time_pup.rb
84
+ - lib/time_pup/adverb_parser.rb
85
+ - lib/time_pup/date_time_parser.rb
86
+ - lib/time_pup/incremental_time.rb
87
+ - lib/time_pup/time_parser.rb
88
+ - lib/time_pup/version.rb
89
+ - spec/spec_helper.rb
90
+ - spec/time_pup/adverb_parser_spec.rb
91
+ - spec/time_pup/date_time_parser_spec.rb
92
+ - spec/time_pup/incremental_time_spec.rb
93
+ - spec/time_pup/time_parser_spec.rb
94
+ - spec/time_pup_spec.rb
95
+ - time_pup.gemspec
96
+ homepage: http://www.hound.cc
97
+ licenses: []
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.0.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Parses time from now (1day2h), weekdays (mon9am), actual dates (15sep2013),
119
+ actual time (1030) and more. See hound.cc/how-to for examples.
120
+ test_files:
121
+ - spec/spec_helper.rb
122
+ - spec/time_pup/adverb_parser_spec.rb
123
+ - spec/time_pup/date_time_parser_spec.rb
124
+ - spec/time_pup/incremental_time_spec.rb
125
+ - spec/time_pup/time_parser_spec.rb
126
+ - spec/time_pup_spec.rb