whenever 0.9.7 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ec69e7c581dc0a3b78c99dc92d7ba20603fe314
4
- data.tar.gz: 02fc72439569835cce71da0fc186ed48568ed1e2
3
+ metadata.gz: 9c8fe56b21ffa57026a2b944ae208bea62a9d7e9
4
+ data.tar.gz: 543d704698ab03d944679daa1e85bee1b3936286
5
5
  SHA512:
6
- metadata.gz: 732ee6e0a5d38ed8f323e814e2e6243306a5c2e84b44d5ce8f05d2c0ef7bf7520341044892906c7ea6899a24a87e840285a001dc54e35a196414da06de42a607
7
- data.tar.gz: 9bbf8365c6fd030b7ba465d06660f1bd84cb8593b957f4482676fa50c6daf684b2de91c98bb84907e2e62f2e493f22b76c1ccbb7dbd469072ebf937e5e12cf85
6
+ metadata.gz: 3d0bd440a4beab5ecde93ccb91fad7cf5b2bf2ffe14a376ad24392fe5b4a3d53ba1d7ce15a53d2debc3b639a35f609436d21ab78de16b99a857fe1e16ed8bed1
7
+ data.tar.gz: 4bb8692d2f7130e45d80fc05a6a54609fd160155014eae330da8f0fc9ed97e9338d523282cd4f8ec197531231493bd04d2409a3d7a6bbc57761ff6ad0ff7f422
@@ -1,5 +1,4 @@
1
1
  language: ruby
2
- script: bundle exec rake
3
2
 
4
3
  before_install:
5
4
  - gem install bundler
@@ -7,12 +6,16 @@ before_install:
7
6
  rvm:
8
7
  - 1.9.3
9
8
  - 2.0.0
10
- - 2.1.0
11
- - 2.2.0
12
- - 2.3.0
13
- - jruby
9
+ - 2.1.10
10
+ - 2.2.6
11
+ - 2.3.3
12
+ - 2.4.0
13
+ - jruby-9.1.9.0
14
14
 
15
15
  gemfile:
16
16
  - Gemfile
17
17
  - gemfiles/activesupport4.1.gemfile
18
18
  - gemfiles/activesupport4.2.gemfile
19
+ env:
20
+ global:
21
+ - JRUBY_OPTS=--debug
@@ -1,5 +1,19 @@
1
1
  ### develop
2
2
 
