Class: Whedon::Schedule

Inherits:
Object
  • Object
show all
Defined in:
lib/whedon/schedule.rb

Overview

A ‘cron line’ is a line in the sense of a crontab (man 5 crontab) file line.

Constant Summary collapse

DAY_S =
24 * 3600
WEEK_S =
7 * DAY_S

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(line) ⇒ Schedule

Returns a new instance of Schedule.

Raises:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/whedon/schedule.rb', line 56

def initialize(line)

  super()

  @original = line

  items = line.split

  @timezone = (TZInfo::Timezone.get(items.last) rescue nil)
  items.pop if @timezone

  raise ParseError.new(
    "not a valid cronline : '#{line}'"
  ) unless items.length == 5 or items.length == 6

  offset = items.length - 5

  @seconds = offset == 1 ? parse_item(items[0], 0, 59) : [ 0 ]
  @minutes = parse_item(items[0 + offset], 0, 59)
  @hours = parse_item(items[1 + offset], 0, 24)
  @days = parse_item(items[2 + offset], 1, 31)
  @months = parse_item(items[3 + offset], 1, 12)
  @weekdays, @monthdays = parse_weekdays(items[4 + offset])

  [ @seconds, @minutes, @hours, @months ].each do |es|

    raise ParseError.new(
      "invalid cronline: '#{line}'"
    ) if es && es.find { |e| ! e.is_a?(Fixnum) }
  end
end

Instance Attribute Details

#daysObject (readonly)

Returns the value of attribute days.



48
49
50
# File 'lib/whedon/schedule.rb', line 48

def days
  @days
end

#hoursObject (readonly)

Returns the value of attribute hours.



47
48
49
# File 'lib/whedon/schedule.rb', line 47

def hours
  @hours
end

#minutesObject (readonly)

Returns the value of attribute minutes.



46
47
48
# File 'lib/whedon/schedule.rb', line 46

def minutes
  @minutes
end

#monthsObject (readonly)

Returns the value of attribute months.



49
50
51
# File 'lib/whedon/schedule.rb', line 49

def months
  @months
end

#originalObject (readonly)

The string used for creating this cronline instance.



43
44
45
# File 'lib/whedon/schedule.rb', line 43

def original
  @original
end

#raise_error_on_duplicateObject

Returns the value of attribute raise_error_on_duplicate.



54
55
56
# File 'lib/whedon/schedule.rb', line 54

def raise_error_on_duplicate
  @raise_error_on_duplicate
end

#secondsObject (readonly)

Returns the value of attribute seconds.



45
46
47
# File 'lib/whedon/schedule.rb', line 45

def seconds
  @seconds
end

#timezoneObject (readonly)

Returns the value of attribute timezone.



52
53
54
# File 'lib/whedon/schedule.rb', line 52

def timezone
  @timezone
end

#weekdaysObject (readonly)

Returns the value of attribute weekdays.



50
51
52
# File 'lib/whedon/schedule.rb', line 50

def weekdays
  @weekdays
end

Instance Method Details

#matches?(time) ⇒ Boolean

Returns true if the given time matches this cron line.

Returns:

  • (Boolean)


90
91
92
93
94
95
96
97
98
99
# File 'lib/whedon/schedule.rb', line 90

def matches?(time)

  time = as_time(time)

  return false unless sub_match?(time, :sec, @seconds)
  return false unless sub_match?(time, :min, @minutes)
  return false unless sub_match?(time, :hour, @hours)
  return false unless date_match?(time)
  true
end

#next_time(now = Time.now) ⇒ Object Also known as: next

Returns the next time that this cron line is supposed to ‘fire’

This is raw, 3 secs to iterate over 1 year on my macbook :( brutal. (Well, I was wrong, takes 0.001 sec on 1.8.7 and 1.9.1)

This method accepts an optional Time parameter. It’s the starting point for the ‘search’. By default, it’s Time.now

Note that the time instance returned will be in the same time zone that the given start point Time (thus a result in the local time zone will be passed if no start time is specified (search start time set to Time.now))

Whedon::CronLine.new('30 7 * * *').next_time(
  Time.mktime(2008, 10, 24, 7, 29))
#=> Fri Oct 24 07:30:00 -0500 2008

Whedon::CronLine.new('30 7 * * *').next_time(
  Time.utc(2008, 10, 24, 7, 29))
#=> Fri Oct 24 07:30:00 UTC 2008

Whedon::CronLine.new('30 7 * * *').next_time(
  Time.utc(2008, 10, 24, 7, 29)).localtime
#=> Fri Oct 24 02:30:00 -0500 2008

(Thanks to K Liu for the note and the examples)



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/whedon/schedule.rb', line 132

def next_time(now=Time.now)

  time = as_time(now)
  time = time - time.usec * 1e-6 + 1
    # small adjustment before starting

  loop do

    unless date_match?(time)
      time += (24 - time.hour) * 3600 - time.min * 60 - time.sec; next
    end
    unless sub_match?(time, :hour, @hours)
      time += (60 - time.min) * 60 - time.sec; next
    end
    unless sub_match?(time, :min, @minutes)
      time += 60 - time.sec; next
    end
    unless sub_match?(time, :sec, @seconds)
      time += 1; next
    end

    break
  end

  if @timezone
    time = @timezone.local_to_utc(time)
    time = time.getlocal unless now.utc?
  end

  time
end

#now?(time = Time.now) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/whedon/schedule.rb', line 101

def now?(time=Time.now)
  matches?(time)
end

#previous_time(now = Time.now) ⇒ Object Also known as: previous, last

Returns the previous the cronline matched. It’s like next_time, but for the past.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/whedon/schedule.rb', line 168

def previous_time(now=Time.now)

  # looks back by slices of two hours,
  #
  # finds for '* * * * sun', '* * 13 * *' and '0 12 13 * *'
  # starting 1970, 1, 1 in 1.8 to 2 seconds (says Rspec)

  start = current = now - 2 * 3600
  result = nil

  loop do
    nex = next_time(current)
    return (result ? result : previous_time(start)) if nex > now
    result = current = nex
  end

  # never reached
end

#to_arrayObject Also known as: to_a

Returns an array of 6 arrays (seconds, minutes, hours, days, months, weekdays). This method is used by the cronline unit tests.



193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/whedon/schedule.rb', line 193

def to_array

  [
    @seconds,
    @minutes,
    @hours,
    @days,
    @months,
    @weekdays,
    @monthdays,
    @timezone ? @timezone.name : nil
  ]
end