viking-biobot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require 'autotest/redgreen'
@@ -0,0 +1,7 @@
1
+ .*swp
2
+ old
3
+ pkg
4
+ test/db.sqlite3
5
+ test.rb
6
+ Session.vim
7
+ config/biobot.yml
data/README ADDED
@@ -0,0 +1 @@
1
+ Biobot is an XMPP bot! :P
@@ -0,0 +1,24 @@
1
+
2
+ Daemonize Library
3
+
4
+ August. 2, 2005 Travis Whitton <whitton@atlantic.net>
5
+
6
+ Daemonize allows you to easily modify any existing Ruby program to run
7
+ as a daemon. See README.rdoc for more details.
8
+
9
+ [How to install]
10
+ 1. su to root
11
+ 2. ruby setup.rb or ruby setup.rb --help for more options
12
+ build the docs if you want to
13
+ 3. rdoc --main README.rdoc lib/daemonize.rb README.rdoc
14
+
15
+ [Copying]
16
+ The Daemonize extension module is copywrited free software by Travis Whitton
17
+ <whitton@atlantic.net>. You can redistribute it under the terms specified in
18
+ the COPYING file of the Ruby distribution.
19
+
20
+ [WARRANTY]
21
+ THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
24
+ PURPOSE.
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |spec|
4
+ spec.name = "biobot"
5
+ spec.summary = "An XMPP bot for Vanderbilt Biostatistics"
6
+ spec.description = "An XMPP bot for Vanderbilt Biostatistics"
7
+ spec.email = "viking415@gmail.com"
8
+ spec.homepage = "http://biostat.mc.vanderbilt.edu"
9
+ spec.authors = ["Jeremy Stephens"]
10
+ spec.add_dependency('activerecord')
11
+ spec.add_dependency('xmpp4r')
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'yaml'
4
+ require 'biobot'
5
+ require 'daemonize'
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: biobot -c <filename>"
10
+
11
+ opts.on("-c", "--config FILENAME", "Specify the configuration file") do |c|
12
+ options[:config] = c
13
+ end
14
+
15
+ opts.on("-d", "--daemonize", "Daemonize the process") do
16
+ options[:daemon] = true
17
+ end
18
+ end.parse!
19
+
20
+ unless options[:config]
21
+ puts "No configuration file specified; see --help"
22
+ exit
23
+ end
24
+ raise Errno::ENOENT unless File.exist?(options[:config])
25
+
26
+ biobot = Biobot::Base.new(YAML.load_file(options[:config]))
27
+ biobot.start
28
+ Signal.trap("TERM") do
29
+ puts "Stopping biobot..."
30
+ biobot.stop
31
+ end
32
+
33
+ Daemonize.daemonize if options[:daemon]
34
+ loop do
35
+ end
@@ -0,0 +1,71 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{biobot}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jeremy Stephens"]
9
+ s.date = %q{2009-06-11}
10
+ s.default_executable = %q{biobot}
11
+ s.description = %q{An XMPP bot for Vanderbilt Biostatistics}
12
+ s.email = %q{viking415@gmail.com}
13
+ s.executables = ["biobot"]
14
+ s.extra_rdoc_files = [
15
+ "README",
16
+ "README.daemonize"
17
+ ]
18
+ s.files = [
19
+ ".autotest",
20
+ ".gitignore",
21
+ "README",
22
+ "README.daemonize",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "bin/biobot",
26
+ "biobot.gemspec",
27
+ "config/biobot.yml-example",
28
+ "lib/biobot.rb",
29
+ "lib/biobot/base.rb",
30
+ "lib/biobot/commands.rb",
31
+ "lib/biobot/commands/greeting.rb",
32
+ "lib/biobot/periodicals.rb",
33
+ "lib/biobot/periodicals/notify.rb",
34
+ "lib/daemonize.rb",
35
+ "test/biobot/commands/test_greeting.rb",
36
+ "test/biobot/periodicals/test_notify.rb",
37
+ "test/biobot/test_base.rb",
38
+ "test/biobot/test_commands.rb",
39
+ "test/biobot/test_periodicals.rb",
40
+ "test/helper.rb"
41
+ ]
42
+ s.homepage = %q{http://biostat.mc.vanderbilt.edu}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.4}
46
+ s.summary = %q{An XMPP bot for Vanderbilt Biostatistics}
47
+ s.test_files = [
48
+ "test/biobot/test_commands.rb",
49
+ "test/biobot/test_periodicals.rb",
50
+ "test/biobot/periodicals/test_notify.rb",
51
+ "test/biobot/test_base.rb",
52
+ "test/biobot/commands/test_greeting.rb",
53
+ "test/helper.rb"
54
+ ]
55
+
56
+ if s.respond_to? :specification_version then
57
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
61
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
62
+ s.add_runtime_dependency(%q<xmpp4r>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<activerecord>, [">= 0"])
65
+ s.add_dependency(%q<xmpp4r>, [">= 0"])
66
+ end
67
+ else
68
+ s.add_dependency(%q<activerecord>, [">= 0"])
69
+ s.add_dependency(%q<xmpp4r>, [">= 0"])
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ xmpp:
2
+ server: localhost.localdomain
3
+ username: biobot
4
+ password: biobot
5
+
6
+ database:
7
+ adapter: sqlite3
8
+ database: test/db.sqlite3
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'xmpp4r'
3
+ require 'active_record'
4
+
5
+ require File.dirname(__FILE__) + '/biobot/base'
6
+ require File.dirname(__FILE__) + '/biobot/commands'
7
+ require File.dirname(__FILE__) + '/biobot/periodicals'
@@ -0,0 +1,60 @@
1
+ module Biobot
2
+ class Base
3
+ @@command_chain = []
4
+ def self.register_command(method)
5
+ @@command_chain << method
6
+ end
7
+
8
+ @@periodicals = []
9
+ def self.register_periodical(method, delay)
10
+ @@periodicals << [method, delay]
11
+ end
12
+
13
+ def initialize(config)
14
+ @username, @password, @server = config['xmpp'].values_at('username', 'password', 'server')
15
+ @jid = @username + "@" + @server
16
+
17
+ # setup active record if database is specified
18
+ if config['database']
19
+ ActiveRecord::Base.establish_connection(config['database'])
20
+ end
21
+
22
+ @client = Jabber::Client.new(@jid)
23
+ @presence = Jabber::Presence.new
24
+
25
+ @client.add_message_callback do |message|
26
+ process(message) if message.body
27
+ end
28
+
29
+ @threads = []
30
+ end
31
+
32
+ def process(message)
33
+ result = nil
34
+ @@command_chain.each do |method|
35
+ result = send(method, message)
36
+ break if result
37
+ end
38
+ result ||= "Huh?"
39
+ message = Jabber::Message.new(message.from, result)
40
+ @client.send(message)
41
+ end
42
+
43
+ def start
44
+ @client.connect(@server)
45
+ @client.auth(@password)
46
+ @client.send(@presence)
47
+
48
+ @@periodicals.each do |(method, delay)|
49
+ thread = Thread.new { loop { self.send(method); sleep(delay) } }
50
+ @threads << thread
51
+ end
52
+ end
53
+
54
+ def stop
55
+ @threads.each { |t| t.exit }
56
+ @threads.clear
57
+ @client.close!
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,10 @@
1
+ module Biobot
2
+ module Commands
3
+ end
4
+ end
5
+
6
+ Dir[File.dirname(__FILE__) + "/commands/*.rb"].each do |filename|
7
+ require filename
8
+ klass = File.basename(filename, '.rb').capitalize
9
+ Biobot::Base.send(:include, Biobot::Commands.const_get(klass))
10
+ end
@@ -0,0 +1,18 @@
1
+ module Biobot
2
+ module Commands
3
+ module Greeting
4
+ def self.included(base)
5
+ base.register_command(:handle_greeting)
6
+ end
7
+
8
+ def handle_greeting(message)
9
+ case message.body.downcase
10
+ when /^hello/, /^hey/, /^hi/, /^sup/, /^greetings/
11
+ 'Hello there!'
12
+ else
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module Biobot
2
+ module Periodicals
3
+ end
4
+ end
5
+
6
+ Dir[File.dirname(__FILE__) + "/periodicals/*.rb"].each do |filename|
7
+ require filename
8
+ klass = File.basename(filename, '.rb').capitalize
9
+ Biobot::Base.send(:include, Biobot::Periodicals.const_get(klass))
10
+ end
@@ -0,0 +1,23 @@
1
+ module Biobot
2
+ module Periodicals
3
+ module Notify
4
+ class Notification < ActiveRecord::Base
5
+ set_table_name 'notifications'
6
+ end
7
+
8
+ def self.included(base)
9
+ base.register_periodical(:handle_notifications, 60)
10
+ end
11
+
12
+ def handle_notifications
13
+ if Notification.count > 0
14
+ Notification.all.each do |notification|
15
+ message = Jabber::Message.new(notification.to, notification.body)
16
+ @client.send(message)
17
+ end
18
+ Notification.delete_all
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ module Daemonize
2
+ VERSION = "0.1.2"
3
+
4
+ # Try to fork if at all possible retrying every 5 sec if the
5
+ # maximum process limit for the system has been reached
6
+ def safefork
7
+ tryagain = true
8
+
9
+ while tryagain
10
+ tryagain = false
11
+ begin
12
+ if pid = fork
13
+ return pid
14
+ end
15
+ rescue Errno::EWOULDBLOCK
16
+ sleep 5
17
+ tryagain = true
18
+ end
19
+ end
20
+ end
21
+
22
+ # This method causes the current running process to become a daemon
23
+ # If closefd is true, all existing file descriptors are closed
24
+ def daemonize(oldmode=0, closefd=false)
25
+ srand # Split rand streams between spawning and daemonized process
26
+ safefork and exit # Fork and exit from the parent
27
+
28
+ # Detach from the controlling terminal
29
+ unless sess_id = Process.setsid
30
+ raise 'Cannot detach from controlled terminal'
31
+ end
32
+
33
+ # Prevent the possibility of acquiring a controlling terminal
34
+ if oldmode.zero?
35
+ trap 'SIGHUP', 'IGNORE'
36
+ exit if pid = safefork
37
+ end
38
+
39
+ Dir.chdir "/" # Release old working directory
40
+ File.umask 0000 # Insure sensible umask
41
+
42
+ if closefd
43
+ # Make sure all file descriptors are closed
44
+ ObjectSpace.each_object(IO) do |io|
45
+ unless [STDIN, STDOUT, STDERR].include?(io)
46
+ io.close rescue nil
47
+ end
48
+ end
49
+ end
50
+
51
+ STDIN.reopen "/dev/null" # Free file descriptors and
52
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible
53
+ STDERR.reopen STDOUT # STDOUT/STDERR should go to a logfile
54
+ return oldmode ? sess_id : 0 # Return value is mostly irrelevant
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + "/../../helper"
2
+
3
+ class TestGreeting < Test::Unit::TestCase
4
+ include Biobot::Commands::Greeting
5
+
6
+ def test_handle_message
7
+ %w{hello hi hey sup greetings}.each do |msg|
8
+ incoming = mock_message('dude@localhost', msg)
9
+ assert_equal 'Hello there!', handle_greeting(incoming)
10
+ end
11
+
12
+ incoming = mock_message('dude@localhost', 'unmatching')
13
+ assert_equal false, handle_greeting(incoming)
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + "/../../helper"
2
+
3
+ class TestNotify < Test::Unit::TestCase
4
+ include Biobot::Periodicals::Notify
5
+
6
+ def setup
7
+ @model = Biobot::Periodicals::Notify::Notification
8
+ @model.stubs(:inspect).returns('Notification')
9
+ @client = stub('Jabber::Client')
10
+ end
11
+
12
+ def test_handling_notifications
13
+ notification = mock("notification", :to => 'foo@localhost', :body => 'huge')
14
+ @model.expects(:count).returns(1)
15
+ @model.expects(:all).returns([notification])
16
+ outgoing = mock_message('biobot@localhost', 'huge')
17
+ Jabber::Message.expects(:new).with('foo@localhost', 'huge').returns(outgoing)
18
+ @client.expects(:send).with(outgoing)
19
+ @model.expects(:delete_all)
20
+
21
+ handle_notifications
22
+ end
23
+ end
@@ -0,0 +1,100 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class TestBase < Test::Unit::TestCase
4
+ def setup
5
+ @client = stub('jabber client', {
6
+ :connect => @client, :auth => nil, :send => nil,
7
+ :add_message_callback => nil
8
+ })
9
+ Jabber::Client.stubs(:new).returns(@client)
10
+
11
+ @presence = stub('jabber presence')
12
+ Jabber::Presence.stubs(:new).returns(@presence)
13
+
14
+ @config = YAML.load(<<-EOF)
15
+ xmpp:
16
+ server: localhost
17
+ username: biobot
18
+ password: secret
19
+ EOF
20
+ end
21
+
22
+ def test_creates_client
23
+ Jabber::Client.expects(:new).with('biobot@localhost').returns(@client)
24
+ Biobot::Base.new(@config)
25
+ end
26
+
27
+ def test_connects_and_authenticates_on_start
28
+ @client.expects(:connect).with('localhost').returns(@client)
29
+ @client.expects(:auth).with('secret')
30
+ Biobot::Base.new(@config).start
31
+ end
32
+
33
+ def test_sends_presence_on_start
34
+ Jabber::Presence.expects(:new).returns(@presence)
35
+ @client.expects(:send).with(@presence)
36
+ Biobot::Base.new(@config).start
37
+ end
38
+
39
+ def test_registers_callback
40
+ @client.expects(:add_message_callback)
41
+ Biobot::Base.new(@config)
42
+ end
43
+
44
+ def test_message_processing_chain
45
+ clear_commands
46
+ Biobot::Base.register_command(:leetsaurus)
47
+ Biobot::Base.register_command(:leetceritops)
48
+ biobot = Biobot::Base.new(@config)
49
+ incoming = mock_message('dude@localhost', 'leetsaurus')
50
+ outgoing = mock_message('biobot@localhost', 'foo')
51
+ biobot.expects(:leetsaurus).with(incoming).returns('foo')
52
+ biobot.expects(:leetceritops).never
53
+ Jabber::Message.expects(:new).with('dude@localhost', 'foo').returns(outgoing)
54
+ @client.expects(:send).with(outgoing)
55
+ biobot.process(incoming)
56
+ clear_commands
57
+ end
58
+
59
+ def test_default_message
60
+ clear_commands
61
+ biobot = Biobot::Base.new(@config)
62
+ incoming = mock_message('dude@localhost', 'leetsaurus')
63
+ outgoing = mock_message('biobot@localhost', 'Huh?')
64
+ Jabber::Message.expects(:new).with('dude@localhost', "Huh?").returns(outgoing)
65
+ @client.expects(:send).with(outgoing)
66
+ biobot.process(incoming)
67
+ clear_commands
68
+ end
69
+
70
+ # can't unstub
71
+ # def test_ignore_composing
72
+ # biobot = Biobot::Base.new(@config)
73
+ # incoming = mock_message('dude@localhost', nil)
74
+ # biobot.expects(:send).never
75
+ # biobot.process(incoming)
76
+ # end
77
+
78
+ def test_timers_for_periodicals_on_start
79
+ clear_periodicals
80
+ Biobot::Base.register_periodical(:leetsaurus, 0.3)
81
+ Thread.expects(:new).once
82
+ Biobot::Base.new(@config).start
83
+ end
84
+
85
+ def test_active_record_usage
86
+ @config['database'] = {
87
+ "adapter" => "sqlite3",
88
+ "database" => "foo.sqlite3"
89
+ }
90
+ assert ActiveRecord::Base
91
+ ActiveRecord::Base.expects(:establish_connection).with(@config['database'])
92
+ Biobot::Base.new(@config)
93
+ end
94
+
95
+ def test_stop
96
+ @client.expects(:close!)
97
+ biobot = Biobot::Base.new(@config)
98
+ biobot.stop
99
+ end
100
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class TestCommands < Test::Unit::TestCase
4
+ def test_truth
5
+ assert true
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/../helper"
2
+
3
+ class TestPeriodicals < Test::Unit::TestCase
4
+ def test_truth
5
+ assert true
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'mocha'
4
+ require 'ruby-debug'
5
+ require 'activerecord'
6
+ require File.dirname(__FILE__) + '/../lib/biobot'
7
+
8
+ module TestHelpers
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ def register_command(*args); end
15
+ def register_periodical(*args); end
16
+ end
17
+
18
+ def mock_message(from, body)
19
+ stub('jabber message', :from => from, :body => body)
20
+ end
21
+
22
+ def clear_commands
23
+ Biobot::Base.send(:class_variable_get, '@@command_chain').clear
24
+ end
25
+
26
+ def clear_periodicals
27
+ Biobot::Base.send(:class_variable_get, '@@periodicals').clear
28
+ end
29
+ end
30
+
31
+ Test::Unit::TestCase.send(:include, TestHelpers)
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: viking-biobot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Stephens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-11 00:00:00 -07:00
13
+ default_executable: biobot
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: xmpp4r
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: An XMPP bot for Vanderbilt Biostatistics
36
+ email: viking415@gmail.com
37
+ executables:
38
+ - biobot
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ - README.daemonize
44
+ files:
45
+ - .autotest
46
+ - .gitignore
47
+ - README
48
+ - README.daemonize
49
+ - Rakefile
50
+ - VERSION
51
+ - bin/biobot
52
+ - biobot.gemspec
53
+ - config/biobot.yml-example
54
+ - lib/biobot.rb
55
+ - lib/biobot/base.rb
56
+ - lib/biobot/commands.rb
57
+ - lib/biobot/commands/greeting.rb
58
+ - lib/biobot/periodicals.rb
59
+ - lib/biobot/periodicals/notify.rb
60
+ - lib/daemonize.rb
61
+ - test/biobot/commands/test_greeting.rb
62
+ - test/biobot/periodicals/test_notify.rb
63
+ - test/biobot/test_base.rb
64
+ - test/biobot/test_commands.rb
65
+ - test/biobot/test_periodicals.rb
66
+ - test/helper.rb
67
+ has_rdoc: false
68
+ homepage: http://biostat.mc.vanderbilt.edu
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.2.0
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: An XMPP bot for Vanderbilt Biostatistics
93
+ test_files:
94
+ - test/biobot/test_commands.rb
95
+ - test/biobot/test_periodicals.rb
96
+ - test/biobot/periodicals/test_notify.rb
97
+ - test/biobot/test_base.rb
98
+ - test/biobot/commands/test_greeting.rb
99
+ - test/helper.rb