gregfitz23-chrono_trigger 0.0.2

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.
@@ -0,0 +1,9 @@
1
+ == 0.0.2 2009-04-02
2
+
3
+ * 1 minor enhancement:
4
+ * Updated to add tasks file
5
+
6
+ == 0.0.1 2009-04-02
7
+
8
+ * 1 major enhancement:
9
+ * Initial release
@@ -0,0 +1,21 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/chrono_trigger.rb
7
+ lib/chrono_trigger/cron_entry.rb
8
+ lib/chrono_trigger/shell.rb
9
+ lib/chrono_trigger/tasks.rb
10
+ lib/chrono_trigger/trigger.rb
11
+ lib/triggers/test_triggers.rb
12
+ script/console
13
+ script/destroy
14
+ script/generate
15
+ tasks/chrono_trigger.rake
16
+ test/test_chrono_trigger.rb
17
+ test/test_cron_entry.rb
18
+ test/test_helper.rb
19
+ test/test_shell.rb
20
+ test/test_trigger.rb
21
+ test/triggers.rb
@@ -0,0 +1,3 @@
1
+ # Remember to add chrono_trigger.rake to lib/tasks in your rails project containing:
2
+ # require 'chrono_trigger/tasks'
3
+
@@ -0,0 +1,58 @@
1
+ = chrono_trigger
2
+
3
+ * http://github.com/gregfitz23/chrono_trigger/tree/master
4
+
5
+ == DESCRIPTION:
6
+
7
+ A cron framework for defining cron tasks using a readable DSL.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ == SYNOPSIS:
12
+
13
+ After installation, create lib/tasks/chrono_trigger.rake containing: require 'chrono_trigger/tasks'
14
+
15
+ Create trigger files (by default in the lib/triggers) directory.
16
+ Triggers should follow the pattern:
17
+
18
+ trigger "name" do
19
+ runs { code to execute }
20
+ on :monday
21
+ every :minutes=>10
22
+ at :hour=>9, :minute=>[30,50]
23
+ end
24
+
25
+ Execute rake RAILS_ENV={env} chrono_trigger:run
26
+
27
+ == REQUIREMENTS:
28
+
29
+ * ActiveSupport >= 2.0.2
30
+
31
+ == INSTALL:
32
+
33
+ * sudo gem install gregfitz23-chrono_trigger
34
+
35
+ == LICENSE:
36
+
37
+ (The MIT License)
38
+
39
+ Copyright (c) 2009 FIXME full name
40
+
41
+ Permission is hereby granted, free of charge, to any person obtaining
42
+ a copy of this software and associated documentation files (the
43
+ 'Software'), to deal in the Software without restriction, including
44
+ without limitation the rights to use, copy, modify, merge, publish,
45
+ distribute, sublicense, and/or sell copies of the Software, and to
46
+ permit persons to whom the Software is furnished to do so, subject to
47
+ the following conditions:
48
+
49
+ The above copyright notice and this permission notice shall be
50
+ included in all copies or substantial portions of the Software.
51
+
52
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
53
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 2
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,11 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module ChronoTrigger
5
+ VERSION = '0.0.2'
6
+ end
7
+
8
+ require "activesupport"
9
+ require "chrono_trigger/shell"
10
+ require "chrono_trigger/trigger"
11
+ require "chrono_trigger/cron_entry"
@@ -0,0 +1,54 @@
1
+ module ChronoTrigger
2
+
3
+ class CronEntry
4
+
5
+ def initialize(options={})
6
+ set_days(options[:days])
7
+ set_hours(options[:hours])
8
+ set_minutes(options[:minutes])
9
+ end
10
+
11
+ DAYS_CONVERSION = {
12
+ :sunday => 0,
13
+ :monday => 1,
14
+ :tuesday => 2,
15
+ :wednesday => 3,
16
+ :thursday => 4,
17
+ :friday => 5,
18
+ :saturday => 6
19
+ }
20
+
21
+ def set_hours(*args)
22
+ args.compact!
23
+ args.flatten!
24
+ raise ChronoTrigger::ConfigurationException.new("Hours must be less than 24") if args.any? {|hour| hour >= 24}
25
+ @hours = args
26
+ end
27
+
28
+ def set_days(*args)
29
+ args.compact!
30
+ args.flatten!
31
+ args.each {|day| raise ChronoTrigger::ConfigurationException.new("Day #{day} setting is invalid") if !DAYS_CONVERSION.keys.include?(day)}
32
+ @days = args.map { |day| DAYS_CONVERSION[day] }
33
+ end
34
+
35
+ def set_minutes(*args)
36
+ args.compact!
37
+ args.flatten!
38
+ raise ChronoTrigger::ConfigurationException.new("Minutes must be less than 60") if args.any? {|minute| minute >= 60}
39
+ @minutes = args
40
+ end
41
+
42
+ def matches?(datetime)
43
+ if @minutes.blank? && !@days.blank?
44
+ raise ChronoTrigger::ConfigurationException.new("Days were specified for a CronEntry with no minutes specified")
45
+ end
46
+
47
+ return false if !@minutes.blank? && !@minutes.include?(datetime.min)
48
+ return false if !@hours.blank? && !@hours.include?(datetime.hour)
49
+ return false if !@days.blank? && !@days.include?(datetime.wday)
50
+ return true
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,36 @@
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
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__), '..', '..', 'tasks', '*.rake')].each do |f|
2
+ load f
3
+ end
@@ -0,0 +1,92 @@
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 hours and minutes the task should run at
22
+ #(e.g. :minute=>10, :hour=>3 or :minute=>[10,20,30], :hour=>[1,2,3])
23
+ def at(options={})
24
+ validate_hours_or_minutes!(options)
25
+
26
+ if hour = options[:hour]
27
+ cron_entry.set_hours(hour)
28
+ end
29
+
30
+ if minute = options[:minute]
31
+ cron_entry.set_minutes(minute)
32
+ end
33
+ end
34
+
35
+ #Specify a repeating interval of hours and minutes to run.
36
+ #Specifying minutes not divisible by 60 result in an exception, use #at instead.
37
+ def every(options={})
38
+ validate_hours_or_minutes!(options)
39
+ if minutes = options[:minutes]
40
+ cron_entry.set_minutes(extract_minutes_for_every(minutes))
41
+ end
42
+
43
+ if hours = options[:hours]
44
+ cron_entry.set_hours(extract_hours_for_every(hours))
45
+ end
46
+ end
47
+
48
+ def dates
49
+ @dates ||= []
50
+ end
51
+
52
+ #Execute this Trigger's code block if the datetime param matches this Trigger's cron entry.
53
+ def execute_on_match(datetime)
54
+ self.execute if cron_entry.matches?(datetime)
55
+ end
56
+
57
+ def execute
58
+ @exec_block.call
59
+ end
60
+
61
+
62
+ private
63
+ def cron_entry
64
+ @cron_entry ||= CronEntry.new
65
+ end
66
+
67
+ #Raise an exception unless minutes and hours are set.
68
+ def validate_hours_or_minutes!(options={})
69
+ unless (options[:hours] || options[:hour]) || (options[:minutes] || options[:minute])
70
+ raise ChronoTrigger::ConfigurationException.new("Hours or minutes not specified in call to 'at' or 'every' method.")
71
+ end
72
+ end
73
+
74
+ def extract_minutes_for_every(minutes)
75
+ extract_for_every(minutes, 60)
76
+ end
77
+
78
+ def extract_hours_for_every(hours)
79
+ extract_for_every(hours, 24)
80
+ end
81
+
82
+ #Extract an array of integers representing the minutes or hours a task should be run at.
83
+ #Raise an exception if time_value is not evenly divisible by base.
84
+ def extract_for_every(time_value, base)
85
+ unless (base % time_value == 0)
86
+ raise ChronoTrigger::ConfigurationException.new("#{time_value} is not evenly divisible by #{base}. Consider using #at instead.")
87
+ end
88
+
89
+ (0...base).select {|num| num % time_value == 0}
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,26 @@
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 "trigger2" do
7
+ runs { puts "trigger 2 runs every 5 minutes; executed at #{Time.now}"}
8
+ every :minutes=>5
9
+ end
10
+
11
+ trigger "trigger3" do
12
+ runs { puts "trigger 3 runs at 9:48; executed at #{Time.now}"}
13
+ at :hour=>9, :minute=>48
14
+ end
15
+
16
+ trigger "trigger4" do
17
+ runs { puts "trigger 4 runs on monday at 9:53 and 9:56; executed at #{Time.now}"}
18
+ on :monday
19
+ at :hour=>9, :minute=>[53, 56]
20
+ end
21
+
22
+ trigger "trigger5" do
23
+ runs { puts "trigger 5 runs on thursday at 9:58/59; executed at #{Time.now}"}
24
+ on :thursday
25
+ at :hour=>9, :minute=>[58, 59]
26
+ end
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,136 @@
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
+ should "raise an exception when setting an hour entry greater than 25" do
111
+ assert_raise ChronoTrigger::ConfigurationException do
112
+ @cron.set_hours(25)
113
+ end
114
+ end
115
+ end #A CronEntry, @cron,
116
+
117
+
118
+ private
119
+ def time_from_options(options={})
120
+ datetime = Time.utc(options[:year] || 2000,
121
+ options[:month] || "jan",
122
+ options[:day]||1,
123
+ options[:hour]||0,
124
+ options[:minutes]||0,
125
+ options[:second]||0)
126
+
127
+ if wday = options[:wday]
128
+ while datetime.wday != wday
129
+ datetime += 1.day
130
+ end
131
+ end
132
+
133
+ datetime
134
+ end
135
+
136
+ end
@@ -0,0 +1,5 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/chrono_trigger'
4
+ require "shoulda"
5
+ require "mocha"
@@ -0,0 +1,52 @@
1
+ class TestShell < Test::Unit::TestCase
2
+
3
+ context "A shell instance, @shell" do
4
+ setup do
5
+ @shell = ChronoTrigger::Shell.new
6
+ end
7
+
8
+ should "return an empty array on call to triggers" do
9
+ assert_equal [], @shell.triggers
10
+ end
11
+
12
+ should "raise an exception unless a block is provided to #trigger" do
13
+ assert_raise(ChronoTrigger::ConfigurationException) { @shell.trigger("test trigger") }
14
+ end
15
+
16
+ context "when provided a valid block" do
17
+ setup do
18
+ @trigger = @shell.trigger("name") { runs { "x" } }
19
+ end
20
+
21
+ should "create a new trigger" do
22
+ assert_equal 1, @shell.triggers.size
23
+ end
24
+
25
+ should "create a trigger that will run x with execute" do
26
+ assert_equal "x", @shell.triggers.first.execute
27
+ end
28
+
29
+ context "and configured to run the next time shell.execute_triggers is called" do
30
+ setup do
31
+ ChronoTrigger::CronEntry.any_instance.stubs(:matches?).returns(true)
32
+ end
33
+
34
+ should "execute the code block" do
35
+ @trigger.expects(:execute)
36
+ @shell.execute_triggers
37
+ end
38
+ end #and configured to run the next time shell.execute_triggers is called
39
+ end #when provided a valid block
40
+
41
+ context "calling load_context with a valid trigger file" do
42
+ setup do
43
+ @shell.load_triggers("test/triggers.rb")
44
+ end
45
+
46
+ should "create 2 triggers" do
47
+ assert_equal 2, @shell.triggers.size
48
+ end
49
+ end #calling load_context with a valid trigger file
50
+ end #A shell instance, @shell
51
+
52
+ end
@@ -0,0 +1,116 @@
1
+ class TestTrigger < Test::Unit::TestCase
2
+
3
+ context "A Trigger, @trigger," do
4
+ setup do
5
+ @trigger = ChronoTrigger::Trigger.new("test trigger")
6
+ end
7
+
8
+ context "and a block of code to run" do
9
+ setup do
10
+ @block_to_run = "hello"
11
+ @trigger.runs { @block_to_run }
12
+ end
13
+
14
+ should "assign @exec_block on call to runs" do
15
+ assert_equal @block_to_run, @trigger.instance_variable_get(:@exec_block).call
16
+ end
17
+
18
+ should "execute @block_to_run on call to execute" do
19
+ assert_equal @block_to_run, @trigger.execute
20
+ end
21
+ end #and a block of code to run
22
+
23
+ context "and a call to #on with some days" do
24
+ setup do
25
+ @days = [:monday, :wednesday]
26
+ @expected_days = [1, 3]
27
+ @trigger.on(@days)
28
+ end
29
+
30
+ should "set the triggers cron entry days" do
31
+ assert_equal @expected_days, @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@days)
32
+ end
33
+ end #and a call to on with some days
34
+
35
+ context "and a call to #at with :hours and :minutes" do
36
+ setup do
37
+ @hours = 10
38
+ @minutes = 5
39
+ @trigger.at :hour=>@hours, :minute=>@minutes
40
+ end
41
+
42
+ should "set the trigger's cron entry's hours" do
43
+ assert_equal [@hours], @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@hours)
44
+ end
45
+
46
+ should "set the trigger's cron entry's minutes" do
47
+ assert_equal [@minutes], @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@minutes)
48
+ end
49
+
50
+ context "that are nil" do
51
+ setup do
52
+ @hours, @minutes = nil, nil
53
+ end
54
+
55
+ should "raise an exception" do
56
+ assert_raise ChronoTrigger::ConfigurationException do
57
+ @trigger.at :hours=>@hours, :minutes=>@minutes
58
+ end
59
+ end
60
+ end #that are nil
61
+ end #and a call to #at with :hours and :minutes
62
+
63
+
64
+ context "on a call to #every" do
65
+ context "for 10 minutes" do
66
+ setup do
67
+ @minutes = 10
68
+ end
69
+
70
+ context "when called" do
71
+ setup do
72
+ @trigger.every :minutes=>@minutes
73
+ end
74
+
75
+ should "set the trigger's cron entry's minutes to [0, 10,20,30,40,50]" do
76
+ assert_equal [0,10,20,30,40,50], @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@minutes)
77
+ end
78
+
79
+ context "in addition to setting #at to hour 2" do
80
+ setup do
81
+ @hour = 2
82
+ @trigger.at :hour=>@hour
83
+ end
84
+
85
+ should "set the trigger's cron entry's minutes to [0, 10,20,30,40,50]" do
86
+ assert_equal [0,10,20,30,40,50], @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@minutes)
87
+ end
88
+
89
+ should "set the trigger's cron entry's hours to 2" do
90
+ assert_equal [2], @trigger.instance_variable_get(:@cron_entry).instance_variable_get(:@hours)
91
+ end
92
+ end #in addition to setting #{}
93
+ end #when called
94
+ end #for 10 minutes
95
+
96
+ context "for 11 minutes" do
97
+ setup do
98
+ @minutes = 11
99
+ end
100
+
101
+ should "raise an exception" do
102
+ assert_raise ChronoTrigger::ConfigurationException do
103
+ @trigger.every :minutes=>@minutes
104
+ end
105
+ end
106
+ end #for 11 minutes
107
+ end #on a call to #every
108
+
109
+ should "raise an exception on call to #every without minutes or hours" do
110
+ assert_raise ChronoTrigger::ConfigurationException do
111
+ @trigger.every()
112
+ end
113
+ end
114
+ end #A Trigger, @trigger,
115
+
116
+ end
@@ -0,0 +1,11 @@
1
+ trigger "test_trigger" do
2
+ runs { "hello world" }
3
+ on :monday
4
+ at :hour=>3, :minute=>10
5
+ end
6
+
7
+ trigger "test_trigger_2" do
8
+ runs { "hello world 2" }
9
+ on :tuesday
10
+ every :hours=>2, :minutes=>10
11
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gregfitz23-chrono_trigger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Greg Fitzgerald
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-03 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: TODO
17
+ email: greg_fitz@yahoo.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - History.txt
26
+ - Manifest.txt
27
+ - PostInstall.txt
28
+ - README.rdoc
29
+ - VERSION.yml
30
+ - lib/chrono_trigger
31
+ - lib/chrono_trigger/cron_entry.rb
32
+ - lib/chrono_trigger/shell.rb
33
+ - lib/chrono_trigger/tasks.rb
34
+ - lib/chrono_trigger/trigger.rb
35
+ - lib/chrono_trigger.rb
36
+ - lib/triggers
37
+ - lib/triggers/test_triggers.rb
38
+ - test/test_chrono_trigger.rb
39
+ - test/test_cron_entry.rb
40
+ - test/test_helper.rb
41
+ - test/test_shell.rb
42
+ - test/test_trigger.rb
43
+ - test/triggers.rb
44
+ has_rdoc: true
45
+ homepage: ""
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --inline-source
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.2.0
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: TODO
71
+ test_files: []
72
+