Class: Fugit::Cron

Inherits:
Object
  • Object
show all
Defined in:
lib/fugit/cron.rb

Defined Under Namespace

Modules: Parser Classes: Frequency, TimeCursor

Constant Summary collapse

SPECIALS =
{
  '@reboot' => :reboot,
  '@yearly' => '0 0 1 1 *',
  '@annually' => '0 0 1 1 *',
  '@monthly' => '0 0 1 * *',
  '@weekly' => '0 0 * * 0',
  '@daily' => '0 0 * * *',
  '@midnight' => '0 0 * * *',
  '@hourly' => '0 * * * *',
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#hoursObject (readonly)

Returns the value of attribute hours.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def hours
  @hours
end

#minutesObject (readonly)

Returns the value of attribute minutes.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def minutes
  @minutes
end

#monthdaysObject (readonly)

Returns the value of attribute monthdays.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def monthdays
  @monthdays
end

#monthsObject (readonly)

Returns the value of attribute months.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def months
  @months
end

#originalObject (readonly)

Returns the value of attribute original.



17
18
19
# File 'lib/fugit/cron.rb', line 17

def original
  @original
end

#secondsObject (readonly)

Returns the value of attribute seconds.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def seconds
  @seconds
end

#timezoneObject (readonly)

Returns the value of attribute timezone.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def timezone
  @timezone
end

#weekdaysObject (readonly)

Returns the value of attribute weekdays.



18
19
20
# File 'lib/fugit/cron.rb', line 18

def weekdays
  @weekdays
end

#zoneObject (readonly)

Returns the value of attribute zone.



17
18
19
# File 'lib/fugit/cron.rb', line 17

def zone
  @zone
end

Class Method Details

.do_parse(s) ⇒ Object



43
44
45
46
47
# File 'lib/fugit/cron.rb', line 43

def do_parse(s)

  parse(s) ||
  fail(ArgumentError.new("not a cron string #{s.inspect}"))
end

.new(original) ⇒ Object



22
23
24
25
# File 'lib/fugit/cron.rb', line 22

def new(original)

  parse(original)
end

.parse(s) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/fugit/cron.rb', line 27

def parse(s)

  return s if s.is_a?(self)

  s = SPECIALS[s] || s

  return nil unless s.is_a?(String)

#p s; Raabro.pp(Parser.parse(s, debug: 3), colors: true)
  h = Parser.parse(s)

  return nil unless h

  self.allocate.send(:init, s, h)
end

Instance Method Details

#==(o) ⇒ Object Also known as: eql?



271
272
273
274
# File 'lib/fugit/cron.rb', line 271

def ==(o)

  o.is_a?(::Fugit::Cron) && o.to_a == to_a
end

#brute_frequency(year = 2017) ⇒ Object

Mostly used as a #next_time sanity check. Avoid for “business” use, it’s slow.

2017 is a non leap year (though it is preceded by a leap second on 2016-12-31)

Nota bene: cron with seconds are not supported.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/fugit/cron.rb', line 215

def brute_frequency(year=2017)

  FREQUENCY_CACHE["#{to_cron_s}|#{year}"] ||=
    begin

      deltas = []

      t = EtOrbi.make_time("#{year}-01-01") - 1
      t0 = nil
      t1 = nil
      loop do
        t1 = next_time(t)
        deltas << (t1 - t).to_i if t0
        t0 ||= t1
        break if deltas.any? && t1.year > year
        break if t1.year - t0.year > 7
        t = t1
      end

      Frequency.new(deltas, t1 - t0)
    end
end

#day_match?(nt) ⇒ Boolean



150
151
152
153
154
155
156
157
158
159
# File 'lib/fugit/cron.rb', line 150

def day_match?(nt)

  return weekday_match?(nt) || monthday_match?(nt) \
    if @weekdays && @monthdays

  return false unless weekday_match?(nt)
  return false unless monthday_match?(nt)

  true
end

#hashObject



277
278
279
280
# File 'lib/fugit/cron.rb', line 277

def hash

  to_a.hash
end

#hour_match?(nt) ⇒ Boolean



117
# File 'lib/fugit/cron.rb', line 117

def hour_match?(nt); ( ! @hours) || @hours.include?(nt.hour); end

#match?(t) ⇒ Boolean



161
162
163
164
165
166
167
# File 'lib/fugit/cron.rb', line 161

def match?(t)

  t = Fugit.do_parse_at(t)

  month_match?(t) && day_match?(t) &&
  hour_match?(t) && min_match?(t) && sec_match?(t)
end

#min_match?(nt) ⇒ Boolean



118
# File 'lib/fugit/cron.rb', line 118

def min_match?(nt); ( ! @minutes) || @minutes.include?(nt.min); end

#month_match?(nt) ⇒ Boolean



116
# File 'lib/fugit/cron.rb', line 116

def month_match?(nt); ( ! @months) || @months.include?(nt.month); end

#monthday_match?(nt) ⇒ Boolean



139
140
141
142
143
144
145
146
147
148
# File 'lib/fugit/cron.rb', line 139

def monthday_match?(nt)

  return true if @monthdays.nil?

  last = (TimeCursor.new(nt).inc_month.time - 24 * 3600).day + 1

  @monthdays
    .collect { |d| d < 1 ? last + d : d }
    .include?(nt.day)
end

#next_time(from = ::EtOrbi::EoTime.now) ⇒ Object



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

def next_time(from=::EtOrbi::EoTime.now)

  from = ::EtOrbi.make_time(from)
  t = TimeCursor.new(from.translate(@timezone))

  loop do
#p [ :l, Fugit.time_to_s(t.time) ]
    (from.to_i == t.to_i) && (t.inc(1); next)
    month_match?(t) || (t.inc_month; next)
    day_match?(t) || (t.inc_day; next)
    hour_match?(t) || (t.inc_hour; next)
    min_match?(t) || (t.inc_min; next)
    sec_match?(t) || (t.inc_sec(@seconds); next)
    break
  end

  t.time.translate(from.zone)
end

#previous_time(from = ::EtOrbi::EoTime.now) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/fugit/cron.rb', line 188

def previous_time(from=::EtOrbi::EoTime.now)

  from = ::EtOrbi.make_time(from)
  t = TimeCursor.new(from.translate(@timezone))

  loop do
#p [ :l, Fugit.time_to_s(t.time) ]
    (from.to_i == t.to_i) && (t.inc(-1); next)
    month_match?(t) || (t.dec_month; next)
    day_match?(t) || (t.dec_day; next)
    hour_match?(t) || (t.dec_hour; next)
    min_match?(t) || (t.dec_min; next)
    sec_match?(t) || (t.dec_sec(@seconds); next)
    break
  end

  t.time.translate(from.zone)
end

#sec_match?(nt) ⇒ Boolean



119
# File 'lib/fugit/cron.rb', line 119

def sec_match?(nt); ( ! @seconds) || @seconds.include?(nt.sec); end

#to_aObject



266
267
268
269
# File 'lib/fugit/cron.rb', line 266

def to_a

  [ @seconds, @minutes, @hours, @monthdays, @months, @weekdays ]
end

#to_cron_sObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/fugit/cron.rb', line 50

def to_cron_s

  @cron_s ||= begin
    [
      @seconds == [ 0 ] ? nil : (@seconds || [ '*' ]).join(','),
      (@minutes || [ '*' ]).join(','),
      (@hours || [ '*' ]).join(','),
      (@monthdays || [ '*' ]).join(','),
      (@months || [ '*' ]).join(','),
      (@weekdays || [ [ '*' ] ]).map { |d| d.compact.join('#') }.join(','),
      @timezone ? @timezone.to_s : nil
    ].compact.join(' ')
  end
end

#weekday_match?(nt) ⇒ Boolean



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/fugit/cron.rb', line 121

def weekday_match?(nt)

  return true if @weekdays.nil?

  wd, hsh = @weekdays.find { |d, _| d == nt.wday }

  return false unless wd
  return true if hsh.nil?

  phsh, nhsh = nt.wday_in_month

  if hsh > 0
    hsh == phsh # positive wday, from the beginning of the month
  else
    hsh == nhsh # negative wday, from the end of the month, -1 == last
  end
end