robut 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +11 -0
- data/Gemfile +2 -3
- data/README.rdoc +38 -19
- data/examples/Chatfile +10 -4
- data/lib/robut.rb +3 -0
- data/lib/robut/connection.rb +10 -72
- data/lib/robut/plugin.rb +94 -13
- data/lib/robut/plugin/echo.rb +3 -13
- data/lib/robut/plugin/google_images.rb +17 -0
- data/lib/robut/plugin/help.rb +7 -15
- data/lib/robut/plugin/meme.rb +22 -53
- data/lib/robut/plugin/pick.rb +18 -0
- data/lib/robut/plugin/ping.rb +3 -9
- data/lib/robut/plugin/quips.rb +60 -0
- data/lib/robut/plugin/say.rb +6 -12
- data/lib/robut/plugin/stock.rb +45 -0
- data/lib/robut/pm.rb +40 -0
- data/lib/robut/presence.rb +35 -0
- data/lib/robut/room.rb +30 -0
- data/lib/robut/version.rb +1 -1
- data/test/mocks/connection_mock.rb +2 -18
- data/test/mocks/presence_mock.rb +25 -0
- data/test/test_helper.rb +3 -1
- data/test/unit/connection_test.rb +58 -25
- data/test/unit/plugin/alias_test.rb +5 -4
- data/test/unit/plugin/echo_test.rb +5 -4
- data/test/unit/plugin/help_test.rb +4 -3
- data/test/unit/plugin/later_test.rb +7 -6
- data/test/unit/plugin/lunch_test.rb +6 -5
- data/test/unit/plugin/pick_test.rb +35 -0
- data/test/unit/plugin/ping_test.rb +4 -3
- data/test/unit/plugin/quips_test.rb +58 -0
- data/test/unit/plugin/say_test.rb +4 -3
- data/test/unit/plugin/weather_test.rb +15 -14
- data/test/unit/plugin_test.rb +62 -1
- data/test/unit/room_test.rb +51 -0
- metadata +28 -20
- data/lib/robut/plugin/rdio.rb +0 -96
- data/lib/robut/plugin/rdio/public/css/rdio.css +0 -141
- data/lib/robut/plugin/rdio/public/css/style.css +0 -79
- data/lib/robut/plugin/rdio/public/css/style_after.css +0 -42
- data/lib/robut/plugin/rdio/public/images/background.png +0 -0
- data/lib/robut/plugin/rdio/public/images/no-album.png +0 -0
- data/lib/robut/plugin/rdio/public/index.html +0 -43
- data/lib/robut/plugin/rdio/public/js/libs/dd_belatedpng.js +0 -13
- data/lib/robut/plugin/rdio/public/js/libs/jquery-1.5.1.min.js +0 -16
- data/lib/robut/plugin/rdio/public/js/libs/modernizr-1.7.min.js +0 -2
- data/lib/robut/plugin/rdio/public/js/rdio.js +0 -129
- data/lib/robut/plugin/rdio/public/js/script.js +0 -3
- data/lib/robut/plugin/rdio/server.rb +0 -57
data/.travis.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
# - 1.8.7
|
4
|
+
- 1.9.2
|
5
|
+
- 1.9.3
|
6
|
+
# - jruby-18mode # JRuby in 1.8 mode
|
7
|
+
# - jruby-19mode # JRuby in 1.9 mode
|
8
|
+
# - rbx-18mode
|
9
|
+
# - rbx-19mode # currently in active development, may or may not work for your project
|
10
|
+
# uncomment this line if your project needs to run something other than `rake`:
|
11
|
+
# script: bundle exec rspec spec
|
data/Gemfile
CHANGED
@@ -8,13 +8,12 @@ group :test do
|
|
8
8
|
gem 'simplecov'
|
9
9
|
gem 'webmock'
|
10
10
|
gem 'time-warp'
|
11
|
+
gem 'mocha'
|
11
12
|
end
|
12
13
|
|
13
14
|
group :plugin do
|
14
15
|
gem 'calc'
|
15
16
|
gem 'twss'
|
16
|
-
gem 'rdio', '0.0.91' # .92 is horked
|
17
|
-
gem 'sinatra'
|
18
17
|
gem 'meme_generator'
|
19
18
|
gem 'nokogiri'
|
20
|
-
end
|
19
|
+
end
|
data/README.rdoc
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
= Robut
|
2
2
|
|
3
|
-
The friendly plugin-enabled HipChat bot.
|
3
|
+
The friendly plugin-enabled HipChat bot.
|
4
|
+
|
5
|
+
== NOTE: Breaking backwards compatibility!
|
6
|
+
|
7
|
+
A little while ago, HipChat changed the way their mention names
|
8
|
+
work. Instead of just using the first name ('@robut'), they now use
|
9
|
+
the full name ('@RobutTRobot'). Starting from v0.4.0, robut uses this
|
10
|
+
new format by default. If you prefer the old style, you can set it in
|
11
|
+
your Chatfile:
|
12
|
+
|
13
|
+
config.mention_name = 'robut'
|
4
14
|
|
5
15
|
== Installation and usage
|
6
16
|
|
@@ -22,8 +32,11 @@ Some of the included plugins require extra gems to be installed:
|
|
22
32
|
|
23
33
|
[Robut::Plugin::TWSS] requires the <tt>twss</tt> gem.
|
24
34
|
[Robut::Plugin::Calc] requires the <tt>calc</tt> gem.
|
25
|
-
[Robut::Plugin::Rdio] requires the <tt>rdio</tt> and <tt>sinatra</tt> gems.
|
26
35
|
[Robut::Plugin::Weather] requires the <tt>nokogiri</tt> gem.
|
36
|
+
[Robut::Plugin::GoogleImages] requires the <tt>google-search</tt> gem.
|
37
|
+
|
38
|
+
A list of known 3rd-party plugins is available on the wiki: https://github.com/justinweiss/robut/wiki/Robut-Plugins
|
39
|
+
Feel free to add your own creations!
|
27
40
|
|
28
41
|
== The Chatfile
|
29
42
|
|
@@ -53,7 +66,7 @@ kind of configuration they support.
|
|
53
66
|
Some plugins might require storage (like the `lunch` plugin). You can
|
54
67
|
configure the type of storage you want to use based on the need for
|
55
68
|
persistence. The default is the HashStore which is in-memory only. Below
|
56
|
-
is an example of using the YamlStore.
|
69
|
+
is an example of using the YamlStore.
|
57
70
|
|
58
71
|
Robut::Connection.configure do |config|
|
59
72
|
# ...
|
@@ -71,13 +84,16 @@ Robut::Connection.configure block:
|
|
71
84
|
Robut::Connection.configure do |config|
|
72
85
|
config.jid = '...@chat.hipchat.com/bot'
|
73
86
|
config.password = 'password'
|
74
|
-
config.nick = '
|
75
|
-
config.
|
76
|
-
|
87
|
+
config.nick = 'Bot Nick'
|
88
|
+
config.rooms = ['1234_room_1@conf.hipchat.com', '1234_room_2@conf.hipchat.com']
|
89
|
+
|
90
|
+
# Custom @mention name
|
91
|
+
config.mention_name = 'Bot'
|
92
|
+
|
77
93
|
# Example of the YamlStore which uses a yaml file for persistence
|
78
94
|
Robut::Storage::YamlStore.file = "~/.robut_store"
|
79
95
|
config.store = Robut::Storage::YamlStore
|
80
|
-
|
96
|
+
|
81
97
|
# Add a logger if you want to debug the connection
|
82
98
|
# config.logger = Logger.new(STDOUT)
|
83
99
|
end
|
@@ -98,16 +114,19 @@ Robut includes a few plugins that we've found useful:
|
|
98
114
|
@robut lunch? # => "Banh Mi!"
|
99
115
|
|
100
116
|
|
101
|
-
[Robut::Plugin::Meme]
|
117
|
+
[Robut::Plugin::Meme] generates meme images using memecaptain.
|
102
118
|
|
103
119
|
@robut meme all_the_things drink; all the beer
|
104
120
|
|
121
|
+
[Robut::Plugin::GoogleImages] does a google image search for a query and returns the first result.
|
105
122
|
|
106
|
-
|
123
|
+
@robut image ship it
|
124
|
+
|
125
|
+
[Robut::Plugin::Sayings] a simple regex listener and responder.
|
107
126
|
|
108
127
|
You're the worst robot ever, @robut. # => I know.
|
109
128
|
|
110
|
-
[Robut::Plugin::TWSS] an interface to the TWSS gem. Listens to anything said in the chat room and responds "That's what she said!" where appropriate.
|
129
|
+
[Robut::Plugin::TWSS] an interface to the TWSS gem. Listens to anything said in the chat room and responds "That's what she said!" where appropriate.
|
111
130
|
|
112
131
|
well hurry up, you're not going fast enough # => "That's what she said!"
|
113
132
|
|
@@ -117,12 +136,12 @@ Robut includes a few plugins that we've found useful:
|
|
117
136
|
@robut echo hello world # => "hello world"
|
118
137
|
|
119
138
|
|
120
|
-
[Robut::Plugin::Say] invokes the "say" command (text-to-speech).
|
139
|
+
[Robut::Plugin::Say] invokes the "say" command (text-to-speech).
|
121
140
|
|
122
141
|
@robut say this rocks # (make sure robut is running on a machine with speakers :)
|
123
142
|
|
124
143
|
|
125
|
-
[Robut::Plugin::Ping] responds with "pong".
|
144
|
+
[Robut::Plugin::Ping] responds with "pong".
|
126
145
|
|
127
146
|
@robut ping # => "pong"
|
128
147
|
|
@@ -132,11 +151,6 @@ Robut includes a few plugins that we've found useful:
|
|
132
151
|
@robut in 5 minutes echo @justin wake up! # => (5 minutes later) "@justin wake up!"
|
133
152
|
|
134
153
|
|
135
|
-
[Robut::Plugin::Rdio] uses the Rdio[http://www.rdio.com] API and a simple web server to queue and play songs on Rdio.
|
136
|
-
|
137
|
-
@robut play ok computer
|
138
|
-
|
139
|
-
|
140
154
|
[Robut::Plugin::Weather] uses Google Weather to fetch for the weather for a given location and day.
|
141
155
|
|
142
156
|
@robut seattle weather saturday? # => "Forecast for Seattle, WA on Sat: Sunny, High: 77F, Low: 55F"
|
@@ -146,6 +160,12 @@ Robut includes a few plugins that we've found useful:
|
|
146
160
|
@robut alias "cowboy" "@robut play bon jovi wanted dead or alive" # Cuz somtimes you need it.
|
147
161
|
@robut alias w weather? # less typing for common stuff
|
148
162
|
|
163
|
+
[Robut::Plugin::Quips] stores and posts Bugzilla-style quips.
|
164
|
+
|
165
|
+
@robut add quip It was great when I wrote it!
|
166
|
+
@robut quip # => It was great when I wrote it!
|
167
|
+
@robut remove quip It was great when I wrote it!
|
168
|
+
|
149
169
|
[Robut::Plugin::Help] lists usage for all the plugins loaded into robut
|
150
170
|
|
151
171
|
@robut help # => command usage
|
@@ -179,5 +199,4 @@ Once your changes are ready:
|
|
179
199
|
|
180
200
|
== Todo
|
181
201
|
|
182
|
-
*
|
183
|
-
* More plugins!
|
202
|
+
* More plugins!
|
data/examples/Chatfile
CHANGED
@@ -8,15 +8,21 @@ Robut::Plugin.plugins << Robut::Plugin::TWSS
|
|
8
8
|
|
9
9
|
# Configure the robut jabber connection and you're good to go!
|
10
10
|
Robut::Connection.configure do |config|
|
11
|
+
# Note that the jid must end with /bot if you don't want robut to
|
12
|
+
# spam the channel, as described by the last bullet point on this
|
13
|
+
# page: https://www.hipchat.com/help/category/xmpp
|
11
14
|
config.jid = '...@chat.hipchat.com/bot'
|
12
15
|
config.password = 'password'
|
13
|
-
config.nick = '
|
16
|
+
config.nick = 'Bot Nick'
|
14
17
|
config.room = '...@conf.hipchat.com'
|
15
|
-
|
18
|
+
|
19
|
+
# Custom @mention name
|
20
|
+
# config.mention_name = 'Bot'
|
21
|
+
|
16
22
|
# Some plugins require storage
|
17
23
|
Robut::Storage::YamlStore.file = ".robut"
|
18
24
|
config.store = Robut::Storage::YamlStore
|
19
|
-
|
25
|
+
|
20
26
|
# Add a logger if you want to debug the connection
|
21
27
|
# config.logger = Logger.new(STDOUT)
|
22
|
-
end
|
28
|
+
end
|
data/lib/robut.rb
CHANGED
data/lib/robut/connection.rb
CHANGED
@@ -19,7 +19,7 @@ class Robut::Connection
|
|
19
19
|
# [+jid+, +password+, +nick+] The HipChat credentials given on
|
20
20
|
# https://www.hipchat.com/account/xmpp
|
21
21
|
#
|
22
|
-
# [+
|
22
|
+
# [+rooms+] The chat room(s) to join, with each in the format <tt>jabber_name</tt>@<tt>conference_server</tt>
|
23
23
|
#
|
24
24
|
# [+logger+] a logger instance to use for debug output.
|
25
25
|
attr_accessor :config
|
@@ -27,15 +27,15 @@ class Robut::Connection
|
|
27
27
|
# The Jabber::Client that's connected to the HipChat server.
|
28
28
|
attr_accessor :client
|
29
29
|
|
30
|
-
# The MUC that wraps the Jabber Chat protocol.
|
31
|
-
attr_accessor :muc
|
32
|
-
|
33
30
|
# The storage instance that's available to plugins
|
34
31
|
attr_accessor :store
|
35
32
|
|
36
33
|
# The roster of currently available people
|
37
34
|
attr_accessor :roster
|
38
35
|
|
36
|
+
# The rooms that robut is connected to.
|
37
|
+
attr_accessor :rooms
|
38
|
+
|
39
39
|
class << self
|
40
40
|
# Class-level config. This is set by the +configure+ class method,
|
41
41
|
# and is used if no configuration is passed to the +initialize+
|
@@ -65,8 +65,8 @@ class Robut::Connection
|
|
65
65
|
self.config = _config || self.class.config
|
66
66
|
|
67
67
|
self.client = Jabber::Client.new(self.config.jid)
|
68
|
-
self.muc = Jabber::MUC::SimpleMUCClient.new(client)
|
69
68
|
self.store = self.config.store || Robut::Storage::HashStore # default to in-memory store only
|
69
|
+
self.config.rooms ||= Array(self.config.room) # legacy support?
|
70
70
|
|
71
71
|
if self.config.logger
|
72
72
|
Jabber.logger = self.config.logger
|
@@ -74,43 +74,6 @@ class Robut::Connection
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# Send +message+ to the room we're currently connected to, or
|
78
|
-
# directly to the person referenced by +to+. +to+ can be either a
|
79
|
-
# jid or the string name of the person.
|
80
|
-
def reply(message, to = nil)
|
81
|
-
if to
|
82
|
-
unless to.kind_of?(Jabber::JID)
|
83
|
-
to = find_jid_by_name(to)
|
84
|
-
end
|
85
|
-
|
86
|
-
msg = Jabber::Message.new(to || muc.room, message)
|
87
|
-
msg.type = :chat
|
88
|
-
client.send(msg)
|
89
|
-
else
|
90
|
-
muc.send(Jabber::Message.new(muc.room, message))
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Sends the chat message +message+ through +plugins+.
|
95
|
-
def handle_message(plugins, time, nick, message)
|
96
|
-
# ignore all messages sent by robut. If you really want robut to
|
97
|
-
# reply to itself, you can use +fake_message+.
|
98
|
-
return if nick == config.nick
|
99
|
-
|
100
|
-
plugins.each do |plugin|
|
101
|
-
begin
|
102
|
-
rsp = plugin.handle(time, nick, message)
|
103
|
-
break if rsp == true
|
104
|
-
rescue => e
|
105
|
-
reply("UH OH! #{plugin.class.name} just crashed!")
|
106
|
-
if config.logger
|
107
|
-
config.logger.error e
|
108
|
-
config.logger.error e.backtrace.join("\n")
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
77
|
# Connects to the specified room with the given credentials, and
|
115
78
|
# enters an infinite loop. Any messages sent to the room will pass
|
116
79
|
# through all the included plugins.
|
@@ -122,36 +85,17 @@ class Robut::Connection
|
|
122
85
|
self.roster = Jabber::Roster::Helper.new(client)
|
123
86
|
roster.wait_for_roster
|
124
87
|
|
125
|
-
|
126
|
-
|
127
|
-
plugins = Robut::Plugin.plugins.map { |p| p.new(self, nil) }
|
128
|
-
handle_message(plugins, time, nick, message)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Add the callback from direct messages. Turns out the
|
132
|
-
# on_private_message callback doesn't do what it sounds like, so I
|
133
|
-
# have to go a little deeper into xmpp4r to get this working.
|
134
|
-
client.add_message_callback(200, self) do |message|
|
135
|
-
if !muc.from_room?(message.from) && message.type == :chat && message.body
|
136
|
-
time = Time.now # TODO: get real timestamp? Doesn't seem like
|
137
|
-
# jabber gives it to us
|
138
|
-
sender_jid = message.from
|
139
|
-
plugins = Robut::Plugin.plugins.map { |p| p.new(self, sender_jid) }
|
140
|
-
handle_message(plugins, time, self.roster[sender_jid].iname, message.body)
|
141
|
-
true
|
142
|
-
else
|
143
|
-
false
|
144
|
-
end
|
88
|
+
rooms = self.config.rooms.collect do |room_name|
|
89
|
+
Robut::Room.new(self, room_name).tap {|r| r.join }
|
145
90
|
end
|
146
91
|
|
147
|
-
|
92
|
+
personal_message = Robut::PM.new(self, rooms)
|
148
93
|
|
149
94
|
trap_signals
|
150
95
|
loop { sleep 1 }
|
151
96
|
end
|
152
97
|
|
153
|
-
|
154
|
-
|
98
|
+
private
|
155
99
|
# Since we're entering an infinite loop, we have to trap TERM and
|
156
100
|
# INT. If something like the Rdio plugin has started a server that
|
157
101
|
# has already trapped those signals, we want to run those signal
|
@@ -167,10 +111,4 @@ class Robut::Connection
|
|
167
111
|
old_signal_callbacks[sig] = trap(sig) { signal_callback.call(sig) }
|
168
112
|
end
|
169
113
|
end
|
170
|
-
|
171
|
-
# Find a jid in the roster with the given name, case-insensitively
|
172
|
-
def find_jid_by_name(name)
|
173
|
-
name = name.downcase
|
174
|
-
roster.items.detect {|jid, item| item.iname.downcase == name}.first
|
175
|
-
end
|
176
|
-
end
|
114
|
+
end
|
data/lib/robut/plugin.rb
CHANGED
@@ -3,6 +3,45 @@
|
|
3
3
|
# module.
|
4
4
|
module Robut::Plugin
|
5
5
|
|
6
|
+
# Contains methods that will be added directly to a class including
|
7
|
+
# Robut::Plugin.
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Sets up a 'matcher' that will try to match input being sent to
|
11
|
+
# this plugin with a regular expression. If the expression
|
12
|
+
# matches, +action+ will be performed. +action+ will be passed any
|
13
|
+
# captured groups in the regular expression as parameters. For
|
14
|
+
# example:
|
15
|
+
#
|
16
|
+
# match /^say hello to (\w+)/ do |name| ...
|
17
|
+
#
|
18
|
+
# The action is run in the context of an instance of a class that
|
19
|
+
# includes Robut::Plugin. Like +handle+, an action explicitly
|
20
|
+
# returning +true+ will stop the plugin chain from matching any
|
21
|
+
# further.
|
22
|
+
#
|
23
|
+
# Supported options:
|
24
|
+
# :sent_to_me - only try to match this regexp if it contains an @reply to robut.
|
25
|
+
# This will also strip the @reply from the message we're trying
|
26
|
+
# to match on, so ^ and $ will still do the right thing.
|
27
|
+
def match(regexp, options = {}, &action)
|
28
|
+
matchers << [regexp, options, action, @last_description]
|
29
|
+
@last_description = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Provides a description for the next matcher
|
33
|
+
def desc(string)
|
34
|
+
@last_description = string
|
35
|
+
end
|
36
|
+
|
37
|
+
# A list of regular expressions to apply to input being sent to
|
38
|
+
# the plugin, along with blocks of actions to perform. Each
|
39
|
+
# element is a [regexp, options, action, description] array.
|
40
|
+
def matchers
|
41
|
+
@matchers ||= []
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
6
45
|
class << self
|
7
46
|
# A list of all available plugin classes. When you require a new
|
8
47
|
# plugin class, you should add it to this list if you want it to
|
@@ -21,10 +60,18 @@ module Robut::Plugin
|
|
21
60
|
# room.
|
22
61
|
attr_accessor :private_sender
|
23
62
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
63
|
+
attr_accessor :reply_to
|
64
|
+
|
65
|
+
# :nodoc:
|
66
|
+
def self.included(klass)
|
67
|
+
klass.send(:extend, ClassMethods)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a new instance of this plugin to reply to a particular
|
71
|
+
# object over that object's connection
|
72
|
+
def initialize(reply_to, private_sender = nil)
|
73
|
+
self.reply_to = reply_to
|
74
|
+
self.connection = reply_to.connection
|
28
75
|
self.private_sender = private_sender
|
29
76
|
end
|
30
77
|
|
@@ -33,9 +80,9 @@ module Robut::Plugin
|
|
33
80
|
# original message was sent. Otherwise, PMs the message to +to+.
|
34
81
|
def reply(message, to = nil)
|
35
82
|
if to == :room
|
36
|
-
|
83
|
+
reply_to.reply(message, nil)
|
37
84
|
else
|
38
|
-
|
85
|
+
reply_to.reply(message, to || private_sender)
|
39
86
|
end
|
40
87
|
end
|
41
88
|
|
@@ -44,7 +91,7 @@ module Robut::Plugin
|
|
44
91
|
# stripped out. This is useful to separate the 'parameters' from the
|
45
92
|
# 'commands' in a message.
|
46
93
|
def words(message, command = nil)
|
47
|
-
reply = at_nick
|
94
|
+
reply = at_nick.downcase
|
48
95
|
command = command.downcase if command
|
49
96
|
message.split.reject {|word| word.downcase == reply || word.downcase == command }
|
50
97
|
end
|
@@ -53,7 +100,7 @@ module Robut::Plugin
|
|
53
100
|
# Given "@robut do this thing", Returns "do this thing"
|
54
101
|
def without_nick(message)
|
55
102
|
possible_nick, command = message.split(' ', 2)
|
56
|
-
if possible_nick ==
|
103
|
+
if possible_nick.casecmp(at_nick) == 0
|
57
104
|
command
|
58
105
|
else
|
59
106
|
message
|
@@ -62,12 +109,12 @@ module Robut::Plugin
|
|
62
109
|
|
63
110
|
# The bot's nickname, for @-replies.
|
64
111
|
def nick
|
65
|
-
connection.config.nick.
|
112
|
+
connection.config.mention_name || connection.config.nick.gsub(/[^0-9a-z]/i, '')
|
66
113
|
end
|
67
114
|
|
68
115
|
# #nick with the @-symbol prepended
|
69
116
|
def at_nick
|
70
|
-
"@#{nick
|
117
|
+
"@#{nick}"
|
71
118
|
end
|
72
119
|
|
73
120
|
# Was +message+ sent to Robut as an @reply?
|
@@ -80,22 +127,56 @@ module Robut::Plugin
|
|
80
127
|
# method. Plugins are handled in the order that they appear in
|
81
128
|
# Robut::Plugin.plugins
|
82
129
|
def handle(time, sender_nick, message)
|
83
|
-
|
130
|
+
if matchers.empty?
|
131
|
+
raise NotImplementedError, "Implement me in #{self.class.name}!"
|
132
|
+
else
|
133
|
+
find_match(message)
|
134
|
+
end
|
84
135
|
end
|
85
136
|
|
86
137
|
# Returns a list of messages describing the commands this plugin
|
87
138
|
# handles.
|
88
139
|
def usage
|
140
|
+
matchers.map do |regexp, options, action, description|
|
141
|
+
next unless description
|
142
|
+
if options[:sent_to_me]
|
143
|
+
at_nick + " " + description
|
144
|
+
else
|
145
|
+
description
|
146
|
+
end
|
147
|
+
end.compact
|
89
148
|
end
|
90
149
|
|
91
150
|
def fake_message(time, sender_nick, msg)
|
92
151
|
# TODO: ensure this connection is threadsafe
|
93
|
-
plugins = Robut::Plugin.plugins.map { |p| p.new(
|
94
|
-
|
152
|
+
plugins = Robut::Plugin.plugins.map { |p| p.new(reply_to, private_sender) }
|
153
|
+
reply_to.handle_message(plugins, time, sender_nick, msg)
|
95
154
|
end
|
96
155
|
|
97
156
|
# Accessor for the store instance
|
98
157
|
def store
|
99
158
|
connection.store
|
100
159
|
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Find and run all the actions associated with matchers that match
|
164
|
+
# +message+.
|
165
|
+
def find_match(message)
|
166
|
+
matchers.each do |regexp, options, action, description|
|
167
|
+
if options[:sent_to_me] && !sent_to_me?(message)
|
168
|
+
next
|
169
|
+
end
|
170
|
+
|
171
|
+
if match_data = without_nick(message).match(regexp)
|
172
|
+
# Return true explicitly if this matcher explicitly returned true
|
173
|
+
break true if instance_exec(*match_data[1..-1], &action) == true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# The matchers defined by this plugin's class
|
179
|
+
def matchers
|
180
|
+
self.class.matchers
|
181
|
+
end
|
101
182
|
end
|