tickle 1.0.2 → 2.0.0rc3
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 +5 -5
- data/.gitignore +3 -1
- data/.travis.yml +12 -0
- data/CHANGES.md +25 -3
- data/Gemfile +14 -1
- data/LICENCE +1 -1
- data/README.md +1 -1
- data/Rakefile +3 -8
- data/benchmarks/main.rb +71 -0
- data/lib/ext/array.rb +6 -0
- data/lib/ext/date_and_time.rb +64 -0
- data/lib/ext/string.rb +39 -0
- data/lib/tickle.rb +23 -113
- data/lib/tickle/filters.rb +58 -0
- data/lib/tickle/handler.rb +223 -80
- data/lib/tickle/helpers.rb +51 -0
- data/lib/tickle/patterns.rb +115 -0
- data/lib/tickle/repeater.rb +232 -116
- data/lib/tickle/tickle.rb +97 -201
- data/lib/tickle/tickled.rb +173 -0
- data/lib/tickle/token.rb +94 -0
- data/lib/tickle/version.rb +2 -2
- data/spec/helpers_spec.rb +36 -0
- data/spec/patterns_spec.rb +240 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/tickle_spec.rb +551 -0
- data/spec/token_spec.rb +82 -0
- data/tickle.gemspec +4 -9
- metadata +34 -74
- data/lib/numerizer/numerizer.rb +0 -103
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1f47be53e642fa9fd7cd412b7d76768807ed9398de11df69a77855f6d2b26b44
|
4
|
+
data.tar.gz: bc3a4d7d5c9048444ef7dfa47e6e55318c3e3577f7ec70145d4500bf441b5c4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6852b109c5091c3abee0bef6c8bf8ea804e9b2a7ff7b7ffd0d995b237f2dc799e3504ef10740a44e320dcd55544e1895e48235bbc745fde25394fc3b315f0121
|
7
|
+
data.tar.gz: 790b5b8790873c0e9a99c882cfe57628fd52ea756738e9c503ff76b38bd664b8ec469a6cc2fe313e823b26a498d6416f39d1986dda1236a3fa62c41c3dc057a3
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGES.md
CHANGED
@@ -1,14 +1,36 @@
|
|
1
1
|
# CH CH CH CH CHANGES! #
|
2
2
|
|
3
|
+
## Friday the 18th of September 2002, v2.0.0rc3
|
3
4
|
|
4
|
-
|
5
|
+
* Changed the dependency from chronic to gitlab-chronic, thanks to @bjonord
|
6
|
+
|
7
|
+
----
|
8
|
+
|
9
|
+
## v2.0.0.rc2, Friday the 8th of December 2017 ##
|
10
|
+
|
11
|
+
* Fixed issue #20 https://github.com/yb66/tickle/pull/20, thanks to [@antogon](https://github.com/antogon)
|
12
|
+
|
13
|
+
----
|
14
|
+
|
15
|
+
|
16
|
+
## Saturday the 7th of November 2015, 2.0.0.rc1 ##
|
17
|
+
|
18
|
+
* Rewrite of the internals.
|
19
|
+
* API should be pretty much the same from the outside, but enough things on the inside change to warrant the major version bump.
|
20
|
+
* Chronic updated to 0.10.2.
|
21
|
+
|
22
|
+
----
|
23
|
+
|
24
|
+
|
25
|
+
## Monday the 11th of November 2013, v1.0.2 ##
|
5
26
|
|
6
27
|
* Shoulda and simplecov aren't runtime dependencies, fixed that in the gemfile.
|
7
28
|
* Got the version number right this time ;-)
|
8
29
|
|
9
30
|
----
|
10
31
|
|
11
|
-
|
32
|
+
|
33
|
+
## Monday the 11th of November 2013, v1.0.1 ##
|
12
34
|
|
13
35
|
* Moved library to new maintainer [https://github.com/yb66/tickle](@yb66)
|
14
36
|
* Moved library to [http://semver.org/](semver).
|
@@ -19,4 +41,4 @@
|
|
19
41
|
* Moved library to Bundler to make it easier to set up and develop against.
|
20
42
|
* Started using Yardoc for more niceness with documentation.
|
21
43
|
|
22
|
-
----
|
44
|
+
----
|
data/Gemfile
CHANGED
@@ -2,7 +2,20 @@ source "https://rubygems.org"
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
|
5
|
+
group :development do
|
6
|
+
gem "maruku"
|
7
|
+
gem "yard"
|
8
|
+
unless RUBY_ENGINE == 'jruby'
|
9
|
+
gem "pry-byebug"
|
10
|
+
gem "pry-state"
|
11
|
+
gem "rb-readline"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
group :test do
|
7
16
|
gem "rspec"
|
17
|
+
gem "rspec-its"
|
18
|
+
gem "timecop"
|
19
|
+
gem "simplecov"
|
20
|
+
gem "rake"
|
8
21
|
end
|
data/LICENCE
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Take a look at the `develop` branch where all this stuff will be happening.
|
|
11
11
|
|
12
12
|
Tickle is a natural language parser for recurring events.
|
13
13
|
|
14
|
-
Tickle is designed to be a complement to [Chronic](https://rubygems.org/gems/chronic) and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc.
|
14
|
+
Tickle is designed to be a complement to [Chronic](https://rubygems.org/gems/chronic) and can interpret things such as "every 2 days", "every Sunday", “Sundays", “Weekly", etc.
|
15
15
|
|
16
16
|
Tickle has one main method, `Tickle.parse`, which returns the next time the event should occur, at which point you simply call `Tickle.parse` again.
|
17
17
|
|
data/Rakefile
CHANGED
@@ -1,13 +1,8 @@
|
|
1
|
-
require '
|
2
|
-
Rake::TestTask.new(:test) do |test|
|
3
|
-
test.libs << 'lib' << 'test'
|
4
|
-
test.pattern = 'test/**/test_*.rb'
|
5
|
-
test.verbose = true
|
6
|
-
end
|
1
|
+
require 'rspec/core/rake_task'
|
7
2
|
|
8
|
-
|
3
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
4
|
|
10
|
-
task :default => :
|
5
|
+
task :default => :spec
|
11
6
|
|
12
7
|
|
13
8
|
desc "(Re-) generate documentation and place it in the docs/ dir. Open the index.html file in there to read it."
|
data/benchmarks/main.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require_relative "../lib/tickle.rb"
|
3
|
+
warn Benchmark.measure {
|
4
|
+
Tickle.parse('day')
|
5
|
+
# Tickle.parse('week')
|
6
|
+
Tickle.parse('month')
|
7
|
+
Tickle.parse('year')
|
8
|
+
Tickle.parse('daily')
|
9
|
+
# Tickle.parse('weekly')
|
10
|
+
Tickle.parse('monthly')
|
11
|
+
Tickle.parse('yearly')
|
12
|
+
Tickle.parse('3 days')
|
13
|
+
# Tickle.parse('3 weeks')
|
14
|
+
Tickle.parse('3 months')
|
15
|
+
Tickle.parse('3 years')
|
16
|
+
Tickle.parse('other day')
|
17
|
+
# Tickle.parse('other week')
|
18
|
+
Tickle.parse('other month')
|
19
|
+
Tickle.parse('other year')
|
20
|
+
Tickle.parse('Monday')
|
21
|
+
Tickle.parse('Wednesday')
|
22
|
+
Tickle.parse('Friday')
|
23
|
+
Tickle.parse('February', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
24
|
+
Tickle.parse('May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
25
|
+
Tickle.parse('june', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
26
|
+
Tickle.parse('beginning of the week')
|
27
|
+
Tickle.parse('middle of the week')
|
28
|
+
Tickle.parse('end of the week')
|
29
|
+
Tickle.parse('beginning of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
30
|
+
Tickle.parse('middle of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
31
|
+
Tickle.parse('end of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
32
|
+
Tickle.parse('beginning of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
33
|
+
Tickle.parse('middle of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
34
|
+
Tickle.parse('end of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
35
|
+
Tickle.parse('the 3rd of May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
36
|
+
Tickle.parse('the 3rd of February', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
37
|
+
Tickle.parse('the 3rd of February 2022', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
38
|
+
Tickle.parse('the 3rd of Feb 2022', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
39
|
+
Tickle.parse('the 4th of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
40
|
+
Tickle.parse('the 10th of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
41
|
+
Tickle.parse('the tenth of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
42
|
+
Tickle.parse('first', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
43
|
+
Tickle.parse('the first of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
44
|
+
Tickle.parse('the thirtieth', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
45
|
+
Tickle.parse('the fifth', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
46
|
+
Tickle.parse('the 1st Wednesday of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
47
|
+
Tickle.parse('the 3rd Sunday of May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
48
|
+
Tickle.parse('the 3rd Sunday of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
49
|
+
Tickle.parse('the 23rd of June', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
50
|
+
Tickle.parse('the twenty third of June', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
51
|
+
Tickle.parse('the thirty first of July', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
52
|
+
Tickle.parse('the twenty first', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
53
|
+
Tickle.parse('the twenty first of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
|
54
|
+
Tickle.parse('starting today and ending one week from now')
|
55
|
+
Tickle.parse('starting tomorrow and ending one week from now')
|
56
|
+
Tickle.parse('starting Monday repeat every month')
|
57
|
+
Tickle.parse('starting May 13th repeat every week')
|
58
|
+
Tickle.parse('starting May 13th repeat every other day')
|
59
|
+
Tickle.parse('every other day starts May 13th')
|
60
|
+
Tickle.parse('every other day starts May 13')
|
61
|
+
Tickle.parse('every other day starting May 13th')
|
62
|
+
Tickle.parse('every other day starting May 13')
|
63
|
+
Tickle.parse('every week starts this wednesday')
|
64
|
+
Tickle.parse('every week starting this wednesday')
|
65
|
+
Tickle.parse('every other day starting May 1st 2021')
|
66
|
+
Tickle.parse('every other day starting May 1 2021')
|
67
|
+
Tickle.parse('every other week starting this Sunday')
|
68
|
+
Tickle.parse('every week starting this wednesday until May 13th')
|
69
|
+
Tickle.parse('every week starting this wednesday ends May 13th')
|
70
|
+
Tickle.parse('every week starting this wednesday ending May 13th')
|
71
|
+
}
|
data/lib/ext/array.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
class Date
|
2
|
+
# returns the days in the sending month
|
3
|
+
def days_in_month
|
4
|
+
d,m,y = mday,month,year
|
5
|
+
d += 1 while Date.valid_civil?(y,m,d)
|
6
|
+
d - 1
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# no idea what this is for
|
11
|
+
def bump(attr, amount=nil)
|
12
|
+
amount ||= 1
|
13
|
+
case attr
|
14
|
+
when :day then
|
15
|
+
Date.civil(self.year, self.month, self.day + amount)
|
16
|
+
when :wday then
|
17
|
+
amount = Date::ABBR_DAYNAMES.index(amount) if amount.is_a?(String)
|
18
|
+
raise Exception, "specified day of week invalid. Use #{Date::ABBR_DAYNAMES}" unless amount
|
19
|
+
diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
|
20
|
+
Date.civil(self.year, self.month, self.day + diff)
|
21
|
+
when :week then
|
22
|
+
Date.civil(self.year, self.month, self.day + (7*amount))
|
23
|
+
when :month then
|
24
|
+
Date.civil(self.year, self.month+amount, self.day)
|
25
|
+
when :year then
|
26
|
+
Date.civil(self.year + amount, self.month, self.day)
|
27
|
+
when :sec then
|
28
|
+
Date.civil(self.year, self.month, self.day, self.hour, self.minute, self.sec + amount)
|
29
|
+
else
|
30
|
+
raise Exception, "type \"#{attr}\" not supported."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Time
|
36
|
+
|
37
|
+
# same again, no idea what this is for
|
38
|
+
def bump(attr, amount=nil)
|
39
|
+
amount ||= 1
|
40
|
+
case attr
|
41
|
+
when :sec then
|
42
|
+
Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec + amount)
|
43
|
+
when :min then
|
44
|
+
Time.local(self.year, self.month, self.day, self.hour, self.min + amount, self.sec)
|
45
|
+
when :hour then
|
46
|
+
Time.local(self.year, self.month, self.day, self.hour + amount, self.min, self.sec)
|
47
|
+
when :day then
|
48
|
+
Time.local(self.year, self.month, self.day + amount, self.hour, self.min, self.sec)
|
49
|
+
when :wday then
|
50
|
+
amount = Time::RFC2822_DAY_NAME.index(amount) if amount.is_a?(String)
|
51
|
+
raise Exception, "specified day of week invalid. Use #{Time::RFC2822_DAY_NAME}" unless amount
|
52
|
+
diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
|
53
|
+
Time.local(self.year, self.month, self.day + diff, self.hour, self.min, self.sec)
|
54
|
+
when :week then
|
55
|
+
Time.local(self.year, self.month, self.day + (amount * 7), self.hour, self.min, self.sec)
|
56
|
+
when :month then
|
57
|
+
Time.local(self.year, self.month + amount, self.day, self.hour, self.min, self.sec)
|
58
|
+
when :year then
|
59
|
+
Time.local(self.year + amount, self.month, self.day, self.hour, self.min, self.sec)
|
60
|
+
else
|
61
|
+
raise Exception, "type \"#{attr}\" not supported."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/ext/string.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Tickle
|
2
|
+
class Ordinal < ::String
|
3
|
+
# returns true if the sending string is a text or numeric ordinal (e.g. first or 1st)
|
4
|
+
def is_ordinal?
|
5
|
+
scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth eighteenth nineteenth twenty thirty thirtieth}
|
6
|
+
regex = /\b(\d*)(st|nd|rd|th)\b/
|
7
|
+
!(self =~ regex).nil? || scanner.include?(self.downcase)
|
8
|
+
end
|
9
|
+
|
10
|
+
def ordinal_as_number
|
11
|
+
return self unless self.is_ordinal?
|
12
|
+
scanner = {/first/ => '1st',
|
13
|
+
/second/ => '2nd',
|
14
|
+
/third/ => '3rd',
|
15
|
+
/fourth/ => '4th',
|
16
|
+
/fifth/ => '5th',
|
17
|
+
/sixth/ => '6th',
|
18
|
+
/seventh/ => '7th',
|
19
|
+
/eighth/ => '8th',
|
20
|
+
/ninth/ => '9th',
|
21
|
+
/tenth/ => '10th',
|
22
|
+
/eleventh/ => '11th',
|
23
|
+
/twelfth/ => '12th',
|
24
|
+
/thirteenth/ => '13th',
|
25
|
+
/fourteenth/ => '14th',
|
26
|
+
/fifteenth/ => '15th',
|
27
|
+
/sixteenth/ => '16th',
|
28
|
+
/seventeenth/ => '17th',
|
29
|
+
/eighteenth/ => '18th',
|
30
|
+
/nineteenth/ => '19th',
|
31
|
+
/twentieth/ => '20th',
|
32
|
+
/thirtieth/ => '30th',
|
33
|
+
}
|
34
|
+
result = self
|
35
|
+
scanner.keys.each {|scanner_item| result = scanner[scanner_item] if scanner_item =~ self}
|
36
|
+
return result.gsub(/\b(\d*)(st|nd|rd|th)\b/, '\1')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/tickle.rb
CHANGED
@@ -7,26 +7,40 @@
|
|
7
7
|
#=============================================================================
|
8
8
|
|
9
9
|
|
10
|
-
|
10
|
+
if ENV["DEBUG"]
|
11
|
+
warn "DEBUG MODE ON"
|
12
|
+
require 'pry-byebug'
|
13
|
+
require 'pry-state'
|
14
|
+
binding.pry
|
15
|
+
end
|
11
16
|
|
12
17
|
require 'date'
|
13
18
|
require 'time'
|
14
|
-
require 'chronic'
|
19
|
+
require 'gitlab-chronic'
|
15
20
|
|
16
21
|
require 'tickle/tickle'
|
17
22
|
require 'tickle/handler'
|
18
23
|
require 'tickle/repeater'
|
19
|
-
|
24
|
+
require_relative "tickle/tickled.rb"
|
25
|
+
require_relative "ext/array.rb"
|
26
|
+
require_relative "ext/date_and_time.rb"
|
27
|
+
require_relative "ext/string.rb"
|
28
|
+
|
20
29
|
|
21
|
-
|
22
|
-
|
30
|
+
# Tickle is a natural language parser for recurring events.
|
31
|
+
module Tickle
|
23
32
|
|
24
|
-
def self.
|
33
|
+
def self.parse(asked, options = {})
|
34
|
+
# check to see if a datetime was passed
|
35
|
+
# if so, give it back
|
36
|
+
# TODO Consider converting to a Tickled
|
37
|
+
return asked if asked.respond_to? :day
|
25
38
|
|
26
|
-
|
27
|
-
|
39
|
+
tickled = Tickled.new asked.dup, options
|
40
|
+
_parse tickled
|
28
41
|
end
|
29
42
|
|
43
|
+
|
30
44
|
def self.is_date(str)
|
31
45
|
begin
|
32
46
|
Date.parse(str.to_s)
|
@@ -35,108 +49,4 @@ module Tickle #:nodoc:
|
|
35
49
|
return false
|
36
50
|
end
|
37
51
|
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class Date #:nodoc:
|
41
|
-
# returns the days in the sending month
|
42
|
-
def days_in_month
|
43
|
-
d,m,y = mday,month,year
|
44
|
-
d += 1 while Date.valid_civil?(y,m,d)
|
45
|
-
d - 1
|
46
|
-
end
|
47
|
-
|
48
|
-
def bump(attr, amount=nil)
|
49
|
-
amount ||= 1
|
50
|
-
case attr
|
51
|
-
when :day then
|
52
|
-
Date.civil(self.year, self.month, self.day + amount)
|
53
|
-
when :wday then
|
54
|
-
amount = Date::ABBR_DAYNAMES.index(amount) if amount.is_a?(String)
|
55
|
-
raise Exception, "specified day of week invalid. Use #{Date::ABBR_DAYNAMES}" unless amount
|
56
|
-
diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
|
57
|
-
Date.civil(self.year, self.month, self.day + diff)
|
58
|
-
when :week then
|
59
|
-
Date.civil(self.year, self.month, self.day + (7*amount))
|
60
|
-
when :month then
|
61
|
-
Date.civil(self.year, self.month+amount, self.day)
|
62
|
-
when :year then
|
63
|
-
Date.civil(self.year + amount, self.month, self.day)
|
64
|
-
else
|
65
|
-
raise Exception, "type \"#{attr}\" not supported."
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
class Time #:nodoc:
|
71
|
-
def bump(attr, amount=nil)
|
72
|
-
amount ||= 1
|
73
|
-
case attr
|
74
|
-
when :sec then
|
75
|
-
Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec + amount)
|
76
|
-
when :min then
|
77
|
-
Time.local(self.year, self.month, self.day, self.hour, self.min + amount, self.sec)
|
78
|
-
when :hour then
|
79
|
-
Time.local(self.year, self.month, self.day, self.hour + amount, self.min, self.sec)
|
80
|
-
when :day then
|
81
|
-
Time.local(self.year, self.month, self.day + amount, self.hour, self.min, self.sec)
|
82
|
-
when :wday then
|
83
|
-
amount = Time::RFC2822_DAY_NAME.index(amount) if amount.is_a?(String)
|
84
|
-
raise Exception, "specified day of week invalid. Use #{Time::RFC2822_DAY_NAME}" unless amount
|
85
|
-
diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
|
86
|
-
Time.local(self.year, self.month, self.day + diff, self.hour, self.min, self.sec)
|
87
|
-
when :week then
|
88
|
-
Time.local(self.year, self.month, self.day + (amount * 7), self.hour, self.min, self.sec)
|
89
|
-
when :month then
|
90
|
-
Time.local(self.year, self.month + amount, self.day, self.hour, self.min, self.sec)
|
91
|
-
when :year then
|
92
|
-
Time.local(self.year + amount, self.month, self.day, self.hour, self.min, self.sec)
|
93
|
-
else
|
94
|
-
raise Exception, "type \"#{attr}\" not supported."
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class String #:nodoc:
|
100
|
-
# returns true if the sending string is a text or numeric ordinal (e.g. first or 1st)
|
101
|
-
def is_ordinal?
|
102
|
-
scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth eighteenth nineteenth twenty thirty thirtieth}
|
103
|
-
regex = /\b(\d*)(st|nd|rd|th)\b/
|
104
|
-
!(self =~ regex).nil? || scanner.include?(self.downcase)
|
105
|
-
end
|
106
|
-
|
107
|
-
def ordinal_as_number
|
108
|
-
return self unless self.is_ordinal?
|
109
|
-
scanner = {/first/ => '1st',
|
110
|
-
/second/ => '2nd',
|
111
|
-
/third/ => '3rd',
|
112
|
-
/fourth/ => '4th',
|
113
|
-
/fifth/ => '5th',
|
114
|
-
/sixth/ => '6th',
|
115
|
-
/seventh/ => '7th',
|
116
|
-
/eighth/ => '8th',
|
117
|
-
/ninth/ => '9th',
|
118
|
-
/tenth/ => '10th',
|
119
|
-
/eleventh/ => '11th',
|
120
|
-
/twelfth/ => '12th',
|
121
|
-
/thirteenth/ => '13th',
|
122
|
-
/fourteenth/ => '14th',
|
123
|
-
/fifteenth/ => '15th',
|
124
|
-
/sixteenth/ => '16th',
|
125
|
-
/seventeenth/ => '17th',
|
126
|
-
/eighteenth/ => '18th',
|
127
|
-
/nineteenth/ => '19th',
|
128
|
-
/twentieth/ => '20th',
|
129
|
-
/thirtieth/ => '30th',
|
130
|
-
}
|
131
|
-
result = self
|
132
|
-
scanner.keys.each {|scanner_item| result = scanner[scanner_item] if scanner_item =~ self}
|
133
|
-
return result.gsub(/\b(\d*)(st|nd|rd|th)\b/, '\1')
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
class Array #:nodoc:
|
138
|
-
# compares two arrays to determine if they both contain the same elements
|
139
|
-
def same?(y)
|
140
|
-
self.sort == y.sort
|
141
|
-
end
|
142
|
-
end
|
52
|
+
end
|