ngauthier-active-listener 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,24 @@
1
+ # Active Listener: Event listening and firing system for ruby
2
+
3
+ ## Description
4
+ This gem allows you to define tasks that can be run at specific time intervals. In the future, we plan to allow event listening and firing.
5
+
6
+ ## Configuration
7
+
8
+ ### Add a config file
9
+
10
+ ### Include in your boot
11
+
12
+ ## Installation
13
+
14
+ ### Latest Stable
15
+ sudo gem install ngauthier-active-listener
16
+
17
+ ### Cutting Edge
18
+ git clone git@github.com:ngauthier/active-listener.git active-listener
19
+ cd active-listener
20
+ rake gem install
21
+
22
+ ## Other notes
23
+ This gem uses Jeweler.
24
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 2
3
+ :patch: 0
4
+ :major: 0
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'active-listener'
3
+
4
+ running = true
5
+ Signal.trap("TERM") do
6
+ running = false
7
+ end
8
+
9
+ if ARGV[0].nil? or ARGV[1].nil? or (ARGV[0] != '--stop' and ARGV[2].nil?)
10
+ puts "USAGE:"
11
+ puts "\tactive-listener <config_file> <log_file> <rake_root>"
12
+ puts "\tactive-listener --stop <pid_file>"
13
+ exit(1)
14
+ end
15
+
16
+ if ARGV[0] == "--stop"
17
+ ActiveListener.stop(:pid_file => ARGV[1])
18
+ exit(0)
19
+ end
20
+
21
+ @al = ActiveListener.new :config => ARGV[0], :log_file => ARGV[1], :rake_root => ARGV[2]
22
+
23
+ if @al.events.empty?
24
+ log = File.new(ARGV[1], 'a')
25
+ log.write "ActiveListener is very boring without events"
26
+ log.close
27
+ running = false
28
+ end
29
+
30
+ while running
31
+ @al.fire_events
32
+ @al.sleep_to_next_event
33
+ end
@@ -0,0 +1,124 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ class ActiveListener
5
+ attr_reader :events
6
+
7
+ def self.autostart(opts = {})
8
+ begin
9
+ config_file = File.expand_path(opts[:config])
10
+ pid_file = File.expand_path(opts[:pid_file])
11
+ log_file = File.expand_path(opts[:log_file])
12
+ rake_root = File.expand_path(opts[:rake_root])
13
+ rescue
14
+ raise "Need :config :pid_file :log_file :rake_root"
15
+ end
16
+ ActiveListener.stop(opts)
17
+ command = [
18
+ "start-stop-daemon --start",
19
+ "--make-pidfile --pidfile #{pid_file}",
20
+ "--background",
21
+ "--exec #{File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'active-listener'))}",
22
+ "--chdir #{File.expand_path(File.dirname(__FILE__))}",
23
+ "--",
24
+ "#{config_file}",
25
+ "#{log_file}",
26
+ "#{rake_root}"
27
+ ].join(" ")
28
+ `#{command}`
29
+ end
30
+
31
+ def self.stop(opts = {})
32
+ pid_file = opts[:pid_file]
33
+ `start-stop-daemon --stop --oknodo --quiet --pidfile #{File.expand_path(pid_file)}`
34
+ end
35
+
36
+ def initialize(opts = {})
37
+ self.events = []
38
+ self.log_file = opts[:log_file]
39
+ self.rake_root = opts[:rake_root]
40
+ clear_log
41
+ log("ActiveListener Initialized")
42
+ load_events(opts[:config])
43
+ end
44
+
45
+ def add_event(evt)
46
+ self.events.push(evt)
47
+ log("Added Event #{evt.inspect}")
48
+ end
49
+
50
+ def fire_events
51
+ self.events.select{|e| e.time_to_fire < 0}.each do |evt|
52
+ log("Firing event: #{evt.inspect}")
53
+ log(evt.fire(:rake_root => rake_root))
54
+ end
55
+ end
56
+
57
+ def sleep_to_next_event
58
+ self.events.sort{|x,y| x.time_to_fire <=> y.time_to_fire}
59
+ if self.events.first
60
+ sleep_time = self.events.first.time_to_fire+0.01
61
+ else
62
+ sleep_time = 0.5
63
+ end
64
+ log("Sleeping for #{sleep_time}")
65
+ sleep(sleep_time)
66
+ end
67
+
68
+ class Event
69
+ def initialize(opts = {})
70
+ self.task = opts[:task] || opts["task"]
71
+ self.period = opts[:period] || opts["period"]
72
+ self.last_fire = 0
73
+ end
74
+
75
+ def time_to_fire
76
+ last_fire + period - Time.now.to_f
77
+ end
78
+
79
+ def fire(opts = {})
80
+ self.last_fire = Time.now.to_f
81
+ Dir.chdir(opts[:rake_root]) if opts[:rake_root]
82
+ `rake #{task}`
83
+ opts[:rake_root]
84
+ end
85
+
86
+ private
87
+
88
+ attr_accessor :task, :period, :last_fire
89
+
90
+ end
91
+
92
+ private
93
+
94
+ attr_writer :events
95
+ attr_accessor :log_file, :rake_root
96
+
97
+ def load_events(config_file)
98
+ return if config_file.nil?
99
+ unless File.exists?(config_file)
100
+ log("Config file not found at #{config_file}")
101
+ return
102
+ end
103
+ log("Loading tasks from #{config_file}")
104
+ f = File.new(config_file,'r')
105
+ yml = YAML.load(f)
106
+ yml["tasks"].each do |task|
107
+ self.add_event(Event.new(task))
108
+ end
109
+ end
110
+
111
+ def clear_log
112
+ return unless log_file
113
+ FileUtils.rm_f log_file
114
+ end
115
+
116
+ def log(text)
117
+ return unless log_file
118
+ f = File.new(log_file, 'a')
119
+ f.write text
120
+ f.write "\n"
121
+ f.close
122
+ end
123
+
124
+ end
@@ -0,0 +1,6 @@
1
+ ---
2
+ tasks:
3
+ - task: test:touch_file
4
+ period: 1
5
+ - task: test:touch_file
6
+ period: 3
@@ -0,0 +1,118 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'active-listener'
3
+
4
+ class ActiveListenerTest < Test::Unit::TestCase
5
+ context "A new listener" do
6
+
7
+ setup do
8
+ @al = ActiveListener.new({})
9
+ end
10
+
11
+ should "have an empty events list" do
12
+ assert @al.events.empty?
13
+ end
14
+
15
+ should "be able to add an event" do
16
+ @al.add_event(
17
+ ActiveListener::Event.new(
18
+ :task => "meh",
19
+ :period => 5
20
+ )
21
+ )
22
+ assert !@al.events.empty?
23
+ end
24
+
25
+ should "sleep when it has no events" do
26
+ @al.sleep_to_next_event
27
+ end
28
+
29
+ context "with a file timer" do
30
+ setup do
31
+ @al.add_event(
32
+ ActiveListener::Event.new(
33
+ :task => "test:touch_file",
34
+ :period => 1
35
+ )
36
+ )
37
+ @sample_file = File.join(File.dirname(__FILE__),'sample.txt')
38
+ FileUtils.rm_f(@sample_file)
39
+ end
40
+
41
+ teardown do
42
+ FileUtils.rm_f(File.join(File.dirname(__FILE__),'sample.txt'))
43
+ end
44
+
45
+ should "touch a file" do
46
+ assert !File.exists?(@sample_file)
47
+ @al.fire_events
48
+ assert File.exists?(@sample_file)
49
+ end
50
+
51
+ should "need to be fired when added" do
52
+ assert @al.events[0].time_to_fire < 0
53
+ end
54
+
55
+ should "need to be fired 1 second after being fired" do
56
+ @al.fire_events
57
+ assert @al.events[0].time_to_fire > 0
58
+ FileUtils.rm_f(@sample_file)
59
+ @al.fire_events
60
+ assert !File.exists?(@sample_file)
61
+ @al.sleep_to_next_event
62
+ assert @al.events[0].time_to_fire < 0
63
+ assert !File.exists?(@sample_file)
64
+ @al.fire_events
65
+ assert File.exists?(@sample_file)
66
+ assert @al.events[0].time_to_fire > 0
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+ context "A listener" do
73
+ setup do
74
+ @config_path = File.join(File.dirname(__FILE__), 'active_listener.yml')
75
+ @sample_file = File.join(File.dirname(__FILE__),'sample.txt')
76
+ FileUtils.rm_f @sample_file
77
+ end
78
+
79
+ should "be able to read events from yaml" do
80
+ @al = ActiveListener.new(:config => @config_path)
81
+ assert @al.events.size > 0
82
+ assert !File.exists?(@sample_file)
83
+ @al.fire_events
84
+ assert File.exists?(@sample_file)
85
+ end
86
+
87
+ end
88
+
89
+ context "An autostarted listener" do
90
+
91
+ setup do
92
+ ActiveListener.autostart(
93
+ :config => File.join(File.dirname(__FILE__), 'active_listener.yml'),
94
+ :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid'),
95
+ :log_file => File.join(File.dirname(__FILE__), 'active_listener.log'),
96
+ :rake_root => File.join(File.dirname(__FILE__), '..')
97
+ )
98
+ @sample_file = File.join(File.dirname(__FILE__),'sample.txt')
99
+ end
100
+
101
+ teardown do
102
+ ActiveListener.stop(
103
+ :pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid')
104
+ )
105
+ FileUtils.rm_f(File.join(File.dirname(__FILE__),'sample.txt'))
106
+ end
107
+
108
+ should "load events from the config file" do
109
+ sleep(1)
110
+ assert File.exists?(@sample_file)
111
+ FileUtils.rm_f(@sample_file)
112
+ assert !File.exists?(@sample_file)
113
+ sleep(1)
114
+ assert File.exists?(@sample_file)
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ class Test::Unit::TestCase
8
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ngauthier-active-listener
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Gauthier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-29 00:00:00 -08:00
13
+ default_executable: active-listener
14
+ dependencies: []
15
+
16
+ description: TODO
17
+ email: nick@smartlogicsolutions.com
18
+ executables:
19
+ - active-listener
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - VERSION.yml
26
+ - README.markdown
27
+ - bin/active-listener
28
+ - lib/activelistener
29
+ - lib/active-listener.rb
30
+ - test/test_helper.rb
31
+ - test/active_listener.log
32
+ - test/active_listener.pid
33
+ - test/active_listener.yml
34
+ - test/active_listener_test.rb
35
+ has_rdoc: true
36
+ homepage: http://github.com/ngauthier/active-listener
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --inline-source
40
+ - --charset=UTF-8
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.2.0
59
+ signing_key:
60
+ specification_version: 2
61
+ summary: TODO
62
+ test_files: []
63
+