timelord 0.0.6 → 0.0.7

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: 7118515e4197e09b3646071ed900c1bcbbf50fb3
4
+ data.tar.gz: 051c646d81d096f4974362d9339e7632e54d4afd
5
+ SHA512:
6
+ metadata.gz: 481b6c8914443af20a384f980c433a106a52187cc063def396e2d53127310ea9e5b38f89a4d09e769c9c8d94f2583d0a28998e322256a6935429b69800c94244
7
+ data.tar.gz: 6531a4775bb7b6c8356755d0195fb19f0863266b7140b54d354ed59f24ff584061c9f5fbfdc571ca8cd02e424ff674fde824cafc096f54bc0fa263669c46e52e
data/Rakefile CHANGED
@@ -1,13 +1,8 @@
1
- require 'bundler'
2
1
  require 'rdoc/task'
3
- require 'rubygems/package_task'
2
+ require "bundler/gem_tasks"
4
3
  require 'rspec/core/rake_task'
5
4
 
6
- specification = Gem::Specification.load("timelord.gemspec")
7
-
8
- RSpec::Core::RakeTask.new do |t|
9
- t.pattern = FileList['spec/**/*_spec.rb']
10
- end
5
+ RSpec::Core::RakeTask.new(:spec)
11
6
 
12
7
  RDoc::Task.new(:rdoc) do |rdoc|
13
8
  rdoc.rdoc_dir = 'doc'
@@ -17,10 +12,4 @@ RDoc::Task.new(:rdoc) do |rdoc|
17
12
  rdoc.rdoc_files.include('lib/**/*.rb')
18
13
  end
19
14
 
20
- Gem::PackageTask.new(specification) do |pkg|
21
- pkg.need_zip = false
22
- pkg.need_tar = false
23
- end
24
-
25
- task :default => [:test]
26
- task :test => [:spec]
15
+ task :default => [:spec]
data/lib/timelord.rb CHANGED
@@ -1,16 +1,13 @@
1
1
  require 'date'
2
+ require 'timelord/matcher'
3
+ require 'timelord/no_matcher'
4
+ require 'timelord/future'
5
+ require 'timelord/next_weekday'
6
+ require 'timelord/current_weekday'
7
+ require 'timelord/matcher_loader'
2
8
 
3
9
  class Timelord
4
- VERSION = "0.0.6"
5
-
6
- SHORT_MONTHS = %w(jan feb mar apr may jun jul aug sep oct nov dec).freeze
7
- LONG_MONTHS = %w(january febuary march april may june july august september october november december).freeze
8
- SHORT_MATCHER = SHORT_MONTHS.join('|').freeze
9
- LONG_MATCHER = LONG_MONTHS.join('|').freeze
10
- ORDINAL_MATCHER = "st|nd|rd|th".freeze
11
- DAY_NAMES = %w(monday tuesday wednesday thursday friday saturday sunday).freeze
12
- SHORT_DAY_NAMES = %w(mon tue wed thu fri sat sun).freeze
13
- DAY_MATCHER = (DAY_NAMES + SHORT_DAY_NAMES).join('|').freeze
10
+ VERSION = "0.0.7"
14
11
 
15
12
  def self.set_date(date)
16
13
  @today = date
@@ -24,6 +21,10 @@ class Timelord
24
21
  @today = Date.today
25
22
  end
26
23
 
24
+ def self.matchers
25
+ @matchers ||= MatcherLoader.new.load_all
26
+ end
27
+
27
28
  # Parses a date str. Second parameter switches between international and american date formats.
28
29
  #
29
30
  # Timelord.parse("Tuesday").to_s # "2011-01-04"
@@ -32,88 +33,9 @@ class Timelord
32
33
  #
33
34
  # For more examples, check out the spec[https://github.com/halogenandtoast/timelord/blob/master/spec/timelord_spec.rb]
34
35
  def self.parse(str, format = :international)