3
+ ### 0.10.0 / November 19, 2017
4
+
5
+ * Modify wheneverize to allow for the creating of 'config' directory when not present
6
+
7
+ * Add --crontab-command to whenever binary for overriding the crontab command. [Martin Grandrath]
8
+
9
+ * Allow setting the path within which Capistrano will execute whenever. [Samuel Johnson](https://github.com/javan/whenever/pull/619)
10
+
11
+ * Allow the use of string literals for month and day-of-week in raw cron syntax.. [Potamianos Gregory](https://github.com/javan/whenever/pull/711)
12
+
13
+ * Include Capistrano default environment variables when executing Whenever. [Karl Li](https://github.com/javan/whenever/pull/719)
14
+
15
+ * Allow configuring an alternative schedule file in Capistrano. [Shinichi Okamoto](https://github.com/javan/whenever/pull/666)
16
+
3
17
  ### 0.9.7 / June 14, 2016
4
18
 
5
19
  * Restore compatibility with Capistrano v3; it has a bug which we have to work around [Ben Langfeld, Chris Gunther, Shohei Yamasaki]
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Javan Makhmali
1
+ Copyright (c) 2017 Javan Makhmali
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -19,7 +19,7 @@ $ cd /apps/my-great-project
19
19
  $ wheneverize .
20
20
  ```
21
21
 
22
- This will create an initial `config/schedule.rb` file for you.
22
+ This will create an initial `config/schedule.rb` file for you (as long as the config folder is already present in your project).
23
23
 
24
24
  ### The `whenever` command
25
25
 
@@ -34,14 +34,21 @@ This will simply show you your `schedule.rb` file converted to cron syntax. It d
34
34
  $ whenever --update-crontab
35
35
  ```
36
36
 
37
+ Other commonly used options include:
38
+ ```sh
39
+ $ whenever --user app # set a user as which to install the crontab
40
+ $ whenever --load-file config/my_schedule.rb # set the schedule file
41
+ $ whenever --crontab-command 'sudo crontab` # override the crontab command
42
+ ```
43
+
37
44
  You can list installed cron jobs using `crontab -l`.
38
45
 
39
- Run `whenever --help` for a complete list of options for selecting the schedule to use, setting variables in the schedule, selecting a user as which to install the crontab, etc.
46
+ Run `whenever --help` for a complete list of options for selecting the schedule to use, setting variables in the schedule, etc.
40
47
 
41
48
  ### Example schedule.rb file
42
49
 
43
50
  ```ruby
44
- every 3.hours do
51
+ every 3.hours do # 1.minute 1.day 1.week 1.month 1.year is also supported
45
52
  runner "MyModel.some_process"
46
53
  rake "my:rake:task"
47
54
  command "/usr/bin/my_great_command"
@@ -113,6 +120,57 @@ Or set the job_template to nil to have your jobs execute normally.
113
120
  set :job_template, nil
114
121
  ```
115
122
 
123
+ ### Parsing dates and times
124
+
125
+ Whenever uses the [Chronic](https://github.com/mojombo/chronic) gem to parse the specified dates and times.
126
+
127
+ You can set your custom Chronic configuration if the defaults don't fit you.
128
+
129
+ For example, to assume a 24 hour clock instead of the default 12 hour clock:
130
+
131
+ ```ruby
132
+ set :chronic_options, :hours24 => true
133
+
134
+ # By default this would run the job every day at 3am
135
+ every 1.day, :at => '3:00' do
136
+ runner "MyModel.nightly_archive_job"
137
+ end
138
+ ```
139
+
140
+ You can see a list of all available options here: <https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb>
141
+
142
+ ### Customize email recipient with the `MAILTO` environment variable
143
+
144
+ Output from the jobs is sent to the email address configured in the `MAILTO` environment variable.
145
+
146
+ There are many ways to further configure the recipient.
147
+
148
+ Example: A global configuration, overriding the environment's value:
149
+
150
+ ```ruby
151
+ env 'MAILTO', 'output_of_cron@example.com'
152
+
153
+ every 3.hours do
154
+ command "/usr/bin/my_great_command"
155
+ end
156
+ ```
157
+
158
+ Example: A `MAILTO` configured for all the jobs in an interval block:
159
+
160
+ ```ruby
161
+ every 3.hours, mailto: 'my_super_command@example.com' do
162
+ command "/usr/bin/my_super_command"
163
+ end
164
+ ```
165
+
166
+ Example: A `MAILTO` configured for a single job:
167
+
168
+ ```ruby
169
+ every 3.hours do
170
+ command "/usr/bin/my_super_command", mailto: 'my_super_command_output@example.com'
171
+ end
172
+ ```
173
+
116
174
  ### Capistrano integration
117
175
 
118
176
  Use the built-in Capistrano recipe for easy crontab updates with deploys. For Capistrano V3, see the next section.
@@ -140,7 +198,7 @@ require "whenever/capistrano"
140
198
 
141
199
  The capistrano variable `:stage` should be the one holding your environment name. This will make the correct `:environment` available in your `schedule.rb`.
142
200
 
143
- If both your environments are on the same server you'll want to namespace them or they'll overwrite each other when you deploy:
201
+ If both your environments are on the same server you'll want to namespace them, or they'll overwrite each other when you deploy:
144
202
 
145
203
  ```ruby
146
204
  set :whenever_environment, defer { stage }
@@ -148,6 +206,13 @@ set :whenever_identifier, defer { "#{application}_#{stage}" }
148
206
  require "whenever/capistrano"
149
207
  ```
150
208
 
209
+ If you use a schedule at an alternative path, you may configure it like so:
210
+
211
+ ```ruby
212
+ set :whenever_load_file, defer { "#{release_path}/somewhere/else/schedule.rb" }
213
+ require "whenever/capistrano"
214
+ ```
215
+
151
216
  ### Capistrano V3 Integration
152
217
 
153
218
  In your "Capfile" file:
@@ -172,10 +237,10 @@ different servers in your capistrano deployment, then you can safely stop readin
172
237
  now and everything should just work the same way it always has.
173
238
 
174
239
  When you define a job in your schedule.rb file, by default it will be deployed to
175
- all servers in the whenever_roles list (which defaults to [:db]).
240
+ all servers in the whenever_roles list (which defaults to `[:db]`).
176
241
 
177
242
  However, if you want to restrict certain jobs to only run on subset of servers,
178
- you can add a :roles => [...] argument to their definitions. **Make sure to add
243
+ you can add a `:roles => [...]` argument to their definitions. **Make sure to add
179
244
  that role to the whenever_roles list in your deploy.rb.**
180
245
 
181
246
  When you run `cap deploy`, jobs with a :roles list specified will only be added to
@@ -184,8 +249,8 @@ the crontabs on servers with one or more of the roles in that list.
184
249
  Jobs with no :roles argument will be deployed to all servers in the whenever_roles
185
250
  list. This is to maintain backward compatibility with previous releases of whenever.
186
251
 
187
- So, for example, with the default whenever_roles of [:db], a job like this would be
188
- deployed to all servers with the :db role:
252
+ So, for example, with the default whenever_roles of `[:db]`, a job like this would be
253
+ deployed to all servers with the `:db` role:
189
254
 
190
255
  ```ruby
191
256
  every :day, :at => '12:20am' do
@@ -193,7 +258,7 @@ every :day, :at => '12:20am' do
193
258
  end
194
259
  ```
195
260
 
196
- If we set whenever_roles to [:db, :app] in deploy.rb, and have the following
261
+ If we set whenever_roles to `[:db, :app]` in deploy.rb, and have the following
197
262
  jobs in schedule.rb:
198
263
 
199
264
  ```ruby
@@ -257,4 +322,4 @@ It's a little bit dated now, but remains a good introduction.
257
322
 
258
323
  ----
259
324
 
260
- Copyright &copy; 2016 Javan Makhmali
325
+ Copyright &copy; 2017 Javan Makhmali
@@ -35,6 +35,9 @@ OptionParser.new do |opts|
35
35
  opts.on('-r', '--roles [role1,role2]', 'Comma-separated list of server roles to generate cron jobs for') do |roles|
36
36
  options[:roles] = roles.split(',').map(&:to_sym) if roles
37
37
  end
38
+ opts.on('-x', '--crontab-command [command]', 'Default: crontab') do |crontab_command|
39
+ options[:crontab_command] = crontab_command if crontab_command
40
+ end
38
41
  opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
39
42
  end.parse!
40
43
 
@@ -58,9 +58,12 @@ if File.exist?(file)
58
58
  warn "[skip] `#{file}' already exists"
59
59
  elsif File.exist?(file.downcase)
60
60
  warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
61
- elsif !File.exist?(File.dirname(file))
62
- warn "[skip] directory `#{File.dirname(file)}' does not exist"
63
61
  else
62
+ dir = File.dirname(file)
63
+ if !File.exist?(dir)
64
+ warn "[add] creating `#{dir}'"
65
+ FileUtils.mkdir_p(dir)
66
+ end
64
67
  puts "[add] writing `#{file}'"
65
68
  File.open(file, "w") { |f| f.write(content) }
66
69
  end
@@ -11,6 +11,7 @@ Capistrano::Configuration.instance(:must_exist).load do
11
11
  _cset(:whenever_variables) { "environment=#{fetch :whenever_environment}" }
12
12
  _cset(:whenever_update_flags) { "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
13
13
  _cset(:whenever_clear_flags) { "--clear-crontab #{fetch :whenever_identifier}" }
14
+ _cset(:whenever_path) { fetch :latest_release }
14
15
 
15
16
  namespace :whenever do
16
17
  desc "Update application's crontab entries using Whenever"
@@ -18,7 +19,7 @@ Capistrano::Configuration.instance(:must_exist).load do
18
19
  args = {
19
20
  :command => fetch(:whenever_command),
20
21
  :flags => fetch(:whenever_update_flags),
21
- :path => fetch(:latest_release)
22
+ :path => fetch(:whenever_path)
22
23
  }
23
24
 
24
25
  if whenever_servers.any?
@@ -38,7 +39,7 @@ Capistrano::Configuration.instance(:must_exist).load do
38
39
  args = {
39
40
  :command => fetch(:whenever_command),
40
41
  :flags => fetch(:whenever_clear_flags),
41
- :path => fetch(:latest_release)
42
+ :path => fetch(:whenever_path)
42
43
  }
43
44
 
44
45
  whenever_run_commands(args)
@@ -4,7 +4,7 @@ namespace :whenever do
4
4
 
5
5
  on roles fetch(:whenever_roles) do |host|
6
6
  args_for_host = block_given? ? args + Array(yield(host)) : args
7
- within release_path do
7
+ within fetch(:whenever_path) do
8
8
  with fetch(:whenever_command_environment_variables) do
9
9
  execute(*args_for_host)
10
10
  end
@@ -12,17 +12,28 @@ namespace :whenever do
12
12
  end
13
13
  end
14
14
 
15
+ def load_file
16
+ file = fetch(:whenever_load_file)
17
+ if file
18
+ "-f #{file}"
19
+ else
20
+ ''
21
+ end
22
+ end
23
+
15
24
  desc "Update application's crontab entries using Whenever"
16
25
  task :update_crontab do
17
26
  setup_whenever_task do |host|
18
27
  roles = host.roles_array.join(",")
19
- [fetch(:whenever_update_flags), "--roles=#{roles}"]
28
+ [fetch(:whenever_update_flags), "--roles=#{roles}", load_file]
20
29
  end
21
30
  end
22
31
 
23
32
  desc "Clear application's crontab entries using Whenever"
24
33
  task :clear_crontab do
25
- setup_whenever_task(fetch(:whenever_clear_flags))
34
+ setup_whenever_task do |host|
35
+ [fetch(:whenever_clear_flags), load_file]
36
+ end
26
37
  end
27
38
 
28
39
  after "deploy:updated", "whenever:update_crontab"
@@ -33,11 +44,13 @@ namespace :load do
33
44
  task :defaults do
34
45
  set :whenever_roles, ->{ :db }
35
46
  set :whenever_command, ->{ [:bundle, :exec, :whenever] }
36
- set :whenever_command_environment_variables, ->{ { rails_env: fetch(:whenever_environment) } }
47
+ set :whenever_command_environment_variables, ->{ fetch(:default_env).merge!(rails_env: fetch(:whenever_environment)) }
37
48
  set :whenever_identifier, ->{ fetch :application }
38
49
  set :whenever_environment, ->{ fetch :rails_env, fetch(:stage, "production") }
39
50
  set :whenever_variables, ->{ "environment=#{fetch :whenever_environment}" }
51
+ set :whenever_load_file, ->{ nil }
40
52
  set :whenever_update_flags, ->{ "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
41
53
  set :whenever_clear_flags, ->{ "--clear-crontab #{fetch :whenever_identifier}" }
54
+ set :whenever_path, ->{ fetch :release_path }
42
55
  end
43
56
  end
@@ -9,9 +9,10 @@ module Whenever
9
9
  def initialize(options={})
10
10
  @options = options
11
11
 
12
- @options[:file] ||= 'config/schedule.rb'
13
- @options[:cut] ||= 0
14
- @options[:identifier] ||= default_identifier
12
+ @options[:crontab_command] ||= 'crontab'
13
+ @options[:file] ||= 'config/schedule.rb'
14
+ @options[:cut] ||= 0
15
+ @options[:identifier] ||= default_identifier
15
16
 
16
17
  if !File.exist?(@options[:file]) && @options[:clear].nil?
17
18
  warn("[fail] Can't find file: #{@options[:file]}")
@@ -28,6 +29,8 @@ module Whenever
28
29
  exit(1)
29
30
  end
30
31
  @options[:cut] = @options[:cut].to_i
32
+
33
+ @timestamp = Time.now.to_s
31
34
  end
32
35
 
33
36
  def run
@@ -55,9 +58,10 @@ module Whenever
55
58
  end
56
59
 
57
60
  def read_crontab
58
- return @current_crontab if @current_crontab
61
+ return @current_crontab if instance_variable_defined?(:@current_crontab)
59
62
 
60
- command = ['crontab -l']
63
+ command = [@options[:crontab_command]]
64
+ command << '-l'
61
65
  command << "-u #{@options[:user]}" if @options[:user]
62
66
 
63
67
  command_results = %x[#{command.join(' ')} 2> /dev/null]
@@ -65,7 +69,7 @@ module Whenever
65
69
  end
66
70
 
67
71
  def write_crontab(contents)
68
- command = ['crontab']
72
+ command = [@options[:crontab_command]]
69
73
  command << "-u #{@options[:user]}" if @options[:user]
70
74
  # Solaris/SmartOS cron does not support the - option to read from stdin.
71
75
  command << "-" unless OS.solaris?
@@ -90,19 +94,19 @@ module Whenever
90
94
 
91
95
  def updated_crontab
92
96
  # Check for unopened or unclosed identifier blocks
93
- if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close}\s*$")).nil?
94
- warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
97
+ if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")).nil?
98
+ warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open(false)}', but no '#{comment_close(false)}'"
95
99
  exit(1)
96
- elsif (read_crontab =~ Regexp.new("^#{comment_open}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
97
- warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
100
+ elsif (read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
101
+ warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close(false)}', but no '#{comment_open(false)}'"
98
102
  exit(1)
99
103
  end
100
104
 
101
105
  # If an existing identier block is found, replace it with the new cron entries
102
- if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
106
+ if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
103
107
  # If the existing crontab file contains backslashes they get lost going through gsub.
104
108
  # .gsub('\\', '\\\\\\') preserves them. Go figure.
105
- read_crontab.gsub(Regexp.new("^#{comment_open}\s*$.+^#{comment_close}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
109
+ read_crontab.gsub(Regexp.new("^#{comment_open_regex}\s*$.+^#{comment_close_regex}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
106
110
  else # Otherwise, append the new cron entries after any existing ones
107
111
  [read_crontab, whenever_cron].join("\n\n")
108
112
  end.gsub(/\n{3,}/, "\n\n") # More than two newlines becomes just two.
@@ -120,16 +124,32 @@ module Whenever
120
124
  stripped_contents.gsub!(/\s+$/, $/)
121
125
  end
122
126
 
123
- def comment_base
124
- "Whenever generated tasks for: #{@options[:identifier]}"
127
+ def comment_base(include_timestamp = true)
128
+ if include_timestamp
129
+ "Whenever generated tasks for: #{@options[:identifier]} at: #{@timestamp}"
130
+ else
131
+ "Whenever generated tasks for: #{@options[:identifier]}"
132
+ end
133
+ end
134
+
135
+ def comment_open(include_timestamp = true)
136
+ "# Begin #{comment_base(include_timestamp)}"
137
+ end
138
+
139
+ def comment_close(include_timestamp = true)
140
+ "# End #{comment_base(include_timestamp)}"
141
+ end
142
+
143
+ def comment_open_regex
144
+ "#{comment_open(false)}(#{timestamp_regex}|)"
125
145
  end
126
146
 
127
- def comment_open
128
- "# Begin #{comment_base}"
147
+ def comment_close_regex
148
+ "#{comment_close(false)}(#{timestamp_regex}|)"
129
149
  end
130
150
 
131
- def comment_close
132
- "# End #{comment_base}"
151
+ def timestamp_regex
152
+ " at: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} ([+-]\\d{4}|UTC)"
133
153
  end
134
154
  end
135
155
  end
@@ -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 '|'})|((\*?[\d\/,\-]*)\s*){5})$/
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
@@ -54,18 +58,18 @@ module Whenever
54
58
 
55
59
  protected
56
60
  def day_given?
57
- months = %w(jan feb mar apr may jun jul aug sep oct nov dec)
58
- @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/])
59
62
  end
60
63
 
61
64
  def parse_symbol
62
65
  shortcut = case @time
63
66
  when *KEYWORDS then "@#{@time}" # :reboot => '@reboot'
64
- when :year then Whenever.seconds(12, :months)
67
+ when :year then Whenever.seconds(1, :year)
65
68
  when :day then Whenever.seconds(1, :day)
66
69
  when :month then Whenever.seconds(1, :month)
67
70
  when :week then Whenever.seconds(1, :week)
68
71
  when :hour then Whenever.seconds(1, :hour)
72
+ when :minute then Whenever.seconds(1, :minute)
69
73
  end
70
74
 
71
75
  if shortcut.is_a?(Numeric)
@@ -94,13 +98,15 @@ module Whenever
94
98
  hour_frequency = (@time / 60 / 60).round
95
99
  timing[0] = @at.is_a?(Time) ? @at.min : @at
96
100
  timing[1] = comma_separated_timing(hour_frequency, 23)
101
+ raise ArgumentError, "Minute must be between 0-59, #{timing[0]} given" unless (0..59).include?(timing[0])
97
102
  when Whenever.seconds(1, :day)...Whenever.seconds(1, :month)
98
103
  day_frequency = (@time / 24 / 60 / 60).round
99
104
  timing[0] = @at.is_a?(Time) ? @at.min : 0
100
105
  timing[1] = @at.is_a?(Time) ? @at.hour : @at
101
106
  timing[2] = comma_separated_timing(day_frequency, 31, 1)
102
- when Whenever.seconds(1, :month)..Whenever.seconds(12, :months)
103
- month_frequency = (@time / 30 / 24 / 60 / 60).round
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
104
110
  timing[0] = @at.is_a?(Time) ? @at.min : 0
105
111
  timing[1] = @at.is_a?(Time) ? @at.hour : 0
106
112
  timing[2] = if @at.is_a?(Time)
@@ -109,6 +115,21 @@ module Whenever
109
115
  @at.zero? ? 1 : @at
110
116
  end
111
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])
112
133
  else
113
134
  return parse_as_string
114
135
  end
@@ -126,7 +147,7 @@ module Whenever
126
147
  return (timing << '1-5') * " " if string.downcase.index('weekday')
127
148
  return (timing << '6,0') * " " if string.downcase.index('weekend')
128
149
 
129
- %w(sun mon tue wed thu fri sat).each_with_index do |day, i|
150
+ DAYS.each_with_index do |day, i|
130
151
  return (timing << i) * " " if string.downcase.index(day)
131
152
  end
132
153