ice_cube 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ice_cube/rule.rb CHANGED
@@ -90,7 +90,7 @@ module IceCube
90
90
  end
91
91
  end
92
92
 
93
- # The key - extremely educated guesses
93
+ # The key to speed - extremely educated guesses
94
94
  # This spidering behavior will go through look for the next suggestion
95
95
  # by constantly moving the farthest back value forward
96
96
  def next_suggestion(date)
@@ -100,13 +100,13 @@ module IceCube
100
100
  compact_suggestions = suggestions.values.compact
101
101
  # find the next date to go to
102
102
  if compact_suggestions.empty?
103
- next_date = date
103
+ attempt_count = 0
104
104
  loop do
105
105
  # keep going through rule suggestions
106
- next_date = self.default_jump(next_date)
107
- return next_date if validate_single_date(next_date)
106
+ next_date = self.default_jump(date, attempt_count += 1)
107
+ return next_date if !next_date.nil? && validate_single_date(next_date)
108
108
  end
109
- else
109
+ else
110
110
  loop do
111
111
  compact_suggestions = suggestions.values.compact
112
112
  min_suggestion = compact_suggestions.min
@@ -41,12 +41,13 @@ module IceCube
41
41
  else
42
42
  date = @rule.next_suggestion(@date)
43
43
  end
44
- #walk through all of the successive dates, looking for the next occurrence (interval-valid), then return it.
44
+ # walk through all of the successive dates, looking for the next occurrence (interval-valid), then return it.
45
45
  begin
46
- return nil if yield(date)
47
46
  return nil if @end_time && date > @end_time
48
47
  return nil if @rule.until_date && date > @rule.until_date # until check
49
- return RuleOccurrence.new(@rule, @start_date, @end_time, date, @index + 1) if @rule.in_interval?(date, @start_date)
48
+ next unless @rule.in_interval?(date, @start_date)
49
+ return nil if yield(date)
50
+ return RuleOccurrence.new(@rule, @start_date, @end_time, date, @index + 1)
50
51
  end while date = @rule.next_suggestion(date)
51
52
  end
52
53
 
@@ -21,7 +21,7 @@ module IceCube
21
21
 
22
22
  protected
23
23
 
24
- def default_jump(date)
24
+ def default_jump(date, attempt_count = nil)
25
25
  goal = date + IceCube::ONE_DAY * @interval
26
26
  adjust(goal, date)
27
27
  end
@@ -19,7 +19,7 @@ module IceCube
19
19
 
20
20
  protected
21
21
 
22
- def default_jump(date)
22
+ def default_jump(date, attempt_count = nil)
23
23
  date + IceCube::ONE_HOUR * @interval
24
24
  end
25
25
 
@@ -19,7 +19,7 @@ module IceCube
19
19
 
20
20
  protected
21
21
 
22
- def default_jump(date)
22
+ def default_jump(date, attempt_count = nil)
23
23
  date + IceCube::ONE_MINUTE
24
24
  end
25
25
 
@@ -7,8 +7,8 @@ module IceCube
7
7
  # and either (1) we're on a valid day of the week (ie: first sunday of the month)
8
8
  # or we're on a valid day of the month (1, 15, -1)
9
9
  # Note: Rollover is not implemented, so the 35th day of the month is invalid.
10
- def in_interval?(date, start_date)
11
- #make sure we're in the proper interval
10
+ def in_interval?(date, start_date)
11
+ # make sure we're in the proper interval
12
12
  months_to_start_date = (date.month - start_date.month) + (date.year - start_date.year) * 12
13
13
  months_to_start_date % @interval == 0
14
14
  end
@@ -23,12 +23,8 @@ module IceCube
23
23
 
24
24
  protected
25
25
 
26
- def default_jump(date)
27
- goal = date
28
- @interval.times do
29
- goal += TimeUtil.days_in_month(goal) * ONE_DAY
30
- end
31
- adjust(goal, date)
26
+ def default_jump(date, attempt_count = 1)
27
+ TimeUtil.date_in_n_months(date, attempt_count * @interval)
32
28
  end
33
29
 
34
30
  private
@@ -19,7 +19,7 @@ module IceCube
19
19
 
20
20
  protected
21
21
 
22
- def default_jump(date)
22
+ def default_jump(date, attempt_count = nil)
23
23
  date + 1
24
24
  end
25
25
 
@@ -29,7 +29,7 @@ module IceCube
29
29
 
30
30
  protected
31
31
 
32
- def default_jump(date)
32
+ def default_jump(date, attempt_count = nil)
33
33
  goal = date + 7 * IceCube::ONE_DAY * @interval
34
34
  adjust(goal, date)
35
35
  end
@@ -24,13 +24,9 @@ module IceCube
24
24
  protected
25
25
 
26
26
  # one year from now, the same month and day of the year
