robut 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +17 -0
- data/README.rdoc +124 -0
- data/Rakefile +27 -0
- data/bin/robut +9 -0
- data/examples/Chatfile +22 -0
- data/lib/robut.rb +5 -0
- data/lib/robut/connection.rb +167 -0
- data/lib/robut/plugin.rb +16 -0
- data/lib/robut/plugin/base.rb +70 -0
- data/lib/robut/plugin/calc.rb +20 -0
- data/lib/robut/plugin/echo.rb +14 -0
- data/lib/robut/plugin/later.rb +73 -0
- data/lib/robut/plugin/lunch.rb +57 -0
- data/lib/robut/plugin/meme.rb +30 -0
- data/lib/robut/plugin/ping.rb +11 -0
- data/lib/robut/plugin/rdio.rb +70 -0
- data/lib/robut/plugin/rdio/public/css/rdio.css +141 -0
- data/lib/robut/plugin/rdio/public/css/style.css +79 -0
- data/lib/robut/plugin/rdio/public/css/style_after.css +42 -0
- 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 +42 -0
- data/lib/robut/plugin/rdio/public/js/libs/dd_belatedpng.js +13 -0
- data/lib/robut/plugin/rdio/public/js/libs/jquery-1.5.1.min.js +16 -0
- data/lib/robut/plugin/rdio/public/js/libs/modernizr-1.7.min.js +2 -0
- data/lib/robut/plugin/rdio/public/js/rdio.js +129 -0
- data/lib/robut/plugin/rdio/public/js/script.js +3 -0
- data/lib/robut/plugin/rdio/server.rb +34 -0
- data/lib/robut/plugin/say.rb +20 -0
- data/lib/robut/plugin/sayings.rb +31 -0
- data/lib/robut/plugin/twss.rb +13 -0
- data/lib/robut/storage.rb +3 -0
- data/lib/robut/storage/base.rb +21 -0
- data/lib/robut/storage/hash_store.rb +26 -0
- data/lib/robut/storage/yaml_store.rb +51 -0
- data/lib/robut/version.rb +4 -0
- data/robut.gemspec +23 -0
- data/test/mocks/connection_mock.rb +26 -0
- data/test/simplecov_helper.rb +2 -0
- data/test/test_helper.rb +7 -0
- data/test/unit/connection_test.rb +123 -0
- data/test/unit/plugin/base_test.rb +16 -0
- data/test/unit/plugin/echo_test.rb +26 -0
- data/test/unit/plugin/later_test.rb +39 -0
- data/test/unit/plugin/lunch_test.rb +35 -0
- data/test/unit/plugin/ping_test.rb +21 -0
- data/test/unit/plugin/say_test.rb +28 -0
- data/test/unit/storage/hash_store_test.rb +15 -0
- data/test/unit/storage/yaml_store_test.rb +42 -0
- data/test/unit/storage/yaml_test.yml +1 -0
- metadata +135 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in robut.gemspec
|
4
|
+
gemspec
|
5
|
+
gem 'rake'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'simplecov'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :plugin do
|
12
|
+
gem 'calc'
|
13
|
+
gem 'twss'
|
14
|
+
gem 'rdio'
|
15
|
+
gem 'sinatra'
|
16
|
+
gem 'meme_generator'
|
17
|
+
end
|
data/README.rdoc
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
= Robut
|
2
|
+
|
3
|
+
The friendly plugin-enabled HipChat bot.
|
4
|
+
|
5
|
+
== Installation and usage
|
6
|
+
|
7
|
+
Robut can be installed by running <tt>gem install robut</tt>. This
|
8
|
+
installs the +robut+ binary. When run, +robut+ reads a Chatfile,
|
9
|
+
connects to the specified HipChat server and chatroom, and feeds every
|
10
|
+
line said in the chatroom through the plugins configured by the
|
11
|
+
Chatfile.
|
12
|
+
|
13
|
+
Once robut is running, the plugins listen to what's being said in the
|
14
|
+
chatroom. Most plugins listen for @replies to robut:
|
15
|
+
|
16
|
+
@robut lunch? # => "Banh Mi!"
|
17
|
+
@robut calc 1 + 1 # => 2
|
18
|
+
|
19
|
+
Others listen to everything, and don't require an @reply.
|
20
|
+
|
21
|
+
Some of the included plugins require extra gems to be installed:
|
22
|
+
|
23
|
+
[Robut::Plugin::TWSS] requires the <tt>twss</tt> gem
|
24
|
+
[Robut::Plugin::Meme] requires the <tt>meme_generator</tt> gem
|
25
|
+
[Robut::Plugin::Calc] requires the <tt>calc</tt> gem
|
26
|
+
[Robut::Plugin::Rdio] requires the <tt>rdio</tt> and <tt>sinatra</tt> gems
|
27
|
+
|
28
|
+
== The Chatfile
|
29
|
+
|
30
|
+
When the +robut+ command runs, it looks for and evals ruby code in a
|
31
|
+
file called +Chatfile+ in the current directory. You can override the
|
32
|
+
configuration file by passing +robut+ a path to a Chatfile as the
|
33
|
+
first parameter:
|
34
|
+
|
35
|
+
robut /path/to/Chatfile
|
36
|
+
|
37
|
+
The Chatfile is just ruby code. A simple example can be found here: Chatfile[https://github.com/justinweiss/robut/blob/master/examples/Chatfile]
|
38
|
+
|
39
|
+
=== Adding and configuring plugins
|
40
|
+
|
41
|
+
Plugins are ruby classes, so enabling a plugin just requires requiring
|
42
|
+
the plugin file, optionally configuring the plugin class, and adding
|
43
|
+
the class to the global plugin list:
|
44
|
+
|
45
|
+
require 'robut/plugin/lunch'
|
46
|
+
Robut::Plugin::Lunch.places = ["Banh Mi", "Mad Oven", "Mod Pizza", "Taphouse"]
|
47
|
+
Robut::Plugin.plugins << Robut::Plugin::Lunch
|
48
|
+
|
49
|
+
Each plugin can be configured differently, or not at all. It's best to
|
50
|
+
look at the docs for the plugins you want to use to figure out what
|
51
|
+
kind of configuration they support.
|
52
|
+
|
53
|
+
Some plugins might require storage (like the `lunch` plugin). You can
|
54
|
+
configure the type of storage you want to use based on the need for
|
55
|
+
persistence. The default is the HashStore which is in-memory only. Below
|
56
|
+
is an example of using the YamlStore.
|
57
|
+
|
58
|
+
Robut::Connection.configure do |config|
|
59
|
+
# ...
|
60
|
+
Robut::Storage::YamlStore.file = "~/.robut_store"
|
61
|
+
config.store = Robut::Storage::YamlStore
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
=== Configuring the HipChat connection
|
66
|
+
|
67
|
+
The Chatfile also configures the HipChat connection. This is done in a
|
68
|
+
Robut::Connection.configure block:
|
69
|
+
|
70
|
+
# Configure the robut jabber connection and you're good to go!
|
71
|
+
Robut::Connection.configure do |config|
|
72
|
+
config.jid = '...@chat.hipchat.com/bot'
|
73
|
+
config.password = 'password'
|
74
|
+
config.nick = 'My Nick'
|
75
|
+
config.room = '...@conf.hipchat.com'
|
76
|
+
|
77
|
+
# Example of the YamlStore which uses a yaml file for persistence
|
78
|
+
Robut::Storage::YamlStore.file = "~/.robut_store"
|
79
|
+
config.store = Robut::Storage::YamlStore
|
80
|
+
|
81
|
+
# Add a logger if you want to debug the connection
|
82
|
+
# config.logger = Logger.new(STDOUT)
|
83
|
+
end
|
84
|
+
|
85
|
+
This block usually goes at the end of the Chatfile.
|
86
|
+
|
87
|
+
== Built-in plugins
|
88
|
+
|
89
|
+
Robut includes a few plugins that we've found useful:
|
90
|
+
|
91
|
+
[Robut::Plugin::Calc] a simple calculator. <br /> <br /> Example: <tt>@robut calc 1 + 1 # => 2</tt>
|
92
|
+
[Robut::Plugin::Lunch] a random decider for lunch locations. <br /> <br /> Example: <tt>@robut lunch? # => "Banh Mi!"</tt>
|
93
|
+
[Robut::Plugin::Meme] an interface to memegenerator.net. <br /> <br /> Example: <tt>@robut meme Y_U_NO FIX THE BUILD?</tt>
|
94
|
+
[Robut::Plugin::Sayings] a simple regex listener and responder. <br /> <br /> Example: <tt>You're the worst robot ever, @robut. # => I know. </tt>
|
95
|
+
[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. <br /> <br /> Example: <tt>well hurry up, you're not going fast enough # => "That's what she said!" </tt>
|
96
|
+
[Robut::Plugin::Echo] echo back whatever it gets. <br /> <br /> Example: <tt>@robut echo hello word</tt>
|
97
|
+
[Robut::Plugin::Say] invokes the "say" command (text-to-speech). <br /> <br /> Example: <tt>@robut say this rocks</tt>
|
98
|
+
[Robut::Plugin::Ping] responds with "pong". <br /> <br /> Example: <tt>@robut ping</tt>
|
99
|
+
[Robut::Plugin::Later] performs the given command after waiting an arbitrary amount of time. <br /> <br /> Example: <tt>@robut in 5 minutes echo @justin wake up!</tt>
|
100
|
+
[Robut::Plugin::Rdio] uses the Rdio[http://www.rdio.com] API and a simple web server to queue and play songs on Rdio. <br /> <br /> Example: <tt>@robut play ok computer</tt>
|
101
|
+
|
102
|
+
== Writing custom plugins
|
103
|
+
|
104
|
+
You can supply your own plugins to Robut. To create a plugin, subclass
|
105
|
+
Robut::Plugin::Base and implement the <tt>handle(time, sender_nick,
|
106
|
+
message)</tt> to perform any plugin-specific logic.
|
107
|
+
|
108
|
+
Robut::Plugin::Base provides a few helper methods that are documented
|
109
|
+
in its class definition.
|
110
|
+
|
111
|
+
== Contributing
|
112
|
+
|
113
|
+
Once you've made your great commits:
|
114
|
+
|
115
|
+
1. Fork robut
|
116
|
+
2. Create a topic branch - git checkout -b my_branch
|
117
|
+
3. Push to your branch - git push origin my_branch
|
118
|
+
4. Send me a pull request
|
119
|
+
5. That's it!
|
120
|
+
|
121
|
+
== Todo
|
122
|
+
|
123
|
+
* Support connections to multiple rooms
|
124
|
+
* More plugins!
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
task :build => :test
|
8
|
+
|
9
|
+
Rake::TestTask.new do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.test_files = FileList['test/**/*_test.rb']
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::TestTask.new(:coverage) do |t|
|
16
|
+
t.libs << "test"
|
17
|
+
t.ruby_opts = ["-rsimplecov_helper"]
|
18
|
+
t.test_files = FileList['test/**/*_test.rb']
|
19
|
+
t.verbose = true
|
20
|
+
end
|
21
|
+
|
22
|
+
Rake::RDocTask.new do |rd|
|
23
|
+
rd.main = "README.rdoc"
|
24
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
25
|
+
rd.rdoc_dir = 'doc'
|
26
|
+
end
|
27
|
+
|
data/bin/robut
ADDED
data/examples/Chatfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Require your plugins here
|
2
|
+
require 'robut/plugin/twss'
|
3
|
+
require 'robut/storage/yaml_store'
|
4
|
+
|
5
|
+
# Add the plugin classes to the Robut plugin list.
|
6
|
+
# Plugins are handled in the order that they appear in this array.
|
7
|
+
Robut::Plugin.plugins << Robut::Plugin::TWSS
|
8
|
+
|
9
|
+
# Configure the robut jabber connection and you're good to go!
|
10
|
+
Robut::Connection.configure do |config|
|
11
|
+
config.jid = '...@chat.hipchat.com/bot'
|
12
|
+
config.password = 'password'
|
13
|
+
config.nick = 'My Nick'
|
14
|
+
config.room = '...@conf.hipchat.com'
|
15
|
+
|
16
|
+
# Some plugins require storage
|
17
|
+
Robut::Storage::YamlStore.file = ".robut"
|
18
|
+
config.store = Robut::Storage::YamlStore
|
19
|
+
|
20
|
+
# Add a logger if you want to debug the connection
|
21
|
+
# config.logger = Logger.new(STDOUT)
|
22
|
+
end
|
data/lib/robut.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'xmpp4r'
|
2
|
+
require 'xmpp4r/muc/helper/simplemucclient'
|
3
|
+
require 'xmpp4r/roster/helper/roster'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
# Handles opening a connection to the HipChat server, and feeds all
|
7
|
+
# messages through our Robut::Plugin list.
|
8
|
+
class Robut::Connection
|
9
|
+
|
10
|
+
# The configuration used by the Robut connection.
|
11
|
+
#
|
12
|
+
# Parameters:
|
13
|
+
#
|
14
|
+
# [+jid+, +password+, +nick+] The HipChat credentials given on
|
15
|
+
# https://www.hipchat.com/account/xmpp
|
16
|
+
#
|
17
|
+
# [+room+] The chat room to join, in the format <tt>jabber_name</tt>@<tt>conference_server</tt>
|
18
|
+
#
|
19
|
+
# [+logger+] a logger instance to use for debug output.
|
20
|
+
attr_accessor :config
|
21
|
+
|
22
|
+
# The Jabber::Client that's connected to the HipChat server.
|
23
|
+
attr_accessor :client
|
24
|
+
|
25
|
+
# The MUC that wraps the Jabber Chat protocol.
|
26
|
+
attr_accessor :muc
|
27
|
+
|
28
|
+
# The storage instance that's available to plugins
|
29
|
+
attr_accessor :store
|
30
|
+
|
31
|
+
# The roster of currently available people
|
32
|
+
attr_accessor :roster
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# Class-level config. This is set by the +configure+ class method,
|
36
|
+
# and is used if no configuration is passed to the +initialize+
|
37
|
+
# method.
|
38
|
+
attr_accessor :config
|
39
|
+
end
|
40
|
+
|
41
|
+
# Configures the connection at the class level. When the +robut+ bin
|
42
|
+
# file is loaded, it evals the file referenced by the first
|
43
|
+
# command-line parameter. This file can configure the connection
|
44
|
+
# instance later created by +robut+ by setting parameters in the
|
45
|
+
# Robut::Connection.configure block.
|
46
|
+
def self.configure
|
47
|
+
self.config = OpenStruct.new
|
48
|
+
yield config
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sets the instance config to +config+, converting it into an
|
52
|
+
# OpenStruct if necessary.
|
53
|
+
def config=(config)
|
54
|
+
@config = config.kind_of?(Hash) ? OpenStruct.new(config) : config
|
55
|
+
end
|
56
|
+
|
57
|
+
# Initializes the connection. If no +config+ is passed, it defaults
|
58
|
+
# to the class_level +config+ instance variable.
|
59
|
+
def initialize(_config = nil)
|
60
|
+
self.config = _config || self.class.config
|
61
|
+
|
62
|
+
self.client = Jabber::Client.new(self.config.jid)
|
63
|
+
self.muc = Jabber::MUC::SimpleMUCClient.new(client)
|
64
|
+
self.store = self.config.store || Robut::Storage::HashStore # default to in-memory store only
|
65
|
+
|
66
|
+
if self.config.logger
|
67
|
+
Jabber.logger = self.config.logger
|
68
|
+
Jabber.debug = true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Send +message+ to the room we're currently connected to, or
|
73
|
+
# directly to the person referenced by +to+. +to+ can be either a
|
74
|
+
# jid or the string name of the person.
|
75
|
+
def reply(message, to = nil)
|
76
|
+
if to
|
77
|
+
unless to.kind_of?(Jabber::JID)
|
78
|
+
to = find_jid_by_name(to)
|
79
|
+
end
|
80
|
+
|
81
|
+
msg = Jabber::Message.new(to || muc.room, message)
|
82
|
+
msg.type = :chat
|
83
|
+
client.send(msg)
|
84
|
+
else
|
85
|
+
muc.send(Jabber::Message.new(muc.room, message))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Sends the chat message +message+ through +plugins+.
|
90
|
+
def handle_message(plugins, time, nick, message)
|
91
|
+
plugins.each do |plugin|
|
92
|
+
begin
|
93
|
+
rsp = plugin.handle(time, nick, message)
|
94
|
+
break if rsp == true
|
95
|
+
rescue => e
|
96
|
+
reply("I just pooped myself trying to run #{plugin.class.name}. AWK-WAAAARD!")
|
97
|
+
if config.logger
|
98
|
+
config.logger.error e
|
99
|
+
config.logger.error e.backtrace.join("\n")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Connects to the specified room with the given credentials, and
|
106
|
+
# enters an infinite loop. Any messages sent to the room will pass
|
107
|
+
# through all the included plugins.
|
108
|
+
def connect
|
109
|
+
client.connect
|
110
|
+
client.auth(config.password)
|
111
|
+
client.send(Jabber::Presence.new.set_type(:available))
|
112
|
+
|
113
|
+
self.roster = Jabber::Roster::Helper.new(client)
|
114
|
+
roster.wait_for_roster
|
115
|
+
|
116
|
+
# Add the callback from messages that occur inside the room
|
117
|
+
muc.on_message do |time, nick, message|
|
118
|
+
plugins = Robut::Plugin.plugins.map { |p| p.new(self, nil) }
|
119
|
+
handle_message(plugins, time, nick, message)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Add the callback from direct messages. Turns out the
|
123
|
+
# on_private_message callback doesn't do what it sounds like, so I
|
124
|
+
# have to go a little deeper into xmpp4r to get this working.
|
125
|
+
client.add_message_callback(200, self) { |message|
|
126
|
+
if !muc.from_room?(message.from) && message.type == :chat && message.body
|
127
|
+
time = Time.now # TODO: get real timestamp? Doesn't seem like
|
128
|
+
# jabber gives it to us
|
129
|
+
sender_jid = message.from
|
130
|
+
plugins = Robut::Plugin.plugins.map { |p| p.new(self, sender_jid) }
|
131
|
+
handle_message(plugins, time, self.roster[sender_jid].iname, message.body)
|
132
|
+
true
|
133
|
+
else
|
134
|
+
false
|
135
|
+
end
|
136
|
+
}
|
137
|
+
|
138
|
+
muc.join(config.room + '/' + config.nick)
|
139
|
+
|
140
|
+
trap_signals
|
141
|
+
loop { sleep 1 }
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# Since we're entering an infinite loop, we have to trap TERM and
|
147
|
+
# INT. If something like the Rdio plugin has started a server that
|
148
|
+
# has already trapped those signals, we want to run those signal
|
149
|
+
# handlers first.
|
150
|
+
def trap_signals
|
151
|
+
old_signal_callbacks = {}
|
152
|
+
signal_callback = Proc.new do |signal|
|
153
|
+
old_signal_callbacks[signal].call if old_signal_callbacks[signal]
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
[:INT, :TERM].each do |sig|
|
158
|
+
old_signal_callbacks[sig] = trap(sig) { signal_callback.call(sig) }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Find a jid in the roster with the given name, case-insensitively
|
163
|
+
def find_jid_by_name(name)
|
164
|
+
name = name.downcase
|
165
|
+
roster.items.detect {|jid, item| item.iname.downcase == name}.first
|
166
|
+
end
|
167
|
+
end
|
data/lib/robut/plugin.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Robut plugins implement a simple interface to listen for messages
|
2
|
+
# and optionally respond to them. All plugins inherit from
|
3
|
+
# Robut::Plugin::Base.
|
4
|
+
module Robut::Plugin
|
5
|
+
autoload :Base, 'robut/plugin/base'
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# A list of all available plugin classes. When you require a new
|
9
|
+
# plugin class, you should add it to this list if you want it to
|
10
|
+
# respond to messages.
|
11
|
+
attr_accessor :plugins
|
12
|
+
end
|
13
|
+
|
14
|
+
self.plugins = []
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# All Robut plugins inherit from this base class. Plugins should
|
2
|
+
# implement the +handle+ method to implement their functionality.
|
3
|
+
class Robut::Plugin::Base
|
4
|
+
|
5
|
+
# A reference to the connection attached to this instance of the
|
6
|
+
# plugin. This is mostly used to communicate back to the server.
|
7
|
+
attr_accessor :connection
|
8
|
+
|
9
|
+
# If we are handling a private message, holds a reference to the
|
10
|
+
# sender of the message. +nil+ if the message was sent to the entire
|
11
|
+
# room.
|
12
|
+
attr_accessor :private_sender
|
13
|
+
|
14
|
+
# Creates a new instance of this plugin that references the
|
15
|
+
# specified connection.
|
16
|
+
def initialize(connection, private_sender = nil)
|
17
|
+
self.connection = connection
|
18
|
+
self.private_sender = private_sender
|
19
|
+
end
|
20
|
+
|
21
|
+
# Send +message+ back to the HipChat server. If +to+ == +:room+,
|
22
|
+
# replies to the room. If +to+ == nil, responds in the manner the
|
23
|
+
# original message was sent. Otherwise, PMs the message to +to+.
|
24
|
+
def reply(message, to = nil)
|
25
|
+
if to == :room
|
26
|
+
connection.reply(message, nil)
|
27
|
+
else
|
28
|
+
connection.reply(message, to || private_sender)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# An ordered list of all words in the message with any reference to
|
33
|
+
# the bot's nick stripped out. If +command+ is passed in, it is also
|
34
|
+
# stripped out. This is useful to separate the 'parameters' from the
|
35
|
+
# 'commands' in a message.
|
36
|
+
def words(message, command = nil)
|
37
|
+
reply = at_nick
|
38
|
+
command = command.downcase if command
|
39
|
+
message.split.reject {|word| word.downcase == reply || word.downcase == command }
|
40
|
+
end
|
41
|
+
|
42
|
+
# The bot's nickname, for @-replies.
|
43
|
+
def nick
|
44
|
+
connection.config.nick.split.first
|
45
|
+
end
|
46
|
+
|
47
|
+
# #nick with the @-symbol prepended
|
48
|
+
def at_nick
|
49
|
+
"@#{nick.downcase}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Was +message+ sent to Robut as an @reply?
|
53
|
+
def sent_to_me?(message)
|
54
|
+
message =~ /(^|\s)@#{nick}(\s|$)/i
|
55
|
+
end
|
56
|
+
|
57
|
+
# Do whatever you need to do to handle this message.
|
58
|
+
# If you want to stop the plugin execution chain, return +true+ from this
|
59
|
+
# method. Plugins are handled in the order that they appear in
|
60
|
+
# Robut::Plugin.plugins
|
61
|
+
def handle(time, sender_nick, message)
|
62
|
+
raise NotImplementedError, "Implement me in #{self.class.name}!"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Accessor for the store instance
|
66
|
+
def store
|
67
|
+
connection.store
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|