whenever 0.9.2 → 0.10.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +17 -7
- data/CHANGELOG.md +63 -0
- data/Gemfile +0 -5
- data/LICENSE +1 -1
- data/README.md +101 -18
- data/Rakefile +3 -10
- data/bin/whenever +3 -0
- data/bin/wheneverize +8 -5
- data/gemfiles/activesupport4.1.gemfile +5 -0
- data/gemfiles/activesupport4.2.gemfile +5 -0
- data/lib/whenever/capistrano/v2/recipes.rb +4 -3
- data/lib/whenever/capistrano/v3/tasks/whenever.rake +20 -7
- data/lib/whenever/capistrano.rb +1 -1
- data/lib/whenever/command_line.rb +49 -28
- data/lib/whenever/cron.rb +43 -21
- data/lib/whenever/job.rb +4 -3
- data/lib/whenever/job_list.rb +54 -24
- data/lib/whenever/numeric.rb +13 -0
- data/lib/whenever/numeric_seconds.rb +48 -0
- data/lib/whenever/os.rb +7 -0
- data/lib/whenever/setup.rb +5 -1
- data/lib/whenever/version.rb +1 -1
- data/lib/whenever.rb +15 -14
- data/test/functional/command_line_test.rb +379 -255
- data/test/functional/output_at_test.rb +227 -249
- data/test/functional/output_default_defined_jobs_test.rb +239 -288
- data/test/functional/output_defined_job_test.rb +65 -91
- data/test/functional/output_env_test.rb +22 -26
- data/test/functional/output_jobs_for_roles_test.rb +46 -66
- data/test/functional/output_jobs_with_mailto_test.rb +168 -0
- data/test/functional/output_redirection_test.rb +231 -309
- data/test/test_case.rb +32 -0
- data/test/test_helper.rb +44 -15
- data/test/unit/capistrano_support_test.rb +126 -148
- data/test/unit/cron_test.rb +327 -210
- data/test/unit/executable_test.rb +142 -0
- data/test/unit/job_test.rb +111 -121
- data/whenever.gemspec +5 -4
- metadata +37 -28
- data/lib/whenever/tasks/whenever.rake +0 -43
data/lib/whenever/cron.rb
CHANGED
|
@@ -3,16 +3,20 @@ require 'chronic'
|
|
|
3
3
|
module Whenever
|
|
4
4
|
module Output
|
|
5
5
|
class Cron
|
|
6
|
+
DAYS = %w(sun mon tue wed thu fri sat)
|
|
7
|
+
MONTHS = %w(jan feb mar apr may jun jul aug sep oct nov dec)
|
|
6
8
|
KEYWORDS = [:reboot, :yearly, :annually, :monthly, :weekly, :daily, :midnight, :hourly]
|
|
7
|
-
REGEX = /^(@(#{KEYWORDS.join '|'})
|
|
9
|
+
REGEX = /^(@(#{KEYWORDS.join '|'})|((\*?[\d\/,\-]*)\s){3}(\*?([\d\/,\-]|(#{MONTHS.join '|'}))*\s)(\*?([\d\/,\-]|(#{DAYS.join '|'}))*))$/i
|
|
8
10
|
|
|
9
11
|
attr_accessor :time, :task
|
|
10
12
|
|
|
11
|
-
def initialize(time = nil, task = nil, at = nil)
|
|
13
|
+
def initialize(time = nil, task = nil, at = nil, options = {})
|
|
14
|
+
chronic_options = options[:chronic_options] || {}
|
|
15
|
+
|
|
12
16
|
@at_given = at
|
|
13
17
|
@time = time
|
|
14
18
|
@task = task
|
|
15
|
-
@at = at.is_a?(String) ? (Chronic.parse(at) || 0) : (at || 0)
|
|
19
|
+
@at = at.is_a?(String) ? (Chronic.parse(at, chronic_options) || 0) : (at || 0)
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
def self.enumerate(item, detect_cron = true)
|
|
@@ -30,10 +34,10 @@ module Whenever
|
|
|
30
34
|
items
|
|
31
35
|
end
|
|
32
36
|
|
|
33
|
-
def self.output(times, job)
|
|
37
|
+
def self.output(times, job, options = {})
|
|
34
38
|
enumerate(times).each do |time|
|
|
35
39
|
enumerate(job.at, false).each do |at|
|
|
36
|
-
yield new(time, job.output, at).output
|
|
40
|
+
yield new(time, job.output, at, options).output
|
|
37
41
|
end
|
|
38
42
|
end
|
|
39
43
|
end
|
|
@@ -43,8 +47,9 @@ module Whenever
|
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def time_in_cron_syntax
|
|
50
|
+
@time = @time.to_i if @time.is_a?(Numeric) # Compatibility with `1.day` format using ruby 2.3 and activesupport
|
|
46
51
|
case @time
|
|
47
|
-
when REGEX then @time # raw cron
|
|
52
|
+
when REGEX then @time # raw cron syntax given
|
|
48
53
|
when Symbol then parse_symbol
|
|
49
54
|
when String then parse_as_string
|
|
50
55
|
else parse_time
|
|
@@ -53,18 +58,18 @@ module Whenever
|
|
|
53
58
|
|
|
54
59
|
protected
|
|
55
60
|
def day_given?
|
|
56
|
-
|
|
57
|
-
@at_given.is_a?(String) && months.any? { |m| @at_given.downcase.index(m) }
|
|
61
|
+
@at_given.is_a?(String) && (MONTHS.any? { |m| @at_given.downcase.index(m) } || @at_given[/\d\/\d/])
|
|
58
62
|
end
|
|
59
63
|
|
|
60
64
|
def parse_symbol
|
|
61
65
|
shortcut = case @time
|
|
62
66
|
when *KEYWORDS then "@#{@time}" # :reboot => '@reboot'
|
|
63
|
-
when :year then
|
|
64
|
-
when :day then 1
|
|
65
|
-
when :month then 1
|
|
66
|
-
when :week then 1
|
|
67
|
-
when :hour then 1
|
|
67
|
+
when :year then Whenever.seconds(1, :year)
|
|
68
|
+
when :day then Whenever.seconds(1, :day)
|
|
69
|
+
when :month then Whenever.seconds(1, :month)
|
|
70
|
+
when :week then Whenever.seconds(1, :week)
|
|
71
|
+
when :hour then Whenever.seconds(1, :hour)
|
|
72
|
+
when :minute then Whenever.seconds(1, :minute)
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
if shortcut.is_a?(Numeric)
|
|
@@ -84,22 +89,24 @@ module Whenever
|
|
|
84
89
|
def parse_time
|
|
85
90
|
timing = Array.new(5, '*')
|
|
86
91
|
case @time
|
|
87
|
-
when 0.seconds
|
|
92
|
+
when Whenever.seconds(0, :seconds)...Whenever.seconds(1, :minute)
|
|
88
93
|
raise ArgumentError, "Time must be in minutes or higher"
|
|
89
|
-
when 1
|
|
94
|
+
when Whenever.seconds(1, :minute)...Whenever.seconds(1, :hour)
|
|
90
95
|
minute_frequency = @time / 60
|
|
91
96
|
timing[0] = comma_separated_timing(minute_frequency, 59, @at || 0)
|
|
92
|
-
when 1
|
|
97
|
+
when Whenever.seconds(1, :hour)...Whenever.seconds(1, :day)
|
|
93
98
|
hour_frequency = (@time / 60 / 60).round
|
|
94
99
|
timing[0] = @at.is_a?(Time) ? @at.min : @at
|
|
95
100
|
timing[1] = comma_separated_timing(hour_frequency, 23)
|
|
96
|
-
|
|
101
|
+
raise ArgumentError, "Minute must be between 0-59, #{timing[0]} given" unless (0..59).include?(timing[0])
|
|
102
|
+
when Whenever.seconds(1, :day)...Whenever.seconds(1, :month)
|
|
97
103
|
day_frequency = (@time / 24 / 60 / 60).round
|
|
98
104
|
timing[0] = @at.is_a?(Time) ? @at.min : 0
|
|
99
105
|
timing[1] = @at.is_a?(Time) ? @at.hour : @at
|
|
100
106
|
timing[2] = comma_separated_timing(day_frequency, 31, 1)
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
raise ArgumentError, "Hour must be between 0-23, #{timing[1]} given" unless (0..23).include?(timing[1])
|
|
108
|
+
when Whenever.seconds(1, :month)...Whenever.seconds(1, :year)
|
|
109
|
+
month_frequency = (@time / 30 / 24 / 60 / 60).round
|
|
103
110
|
timing[0] = @at.is_a?(Time) ? @at.min : 0
|
|
104
111
|
timing[1] = @at.is_a?(Time) ? @at.hour : 0
|
|
105
112
|
timing[2] = if @at.is_a?(Time)
|
|
@@ -108,6 +115,21 @@ module Whenever
|
|
|
108
115
|
@at.zero? ? 1 : @at
|
|
109
116
|
end
|
|
110
117
|
timing[3] = comma_separated_timing(month_frequency, 12, 1)
|
|
118
|
+
raise ArgumentError, "Day must be between 1-31, #{timing[2]} given" unless (1..31).include?(timing[2])
|
|
119
|
+
when Whenever.seconds(1, :year)
|
|
120
|
+
timing[0] = @at.is_a?(Time) ? @at.min : 0
|
|
121
|
+
timing[1] = @at.is_a?(Time) ? @at.hour : 0
|
|
122
|
+
timing[2] = if @at.is_a?(Time)
|
|
123
|
+
day_given? ? @at.day : 1
|
|
124
|
+
else
|
|
125
|
+
1
|
|
126
|
+
end
|
|
127
|
+
timing[3] = if @at.is_a?(Time)
|
|
128
|
+
day_given? ? @at.month : 1
|
|
129
|
+
else
|
|
130
|
+
@at.zero? ? 1 : @at
|
|
131
|
+
end
|
|
132
|
+
raise ArgumentError, "Month must be between 1-12, #{timing[3]} given" unless (1..12).include?(timing[3])
|
|
111
133
|
else
|
|
112
134
|
return parse_as_string
|
|
113
135
|
end
|
|
@@ -125,7 +147,7 @@ module Whenever
|
|
|
125
147
|
return (timing << '1-5') * " " if string.downcase.index('weekday')
|
|
126
148
|
return (timing << '6,0') * " " if string.downcase.index('weekend')
|
|
127
149
|
|
|
128
|
-
|
|
150
|
+
DAYS.each_with_index do |day, i|
|
|
129
151
|
return (timing << i) * " " if string.downcase.index(day)
|
|
130
152
|
end
|
|
131
153
|
|
|
@@ -133,7 +155,7 @@ module Whenever
|
|
|
133
155
|
end
|
|
134
156
|
|
|
135
157
|
def comma_separated_timing(frequency, max, start = 0)
|
|
136
|
-
return start if frequency.
|
|
158
|
+
return start if frequency.nil? || frequency == "" || frequency.zero?
|
|
137
159
|
return '*' if frequency == 1
|
|
138
160
|
return frequency if frequency > (max * 0.5).ceil
|
|
139
161
|
|
data/lib/whenever/job.rb
CHANGED
|
@@ -2,14 +2,15 @@ require 'shellwords'
|
|
|
2
2
|
|
|
3
3
|
module Whenever
|
|
4
4
|
class Job
|
|
5
|
-
attr_reader :at, :roles
|
|
5
|
+
attr_reader :at, :roles, :mailto
|
|
6
6
|
|
|
7
7
|
def initialize(options = {})
|
|
8
8
|
@options = options
|
|
9
9
|
@at = options.delete(:at)
|
|
10
10
|
@template = options.delete(:template)
|
|
11
|
+
@mailto = options.fetch(:mailto, :default_mailto)
|
|
11
12
|
@job_template = options.delete(:job_template) || ":job"
|
|
12
|
-
@roles = Array
|
|
13
|
+
@roles = Array(options.delete(:roles))
|
|
13
14
|
@options[:output] = options.has_key?(:output) ? Whenever::Output::Redirection.new(options[:output]).to_s : ''
|
|
14
15
|
@options[:environment_variable] ||= "RAILS_ENV"
|
|
15
16
|
@options[:environment] ||= :production
|
|
@@ -40,7 +41,7 @@ module Whenever
|
|
|
40
41
|
else
|
|
41
42
|
option
|
|
42
43
|
end
|
|
43
|
-
end.
|
|
44
|
+
end.gsub(/\s+/m, " ").strip
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def escape_single_quotes(str)
|
data/lib/whenever/job_list.rb
CHANGED
|
@@ -30,10 +30,17 @@ module Whenever
|
|
|
30
30
|
return if @pre_set_variables[variable]
|
|
31
31
|
|
|
32
32
|
instance_variable_set("@#{variable}".to_sym, value)
|
|
33
|
-
self.class.send(:attr_reader, variable.to_sym)
|
|
34
33
|
@set_variables[variable] = value
|
|
35
34
|
end
|
|
36
35
|
|
|
36
|
+
def method_missing(name, *args, &block)
|
|
37
|
+
@set_variables.has_key?(name) ? @set_variables[name] : super
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.respond_to?(name, include_private = false)
|
|
41
|
+
@set_variables.has_key?(name) || super
|
|
42
|
+
end
|
|
43
|
+
|
|
37
44
|
def env(variable, value)
|
|
38
45
|
@env[variable.to_s] = value
|
|
39
46
|
end
|
|
@@ -45,18 +52,21 @@ module Whenever
|
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
def job_type(name, template)
|
|
48
|
-
class_eval do
|
|
55
|
+
singleton_class.class_eval do
|
|
49
56
|
define_method(name) do |task, *args|
|
|
50
57
|
options = { :task => task, :template => template }
|
|
51
58
|
options.merge!(args[0]) if args[0].is_a? Hash
|
|
52
59
|
|
|
60
|
+
options[:mailto] ||= @options.fetch(:mailto, :default_mailto)
|
|
61
|
+
|
|
53
62
|
# :cron_log was an old option for output redirection, it remains for backwards compatibility
|
|
54
63
|
options[:output] = (options[:cron_log] || @cron_log) if defined?(@cron_log) || options.has_key?(:cron_log)
|
|
55
64
|
# :output is the newer, more flexible option.
|
|
56
65
|
options[:output] = @output if defined?(@output) && !options.has_key?(:output)
|
|
57
66
|
|
|
58
|
-
@jobs[
|
|
59
|
-
@jobs[@current_time_scope]
|
|
67
|
+
@jobs[options.fetch(:mailto)] ||= {}
|
|
68
|
+
@jobs[options.fetch(:mailto)][@current_time_scope] ||= []
|
|
69
|
+
@jobs[options.fetch(:mailto)][@current_time_scope] << Whenever::Job.new(@options.merge(@set_variables).merge(options))
|
|
60
70
|
end
|
|
61
71
|
end
|
|
62
72
|
end
|
|
@@ -73,13 +83,13 @@ module Whenever
|
|
|
73
83
|
# Only works for setting values as strings.
|
|
74
84
|
#
|
|
75
85
|
def pre_set(variable_string = nil)
|
|
76
|
-
return if variable_string.
|
|
86
|
+
return if variable_string.nil? || variable_string == ""
|
|
77
87
|
|
|
78
88
|
pairs = variable_string.split('&')
|
|
79
89
|
pairs.each do |pair|
|
|
80
90
|
next unless pair.index('=')
|
|
81
91
|
variable, value = *pair.split('=')
|
|
82
|
-
unless variable.
|
|
92
|
+
unless variable.nil? || variable == "" || value.nil? || value == ""
|
|
83
93
|
variable = variable.strip.to_sym
|
|
84
94
|
set(variable, value.strip)
|
|
85
95
|
@pre_set_variables[variable] = value
|
|
@@ -92,7 +102,7 @@ module Whenever
|
|
|
92
102
|
|
|
93
103
|
output = []
|
|
94
104
|
@env.each do |key, val|
|
|
95
|
-
output << "#{key}=#{val.
|
|
105
|
+
output << "#{key}=#{val.nil? || val == "" ? '""' : val}\n"
|
|
96
106
|
end
|
|
97
107
|
output << "\n"
|
|
98
108
|
|
|
@@ -125,31 +135,51 @@ module Whenever
|
|
|
125
135
|
entries.map { |entry| entry.join(' ') }
|
|
126
136
|
end
|
|
127
137
|
|
|
138
|
+
def cron_jobs_of_time(time, jobs)
|
|
139
|
+
shortcut_jobs, regular_jobs = [], []
|
|
140
|
+
|
|
141
|
+
jobs.each do |job|
|
|
142
|
+
next unless roles.empty? || roles.any? do |r|
|
|
143
|
+
job.has_role?(r)
|
|
144
|
+
end
|
|
145
|
+
Whenever::Output::Cron.output(time, job, :chronic_options => @chronic_options) do |cron|
|
|
146
|
+
cron << "\n\n"
|
|
147
|
+
|
|
148
|
+
if cron[0,1] == "@"
|
|
149
|
+
shortcut_jobs << cron
|
|
150
|
+
else
|
|
151
|
+
regular_jobs << cron
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
shortcut_jobs.join + combine(regular_jobs).join
|
|
157
|
+
end
|
|
158
|
+
|
|
128
159
|
def cron_jobs
|
|
129
160
|
return if @jobs.empty?
|
|
130
161
|
|
|
131
|
-
|
|
132
|
-
regular_jobs = []
|
|
162
|
+
output = []
|
|
133
163
|
|
|
134
|
-
|
|
135
|
-
@jobs.each do |time, jobs|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
job.has_role?(r)
|
|
139
|
-
end
|
|
140
|
-
Whenever::Output::Cron.output(time, job) do |cron|
|
|
141
|
-
cron << "\n\n"
|
|
164
|
+
# jobs with default mailto's must be output before the ones with non-default mailto's.
|
|
165
|
+
@jobs.delete(:default_mailto) { Hash.new }.each do |time, jobs|
|
|
166
|
+
output << cron_jobs_of_time(time, jobs)
|
|
167
|
+
end
|
|
142
168
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
end
|
|
169
|
+
@jobs.each do |mailto, time_and_jobs|
|
|
170
|
+
output_jobs = []
|
|
171
|
+
|
|
172
|
+
time_and_jobs.each do |time, jobs|
|
|
173
|
+
output_jobs << cron_jobs_of_time(time, jobs)
|
|
149
174
|
end
|
|
175
|
+
|
|
176
|
+
output_jobs.reject! { |output_job| output_job.empty? }
|
|
177
|
+
|
|
178
|
+
output << "MAILTO=#{mailto}\n\n" unless output_jobs.empty?
|
|
179
|
+
output << output_jobs
|
|
150
180
|
end
|
|
151
181
|
|
|
152
|
-
|
|
182
|
+
output.join
|
|
153
183
|
end
|
|
154
184
|
end
|
|
155
185
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class Numeric
|
|
2
|
+
def respond_to?(method, include_private = false)
|
|
3
|
+
super || Whenever::NumericSeconds.public_method_defined?(method)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def method_missing(method, *args, &block)
|
|
7
|
+
if Whenever::NumericSeconds.public_method_defined?(method)
|
|
8
|
+
Whenever::NumericSeconds.new(self).send(method)
|
|
9
|
+
else
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Whenever
|
|
2
|
+
class NumericSeconds
|
|
3
|
+
attr_reader :number
|
|
4
|
+
|
|
5
|
+
def self.seconds(number, units)
|
|
6
|
+
new(number).send(units)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(number)
|
|
10
|
+
@number = number.to_i
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def seconds
|
|
14
|
+
number
|
|
15
|
+
end
|
|
16
|
+
alias :second :seconds
|
|
17
|
+
|
|
18
|
+
def minutes
|
|
19
|
+
number * 60
|
|
20
|
+
end
|
|
21
|
+
alias :minute :minutes
|
|
22
|
+
|
|
23
|
+
def hours
|
|
24
|
+
number * 3_600
|
|
25
|
+
end
|
|
26
|
+
alias :hour :hours
|
|
27
|
+
|
|
28
|
+
def days
|
|
29
|
+
number * 86_400
|
|
30
|
+
end
|
|
31
|
+
alias :day :days
|
|
32
|
+
|
|
33
|
+
def weeks
|
|
34
|
+
number * 604_800
|
|
35
|
+
end
|
|
36
|
+
alias :week :weeks
|
|
37
|
+
|
|
38
|
+
def months
|
|
39
|
+
number * 2_592_000
|
|
40
|
+
end
|
|
41
|
+
alias :month :months
|
|
42
|
+
|
|
43
|
+
def years
|
|
44
|
+
number * 31_557_600
|
|
45
|
+
end
|
|
46
|
+
alias :year :years
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/whenever/os.rb
ADDED
data/lib/whenever/setup.rb
CHANGED
|
@@ -5,6 +5,10 @@ set :environment, "production"
|
|
|
5
5
|
# Path defaults to the directory `whenever` was run from
|
|
6
6
|
set :path, Whenever.path
|
|
7
7
|
|
|
8
|
+
# Custom Chronic configuration for time parsing, empty by default
|
|
9
|
+
# Full list of options at: https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
|
|
10
|
+
set :chronic_options, {}
|
|
11
|
+
|
|
8
12
|
# All jobs are wrapped in this template.
|
|
9
13
|
# http://blog.scoutapp.com/articles/2010/09/07/rvm-and-cron-in-production
|
|
10
14
|
set :job_template, "/bin/bash -l -c ':job'"
|
|
@@ -23,4 +27,4 @@ set :bundle_command, Whenever.bundler? ? "bundle exec" : ""
|
|
|
23
27
|
job_type :command, ":task :output"
|
|
24
28
|
job_type :rake, "cd :path && :environment_variable=:environment :bundle_command rake :task --silent :output"
|
|
25
29
|
job_type :script, "cd :path && :environment_variable=:environment :bundle_command script/:task :output"
|
|
26
|
-
job_type :runner, "cd :path && :runner_command -e :environment ':task' :output"
|
|
30
|
+
job_type :runner, "cd :path && :bundle_command :runner_command -e :environment ':task' :output"
|
data/lib/whenever/version.rb
CHANGED
data/lib/whenever.rb
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require '
|
|
1
|
+
require 'whenever/numeric'
|
|
2
|
+
require 'whenever/numeric_seconds'
|
|
3
|
+
require 'whenever/job_list'
|
|
4
|
+
require 'whenever/job'
|
|
5
|
+
require 'whenever/command_line'
|
|
6
|
+
require 'whenever/cron'
|
|
7
|
+
require 'whenever/output_redirection'
|
|
8
|
+
require 'whenever/os'
|
|
3
9
|
|
|
4
10
|
module Whenever
|
|
5
|
-
autoload :JobList, 'whenever/job_list'
|
|
6
|
-
autoload :Job, 'whenever/job'
|
|
7
|
-
autoload :CommandLine, 'whenever/command_line'
|
|
8
|
-
|
|
9
|
-
module Output
|
|
10
|
-
autoload :Cron, 'whenever/cron'
|
|
11
|
-
autoload :Redirection, 'whenever/output_redirection'
|
|
12
|
-
end
|
|
13
|
-
|
|
14
11
|
def self.cron(options)
|
|
15
12
|
Whenever::JobList.new(options).generate_cron_output
|
|
16
13
|
end
|
|
17
14
|
|
|
15
|
+
def self.seconds(number, units)
|
|
16
|
+
Whenever::NumericSeconds.seconds(number, units)
|
|
17
|
+
end
|
|
18
|
+
|
|
18
19
|
def self.path
|
|
19
20
|
Dir.pwd
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def self.bin_rails?
|
|
23
|
-
File.
|
|
24
|
+
File.exist?(File.join(path, 'bin', 'rails'))
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def self.script_rails?
|
|
27
|
-
File.
|
|
28
|
+
File.exist?(File.join(path, 'script', 'rails'))
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def self.bundler?
|
|
31
|
-
File.
|
|
32
|
+
File.exist?(File.join(path, 'Gemfile'))
|
|
32
33
|
end
|
|
33
34
|
end
|