ngauthier-active-listener 0.2.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.
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
+