viking-biobot 0.0.1

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 @@
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