safubot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.md +19 -0
  4. data/README.md +43 -0
  5. data/Rakefile +1 -0
  6. data/doc/Gemfile.html +119 -0
  7. data/doc/Object.html +171 -0
  8. data/doc/Rakefile.html +117 -0
  9. data/doc/Safubot.html +173 -0
  10. data/doc/Safubot/Bot.html +827 -0
  11. data/doc/Safubot/Evented.html +346 -0
  12. data/doc/Safubot/KnownUser.html +344 -0
  13. data/doc/Safubot/Log.html +254 -0
  14. data/doc/Safubot/Query.html +217 -0
  15. data/doc/Safubot/Request.html +201 -0
  16. data/doc/Safubot/Response.html +174 -0
  17. data/doc/Safubot/Test.html +244 -0
  18. data/doc/Safubot/Twitter.html +153 -0
  19. data/doc/Safubot/Twitter/Bot.html +591 -0
  20. data/doc/Safubot/Twitter/DirectMessage.html +327 -0
  21. data/doc/Safubot/Twitter/Tweet.html +522 -0
  22. data/doc/Safubot/XMPP.html +153 -0
  23. data/doc/Safubot/XMPP/Bot.html +403 -0
  24. data/doc/Safubot/XMPP/Message.html +298 -0
  25. data/doc/created.rid +14 -0
  26. data/doc/foo_rb.html +115 -0
  27. data/doc/images/add.png +0 -0
  28. data/doc/images/brick.png +0 -0
  29. data/doc/images/brick_link.png +0 -0
  30. data/doc/images/bug.png +0 -0
  31. data/doc/images/bullet_black.png +0 -0
  32. data/doc/images/bullet_toggle_minus.png +0 -0
  33. data/doc/images/bullet_toggle_plus.png +0 -0
  34. data/doc/images/date.png +0 -0
  35. data/doc/images/delete.png +0 -0
  36. data/doc/images/find.png +0 -0
  37. data/doc/images/loadingAnimation.gif +0 -0
  38. data/doc/images/macFFBgHack.png +0 -0
  39. data/doc/images/package.png +0 -0
  40. data/doc/images/page_green.png +0 -0
  41. data/doc/images/page_white_text.png +0 -0
  42. data/doc/images/page_white_width.png +0 -0
  43. data/doc/images/plugin.png +0 -0
  44. data/doc/images/ruby.png +0 -0
  45. data/doc/images/tag_blue.png +0 -0
  46. data/doc/images/tag_green.png +0 -0
  47. data/doc/images/transparent.png +0 -0
  48. data/doc/images/wrench.png +0 -0
  49. data/doc/images/wrench_orange.png +0 -0
  50. data/doc/images/zoom.png +0 -0
  51. data/doc/index.html +112 -0
  52. data/doc/js/darkfish.js +153 -0
  53. data/doc/js/jquery.js +18 -0
  54. data/doc/js/navigation.js +142 -0
  55. data/doc/js/search.js +94 -0
  56. data/doc/js/search_index.js +1 -0
  57. data/doc/js/searcher.js +228 -0
  58. data/doc/lib/safubot/bot_rb.html +115 -0
  59. data/doc/lib/safubot/evented_rb.html +115 -0
  60. data/doc/lib/safubot/known_user_rb.html +115 -0
  61. data/doc/lib/safubot/log_rb.html +115 -0
  62. data/doc/lib/safubot/safubot_rb.html +115 -0
  63. data/doc/lib/safubot/spec/bot_spec_rb.html +115 -0
  64. data/doc/lib/safubot/spec/twitter_spec_rb.html +137 -0
  65. data/doc/lib/safubot/test_helper_rb.html +115 -0
  66. data/doc/lib/safubot/twitter_rb.html +115 -0
  67. data/doc/lib/safubot/version_rb.html +115 -0
  68. data/doc/lib/safubot/xmpp_rb.html +115 -0
  69. data/doc/lib/safubot_rb.html +115 -0
  70. data/doc/rdoc.css +543 -0
  71. data/doc/table_of_contents.html +224 -0
  72. data/lib/safubot.rb +20 -0
  73. data/lib/safubot/bot.rb +177 -0
  74. data/lib/safubot/evented.rb +52 -0
  75. data/lib/safubot/known_user.rb +27 -0
  76. data/lib/safubot/log.rb +21 -0
  77. data/lib/safubot/test_helper.rb +62 -0
  78. data/lib/safubot/twitter.rb +279 -0
  79. data/lib/safubot/version.rb +3 -0
  80. data/lib/safubot/xmpp.rb +144 -0
  81. data/safubot.gemspec +32 -0
  82. data/spec/fixtures/twitter/direct_message +1 -0
  83. data/spec/fixtures/twitter/tweet +1 -0
  84. data/spec/fixtures/xmpp/message +3 -0
  85. data/spec/helper.rb +12 -0
  86. data/spec/safubot/bot_spec.rb +41 -0
  87. data/spec/safubot/evented_spec.rb +45 -0
  88. data/spec/safubot/known_user_spec.rb +22 -0
  89. data/spec/safubot/twitter_spec.rb +60 -0
  90. data/spec/safubot/xmpp_spec.rb +35 -0
  91. metadata +260 -0
