chrono_trigger 0.1.7 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +0,0 @@
1
- module ChronoTrigger
2
-
3
- class ConfigurationException < Exception; end
4
-
5
- class Shell
6
-
7
- DEFAULT_TRIGGERS = "lib/triggers/*.rb"
8
- #Load triggers defined in the trigger files by evaluating them in the context of this Shell instance.
9
- def load_triggers(files = Dir.glob("#{DEFAULT_TRIGGERS}"))
10
- files.each { |file| self.instance_eval(File.read(file), file) }
11
- end
12
-
13
- #Instantiate a trigger and evaluate the passed in block in the context of the trigger.
14
- #This is the initial method call when setting up a configuration using the DSL.
15
- def trigger(name, &block)
16
- raise ConfigurationException.new("No configuration specified for trigger #{name}") unless block_given?
17
-
18
- trigger = Trigger.new(name)
19
- trigger.instance_eval(&block)
20
-
21
- triggers << trigger
22
- trigger
23
- end
24
-
25
- #Run execute on any trigger who's cron entry matches the current time.
26
- def execute_triggers
27
- now = Time.now
28
- triggers.map {|trigger| trigger.execute_on_match(now)}
29
- end
30
-
31
- def triggers
32
- @triggers ||= []
33
- end
34
-
35
- end
36
- end
@@ -1,3 +0,0 @@
1
- Dir[File.join(File.dirname(__FILE__), '..', 'tasks', '*.rake')].each do |f|
2
- load f
3
- end
@@ -1,127 +0,0 @@
1
- module ChronoTrigger
2
- class Trigger
3
-
4
- attr_accessor :name
5
-
6
- def initialize(name)
7
- self.name = name
8
- end
9
-
10
- #Define the code to be run when the cron job is ready to be executed.
11
- def runs(&block)
12
- @exec_block = block
13
- end
14
-
15
- #Specify what days the task should run on.
16
- #Values are :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
17
- def on(*days)
18
- cron_entry.set_days(days)
19
- end
20
-
21
- #Specify what calendar day the task should run on; think monthly jobs.
22
- #Values are 1-31
23
- def monthly_on(*calendar_day)
24
- cron_entry.set_calendar_days(calendar_day)
25
- end
26
-
27
- #Specify what hours and minutes the task should run at
28
- #(e.g. :minute=>10, :hour=>3 or :minute=>[10,20,30], :hour=>[1,2,3])
29
- def at(options={})
30
- validate_hours_or_minutes!(options)
31
-
32
- if hour = (options[:hour] || options[:hours])
33
- cron_entry.set_hours(hour)
34
- end
35
-
36
- if minute = (options[:minute] || options[:minutes])
37
- cron_entry.set_minutes(minute)
38
- end
39
- end
40
-
41
- #Specify a repeating interval of hours and minutes to run.
42
- #Specifying minutes not divisible by 60 result in an exception, use #at instead.
43
- def every(options={})
44
- validate_hours_or_minutes!(options)
45
- if minutes = (options[:minutes] || options[:minute])
46
- cron_entry.set_minutes(extract_minutes_for_every(minutes))
47
- end
48
-
49
- if hours = (options[:hours] || options[:hour])
50
- cron_entry.set_hours(extract_hours_for_every(hours))
51
- end
52
- end
53
-
54
- def dates
55
- @dates ||= []
56
- end
57
-
58
- #Execute this Trigger's code block if the datetime param matches this Trigger's cron entry.
59
- def execute_on_match(datetime)
60
- self.execute if cron_entry.matches?(datetime)
61
- end
62
-
63
- def execute
64
- defined?(ActiveRecord) ? execute_with_active_record : execute_without_active_record
65
- end
66
-
67
-
68
- private
69
- def cron_entry
70
- @cron_entry ||= CronEntry.new
71
- end
72
-
73
- #Raise an exception unless minutes and hours are set.
74
- def validate_hours_or_minutes!(options={})
75
- unless (options[:hours] || options[:hour]) || (options[:minutes] || options[:minute])
76
- raise ChronoTrigger::ConfigurationException.new("Hours or minutes not specified in call to 'at' or 'every' method.")
77
- end
78
- end
79
-
80
- def extract_minutes_for_every(minutes)
81
- extract_for_every(minutes, 60)
82
- end
83
-
84
- def extract_hours_for_every(hours)
85
- extract_for_every(hours, 24)
86
- end
87
-
88
- #Extract an array of integers representing the minutes or hours a task should be run at.
89
- #Raise an exception if time_value is not evenly divisible by base.
90
- def extract_for_every(time_value, base)
91
- unless (base % time_value == 0)
92
- raise ChronoTrigger::ConfigurationException.new("#{time_value} is not evenly divisible by #{base}. Consider using #at instead.")
93
- end
94
-
95
- (0...base).select {|num| num % time_value == 0}
96
- end
97
-
98
- # When ActiveRecord is defined, attempt to rescue ConnectionNotEstablished errors once,
99
- # and reestablish the connection to the database. If this fails, normal exception logging will take place.
100
- #
101
- def execute_with_active_record
102
- begin
103
- @exec_block.call
104
- rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::StatementInvalid
105
- ActiveRecord::Base.connection.reconnect!
106
- execute_without_active_record
107
- rescue Exception
108
- log_exception
109
- end
110
- end
111
-
112
- # Execute the execution block and log all exceptions.
113
- #
114
- def execute_without_active_record
115
- begin
116
- @exec_block.call
117
- rescue Exception
118
- log_exception
119
- end
120
- end
121
-
122
- def log_exception
123
- STDERR.puts "Exception #{$!.inspect} caught in Trigger##{self.name}. Backtrace:"
124
- STDERR.puts $!.backtrace
125
- end
126
- end
127
- end
@@ -1,14 +0,0 @@
1
- namespace :chrono_trigger do
2
-
3
- run_task_name = defined?(RAILS_ROOT) ? {:run => :environment} : :run
4
- desc "Execute all triggers in loop, sleeping 1 minute between checks."
5
- task run_task_name do
6
- shell = ChronoTrigger::Shell.new
7
- shell.load_triggers
8
- loop do
9
- shell.execute_triggers
10
- sleep 1.minute.to_i
11
- end
12
-
13
- end
14
- end
@@ -1,31 +0,0 @@
1
- trigger "trigger1" do
2
- runs { puts "trigger 1 runs every 1 minutes; executed at #{Time.now}" }
3
- every :minutes=>1
4
- end
5
-
6
- trigger "exception trigger" do
7
- runs { raise Exception.new("test exception")}
8
- every :minutes=>2
9
- end
10
-
11
- trigger "trigger2" do
12
- runs { puts "trigger 2 runs every 5 minutes; executed at #{Time.now}"}
13
- every :minutes=>5
14
- end
15
-
16
- trigger "trigger3" do
17
- runs { puts "trigger 3 runs at 9:48; executed at #{Time.now}"}
18
- at :hour=>9, :minute=>48
19
- end
20
-
21
- trigger "trigger4" do
22
- runs { puts "trigger 4 runs on monday at 9:53 and 9:56; executed at #{Time.now}"}
23
- on :monday
24
- at :hour=>9, :minute=>[53, 56]
25
- end
26
-
27
- trigger "trigger5" do
28
- runs { puts "trigger 5 runs on thursday at 9:58/59; executed at #{Time.now}"}
29
- on :thursday
30
- at :hour=>9, :minute=>[58, 59]
31
- end
data/script/console DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # File: script/console
3
- irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
-
5
- libs = " -r irb/completion"
6
- # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
- # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
- libs << " -r #{File.dirname(__FILE__) + '/../lib/chrono_trigger.rb'}"
9
- puts "Loading chrono_trigger gem"
10
- exec "#{irb} #{libs} --simple-prompt"
data/script/destroy DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
-
4
- begin
5
- require 'rubigen'
6
- rescue LoadError
7
- require 'rubygems'
8
- require 'rubigen'
9
- end
10
- require 'rubigen/scripts/destroy'
11
-
12
- ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
- RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
- RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
-
4
- begin
5
- require 'rubigen'
6
- rescue LoadError
7
- require 'rubygems'
8
- require 'rubigen'
9
- end
10
- require 'rubigen/scripts/generate'
11
-
12
- ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
- RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
- RubiGen::Scripts::Generate.new.run(ARGV)
@@ -1,11 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- class TestChronoTrigger < Test::Unit::TestCase
4
-
5
- def setup
6
- end
7
-
8
- def test_truth
9
- assert true
10
- end
11
- end
@@ -1,198 +0,0 @@
1
- class TestCronEntry < Test::Unit::TestCase
2
-
3
- class << self
4
-
5
- def should_match(options={})
6
- context "and a datetime of #{options.inspect}" do
7
- setup do
8
- @datetime = time_from_options(options)
9
- end
10
-
11
- should "return true on a call to matches?" do
12
- assert @cron.matches?(@datetime)
13
- end
14
- end #and a datetime of options[]
15
- end
16
-
17
- def should_not_match(options={})
18
- context "and a datetime of #{options.inspect}" do
19
- setup do
20
- @datetime = time_from_options(options)
21
- end
22
-
23
- should "return false on a call to matches?" do
24
- assert !@cron.matches?(@datetime)
25
- end
26
- end #and a datetime of options[]
27
- end
28
-
29
- end
30
-
31
- context "A CronEntry, @cron," do
32
- setup do
33
- @cron = ChronoTrigger::CronEntry.new
34
- end
35
-
36
- context "with a minutes entry of 10 minutes" do
37
- setup do
38
- @cron.set_minutes(10)
39
- end
40
-
41
- should_match(:minutes=>10)
42
-
43
- should_not_match(:minutes=>11)
44
-
45
- context "and 25 minutes" do
46
- setup do
47
- @cron.set_minutes(10, 25)
48
- end
49
-
50
- should_match(:minutes=>25)
51
-
52
- should_match(:minutes=>10)
53
-
54
- should_not_match(:minutes=>12)
55
-
56
- context "and a day entry of monday" do
57
- setup do
58
- @cron.set_days(:monday)
59
- end
60
-
61
- should_match(:minutes=>10, :wday=>1)
62
-
63
- should_not_match(:minutes=>10, :wday=>2)
64
-
65
- context "and wednesday" do
66
- setup do
67
- @cron.set_days(:monday, :wednesday)
68
- end
69
-
70
- should_match(:minutes=>10, :wday=>1)
71
-
72
- should_match(:minutes=>10, :wday=>3)
73
-
74
- should_not_match(:minutes=>25, :wday=>5)
75
-
76
- should_not_match(:minutes=>11, :wday=>3)
77
-
78
- context "and an hour entry of 2" do
79
- setup do
80
- @cron.set_hours(5)
81
- end
82
-
83
- should_match(:minutes=>25, :wday=>3, :hour=>5)
84
-
85
- should_not_match(:minutes=>25, :wday=>3, :hour=>6)
86
- end #and an hour entry of 2
87
- end #and wednesday
88
- end #and a day entry of monday
89
- end #and 25 minutes
90
- end #with a minutes entry of 10 minutes
91
-
92
- context "with a day entry of monday" do
93
- setup do
94
- @cron.set_days(:monday)
95
- end
96
-
97
- context "and no minutes_entry" do
98
- setup do
99
- @cron.set_minutes(nil)
100
- end
101
-
102
- should "raise a ChronoTrigger::CronEntry:ConfigException exception on matches?" do
103
- assert_raise ChronoTrigger::ConfigurationException do
104
- @cron.matches?(time_from_options)
105
- end
106
- end
107
- end #and no minutes_entry
108
- end #with a day entry
109
-
110
- context "with a calendar_day entry of 25" do
111
- setup do
112
- @cron.set_calendar_days(25)
113
- end
114
-
115
- should "raise an exception when setting a calendar_day and no hour and minutes" do
116
- assert_raise ChronoTrigger::ConfigurationException do
117
- @cron.matches?(time_from_options(:day => 25))
118
- end
119
- end
120
-
121
- context "with a hour entry of 10" do
122
- setup do
123
- @cron.set_hours(10)
124
- end
125
-
126
- should "raise an exception when setting a calendar_day and hour but no minutes" do
127
- assert_raise ChronoTrigger::ConfigurationException do
128
- @cron.matches?(time_from_options(:hour=> 10, :day => 25))
129
- end
130
- end
131
-
132
- context "with a minutes entry of 5" do
133
- setup do
134
- @cron.set_minutes(5)
135
- end
136
-
137
- should_match(:minutes => 5, :hour => 10, :day => 25)
138
- should_not_match(:minutes => 4, :hour => 10, :day => 25)
139
- should_not_match(:minutes => 5, :hour => 11, :day => 25)
140
- should_not_match(:minutes => 5, :hour => 10, :day => 26)
141
-
142
- context "with an additional calendar_day entry of 26" do
143
- setup do
144
- @cron.set_calendar_days([25, 26])
145
- end
146
-
147
- should_match(:minutes => 5, :hour => 10, :day => 25)
148
- should_match(:minutes => 5, :hour => 10, :day => 26)
149
-
150
- should "raise an exception when setting a calendar_day is outside the acceptable range" do
151
- assert_raise ChronoTrigger::ConfigurationException do
152
- @cron.set_calendar_days(-1)
153
- end
154
- end
155
- end
156
-
157
- context "with a day entry of tuesday" do
158
- setup do
159
- @cron.set_days(:wednesday)
160
- end
161
-
162
- should "raise an exception when setting a calendar_day with a day" do
163
- assert_raise ChronoTrigger::ConfigurationException do
164
- @cron.matches?(time_from_options(:minutes => 5, :hour => 10, :day => 25, :wday => 3))
165
- end
166
- end
167
- end
168
- end
169
- end
170
- end
171
-
172
- should "raise an exception when setting an hour entry greater than 25" do
173
- assert_raise ChronoTrigger::ConfigurationException do
174
- @cron.set_hours(25)
175
- end
176
- end
177
- end #A CronEntry, @cron,
178
-
179
-
180
- private
181
- def time_from_options(options={})
182
- datetime = Time.utc(options[:year] || 2000,
183
- options[:month] || "jan",
184
- options[:day]||1,
185
- options[:hour]||0,
186
- options[:minutes]||0,
187
- options[:second]||0)
188
-
189
- if wday = options[:wday]
190
- while datetime.wday != wday
191
- datetime += 1.day
192
- end
193
- end
194
-
195
- datetime
196
- end
197
-
198
- end