time_pup 0.0.1

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 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