@@ -0,0 +1,224 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
6
+
7
+ <title>Table of Contents</title>
8
+
9
+ <link type="text/css" media="screen" href="./rdoc.css" rel="stylesheet">
10
+
11
+ <script type="text/javascript">
12
+ var rdoc_rel_prefix = "./";
13
+ </script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="./js/jquery.js"></script>
16
+ <script type="text/javascript" charset="utf-8" src="./js/navigation.js"></script>
17
+ <script type="text/javascript" charset="utf-8" src="./js/search_index.js"></script>
18
+ <script type="text/javascript" charset="utf-8" src="./js/search.js"></script>
19
+ <script type="text/javascript" charset="utf-8" src="./js/searcher.js"></script>
20
+ <script type="text/javascript" charset="utf-8" src="./js/darkfish.js"></script>
21
+
22
+
23
+ <body class="indexpage">
24
+ <h1>Table of Contents</h1>
25
+
26
+ <h2>Pages</h2>
27
+ <ul>
28
+ <li class="file">
29
+ <a href="Gemfile.html">Gemfile</a>
30
+ </li>
31
+ <li class="file">
32
+ <a href="Rakefile.html">Rakefile</a>
33
+ </li>
34
+
35
+ </ul>
36
+
37
+ <h2 id="classes">Classes/Modules</h2>
38
+ <ul>
39
+ <li class="module">
40
+ <a href="Safubot.html">Safubot</a>
41
+ </li>
42
+ <li class="class">
43
+ <a href="Safubot/Bot.html">Safubot::Bot</a>
44
+ </li>
45
+ <li class="module">
46
+ <a href="Safubot/Evented.html">Safubot::Evented</a>
47
+ </li>
48
+ <li class="class">
49
+ <a href="Safubot/KnownUser.html">Safubot::KnownUser</a>
50
+ </li>
51
+ <li class="module">
52
+ <a href="Safubot/Log.html">Safubot::Log</a>
53
+ </li>
54
+ <li class="class">
55
+ <a href="Safubot/Query.html">Safubot::Query</a>
56
+ </li>
57
+ <li class="class">
58
+ <a href="Safubot/Request.html">Safubot::Request</a>
59
+ </li>
60
+ <li class="class">
61
+ <a href="Safubot/Response.html">Safubot::Response</a>
62
+ </li>
63
+ <li class="module">
64
+ <a href="Safubot/Test.html">Safubot::Test</a>
65
+ </li>
66
+ <li class="module">
67
+ <a href="Safubot/Twitter.html">Safubot::Twitter</a>
68
+ </li>
69
+ <li class="class">
70
+ <a href="Safubot/Twitter/Bot.html">Safubot::Twitter::Bot</a>
71
+ </li>
72
+ <li class="class">
73
+ <a href="Safubot/Twitter/DirectMessage.html">Safubot::Twitter::DirectMessage</a>
74
+ </li>
75
+ <li class="class">
76
+ <a href="Safubot/Twitter/Tweet.html">Safubot::Twitter::Tweet</a>
77
+ </li>
78
+ <li class="module">
79
+ <a href="Safubot/XMPP.html">Safubot::XMPP</a>
80
+ </li>
81
+ <li class="class">
82
+ <a href="Safubot/XMPP/Bot.html">Safubot::XMPP::Bot</a>
83
+ </li>
84
+ <li class="class">
85
+ <a href="Safubot/XMPP/Message.html">Safubot::XMPP::Message</a>
86
+ </li>
87
+ <li class="class">
88
+ <a href="Object.html">Object</a>
89
+ </li>
90
+
91
+ </ul>
92
+
93
+ <h2 id="methods">Methods</h2>
94
+ <ul>
95
+
96
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-c-5B-5D">::[] &mdash; Safubot::Twitter::Tweet</a>
97
+
98
+ <li class="method"><a href="Safubot/KnownUser.html#method-c-by_twitter">::by_twitter &mdash; Safubot::KnownUser</a>
99
+
100
+ <li class="method"><a href="Safubot/KnownUser.html#method-c-by_xmpp">::by_xmpp &mdash; Safubot::KnownUser</a>
101
+
102
+ <li class="method"><a href="Safubot/Test.html#method-c-clean_environment">::clean_environment &mdash; Safubot::Test</a>
103
+
104
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-c-from">::from &mdash; Safubot::Twitter::Tweet</a>
105
+
106
+ <li class="method"><a href="Safubot/XMPP/Message.html#method-c-from">::from &mdash; Safubot::XMPP::Message</a>
107
+
108
+ <li class="method"><a href="Safubot/Twitter/DirectMessage.html#method-c-from">::from &mdash; Safubot::Twitter::DirectMessage</a>
109
+
110
+ <li class="method"><a href="Safubot/Log.html#method-c-method_missing">::method_missing &mdash; Safubot::Log</a>
111
+
112
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-c-new">::new &mdash; Safubot::Twitter::Bot</a>
113
+
114
+ <li class="method"><a href="Safubot/Bot.html#method-c-new">::new &mdash; Safubot::Bot</a>
115
+
116
+ <li class="method"><a href="Safubot/XMPP/Bot.html#method-c-new">::new &mdash; Safubot::XMPP::Bot</a>
117
+
118
+ <li class="method"><a href="Safubot/Log.html#method-c-path-3D">::path= &mdash; Safubot::Log</a>
119
+
120
+ <li class="method"><a href="Safubot/Test.html#method-c-request">::request &mdash; Safubot::Test</a>
121
+
122
+ <li class="method"><a href="Safubot/Bot.html#method-i-answer">#answer &mdash; Safubot::Bot</a>
123
+
124
+ <li class="method"><a href="Safubot/Evented.html#method-i-bind">#bind &mdash; Safubot::Evented</a>
125
+
126
+ <li class="method"><a href="Safubot/Bot.html#method-i-concurrently">#concurrently &mdash; Safubot::Bot</a>
127
+
128
+ <li class="method"><a href="Safubot/Bot.html#method-i-cycle">#cycle &mdash; Safubot::Bot</a>
129
+
130
+ <li class="method"><a href="Safubot/Bot.html#method-i-dispatch">#dispatch &mdash; Safubot::Bot</a>
131
+
132
+ <li class="method"><a href="Safubot/Evented.html#method-i-emit">#emit &mdash; Safubot::Evented</a>
133
+
134
+ <li class="method"><a href="Safubot/Bot.html#method-i-enable_twitter">#enable_twitter &mdash; Safubot::Bot</a>
135
+
136
+ <li class="method"><a href="Safubot/Bot.html#method-i-enable_xmpp">#enable_xmpp &mdash; Safubot::Bot</a>
137
+
138
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-handle_message">#handle_message &mdash; Safubot::Twitter::Bot</a>
139
+
140
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-handle_request">#handle_request &mdash; Safubot::Twitter::Bot</a>
141
+
142
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-handle_tweet">#handle_tweet &mdash; Safubot::Twitter::Bot</a>
143
+
144
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-header_mentions">#header_mentions &mdash; Safubot::Twitter::Tweet</a>
145
+
146
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-make_request">#make_request &mdash; Safubot::Twitter::Tweet</a>
147
+
148
+ <li class="method"><a href="Safubot/Twitter/DirectMessage.html#method-i-make_request">#make_request &mdash; Safubot::Twitter::DirectMessage</a>
149
+
150
+ <li class="method"><a href="Safubot/Query.html#method-i-make_request">#make_request &mdash; Safubot::Query</a>
151
+
152
+ <li class="method"><a href="Safubot/XMPP/Message.html#method-i-make_request">#make_request &mdash; Safubot::XMPP::Message</a>
153
+
154
+ <li class="method"><a href="Safubot/KnownUser.html#method-i-merge">#merge &mdash; Safubot::KnownUser</a>
155
+
156
+ <li class="method"><a href="Safubot/Evented.html#method-i-on">#on &mdash; Safubot::Evented</a>
157
+
158
+ <li class="method"><a href="Safubot/Evented.html#method-i-once">#once &mdash; Safubot::Evented</a>
159
+
160
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-original_tweet">#original_tweet &mdash; Safubot::Twitter::Tweet</a>
161
+
162
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-posted_at">#posted_at &mdash; Safubot::Twitter::Tweet</a>
163
+
164
+ <li class="method"><a href="Safubot/Bot.html#method-i-process">#process &mdash; Safubot::Bot</a>
165
+
166
+ <li class="method"><a href="Safubot/Bot.html#method-i-process_request">#process_request &mdash; Safubot::Bot</a>
167
+
168
+ <li class="method"><a href="Safubot/Bot.html#method-i-pull">#pull &mdash; Safubot::Bot</a>
169
+
170
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-pull">#pull &mdash; Safubot::Twitter::Bot</a>
171
+
172
+ <li class="method"><a href="Safubot/Bot.html#method-i-push">#push &mdash; Safubot::Bot</a>
173
+
174
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-reply">#reply &mdash; Safubot::Twitter::Bot</a>
175
+
176
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-reply_header">#reply_header &mdash; Safubot::Twitter::Bot</a>
177
+
178
+ <li class="method"><a href="Safubot/Bot.html#method-i-request_error">#request_error &mdash; Safubot::Bot</a>
179
+
180
+ <li class="method"><a href="Safubot/Bot.html#method-i-respond">#respond &mdash; Safubot::Bot</a>
181
+
182
+ <li class="method"><a href="Safubot/Bot.html#method-i-respond_now">#respond_now &mdash; Safubot::Bot</a>
183
+
184
+ <li class="method"><a href="Safubot/XMPP/Bot.html#method-i-run">#run &mdash; Safubot::XMPP::Bot</a>
185
+
186
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-run">#run &mdash; Safubot::Twitter::Bot</a>
187
+
188
+ <li class="method"><a href="Safubot/Bot.html#method-i-run">#run &mdash; Safubot::Bot</a>
189
+
190
+ <li class="method"><a href="Safubot/XMPP/Bot.html#method-i-send">#send &mdash; Safubot::XMPP::Bot</a>
191
+
192
+ <li class="method"><a href="Safubot/Twitter/Bot.html#method-i-send">#send &mdash; Safubot::Twitter::Bot</a>
193
+
194
+ <li class="method"><a href="Safubot/Bot.html#method-i-stop">#stop &mdash; Safubot::Bot</a>
195
+
196
+ <li class="method"><a href="Safubot/XMPP/Bot.html#method-i-stop">#stop &mdash; Safubot::XMPP::Bot</a>
197
+
198
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-targetless_text">#targetless_text &mdash; Safubot::Twitter::Tweet</a>
199
+
200
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-text">#text &mdash; Safubot::Twitter::Tweet</a>
201
+
202
+ <li class="method"><a href="Safubot/Twitter/DirectMessage.html#method-i-text">#text &mdash; Safubot::Twitter::DirectMessage</a>
203
+
204
+ <li class="method"><a href="Safubot/KnownUser.html#method-i-tweets">#tweets &mdash; Safubot::KnownUser</a>
205
+
206
+ <li class="method"><a href="Safubot/Evented.html#method-i-unbind">#unbind &mdash; Safubot::Evented</a>
207
+
208
+ <li class="method"><a href="Safubot/XMPP/Message.html#method-i-user">#user &mdash; Safubot::XMPP::Message</a>
209
+
210
+ <li class="method"><a href="Safubot/Twitter/DirectMessage.html#method-i-user">#user &mdash; Safubot::Twitter::DirectMessage</a>
211
+
212
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-user">#user &mdash; Safubot::Twitter::Tweet</a>
213
+
214
+ <li class="method"><a href="Safubot/Twitter/Tweet.html#method-i-username">#username &mdash; Safubot::Twitter::Tweet</a>
215
+
216
+ </ul>
217
+
218
+
219
+ <footer id="validator-badges">
220
+ <p><a href="http://validator.w3.org/check/referer">[Validate]</a>
221
+ <p>Generated by <a href="https://github.com/rdoc/rdoc">RDoc</a> 3.11.
222
+ <p>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish Rdoc Generator</a> 3.
223
+ </footer>
224
+
data/lib/safubot.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "eventmachine"
2
+ require "mongo_mapper"
3
+
4
+ require "safubot/log"
5
+ require "safubot/evented"
6
+ require "safubot/known_user"
7
+ require "safubot/bot"
8
+ require "safubot/twitter"
9
+ require "safubot/xmpp"
10
+ require "safubot/test_helper"
11
+
12
+ module Safubot
13
+ class << self
14
+ attr_accessor :mode
15
+ end
16
+ end
17
+
18
+ Safubot::mode ||= :production
19
+
20
+
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Safubot
4
+ # Defines elements of the input queue, agnostic of the transfer medium.
5
+ # May be extended by service-specific modules.
6
+ class Request
7
+ include MongoMapper::Document
8
+ safe
9
+ key :errors, Hash # Errors encountered during processing.
10
+ key :processed, Boolean, :default => false # Have we processed this request?
11
+ key :success, Boolean, :default => false # Did we *successfully* process this request?
12
+ key :text, String # The actual content.
13
+ belongs_to :source, :polymorphic => true # The concrete medium-specific source.
14
+ belongs_to :user, :polymorphic => true
15
+ many :responses, :class_name => "Safubot::Response"
16
+ timestamps!
17
+
18
+ attr_accessor :callback # If a callback is set, responses will be sent to it instead of Response.
19
+
20
+ end
21
+
22
+ # Defines elements of the output queue, agnostic of the transfer medium.
23
+ # May be extended by service-specific modules.
24
+ class Response
25
+ include MongoMapper::Document
26
+ safe
27
+ key :errors, Hash # Errors encountered during dispatch by timestamp.
28
+ key :dispatched, Boolean, :default => false
29
+ key :text, String
30
+ belongs_to :request, :polymorphic => true
31
+ timestamps!
32
+ end
33
+
34
+ # Here's where we define the main Safubot instance.
35
+ class Bot
36
+ include Evented
37
+
38
+ attr_reader :opts, :twitter, :xmpp
39
+
40
+ def request_error(req, e)
41
+ Log.error "Error processing #{req.source.class} '#{req.text}': #{e}\n#{e.backtrace.join("\n\t")}"
42
+ req.errors[Time.now] = e
43
+ req.save
44
+ emit(:request_error, req, e)
45
+ end
46
+
47
+ def process_request(req)
48
+ begin
49
+ emit(:request, req)
50
+ rescue Exception => e
51
+ request_error(req, e)
52
+ ensure
53
+ req.processed = true
54
+ req.save
55
+ end
56
+ end
57
+
58
+ def dispatch(resp)
59
+ # Performs appropriate dispatch operation for response type.
60
+ begin
61
+ source = resp.request.source
62
+ if Safubot::mode != :production
63
+ Log.info "#{source.class} Response to #{source.username}: #{resp.text}"
64
+ else
65
+ if @twitter && [Twitter::Tweet, Twitter::DirectMessage].include?(source.class)
66
+ @twitter.send(resp)
67
+ elsif @xmpp && [XMPP::Message].include?(source.class)
68
+ @xmpp.send(resp)
69
+ else
70
+ raise NotImplementedError, "Don't know how to send response to a #{source.class}!"
71
+ end
72
+ end
73
+
74
+ resp.dispatched = true
75
+ resp.save
76
+ rescue Exception => e
77
+ Log.error "Error dispatching #{source.class} '#{resp.text}': #{e}"
78
+ resp.errors[Time.now] = e
79
+ resp.save
80
+ emit(:dispatch_error, resp, e)
81
+ end
82
+ end
83
+
84
+ def pull
85
+ @twitter.pull
86
+ end
87
+
88
+ def process
89
+ Request.where(:processed => false).each do |req|
90
+ concurrently(req) { process_request(req) }
91
+ end
92
+ end
93
+
94
+ # Adds a response to the queue.
95
+ # @param req Request to respond to.
96
+ # @param text Contents of the response.
97
+ def respond(req, text)
98
+ Log.info("#{req.user.name}: #{req.text}\nsafubot: #{text}")
99
+ Response.create(:request => req, :text => text)
100
+ end
101
+
102
+ # Respond + push
103
+ def respond_now(req, text)
104
+ respond(req, text)
105
+ push
106
+ end
107
+
108
+ def push
109
+ Response.where(:dispatched => false).each(&method(:dispatch))
110
+ end
111
+
112
+ def cycle
113
+ pull; process; push
114
+ end
115
+
116
+ # Wraps EM::defer with error handling and response pushing for the given request.
117
+ # @param req The Request being processed.
118
+ # @param blk The operation to be performed in a separate thread.
119
+ def concurrently(req, &blk)
120
+ EventMachine::defer do
121
+ begin
122
+ blk.call
123
+ rescue Exception => e
124
+ request_error(req, e)
125
+ end
126
+
127
+ push
128
+ end
129
+ end
130
+
131
+ def run
132
+ EventMachine::run do
133
+ EM::error_handler do |e|
134
+ if e.is_a? Interrupt
135
+ Log.error("Received interrupt, shutting down.")
136
+ stop
137
+ else
138
+ Log.error("Unhandled exception: #{e}\n#{e.backtrace.join("\t\n")}")
139
+ end
140
+ end
141
+
142
+ cycle
143
+ @twitter.run if @twitter
144
+ @xmpp.run if @xmpp
145
+ end
146
+ end
147
+
148
+ def stop
149
+ @twitter.stop if @twitter
150
+ @xmpp.stop if @xmpp
151
+ EM::stop_event_loop
152
+ end
153
+
154
+ def enable_twitter(opts={})
155
+ @twitter = Twitter::Bot.new(opts)
156
+ @twitter.on(:request) do |req|
157
+ process; push
158
+ end
159
+ end
160
+
161
+ def enable_xmpp(options={})
162
+ defaults = { :jid => nil, :password => nil }
163
+ @xmpp = XMPP::Bot.new(defaults.merge(options))
164
+ @xmpp.on(:request) do |req|
165
+ process; push
166
+ end
167
+ end
168
+
169
+ def initialize(options={})
170
+ defaults = { :database => "safubot" }
171
+ @opts = defaults.merge(options)
172
+ MongoMapper.database = @opts[:database]
173
+ MongoMapper.connection = Mongo::Connection.new('localhost', 27017, :pool_size => 5)
174
+ @handlers = {}
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,52 @@
1
+ module Safubot
2
+ ##
3
+ # A mixin granting simple event firing and handler binding.
4
+ module Evented
5
+ ##
6
+ # Binds an event handler, which is a Hash of the form:
7
+ #
8
+ # { :evid => Symbol, :id => Symbol, :repeat => Boolean, :proc => Proc }
9
+ #
10
+ # See {on}[rdoc-ref:Safubot::Evented#on] and {once}[rdoc-ref:Safubot::Evented#once] for sugar.
11
+ def bind(evid, handler)
12
+ @handlers ||= {}
13
+ @handlers[evid] ||= {}
14
+ handler[:evid] = evid
15
+ handler[:id] ||= @handlers[evid].length
16
+ @handlers[evid][handler[:id]] = handler
17
+ end
18
+
19
+ ##
20
+ # Unbinds the given handler.
21
+ def unbind(handler)
22
+ @handlers[handler[:evid]].delete(handler[:id])
23
+ end
24
+
25
+ ##
26
+ # Binds a block to the specified event id.
27
+ # Returns the bound handler.
28
+ def on(evid, opts={}, &callback)
29
+ bind(evid, { :repeat => true, :proc => callback }.merge(opts))
30
+ end
31
+
32
+ ##
33
+ # Binds a block to the specified event id, to be executed only once.
34
+ # Returns the bound handler.
35
+ def once(evid, opts={}, &callback)
36
+ bind(evid, { :repeat => false, :proc => callback }.merge(opts))
37
+ end
38
+
39
+ ##
40
+ # Fires an evid event with the given arguments.
41
+ def emit(evid, *args)
42
+ return unless @handlers && @handlers[evid]
43
+ @handlers[evid].each do |id, handler|
44
+ begin
45
+ handler[:proc].call(*args)
46
+ ensure
47
+ @handlers[evid].delete(id) if !handler[:repeat]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end