27
- def default_jump(date)
28
- #jump by months since there's no reliable way to jump by year
29
- goal = date
30
- (@interval * 12).times do
31
- goal += TimeUtil.days_in_month(goal) * ONE_DAY
32
- end
33
- adjust(goal, date)
27
+ def default_jump(date, attempt_count = 1)
28
+ # jump by months since there's no reliable way to jump by year
29
+ TimeUtil.date_in_n_months(date, attempt_count * @interval * 12)
34
30
  end
35
31
 
36
32
  private
@@ -125,9 +125,9 @@ module IceCube
125
125
 
126
126
  # Retrieve the first (n) occurrences of the schedule. May return less than
127
127
  # n results, if the rules end before n results are reached.
128
- def first(n = 1)
129
- dates = find_occurrences { |head| head.first(n) }
130
- dates.slice(0, n)
128
+ def first(n = nil)
129
+ dates = find_occurrences { |head| head.first(n || 1) }
130
+ n.nil? ? dates.first : dates.slice(0, n)
131
131
  end
132
132
 
133
133
  # Add a rule of any type as an recurrence in this schedule
@@ -16,16 +16,56 @@ module TimeUtil
16
16
  end
17
17
  end
18
18
 
19
- def self.is_leap?(date)
20
- (date.year % 4 == 0 && date.year % 100 != 0) || (date.year % 400 == 0)
19
+ # TODO can we improve this more?
20
+ def self.date_in_n_months(date, month_distance)
21
+
22
+ next_mark = date
23
+ days_in_month_of_next_mark = days_in_month(next_mark)
24
+
25
+ month_distance.times do
26
+
27
+ prev_mark = next_mark
28
+ next_mark += days_in_month_of_next_mark * ONE_DAY
29
+
30
+ # only moving one day at a time, so this suffices
31
+ months_covered = next_mark.month - prev_mark.month
32
+ months_covered += 12 if months_covered < 0
33
+
34
+ # step back to the end of the previous month of months_covered went too far
35
+ if months_covered == 2
36
+ next_mark -= next_mark.mday * ONE_DAY
37
+ end
38
+
39
+ days_in_month_of_next_mark = days_in_month(next_mark)
40
+ next_mark = adjust(next_mark, prev_mark)
41
+
42
+ end
43
+
44
+ # at the end, there's a chance we're not on the correct day,
45
+ # but if we're not - we will always be behind it in the correct month
46
+ # if there exists no proper day in the month for us, return nil - otherwise, return that date
47
+
48
+ if days_in_month_of_next_mark >= date.mday
49
+ next_mark += (date.mday - next_mark.mday) * ONE_DAY
50
+ end
51
+
52
+ end
53
+
54
+ def adjust(goal, date)
55
+ return goal if goal.utc_offset == date.utc_offset
56
+ goal - goal.utc_offset + date.utc_offset
57
+ end
58
+
59
+ def self.is_leap?(year)
60
+ (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
21
61
  end
22
62
 
23
63
  def self.days_in_year(date)
24
- is_leap?(date) ? 366 : 365
64
+ is_leap?(date.year) ? 366 : 365
25
65
  end
26
66
 
27
67
  def self.days_in_month(date)
28
- is_leap?(date) ? LeapYearMonthDays[date.month - 1] : CommonYearMonthDays[date.month - 1]
68
+ is_leap?(date.year) ? LeapYearMonthDays[date.month - 1] : CommonYearMonthDays[date.month - 1]
29
69
  end
30
70
 
31
71
  def self.ical_format(time)
@@ -1,5 +1,5 @@
1
1
  module IceCube
2
2
 
3
- VERSION = '0.4.5'
3
+ VERSION = '0.5.0'
4
4
 
5
5
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ice_cube
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 11
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
- - 4
8
8
  - 5
9
- version: 0.4.5
9
+ - 0
10
+ version: 0.5.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - John Crepezzi
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-08-01 00:00:00 -04:00
18
+ date: 2010-08-04 00:00:00 -04:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: rspec
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -71,23 +74,27 @@ rdoc_options: []
71
74
  require_paths:
72
75
  - lib
73
76
  required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
74
78
  requirements:
75
79
  - - ">="
76
80
  - !ruby/object:Gem::Version
81
+ hash: 3
77
82
  segments:
78
83
  - 0
79
84
  version: "0"
80
85
  required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
81
87
  requirements:
82
88
  - - ">="
83
89
  - !ruby/object:Gem::Version
90
+ hash: 3
84
91
  segments:
85
92
  - 0
86
93
  version: "0"
87
94
  requirements: []
88
95
 
89
96
  rubyforge_project: ice-cube
90
- rubygems_version: 1.3.6
97
+ rubygems_version: 1.3.7
91
98
  signing_key:
92
99
  specification_version: 3
93
100
  summary: Ruby Date Recurrence Library