35
- if str =~ /\b(\d{4})\/(\d{1,2})\/(\d{1,2})\b/i
36
- Date.civil($1.to_i, $2.to_i, $3.to_i)
37
- elsif str =~ /\b(\d{4})\-(\d{1,2})\-(\d{1,2})\b/i
38
- Date.civil($1.to_i, $2.to_i, $3.to_i)
39
- elsif str =~ /\b(\d{1,2})\/(\d{1,2})\/(\d{2}(\d{2})?)\b/i
40
- if format == :american
41
- Date.civil($3.to_i, $1.to_i, $2.to_i)
42
- else
43
- Date.civil($3.to_i, $2.to_i, $1.to_i)
44
- end
45
- elsif str =~ /\b(\d{1,2})\/(\d{1,2})\b/i
46
- date = if format == :american
47
- Date.civil(today.year, $1.to_i, $2.to_i)
48
- else
49
- Date.civil(today.year, $2.to_i, $1.to_i)
50
- end
51
- set_to_future(date)
52
- elsif str =~ /\b(\d{1,2})\s+(#{SHORT_MATCHER})\b/i
53
- date = Date.civil(today.year, SHORT_MONTHS.index($2.downcase) + 1, $1.to_i)
54
- set_to_future(date)
55
- elsif str =~ /\b(#{SHORT_MATCHER})\s+(\d{1,2})\b/i
56
- date = Date.civil(today.year, SHORT_MONTHS.index($1.downcase) + 1, $2.to_i)
57
- set_to_future(date)
58
- elsif str =~ /\b(\d{1,2})\s+(#{LONG_MATCHER})\b/i
59
- date = Date.civil(today.year, LONG_MONTHS.index($2.downcase) + 1, $1.to_i)
60
- set_to_future(date)
61
- elsif str =~ /\b(#{LONG_MATCHER})\s+(\d{1,2})\b/i
62
- date = Date.civil(today.year, LONG_MONTHS.index($1.downcase) + 1, $2.to_i)
63
- set_to_future(date)
64
- elsif str =~ /\b(\d{1,2})(#{ORDINAL_MATCHER})\b/i
65
- date = Date.civil(today.year, today.month, $1.to_i)
66
- set_to_future(date)
67
- elsif str =~/\bnext (#{DAY_MATCHER})\b/i
68
- expected_index = DAY_NAMES.index($1.downcase) || SHORT_DAY_NAMES.index($1.downcase)
69
- next_weekday(expected_index)
70
- elsif str =~/\bnext tues\b/
71
- next_weekday(DAY_NAMES.index("tuesday"))
72
- elsif str =~/\bnext (thur|thurs)\b/
73
- next_weekday(DAY_NAMES.index("thursday"))
74
- elsif str =~/\b(#{DAY_MATCHER})\b/i
75
- expected_index = DAY_NAMES.index($1.downcase) || SHORT_DAY_NAMES.index($1.downcase)
76
- current_weekday(expected_index)
77
- elsif str =~/\btues\b/
78
- current_weekday(DAY_NAMES.index("tuesday"))
79
- elsif str =~/\b(thur|thurs)\b/
80
- current_weekday(DAY_NAMES.index("thursday"))
81
- elsif str =~ /\b(today|tod)\b/i
82
- today
83
- elsif str =~ /\b(tomorrow|tom)\b/i
84
- today + 1
85
- end
86
- end
87
-
88
- private
89
-
90
- def self.next_weekday(date_index)
91
- current_date = today.strftime("%A").downcase
92
- current_index = DAY_NAMES.index(current_date)
93
- if date_index <= current_index
94
- today + (7 - current_index + date_index) + 7
95
- else
96
- diff = date_index - current_index
97
- today + diff + 7
98
- end
99
- end
100
-
101
- def self.current_weekday(date_index)
102
- current_date = today.strftime("%A").downcase
103
- current_index = DAY_NAMES.index(current_date)
104
- if date_index <= current_index
105
- today + (7 - current_index + date_index)
106
- else
107
- diff = date_index - current_index
108
- today + diff
109
- end
110
- end
111
-
112
- def self.set_to_future(date)
113
- today = Date.today
114
- if date && date < today
115
- date = Date.civil(date.year + 1, date.month, date.day)
116
- end
117
- return date
36
+ matchers.
37
+ map { |matcher| matcher.new(str, format: format, today: today) }.
38
+ detect(&:matches?).
39
+ to_date
118
40
  end
119
41
  end
@@ -0,0 +1,33 @@
1
+ class CurrentWeekday
2
+ ONE_WEEK = 7
3
+ ZERO_WEEKS = 0
4
+
5
+ def initialize(date_index, today)
6
+ @date_index = date_index
7
+ @today = today
8
+ end
9
+
10
+ def to_date
11
+ today + amount_to_increase
12
+ end
13
+
14
+ private
15
+ attr_reader :today, :date_index
16
+
17
+ def current_index
18
+ today.cwday - 1
19
+ end
20
+
21
+ def amount_to_increase
22
+ diff = date_index - current_index
23
+ diff + number_of_weeks
24
+ end
25
+
26
+ def number_of_weeks
27
+ if date_index <= current_index
28
+ ONE_WEEK
29
+ else
30
+ ZERO_WEEKS
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ class Future
2
+ def initialize(date)
3
+ @current_date = date.dup
4
+ end
5
+
6
+ def to_date
7
+ if current_date < today
8
+ current_date.next_year
9
+ else
10
+ current_date
11
+ end
12
+ end
13
+
14
+ private
15
+ attr_reader :current_date
16
+
17
+ def today
18
+ Date.today
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ class Matcher
2
+
3
+ SHORT_MONTHS = %w(jan feb mar apr may jun jul aug sep oct nov dec).freeze
4
+ LONG_MONTHS = %w(january febuary march april may june july august september october november december).freeze
5
+ SHORT_MATCHER = SHORT_MONTHS.join('|').freeze
6
+ LONG_MATCHER = LONG_MONTHS.join('|').freeze
7
+ ORDINAL_MATCHER = "st|nd|rd|th".freeze
8
+ DAY_NAMES = %w(monday tuesday wednesday thursday friday saturday sunday).freeze
9
+ SHORT_DAY_NAMES = %w(mon tue wed thu fri sat sun).freeze
10
+ DAY_MATCHER = (DAY_NAMES + SHORT_DAY_NAMES).join('|').freeze
11
+
12
+ def initialize(string, options = {})
13
+ @string = string
14
+ @format = options[:format] || :international
15
+ @today = options[:today] || Date.today
16
+ end
17
+
18
+ def matches?
19
+ @match ||= self.class::REGEX.match(string)
20
+ end
21
+
22
+ private
23
+ attr_reader :string, :match, :format, :today
24
+ end
@@ -0,0 +1,27 @@
1
+ class MatcherLoader
2
+ def load_all
3
+ matchers = files.map { |file| get_class(file) }
4
+ sort_matchers(matchers) + [NoMatcher]
5
+ end
6
+
7
+ private
8
+
9
+ def files
10
+ Dir.glob(File.join(File.dirname(__FILE__), "matchers", "**"))
11
+ end
12
+
13
+ def get_class(file)
14
+ require file
15
+ Object.const_get(get_class_name(file))
16
+ end
17
+
18
+ def get_class_name(file)
19
+ File.basename(file, ".rb").
20
+ gsub(/(_[a-z])/) { |a| a[1..-1].upcase }.
21
+ gsub(/^[a-z]/) { |a| a.upcase }
22
+ end
23
+
24
+ def sort_matchers(matchers)
25
+ matchers.sort { |a, b| b::REGEX.to_s.length <=> a::REGEX.to_s.length }
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ class CurrentThursdayMatcher < Matcher
2
+ REGEX = /\b(thur|thurs)\b/
3
+
4
+ def to_date
5
+ CurrentWeekday.new(date_index, today).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def date_index
11
+ DAY_NAMES.index("thursday")
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CurrentTuesdayMatcher < Matcher
2
+ REGEX = /\btues\b/
3
+
4
+ def to_date
5
+ CurrentWeekday.new(date_index, today).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def date_index
11
+ DAY_NAMES.index("tuesday")
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CurrentWeekdayMatcher < Matcher
2
+ REGEX = /\b(#{DAY_MATCHER})\b/i
3
+
4
+ def to_date
5
+ CurrentWeekday.new(date_index, today).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def date_index
11
+ DAY_NAMES.index(match[1].downcase) || SHORT_DAY_NAMES.index(match[1].downcase)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class DayLongMonthMatcher < Matcher
2
+ REGEX = /\b(\d{1,2})\s+(#{LONG_MATCHER})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ Date.civil(today.year, LONG_MONTHS.index(match[2].downcase) + 1, match[1].to_i)
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ class DayNumericMonthMatcher < Matcher
2
+ REGEX = /\b(\d{1,2})\/(\d{1,2})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ if format == :american
12
+ Date.civil(today.year, match[1].to_i, match[2].to_i)
13
+ else
14
+ Date.civil(today.year, match[2].to_i, match[1].to_i)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ class DayShortMonthMatcher < Matcher
2
+ REGEX = /\b(\d{1,2})\s+(#{SHORT_MATCHER})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ Date.civil(today.year, SHORT_MONTHS.index(match[2].downcase) + 1, match[1].to_i)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class LongMonthDayMatcher < Matcher
2
+ REGEX = /\b(#{LONG_MATCHER})\s+(\d{1,2})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ Date.civil(today.year, LONG_MONTHS.index(match[1].downcase) + 1, match[2].to_i)
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class NextThursdayMatcher < Matcher
2
+ REGEX = /\bnext (thur|thurs)\b/
3
+
4
+ def to_date
5
+ NextWeekday.new(DAY_NAMES.index("thursday"), today).to_date
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class NextTuesdayMatcher < Matcher
2
+ REGEX = /\bnext tues\b/
3
+
4
+ def to_date
5
+ NextWeekday.new(DAY_NAMES.index("tuesday"), today).to_date
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ class NextWeekdayMatcher < Matcher
2
+ REGEX = /\bnext (#{DAY_MATCHER})\b/i
3
+
4
+ def to_date
5
+ NextWeekday.new(date_index, today).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def date_index
11
+ DAY_NAMES.index(match[1].downcase) || SHORT_DAY_NAMES.index(match[1].downcase)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class OrdinalMatcher < Matcher
2
+ REGEX = /\b(\d{1,2})(#{ORDINAL_MATCHER})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ Date.civil(today.year, today.month, match[1].to_i)
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class ShortMonthDayMatcher < Matcher
2
+ REGEX = /\b(#{SHORT_MATCHER})\s+(\d{1,2})\b/i
3
+
4
+ def to_date
5
+ Future.new(parse_date).to_date
6
+ end
7
+
8
+ private
9
+
10
+ def parse_date
11
+ Date.civil(today.year, SHORT_MONTHS.index(match[1].downcase) + 1, match[2].to_i)
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class TodayMatcher < Matcher
2
+ REGEX = /\b(today|tod)\b/i
3
+
4
+ def to_date
5
+ today
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class TomorrowMatcher < Matcher
2
+ REGEX = /\b(tomorrow|tom)\b/i
3
+
4
+ def to_date
5
+ today + 1
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class YearFirstMatcher < Matcher
2
+ REGEX = /\b(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})\b/i
3
+
4
+ def to_date
5
+ Date.civil(match[1].to_i, match[2].to_i, match[3].to_i)
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ class YearLastMatcher < Matcher
2
+ REGEX = /\b(\d{1,2})\/(\d{1,2})\/(\d{2}(\d{2})?)\b/i
3
+
4
+ def to_date
5
+ if format == :american
6
+ Date.civil(match[3].to_i, match[1].to_i, match[2].to_i)
7
+ else
8
+ Date.civil(match[3].to_i, match[2].to_i, match[1].to_i)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ class NextWeekday
2
+ ONE_WEEK = 7
3
+ TWO_WEEKS = 14
4
+
5
+ def initialize(date_index, today)
6
+ @date_index = date_index
7
+ @today = today
8
+ end
9
+
10
+ def to_date
11
+ today + amount_to_increase
12
+ end
13
+
14
+ private
15
+ attr_reader :today, :date_index
16
+
17
+ def amount_to_increase
18
+ diff = date_index - current_index
19
+ diff + number_of_weeks
20
+ end
21
+
22
+ def number_of_weeks
23
+ if date_index <= current_index
24
+ TWO_WEEKS
25
+ else
26
+ ONE_WEEK
27
+ end
28
+ end
29
+
30
+ def current_index
31
+ today.cwday - 1
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ class NoMatcher
2
+ def initialize(string, options)
3
+ end
4
+
5
+ def matches?
6
+ true
7
+ end
8
+
9
+ def to_date
10
+ nil
11
+ end
12
+ end
metadata CHANGED
@@ -1,83 +1,112 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timelord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
5
- prerelease:
4
+ version: 0.0.7
6
5
  platform: ruby
7
6
  authors:
8
7
  - Matthew Mongeau
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-02-11 00:00:00.000000000Z
11
+ date: 2014-04-13 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: timecop
16
- requirement: &70233931643220 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
- version_requirements: *70233931643220
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: rspec
27
- requirement: &70233931641880 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ! '>='
31
+ - - ">="
31
32
  - !ruby/object:Gem::Version
32
33
  version: '0'
33
34
  type: :development
34
35
  prerelease: false
35
- version_requirements: *70233931641880
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: rake
38
- requirement: &70233931640280 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ! '>='
45
+ - - ">="
42
46
  - !ruby/object:Gem::Version
43
47
  version: '0'
44
48
  type: :development
45
49
  prerelease: false
46
- version_requirements: *70233931640280
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
47
55
  description:
48
56
  email: halogenandtoast@gmail.com
49
57
  executables: []
50
58
  extensions: []
51
59
  extra_rdoc_files: []
52
60
  files:
53
- - README.rdoc
54
61
  - LICENSE
62
+ - README.rdoc
55
63
  - Rakefile
56
64
  - lib/timelord.rb
65
+ - lib/timelord/current_weekday.rb
66
+ - lib/timelord/future.rb
67
+ - lib/timelord/matcher.rb
68
+ - lib/timelord/matcher_loader.rb
69
+ - lib/timelord/matchers/current_thursday_matcher.rb
70
+ - lib/timelord/matchers/current_tuesday_matcher.rb
71
+ - lib/timelord/matchers/current_weekday_matcher.rb
72
+ - lib/timelord/matchers/day_long_month_matcher.rb
73
+ - lib/timelord/matchers/day_numeric_month_matcher.rb
74
+ - lib/timelord/matchers/day_short_month_matcher.rb
75
+ - lib/timelord/matchers/long_month_day_matcher.rb
76
+ - lib/timelord/matchers/next_thursday_matcher.rb
77
+ - lib/timelord/matchers/next_tuesday_matcher.rb
78
+ - lib/timelord/matchers/next_weekday_matcher.rb
79
+ - lib/timelord/matchers/ordinal_matcher.rb
80
+ - lib/timelord/matchers/short_month_day_matcher.rb
81
+ - lib/timelord/matchers/today_matcher.rb
82
+ - lib/timelord/matchers/tomorrow_matcher.rb
83
+ - lib/timelord/matchers/year_first_matcher.rb
84
+ - lib/timelord/matchers/year_last_matcher.rb
85
+ - lib/timelord/next_weekday.rb
86
+ - lib/timelord/no_matcher.rb
57
87
  - spec/spec_helper.rb
58
88
  - spec/timelord_spec.rb
59
89
  homepage: http://github.com/halogenandtoast/timelord
60
90
  licenses: []
91
+ metadata: {}
61
92
  post_install_message:
62
93
  rdoc_options: []
63
94
  require_paths:
64
95
  - lib
65
96
  required_ruby_version: !ruby/object:Gem::Requirement
66
- none: false
67
97
  requirements:
68
- - - ! '>='
98
+ - - ">="
69
99
  - !ruby/object:Gem::Version
70
100
  version: '0'
71
101
  required_rubygems_version: !ruby/object:Gem::Requirement
72
- none: false
73
102
  requirements:
74
- - - ! '>='
103
+ - - ">="
75
104
  - !ruby/object:Gem::Version
76
105
  version: '0'
77
106
  requirements: []
78
107
  rubyforge_project:
79
- rubygems_version: 1.8.16
108
+ rubygems_version: 2.2.2
80
109
  signing_key:
81
- specification_version: 3
110
+ specification_version: 4
82
111
  summary: Pull dates out of strings
83
112
  test_files: []