ice_cube 0.4.5 → 0.5.0

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