jabbot 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +157 -0
- data/Rakefile +4 -33
- data/lib/jabbot.rb +7 -41
- data/lib/jabbot/bot.rb +19 -9
- data/lib/jabbot/config.rb +2 -1
- data/lib/jabbot/macros.rb +65 -10
- data/lib/jabbot/version.rb +3 -0
- data/test/helper.rb +64 -0
- data/test/test_bot.rb +11 -41
- data/test/test_config.rb +17 -17
- data/test/test_handler.rb +76 -78
- data/test/test_hash.rb +5 -5
- data/test/test_macros.rb +31 -0
- metadata +48 -42
- data/README.rdoc +0 -141
- data/VERSION.yml +0 -4
- data/test/test_helper.rb +0 -38
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2009-2010 Jan-Erik Rediger (badboy\_)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
# Jabbot
|
2
|
+
|
3
|
+
Official URL: http://github.com/badboy/jabbot/tree/master
|
4
|
+
Jan-Erik Rediger (badboy\_) (http://badboy.pytalhost.de)
|
5
|
+
|
6
|
+
## Description
|
7
|
+
|
8
|
+
Jabbot is a Ruby micro-framework for creating Jabber/MUC bots,
|
9
|
+
heavily inspired by Sinatra and Twibot.
|
10
|
+
|
11
|
+
I modified the code of Twibot to fit my needs.
|
12
|
+
The original Twibot code is located at:
|
13
|
+
http://github.com/cjohansen/twibot/tree/master
|
14
|
+
|
15
|
+
A big thank you to Christian Johansen, who wrote the code for Twibot.
|
16
|
+
Jabbot is heavily based on his code.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### Simple example
|
21
|
+
|
22
|
+
# Receive messages, and post them publicly
|
23
|
+
message do |message, params|
|
24
|
+
post message.text
|
25
|
+
end
|
26
|
+
|
27
|
+
# Respond to query if they come from the right crowd
|
28
|
+
# post "message" => "user" is just some syntax sugar
|
29
|
+
# post "message", "user" will work to
|
30
|
+
query :from => [:cjno, :irbno] do |message, params|
|
31
|
+
post "#{message.user} I agree" => message.user
|
32
|
+
end
|
33
|
+
|
34
|
+
# Log every single line
|
35
|
+
# (you can use "message :all" too ;)
|
36
|
+
message do |message, params|
|
37
|
+
MyApp.log_message(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
### Running the bot
|
41
|
+
|
42
|
+
To run the bot, simply do:
|
43
|
+
|
44
|
+
ruby bot.rb
|
45
|
+
|
46
|
+
Jabbot uses the [at\_exit hook](http://ruby-doc.org/core/classes/Kernel.html#M005932) to start.
|
47
|
+
|
48
|
+
### Configuration
|
49
|
+
|
50
|
+
Jabbot looks for a configuration file in ./config/bot.yml. It should contain
|
51
|
+
atleast:
|
52
|
+
|
53
|
+
login: jabber_login
|
54
|
+
password: jabber_password
|
55
|
+
channel: channel_to_join
|
56
|
+
server: server_to_connect_to
|
57
|
+
nick: mybot
|
58
|
+
|
59
|
+
You can also configure with Ruby:
|
60
|
+
|
61
|
+
configure do |conf|
|
62
|
+
conf.login = "my_account"
|
63
|
+
conf.nick = "mybot"
|
64
|
+
do
|
65
|
+
|
66
|
+
If you don't specify login and/or password in any of these ways, Jabbot will fail
|
67
|
+
Nick is automatically set to "jabbot" unless something different is defined
|
68
|
+
If you want you can set the Jabber Resource:
|
69
|
+
|
70
|
+
configure do |conf|
|
71
|
+
conf.resource ="mybot_resource"
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
Default is "jabbot".
|
76
|
+
|
77
|
+
### "Routes"
|
78
|
+
|
79
|
+
Like Sinatra, and other web app frameworks, Jabbot supports "routes":
|
80
|
+
patterns to match incoming tweets and messages:
|
81
|
+
|
82
|
+
message "time :country :city" do |message, params|
|
83
|
+
time = MyTimeService.lookup(params[:country], params[:city])
|
84
|
+
post "Time is #{time} in #{params[:city]}, #{params[:country]}"
|
85
|
+
end
|
86
|
+
|
87
|
+
You can have several "message" blocks (or "join", "leave", "query" or "subject").
|
88
|
+
Every matching block will be called.
|
89
|
+
|
90
|
+
Jabbot also supports regular expressions as routes:
|
91
|
+
|
92
|
+
message /^time ([^\s]*) ([^\s]*)/ do |message, params|
|
93
|
+
# params is an array of matches when using regexp routes
|
94
|
+
time = MyTimeService.lookup(params[0], params[1])
|
95
|
+
post "Time is #{time} in #{params[:city]}, #{params[:country]}"
|
96
|
+
end
|
97
|
+
|
98
|
+
## Requirements
|
99
|
+
|
100
|
+
xmpp4r. You'll need atleast 0.4.
|
101
|
+
You can get it via rubygems:
|
102
|
+
|
103
|
+
gem install xmpp4r
|
104
|
+
|
105
|
+
or get it from: http://home.gna.org/xmpp4r/
|
106
|
+
|
107
|
+
## Installation
|
108
|
+
|
109
|
+
Jabbot is available via gem:
|
110
|
+
|
111
|
+
gem install jabbot
|
112
|
+
|
113
|
+
## Is it Ruby 1.9?
|
114
|
+
|
115
|
+
All tests passes on Ruby 1.9.
|
116
|
+
Seems like it works :)
|
117
|
+
|
118
|
+
## Samples
|
119
|
+
|
120
|
+
There are two examples in the [samples][] directory:
|
121
|
+
|
122
|
+
* [jabbot_example.rb][] is a working sample without real functionality.
|
123
|
+
* [black.rb][] is the code I use for my own bot (without the config of course).
|
124
|
+
|
125
|
+
## Contributors
|
126
|
+
|
127
|
+
* Christian Johansen (cjohansen) (author of Twibot) - http://www.cjohansen.no
|
128
|
+
|
129
|
+
## License
|
130
|
+
|
131
|
+
The code is released under the MIT license. See [LICENSE][].
|
132
|
+
|
133
|
+
## Contribute
|
134
|
+
|
135
|
+
If you'd like to hack on jabbot, start by forking my repo on GitHub:
|
136
|
+
|
137
|
+
http://github.com/badboy/jabbot
|
138
|
+
|
139
|
+
jabbot needs xmpp4r, so just install it:
|
140
|
+
|
141
|
+
gem install xmpp4r
|
142
|
+
|
143
|
+
Then:
|
144
|
+
|
145
|
+
1. Clone down your fork
|
146
|
+
2. Create a thoughtfully named topic branch to contain your change
|
147
|
+
3. Hack away
|
148
|
+
4. Add tests and make sure everything still passes by running `rake`
|
149
|
+
5. If you are adding new functionality, document it in the README
|
150
|
+
6. Do not change the version number, I will do that on my end
|
151
|
+
7. If necessary, rebase your commits into logical chunks, without errors
|
152
|
+
8. Push the branch up to GitHub
|
153
|
+
9. Send me (badboy) a pull request for your branch
|
154
|
+
|
155
|
+
[LICENSE]: http://github.com/badboy/jabbot/blob/master/LICENSE
|
156
|
+
[jabbot_example.rb]: http://github.com/badboy/jabbot/blob/master/samples/jabbot_example.rb
|
157
|
+
[black.rb]: http://github.com/badboy/jabbot/blob/master/samples/black.rb
|
data/Rakefile
CHANGED
@@ -1,24 +1,11 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rake'
|
3
|
-
|
4
1
|
begin
|
5
|
-
require '
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "jabbot"
|
8
|
-
gem.summary = %Q{Simple framework for creating Jabber/MUC bots, inspired by Sinatra and Twibot}
|
9
|
-
gem.email = "badboy@archlinux.us"
|
10
|
-
gem.homepage = "http://github.com/badboy/jabbot"
|
11
|
-
gem.authors = ["BadBoy_"]
|
12
|
-
gem.add_dependency('xmpp4r', '>=0.4')
|
13
|
-
gem.add_development_dependency('thoughtbot-shoulda', '>=2.10.1')
|
14
|
-
gem.add_development_dependency('jeweler', '>=0.10.2')
|
15
|
-
|
16
|
-
gem.rubyforge_project = 'jabbot'
|
17
|
-
end
|
2
|
+
require 'mg'
|
18
3
|
rescue LoadError
|
19
|
-
|
4
|
+
abort "Please `gem install mg`"
|
20
5
|
end
|
21
6
|
|
7
|
+
MG.new("jabbot.gemspec")
|
8
|
+
|
22
9
|
require 'rake/testtask'
|
23
10
|
Rake::TestTask.new(:test) do |test|
|
24
11
|
test.libs << 'lib' << 'test'
|
@@ -27,19 +14,3 @@ Rake::TestTask.new(:test) do |test|
|
|
27
14
|
end
|
28
15
|
|
29
16
|
task :default => :test
|
30
|
-
|
31
|
-
require 'rake/rdoctask'
|
32
|
-
Rake::RDocTask.new do |rdoc|
|
33
|
-
if File.exist?('VERSION.yml')
|
34
|
-
config = YAML.load(File.read('VERSION.yml'))
|
35
|
-
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
36
|
-
else
|
37
|
-
version = ""
|
38
|
-
end
|
39
|
-
|
40
|
-
rdoc.rdoc_dir = 'rdoc'
|
41
|
-
rdoc.title = "jabbot #{version}"
|
42
|
-
rdoc.rdoc_files.include('README*')
|
43
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
-
end
|
45
|
-
|
data/lib/jabbot.rb
CHANGED
@@ -6,47 +6,14 @@ require 'xmpp4r/version/helper/simpleresponder'
|
|
6
6
|
require 'yaml'
|
7
7
|
require File.join(File.dirname(__FILE__), 'hash')
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# :startdoc:
|
16
|
-
|
17
|
-
# Returns the version string for the library.
|
18
|
-
#
|
19
|
-
def self.version
|
20
|
-
VERSION
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns the library path for the module. If any arguments are given,
|
24
|
-
# they will be joined to the end of the libray path using
|
25
|
-
# <tt>File.join</tt>.
|
26
|
-
#
|
27
|
-
def self.libpath( *args )
|
28
|
-
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Returns the lpath for the module. If any arguments are given,
|
32
|
-
# they will be joined to the end of the path using
|
33
|
-
# <tt>File.join</tt>.
|
34
|
-
#
|
35
|
-
def self.path( *args )
|
36
|
-
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Utility method used to require all files ending in .rb that lie in the
|
40
|
-
# directory below this file that has the same name as the filename passed
|
41
|
-
# in. Optionally, a specific _directory_ name can be passed in such that
|
42
|
-
# the _filename_ does not have to be equivalent to the directory.
|
43
|
-
#
|
44
|
-
def self.require_all_libs_relative_to( fname, dir = nil )
|
45
|
-
dir ||= File.basename(fname, '.*')
|
46
|
-
search_me = File.expand_path(File.join(File.dirname(fname), dir, '**', '*.rb'))
|
47
|
-
Dir.glob(search_me).sort.each {|rb| require rb }
|
48
|
-
end
|
9
|
+
require 'jabbot/bot.rb'
|
10
|
+
require 'jabbot/config.rb'
|
11
|
+
require 'jabbot/handlers.rb'
|
12
|
+
require 'jabbot/macros.rb'
|
13
|
+
require 'jabbot/message.rb'
|
14
|
+
require 'jabbot/version.rb'
|
49
15
|
|
16
|
+
module Jabbot
|
50
17
|
@@app_file = lambda do
|
51
18
|
ignore = [
|
52
19
|
/lib\/twibot.*\.rb/, # Library
|
@@ -79,6 +46,5 @@ module Jabbot
|
|
79
46
|
end # module Jabbot
|
80
47
|
|
81
48
|
Thread.abort_on_exception = true
|
82
|
-
Jabbot.require_all_libs_relative_to(__FILE__)
|
83
49
|
|
84
50
|
# EOF
|
data/lib/jabbot/bot.rb
CHANGED
@@ -9,7 +9,7 @@ module Jabbot
|
|
9
9
|
class Bot
|
10
10
|
include Jabbot::Handlers
|
11
11
|
attr_reader :client
|
12
|
-
attr_reader :
|
12
|
+
attr_reader :users
|
13
13
|
|
14
14
|
Message = Struct.new(:user, :text, :time) do
|
15
15
|
def to_s
|
@@ -22,16 +22,26 @@ module Jabbot
|
|
22
22
|
@config = options || Jabbot::Config.default << Jabbot::FileConfig.new
|
23
23
|
@log = nil
|
24
24
|
@abort = false
|
25
|
-
@
|
25
|
+
@users = []
|
26
26
|
|
27
27
|
rescue Exception => krash
|
28
28
|
raise SystemExit.new(krash.message)
|
29
29
|
end
|
30
30
|
|
31
|
+
# Enable debugging mode.
|
32
|
+
# All xmpp4r-internal calls to Jabber::Debuglog are
|
33
|
+
# printed to $stderr by default.
|
34
|
+
# You may change the logger by using
|
35
|
+
# Jabber::Logger = Logger.new(…)
|
36
|
+
def debug!
|
37
|
+
Jabber::debug = true
|
38
|
+
end
|
39
|
+
|
31
40
|
#
|
32
41
|
# connect to Jabber and join channel
|
33
42
|
#
|
34
43
|
def connect
|
44
|
+
#Jabber::debug = true
|
35
45
|
@jid = Jabber::JID.new(login)
|
36
46
|
@mucjid = Jabber::JID.new("#{channel}@#{server}")
|
37
47
|
|
@@ -46,7 +56,7 @@ module Jabbot
|
|
46
56
|
else
|
47
57
|
@jid.resource = config[:resource] || "jabbot"
|
48
58
|
@mucjid.resource = config[:nick] || "jabbot"
|
49
|
-
@
|
59
|
+
@users << config[:nick]
|
50
60
|
end
|
51
61
|
|
52
62
|
@client = Jabber::Client.new(@jid)
|
@@ -74,6 +84,7 @@ module Jabbot
|
|
74
84
|
exit
|
75
85
|
end
|
76
86
|
|
87
|
+
debug! if config[:debug]
|
77
88
|
connect
|
78
89
|
poll
|
79
90
|
end
|
@@ -143,8 +154,8 @@ module Jabbot
|
|
143
154
|
end
|
144
155
|
|
145
156
|
muc.on_join do |time, nick|
|
146
|
-
unless @
|
147
|
-
@
|
157
|
+
unless @users.include? nick
|
158
|
+
@users << nick
|
148
159
|
end
|
149
160
|
if time.nil?
|
150
161
|
begin
|
@@ -155,9 +166,9 @@ module Jabbot
|
|
155
166
|
end
|
156
167
|
end
|
157
168
|
end
|
158
|
-
|
169
|
+
|
159
170
|
muc.on_leave do |time, nick|
|
160
|
-
@
|
171
|
+
@users.delete(nick)
|
161
172
|
if time.nil?
|
162
173
|
begin
|
163
174
|
dispatch_messages(:leave, [Message.new(nick, "leave", Time.now)])
|
@@ -167,7 +178,7 @@ module Jabbot
|
|
167
178
|
end
|
168
179
|
end
|
169
180
|
end
|
170
|
-
|
181
|
+
|
171
182
|
muc.on_subject do |time, nick, subject|
|
172
183
|
if time.nil?
|
173
184
|
begin
|
@@ -213,7 +224,6 @@ module Jabbot
|
|
213
224
|
@conf = nil
|
214
225
|
end
|
215
226
|
|
216
|
-
private
|
217
227
|
#
|
218
228
|
# Map configuration settings
|
219
229
|
#
|
data/lib/jabbot/config.rb
CHANGED
data/lib/jabbot/macros.rb
CHANGED
@@ -1,54 +1,105 @@
|
|
1
1
|
module Jabbot
|
2
|
-
|
3
|
-
|
4
|
-
def self.prompt=(p)
|
5
|
-
@@prompt = f
|
6
|
-
end
|
7
|
-
|
2
|
+
# Defines the DSL used for bots.
|
8
3
|
module Macros
|
9
4
|
def self.included(mod)
|
10
5
|
@@bot = nil
|
11
6
|
end
|
12
7
|
|
8
|
+
# Configure the bot
|
9
|
+
# The block gets passed an instance of OpenStruct used as the config
|
10
|
+
# See lib/jabbot/config.rb for possible options
|
13
11
|
def configure(&blk)
|
14
12
|
bot.configure(&blk)
|
15
13
|
end
|
16
14
|
|
15
|
+
# Returns the current config hash
|
16
|
+
def config
|
17
|
+
bot.config
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add message handler
|
21
|
+
# pattern - can be a String containing :matches
|
22
|
+
# or a Regexp with matching groups
|
23
|
+
# options - Hash defining users to receive messages from
|
24
|
+
# { :from => ['user1', 'user2', ...] }
|
25
|
+
# blk - The block to execute on successfull match
|
17
26
|
def message(pattern = nil, options = {}, &blk)
|
18
27
|
add_handler(:message, pattern, options, &blk)
|
19
28
|
end
|
20
29
|
|
30
|
+
# Add query handler
|
31
|
+
# Only private messages are matched against this handler
|
32
|
+
#
|
33
|
+
# pattern - can be a String containing :matches
|
34
|
+
# or a Regexp with matching groups
|
35
|
+
# options - Hash defining users to receive messages from
|
36
|
+
# { :from => ['user1', 'user2', ...] }
|
37
|
+
# blk - The block to execute on successfull match
|
21
38
|
def query(pattern = nil, options = {}, &blk)
|
22
39
|
add_handler(:private, pattern, options, &blk)
|
23
40
|
end
|
24
41
|
alias_method :private_message, :query
|
25
42
|
|
43
|
+
# Add join handler
|
44
|
+
# Block gets executed when new user joins
|
45
|
+
#
|
46
|
+
# options - Hash defining users to react on joins
|
47
|
+
# { :from => ['user1', 'user2', ...] }
|
48
|
+
# blk - The block to execute on successfull match
|
26
49
|
def join(options = {}, &blk)
|
27
50
|
add_handler(:join, /\Ajoin\Z/, options, &blk)
|
28
51
|
end
|
29
|
-
|
52
|
+
|
53
|
+
# Add leave handler
|
54
|
+
# Block gets executed when user leaves the channel
|
55
|
+
#
|
56
|
+
# options - Hash defining users to react on leaves
|
57
|
+
# { :from => ['user1', 'user2', ...] }
|
58
|
+
# blk - The block to execute on successfull match
|
30
59
|
def leave(options = {}, &blk)
|
31
60
|
add_handler(:leave, /\Aleave\Z/, options, &blk)
|
32
61
|
end
|
33
62
|
|
63
|
+
# Add subject/topic handler
|
64
|
+
# Block gets executed when topic gets changed
|
65
|
+
#
|
66
|
+
# pattern - can be a String containing :matches
|
67
|
+
# or a Regexp with matching groups
|
68
|
+
# options - Hash defining users
|
69
|
+
# { :from => ['user1', 'user2', ...] }
|
70
|
+
# blk - The block to execute on successfull match
|
34
71
|
def subject(pattern = nil, options = {}, &blk)
|
35
72
|
add_handler(:subject, pattern, options, &blk)
|
36
73
|
end
|
37
74
|
alias_method :topic, :subject
|
38
75
|
|
76
|
+
# Returns the Jabber::Client instance used
|
77
|
+
# You may execute low-level functions on this object if needed
|
39
78
|
def client
|
40
79
|
bot.client
|
41
80
|
end
|
42
81
|
|
82
|
+
# Close the connection and exit the bot
|
43
83
|
def close
|
44
84
|
bot.close
|
45
85
|
end
|
46
86
|
alias_method :quit, :close
|
47
87
|
|
48
|
-
|
49
|
-
|
88
|
+
# Get array of all users in the channel
|
89
|
+
def users
|
90
|
+
bot.users
|
50
91
|
end
|
51
92
|
|
93
|
+
# Post message back to the channel
|
94
|
+
# msg - Message to send, can be a String to be send
|
95
|
+
# or a Hash: { msg => user }
|
96
|
+
# to - User to send the message to,
|
97
|
+
# left blank if syntax-sugar variant is used
|
98
|
+
#
|
99
|
+
# Syntax-sugar variant:
|
100
|
+
# post "msg" => "user1"
|
101
|
+
# is the same as
|
102
|
+
# post "msg", "user1"
|
52
103
|
def post(msg, to=nil)
|
53
104
|
if msg.is_a?(Hash) && msg.keys.size == 1
|
54
105
|
to = msg.values.first
|
@@ -57,15 +108,19 @@ module Jabbot
|
|
57
108
|
bot.send_message(msg, to)
|
58
109
|
end
|
59
110
|
|
111
|
+
# Returns boolean wether to start the bot at_exit
|
60
112
|
def run?
|
61
113
|
!@@bot.nil?
|
62
114
|
end
|
63
115
|
|
64
|
-
|
116
|
+
private
|
117
|
+
|
118
|
+
# Low-level method to add new Handler to the bot
|
65
119
|
def add_handler(type, pattern, options, &blk)
|
66
120
|
bot.add_handler(type, Jabbot::Handler.new(pattern, options, &blk))
|
67
121
|
end
|
68
122
|
|
123
|
+
# Low-level method to create new instance of a bot
|
69
124
|
def bot
|
70
125
|
return @@bot unless @@bot.nil?
|
71
126
|
|