timelord 0.0.6 → 0.0.7

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: 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: []