jabbot 0.3.2 → 1.0.0
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.
- checksums.yaml +7 -0
- data/README.md +72 -70
- data/lib/jabbot.rb +1 -2
- data/lib/jabbot/bot.rb +72 -58
- data/lib/jabbot/config.rb +67 -95
- data/lib/jabbot/handlers.rb +6 -14
- data/lib/jabbot/version.rb +3 -0
- data/test/helper.rb +1 -31
- data/test/test_bot.rb +5 -33
- data/test/test_config.rb +6 -67
- data/test/test_macros.rb +2 -2
- metadata +73 -64
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 275301838af799f27e719e700580c9d4accd3b61
|
4
|
+
data.tar.gz: 537c0a93513ab40c135ec60e526b5983b36b56c8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 398e664b0beb9b285f7c3de5122449639b135913d98a43214240363757068d34a87537e88fe7cdef7efccf62ff6739c686f800a105bf84546a496c806999488f
|
7
|
+
data.tar.gz: 62509ecd7c7e52fce6bb59ed314d878f6f7f2ca908237f641e969ff426019476ba4f6d59614fc74ef32d86d74deaeb84ee7d308d9358ebcb5b1284f4730ba682
|
data/README.md
CHANGED
@@ -2,79 +2,79 @@
|
|
2
2
|
|
3
3
|
## Description
|
4
4
|
|
5
|
-
Jabbot is a Ruby micro-framework for creating Jabber/MUC bots,
|
6
|
-
heavily inspired by Sinatra and Twibot.
|
5
|
+
Jabbot is a Ruby micro-framework for creating Jabber/MUC bots, heavily inspired by Sinatra and Twibot.
|
7
6
|
|
8
|
-
I modified the code of Twibot to fit my needs.
|
9
|
-
The original Twibot code is located at:
|
10
|
-
http://github.com/cjohansen/twibot/tree/master
|
7
|
+
I modified the code of Twibot to fit my needs. The original Twibot code is located at: <http://github.com/cjohansen/twibot>
|
11
8
|
|
12
|
-
A big thank you to Christian Johansen, who wrote the code for Twibot.
|
13
|
-
Jabbot is heavily based on his code.
|
9
|
+
A big thank you to Christian Johansen, who wrote the code for Twibot. Jabbot is heavily based on his code.
|
14
10
|
|
15
11
|
If your curious if this code is stable enough:
|
16
|
-
I have a bot instance running on my server for
|
17
|
-
and it works great :)
|
12
|
+
I have a bot instance running on my server for years now and it works great :)
|
18
13
|
|
19
|
-
|
14
|
+
Just keep in mind that the code is not the most beautiful, maybe has bugs or rough edges. Feel free to improve it. I use it as is.
|
20
15
|
|
21
|
-
### Simple example
|
22
16
|
|
23
|
-
|
24
|
-
message do |message, params|
|
25
|
-
post message.text
|
26
|
-
end
|
17
|
+
## Usage
|
27
18
|
|
28
|
-
|
29
|
-
# query "message" => "user" is just some syntax sugar
|
30
|
-
# query "message", "user" will work, too
|
31
|
-
query :from => [:cjno, :irbno] do |message, params|
|
32
|
-
post "#{message.user} I agree" => message.user
|
33
|
-
end
|
19
|
+
### Simple example
|
34
20
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
21
|
+
~~~ruby
|
22
|
+
configure do |conf|
|
23
|
+
conf.login = "my_account"
|
24
|
+
conf.password = "my_account"
|
25
|
+
conf.nick = "mybot"
|
26
|
+
conf.channel = "mychannel"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Receive messages, and post them publicly
|
30
|
+
message do |message, params|
|
31
|
+
post message.text
|
32
|
+
end
|
33
|
+
|
34
|
+
# Respond to query if they come from the right crowd
|
35
|
+
# query "message" => "user" is just some syntax sugar
|
36
|
+
# query "message", "user" will work, too
|
37
|
+
query :from => [:cjno, :irbno] do |message, params|
|
38
|
+
post "#{message.user} I agree" => message.user
|
39
|
+
end
|
40
|
+
|
41
|
+
# Log every single line
|
42
|
+
# (you can use "message :all" too ;)
|
43
|
+
message do |message, params|
|
44
|
+
MyApp.log_message(message)
|
45
|
+
end
|
46
|
+
~~~
|
40
47
|
|
41
48
|
### Running the bot
|
42
49
|
|
43
50
|
To run the bot, simply do:
|
44
51
|
|
45
|
-
|
52
|
+
~~~
|
53
|
+
ruby bot.rb
|
54
|
+
~~~
|
46
55
|
|
47
56
|
Jabbot uses the [at\_exit hook](http://ruby-doc.org/core/classes/Kernel.html#M005932) to start.
|
48
57
|
|
49
58
|
### Configuration
|
50
59
|
|
51
|
-
|
52
|
-
|
53
|
-
Jabbot looks for a configuration file in ./config/bot.yml. It should contain
|
54
|
-
atleast:
|
60
|
+
You have to configure your bot via ruby:
|
55
61
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
62
|
+
~~~ruby
|
63
|
+
configure do |conf|
|
64
|
+
conf.login = "my_account"
|
65
|
+
conf.nick = "mybot"
|
66
|
+
end
|
67
|
+
~~~
|
61
68
|
|
62
|
-
|
69
|
+
If you don't specify login and/or password in any of these ways, Jabbot will fail. The nick is automatically set to "jabbot" unless something different is defined. If you want you can set the XMPP Resource:
|
63
70
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
71
|
+
~~~ruby
|
72
|
+
configure do |conf|
|
73
|
+
conf.resource ="mybot_resource"
|
74
|
+
end
|
75
|
+
~~~
|
68
76
|
|
69
|
-
|
70
|
-
Nick is automatically set to "jabbot" unless something different is defined
|
71
|
-
If you want you can set the XMPP Resource:
|
72
|
-
|
73
|
-
configure do |conf|
|
74
|
-
conf.resource ="mybot_resource"
|
75
|
-
end
|
76
|
-
|
77
|
-
Default is "jabbot".
|
77
|
+
Default resource is "jabbot".
|
78
78
|
|
79
79
|
### "Routes"
|
80
80
|
|
@@ -91,39 +91,45 @@ Every matching block will be called.
|
|
91
91
|
|
92
92
|
Jabbot also supports regular expressions as routes:
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
~~~ruby
|
95
|
+
message /^time ([^\s]*) ([^\s]*)/ do |message, params|
|
96
|
+
# params is an array of matches when using regexp routes
|
97
|
+
time = MyTimeService.lookup(params[0], params[1])
|
98
|
+
post "Time is #{time} in #{params[:city]}, #{params[:country]}"
|
99
|
+
end
|
100
|
+
~~~
|
99
101
|
|
100
102
|
If all you need is exact word matching you can say so:
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
-
|
104
|
+
~~~ruby
|
105
|
+
message :exact => "pattern" do |message, params|
|
106
|
+
...
|
107
|
+
end
|
108
|
+
~~~
|
105
109
|
|
106
110
|
Internally this pattern is translated to `/\Apattern\Z/`, so you can use regex literals.
|
107
111
|
|
108
112
|
## Requirements
|
109
113
|
|
110
|
-
xmpp4r. You'll need atleast 0.4.
|
111
|
-
|
112
|
-
|
113
|
-
gem install xmpp4r
|
114
|
+
* xmpp4r. You'll need atleast 0.4. You can get it via rubygems: `gem install xmpp4r`
|
115
|
+
* eventmachine. `gem install eventmachine`
|
114
116
|
|
115
|
-
or get it from: http://home.gna.org/xmpp4r/
|
116
117
|
|
117
118
|
## Installation
|
118
119
|
|
119
120
|
Jabbot is available via gem:
|
120
121
|
|
121
|
-
|
122
|
+
~~~
|
123
|
+
gem install jabbot
|
124
|
+
~~~
|
122
125
|
|
123
126
|
## Is it Ruby 1.9?
|
124
127
|
|
125
|
-
|
126
|
-
|
128
|
+
Absolutely! I run it on 1.9.3 without problems (thanks to the updated xmpp4r).
|
129
|
+
|
130
|
+
## Is it Ruby 2.x?
|
131
|
+
|
132
|
+
It should, test pass. I'm not sure if it will work as expected.
|
127
133
|
|
128
134
|
## Samples
|
129
135
|
|
@@ -146,10 +152,6 @@ If you'd like to hack on jabbot, start by forking my repo on GitHub:
|
|
146
152
|
|
147
153
|
http://github.com/badboy/jabbot
|
148
154
|
|
149
|
-
jabbot needs xmpp4r, so just install it:
|
150
|
-
|
151
|
-
gem install xmpp4r
|
152
|
-
|
153
155
|
Then:
|
154
156
|
|
155
157
|
1. Clone down your fork
|
data/lib/jabbot.rb
CHANGED
@@ -6,14 +6,13 @@ require 'xmpp4r/version/helper/simpleresponder'
|
|
6
6
|
require 'yaml'
|
7
7
|
require File.join(File.dirname(__FILE__), 'hash')
|
8
8
|
|
9
|
+
require 'jabbot/version.rb'
|
9
10
|
require 'jabbot/bot.rb'
|
10
11
|
require 'jabbot/config.rb'
|
11
12
|
require 'jabbot/handlers.rb'
|
12
13
|
require 'jabbot/macros.rb'
|
13
14
|
|
14
15
|
module Jabbot
|
15
|
-
VERSION = '0.3.2'
|
16
|
-
|
17
16
|
@@app_file = lambda do
|
18
17
|
ignore = [
|
19
18
|
/lib\/twibot.*\.rb/, # Library
|
data/lib/jabbot/bot.rb
CHANGED
@@ -5,6 +5,38 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'handlers')
|
|
5
5
|
require 'eventmachine'
|
6
6
|
|
7
7
|
module Jabbot
|
8
|
+
# A message consists of the username, the text, a time when it was received
|
9
|
+
# and the type of the message.
|
10
|
+
#
|
11
|
+
# The type could be one Symbol of:
|
12
|
+
#
|
13
|
+
# * :public
|
14
|
+
# * :private
|
15
|
+
# * :join
|
16
|
+
# * :leave
|
17
|
+
# * :subject
|
18
|
+
#
|
19
|
+
Message = Struct.new(:user, :text, :time, :type) do
|
20
|
+
# Public: Converts the message to printable text.
|
21
|
+
#
|
22
|
+
# Returns a String containing the user's name and the text.
|
23
|
+
def to_s
|
24
|
+
"#{user}: #{text}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Encode a message in JSON
|
28
|
+
#
|
29
|
+
# Returns the json-ified String of the Hash representation of this message.
|
30
|
+
def to_json(*a)
|
31
|
+
{
|
32
|
+
:user => user,
|
33
|
+
:text => text,
|
34
|
+
:time => time,
|
35
|
+
:type => type
|
36
|
+
}.to_json(*a)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
8
40
|
# The main Bot class.
|
9
41
|
#
|
10
42
|
# It handles the connection as well as the method dispatching.
|
@@ -13,29 +45,17 @@ module Jabbot
|
|
13
45
|
attr_reader :client
|
14
46
|
attr_reader :users
|
15
47
|
|
16
|
-
Message = Struct.new(:user, :text, :time, :type) do
|
17
|
-
def to_s
|
18
|
-
"#{user}: #{text}"
|
19
|
-
end
|
20
|
-
|
21
|
-
# Encode a message in JSON
|
22
|
-
# A message is just a hash of its values
|
23
|
-
def to_json(*a)
|
24
|
-
{
|
25
|
-
:user => user,
|
26
|
-
:text => text,
|
27
|
-
:time => time,
|
28
|
-
:type => type
|
29
|
-
}.to_json(*a)
|
30
|
-
end
|
31
|
-
end
|
32
48
|
|
33
49
|
# Public: Initialize a Bot instance.
|
34
50
|
#
|
35
|
-
# options - A Jabbot::Config options instance
|
36
|
-
|
37
|
-
|
38
|
-
@config = options
|
51
|
+
# options - A Jabbot::Config options instance or a Hash of key-value
|
52
|
+
# configuration options (default: {}).
|
53
|
+
def initialize(options={})
|
54
|
+
@config = if options.kind_of?(Jabbot::Config)
|
55
|
+
options
|
56
|
+
else
|
57
|
+
Jabbot::Config.new(options)
|
58
|
+
end
|
39
59
|
@log = nil
|
40
60
|
@abort = false
|
41
61
|
@users = []
|
@@ -64,21 +84,21 @@ module Jabbot
|
|
64
84
|
#
|
65
85
|
# Returns nothing.
|
66
86
|
def connect
|
67
|
-
@jid = Jabber::JID.new(login)
|
68
|
-
@mucjid = Jabber::JID.new("#{channel}@#{server}")
|
87
|
+
@jid = Jabber::JID.new(config.login)
|
88
|
+
@mucjid = Jabber::JID.new("#{config.channel}@#{config.server}")
|
69
89
|
|
70
90
|
if @jid.node.nil?
|
71
91
|
raise "Your Jabber ID must contain a user name and therefore contain one @ character."
|
72
92
|
elsif @jid.resource
|
73
|
-
raise "If you intend to set a custom resource,
|
93
|
+
raise "If you intend to set a custom resource, define so in the config."
|
74
94
|
elsif @mucjid.node.nil?
|
75
95
|
raise "Please set a room name, e.g. myroom@conference.jabber.org"
|
76
96
|
elsif @mucjid.resource
|
77
97
|
raise "The MUC room must not contain a resource. Remove the slash!"
|
78
98
|
else
|
79
|
-
@jid.resource = config
|
80
|
-
@mucjid.resource = config
|
81
|
-
@users << config
|
99
|
+
@jid.resource = config.resource
|
100
|
+
@mucjid.resource = config.nick
|
101
|
+
@users << config.nick
|
82
102
|
end
|
83
103
|
|
84
104
|
@client = Jabber::Client.new(@jid)
|
@@ -92,10 +112,10 @@ module Jabbot
|
|
92
112
|
end
|
93
113
|
begin
|
94
114
|
@client.connect
|
95
|
-
@client.auth(password)
|
115
|
+
@client.auth(config.password)
|
96
116
|
@muc = Jabber::MUC::SimpleMUCClient.new(@client)
|
97
117
|
muc_handlers.call(@muc)
|
98
|
-
@muc.join(@mucjid)
|
118
|
+
@muc.join(@mucjid, config.channel_password)
|
99
119
|
@connected = true
|
100
120
|
rescue => errmsg
|
101
121
|
@connected = false
|
@@ -112,7 +132,7 @@ module Jabbot
|
|
112
132
|
#
|
113
133
|
# Returns nothing.
|
114
134
|
def run!
|
115
|
-
puts "Jabbot #{Jabbot::VERSION} imposing as #{login} on #{channel}@#{server}"
|
135
|
+
puts "Jabbot #{Jabbot::VERSION} imposing as #{config.login} on #{config.channel}@#{config.server}"
|
116
136
|
|
117
137
|
onclose_block = proc {
|
118
138
|
close
|
@@ -121,11 +141,11 @@ module Jabbot
|
|
121
141
|
}
|
122
142
|
|
123
143
|
Kernel.trap(:INT, onclose_block)
|
124
|
-
Kernel.trap(:QUIT, onclose_block)
|
144
|
+
Kernel.trap(:QUIT, onclose_block) rescue nil
|
125
145
|
|
126
|
-
debug! if config
|
146
|
+
debug! if config.debug
|
127
147
|
|
128
|
-
#
|
148
|
+
# Connect the bot and keep it running.
|
129
149
|
EventMachine.run do
|
130
150
|
connect
|
131
151
|
|
@@ -175,13 +195,13 @@ module Jabbot
|
|
175
195
|
# * leaves
|
176
196
|
# * subject changes
|
177
197
|
#
|
178
|
-
# Returs
|
198
|
+
# Returs a Proc to be called to assign the handlers.
|
179
199
|
def muc_handlers
|
180
200
|
Proc.new do |muc|
|
181
201
|
muc.on_message do |time, nick, text|
|
182
|
-
if time.nil?
|
202
|
+
if time.nil? # Don't process messages from the past.
|
183
203
|
begin
|
184
|
-
dispatch_messages(:message, [Message.new(nick, text, Time.now, :public)]) unless nick == config
|
204
|
+
dispatch_messages(:message, [Message.new(nick, text, Time.now, :public)]) unless nick == config.nick
|
185
205
|
rescue Exception => boom
|
186
206
|
log.fatal boom.inspect
|
187
207
|
log.fatal boom.backtrace[0..5].join("\n")
|
@@ -190,9 +210,9 @@ module Jabbot
|
|
190
210
|
end
|
191
211
|
|
192
212
|
muc.on_private_message do |time, nick, text|
|
193
|
-
if time.nil?
|
213
|
+
if time.nil? # Don't process messages from the past.
|
194
214
|
begin
|
195
|
-
dispatch_messages(:private, [Message.new(nick, text, Time.now, :
|
215
|
+
dispatch_messages(:private, [Message.new(nick, text, Time.now, :private)]) unless nick == config.nick
|
196
216
|
rescue Exception => boom
|
197
217
|
log.fatal boom.inspect
|
198
218
|
log.fatal boom.backtrace[0..5].join("\n")
|
@@ -204,9 +224,9 @@ module Jabbot
|
|
204
224
|
unless @users.include? nick
|
205
225
|
@users << nick
|
206
226
|
end
|
207
|
-
if time.nil?
|
227
|
+
if time.nil? # Don't process messages from the past.
|
208
228
|
begin
|
209
|
-
dispatch_messages(:join, [Message.new(nick, "join", Time.now, :join)]) unless nick == config
|
229
|
+
dispatch_messages(:join, [Message.new(nick, "join", Time.now, :join)]) unless nick == config.nick
|
210
230
|
rescue Exception => boom
|
211
231
|
log.fatal boom.inspect
|
212
232
|
log.fatal boom.backtrace[0..5].join("\n")
|
@@ -216,7 +236,7 @@ module Jabbot
|
|
216
236
|
|
217
237
|
muc.on_leave do |time, nick|
|
218
238
|
@users.delete(nick)
|
219
|
-
if time.nil?
|
239
|
+
if time.nil? # Don't process messages from the past.
|
220
240
|
begin
|
221
241
|
dispatch_messages(:leave, [Message.new(nick, "leave", Time.now, :leave)])
|
222
242
|
rescue Exception => boom
|
@@ -227,7 +247,7 @@ module Jabbot
|
|
227
247
|
end
|
228
248
|
|
229
249
|
muc.on_subject do |time, nick, subject|
|
230
|
-
if time.nil?
|
250
|
+
if time.nil? # Don't process messages from the past.
|
231
251
|
begin
|
232
252
|
dispatch_messages(:subject, [Message.new(nick, subject, Time.now, :subject)])
|
233
253
|
rescue Exception => boom
|
@@ -239,7 +259,7 @@ module Jabbot
|
|
239
259
|
end
|
240
260
|
end
|
241
261
|
|
242
|
-
# Dispatch a collection of messages.
|
262
|
+
# Internal: Dispatch a collection of messages.
|
243
263
|
#
|
244
264
|
# type - The Symbol type to be processed.
|
245
265
|
# messages - An Array of String messages to be dispatched.
|
@@ -255,9 +275,9 @@ module Jabbot
|
|
255
275
|
# Returns logger instance.
|
256
276
|
def log
|
257
277
|
return @log if @log
|
258
|
-
os = config
|
278
|
+
os = config.log_file ? File.open(config.log_file, "a") : $stdout
|
259
279
|
@log = Logger.new(os)
|
260
|
-
@log.level = Logger.const_get(config
|
280
|
+
@log.level = Logger.const_get(config.log_level ? config.log_level.upcase : "INFO")
|
261
281
|
@log
|
262
282
|
end
|
263
283
|
|
@@ -266,26 +286,20 @@ module Jabbot
|
|
266
286
|
# Returns the configure Hash.
|
267
287
|
def configure
|
268
288
|
yield @config
|
269
|
-
@conf = @config.to_hash
|
270
|
-
end
|
271
|
-
|
272
|
-
# Internal: Maps configuration settings to real methods.
|
273
|
-
#
|
274
|
-
# Returns the value of the configuration setting
|
275
|
-
# or nil if none is found.
|
276
|
-
def method_missing(name, *args, &block)
|
277
|
-
return super unless config.key?(name)
|
278
|
-
|
279
|
-
self.class.send(:define_method, name) { config[name] }
|
280
|
-
config[name]
|
281
289
|
end
|
282
290
|
|
283
291
|
# Public: Get the current configuration settings.
|
284
292
|
#
|
285
293
|
# Returns the configuration Hash.
|
286
294
|
def config
|
287
|
-
|
288
|
-
|
295
|
+
@config
|
296
|
+
end
|
297
|
+
|
298
|
+
# Public: Easy access to the bot's nickname
|
299
|
+
#
|
300
|
+
# Returns the configured nick String.
|
301
|
+
def nick
|
302
|
+
@config.nick
|
289
303
|
end
|
290
304
|
end
|
291
305
|
end
|
data/lib/jabbot/config.rb
CHANGED
@@ -1,108 +1,80 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
1
|
module Jabbot
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
2
|
+
# Default configuration values.
|
3
|
+
# If an option is not set on creation,
|
4
|
+
# it gets the default value instead.
|
5
|
+
DEFAULT_CONFIG = {
|
6
|
+
:login => nil,
|
7
|
+
:password => nil,
|
8
|
+
:nick => 'jabbot',
|
9
|
+
:server => nil,
|
10
|
+
:channel => nil,
|
11
|
+
:channel_password => nil,
|
12
|
+
:resource => 'jabbot',
|
13
|
+
:log_level => 'info',
|
14
|
+
:log_file => nil,
|
15
|
+
:debug => false
|
16
|
+
}
|
17
|
+
|
18
|
+
# The main configuration of Jabbot.
|
19
|
+
# It's nothing more than a simple struct of key-value pairs.
|
7
20
|
#
|
8
|
-
#
|
9
|
-
# config << Jabbot::CliConfig.new
|
10
|
-
# config.to_hash
|
21
|
+
# Examples:
|
11
22
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
23
|
+
# Jabbot::Config.new({:login => "jabbot@server.com", :password => "secret",
|
24
|
+
# :debug => true})
|
25
|
+
# # => #<struct Jabbot::Config login="jabbot@server.com", password="secret",
|
26
|
+
# nick="jabbot", server=nil, channel=nil, resource="jabbot",
|
27
|
+
# log_level="info", log_file=nil, debug=true>
|
17
28
|
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
29
|
+
# Jabbot::Config.new("jabbot@server.com", "secret")
|
30
|
+
# # => #<struct Jabbot::Config login="jabbot@server.com", password="secret",
|
31
|
+
# nick="jabbot", server=nil, channel=nil, resource="jabbot",
|
32
|
+
# log_level="info", log_file=nil, debug=false>
|
33
|
+
#
|
34
|
+
# config.login
|
35
|
+
# # => "jabbot@server.com"
|
36
|
+
# config.channel
|
37
|
+
# # => nil
|
38
|
+
# config.channel = "room@conference.server.com"
|
39
|
+
# # => "room@conference.server.com"
|
40
|
+
#
|
41
|
+
Config = Struct.new(
|
42
|
+
# We need the correct order here, so this is done manually.
|
43
|
+
:login,
|
44
|
+
:password,
|
45
|
+
:nick,
|
46
|
+
:server,
|
47
|
+
:channel,
|
48
|
+
:channel_password,
|
49
|
+
:resource,
|
50
|
+
:log_level,
|
51
|
+
:log_file,
|
52
|
+
:debug
|
53
|
+
) do
|
54
|
+
# Public: Initialize new configuration object.
|
41
55
|
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
56
|
+
# *args - Any number of valid arguments passed to the super class.
|
57
|
+
# If there is only one argument and it is kind of a Hash,
|
58
|
+
# it is treated as the key-value pairs are the options.
|
59
|
+
# If there is a default value for an option key,
|
60
|
+
# it is set if needed.
|
61
|
+
def initialize(*args)
|
62
|
+
# First: call the super class.
|
63
|
+
super
|
48
64
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# name, *args and &block as described in the core classes.
|
53
|
-
#
|
54
|
-
# Returns the configuration value if any.
|
55
|
-
def method_missing(name, *args, &block)
|
56
|
-
regex = /=$/
|
57
|
-
attr_name = name.to_s.sub(regex, '').to_sym
|
58
|
-
return super if name == attr_name && !@settings.key?(attr_name)
|
65
|
+
# If we got a hash, treat it as the configuration options.
|
66
|
+
if args.size == 1 && args.first.kind_of?(Hash)
|
67
|
+
self.login = nil # Reset first value.
|
59
68
|
|
60
|
-
|
61
|
-
|
69
|
+
args.first.each do |key, value|
|
70
|
+
send("#{key}=", value)
|
71
|
+
end
|
62
72
|
end
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# Public: Merges configurations and returns a hash with all options
|
68
|
-
#
|
69
|
-
# Returns a Hash of the configuration.
|
70
|
-
def to_hash
|
71
|
-
hash = {}.merge(@settings)
|
72
|
-
@configs.each { |conf| hash.merge!(conf.to_hash) }
|
73
|
-
hash
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.default
|
77
|
-
Config.new({}.merge(DEFAULT))
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Deprecated: Configuration from files
|
82
|
-
class FileConfig < Config
|
83
|
-
# Public: Initializes a new FileConfig object.
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# fos - Accepts a Stream or a String filename to read configuration from
|
87
|
-
# (default: "./config/bot.yml")
|
88
|
-
# If a stream is passed it is not closed from within the method.
|
89
|
-
def initialize(fos = File.expand_path("config/bot.yml"))
|
90
|
-
warn "Jabbot::FileConfig is deprecated and will be removed in the next version."
|
91
|
-
|
92
|
-
stream = fos.is_a?(String) ? File.open(fos, "r") : fos
|
93
|
-
|
94
|
-
begin
|
95
|
-
config = YAML.load(stream.read)
|
96
|
-
config.symbolize_keys! if config
|
97
|
-
rescue Exception => err
|
98
|
-
puts err.message
|
99
|
-
puts "Unable to load configuration, aborting"
|
100
|
-
exit
|
101
|
-
ensure
|
102
|
-
stream.close if fos.is_a?(String)
|
74
|
+
# Set defaults.
|
75
|
+
DEFAULT_CONFIG.each do |key, value|
|
76
|
+
self.send(key.to_s) || self.send("#{key}=", value)
|
103
77
|
end
|
104
|
-
|
105
|
-
super config.is_a?(Hash) ? config : {}
|
106
78
|
end
|
107
79
|
end
|
108
80
|
end
|
data/lib/jabbot/handlers.rb
CHANGED
@@ -29,21 +29,11 @@ module Jabbot
|
|
29
29
|
@handlers ||= {
|
30
30
|
:message => [],
|
31
31
|
:private => [],
|
32
|
-
:join
|
32
|
+
:join => [],
|
33
33
|
:subject => [],
|
34
|
-
:leave
|
34
|
+
:leave => []
|
35
35
|
}
|
36
36
|
end
|
37
|
-
|
38
|
-
# Deprecated: Set the handler types and Arrays
|
39
|
-
#
|
40
|
-
# hash - A hash containing the handler types and associated Arrays
|
41
|
-
# (see `handlers`).
|
42
|
-
#
|
43
|
-
# Returns nothing.
|
44
|
-
def handlers=(hash)
|
45
|
-
@handlers = hash
|
46
|
-
end
|
47
37
|
end
|
48
38
|
|
49
39
|
# A Handler consists of a pattern to match a given message,
|
@@ -171,9 +161,9 @@ module Jabbot
|
|
171
161
|
attr_reader :pattern
|
172
162
|
|
173
163
|
# Internal: Determines if this handler is suited to handle
|
174
|
-
#
|
164
|
+
# a message.
|
175
165
|
#
|
176
|
-
# Returns
|
166
|
+
# Returns true if it recognized the given message, false otherwise.
|
177
167
|
def recognize?(message)
|
178
168
|
return false if @pattern && message.text !~ @pattern
|
179
169
|
|
@@ -209,6 +199,8 @@ module Jabbot
|
|
209
199
|
# message - The incoming String message.
|
210
200
|
# params - The hash containing matched tokens.
|
211
201
|
#
|
202
|
+
# Both arguments are passed to the underlying handler block.
|
203
|
+
#
|
212
204
|
# Returns the return from the handler block.
|
213
205
|
def handle(message, params)
|
214
206
|
@handler.call(message, params) if @handler
|
data/test/helper.rb
CHANGED
@@ -9,36 +9,6 @@ $LOAD_PATH.unshift(dir)
|
|
9
9
|
|
10
10
|
require 'jabbot'
|
11
11
|
|
12
|
-
module Test::Unit::Assertions
|
13
|
-
def assert_hashes_equal(expected, actual, message = nil)
|
14
|
-
full_message = build_message(message, <<EOT, expected.inspect, actual.inspect)
|
15
|
-
<?> expected but was
|
16
|
-
<?>.
|
17
|
-
EOT
|
18
|
-
assert_block(full_message) do
|
19
|
-
break false if expected.keys.length != actual.keys.length
|
20
|
-
expected.keys.all? { |k| expected[k] == actual[k] }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def assert_hashes_not_equal(expected, actual, message = nil)
|
25
|
-
full_message = build_message(message, <<EOT, expected.inspect, actual.inspect)
|
26
|
-
<?> expected but was
|
27
|
-
<?>.
|
28
|
-
EOT
|
29
|
-
assert_block(full_message) do
|
30
|
-
break false if expected.keys.length != actual.keys.length
|
31
|
-
expected.keys.any? { |k| expected[k] != actual[k] }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
TEST_DIR = File.join(File.dirname(__FILE__), *%w[.])
|
37
|
-
|
38
|
-
def testpath(path)
|
39
|
-
File.join(TEST_DIR, path)
|
40
|
-
end
|
41
|
-
|
42
12
|
# test/spec/mini 3
|
43
13
|
# http://gist.github.com/25455
|
44
14
|
# chris@ozmm.org
|
@@ -46,7 +16,7 @@ end
|
|
46
16
|
def context(*args, &block)
|
47
17
|
return super unless (name = args.first) && block
|
48
18
|
require 'test/unit'
|
49
|
-
klass = Class.new(
|
19
|
+
klass = Class.new(Test::Unit::TestCase) do
|
50
20
|
def self.test(name, &block)
|
51
21
|
define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
|
52
22
|
end
|
data/test/test_bot.rb
CHANGED
@@ -2,49 +2,21 @@ require 'helper'
|
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
4
|
context "Bot" do
|
5
|
-
test "raise no exceptions when initialized" do
|
6
|
-
assert_nothing_raised do
|
7
|
-
Jabbot::Bot.new Jabbot::Config.new
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
test "raise exception when initialized without config file" do
|
12
|
-
assert_raise SystemExit do
|
13
|
-
Jabbot::Bot.new
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
test "raise no exception on initialize when config file exists" do
|
18
|
-
if File.exists?("config")
|
19
|
-
FileUtils.rm("config/bot.yml")
|
20
|
-
else
|
21
|
-
FileUtils.mkdir("config")
|
22
|
-
end
|
23
|
-
|
24
|
-
File.open("config/bot.yml", "w") { |f| f.puts "" }
|
25
|
-
|
26
|
-
assert_nothing_raised do
|
27
|
-
Jabbot::Bot.new
|
28
|
-
end
|
29
|
-
|
30
|
-
FileUtils.rm_rf("config")
|
31
|
-
end
|
32
|
-
|
33
5
|
test "provide configuration settings as methods" do
|
34
|
-
bot = Jabbot::Bot.new
|
35
|
-
assert_equal "jabbot", bot.login
|
6
|
+
bot = Jabbot::Bot.new :login => "jabbot"
|
7
|
+
assert_equal "jabbot", bot.config.login
|
36
8
|
end
|
37
9
|
|
38
10
|
test "return logger instance" do
|
39
|
-
bot = Jabbot::Bot.new
|
11
|
+
bot = Jabbot::Bot.new
|
40
12
|
assert bot.log.is_a?(Logger)
|
41
13
|
end
|
42
14
|
|
43
15
|
test "respect configured log level" do
|
44
|
-
bot = Jabbot::Bot.new(
|
16
|
+
bot = Jabbot::Bot.new(:log_level => "info")
|
45
17
|
assert_equal Logger::INFO, bot.log.level
|
46
18
|
|
47
|
-
bot = Jabbot::Bot.new(
|
19
|
+
bot = Jabbot::Bot.new(:log_level => "warn")
|
48
20
|
assert_equal Logger::WARN, bot.log.level
|
49
21
|
end
|
50
22
|
end
|
data/test/test_config.rb
CHANGED
@@ -2,80 +2,19 @@ require 'helper'
|
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
context "Config" do
|
5
|
-
test "default
|
6
|
-
assert_not_nil Jabbot::Config::DEFAULT
|
7
|
-
assert Jabbot::Config::DEFAULT.is_a?(Hash)
|
8
|
-
end
|
9
|
-
|
10
|
-
test "initialize with no options" do
|
11
|
-
assert_hashes_equal({}, Jabbot::Config.new.settings)
|
12
|
-
end
|
13
|
-
|
14
|
-
test "return config from add" do
|
15
|
-
config = Jabbot::Config.new
|
16
|
-
assert_equal config, config.add(Jabbot::Config.new)
|
17
|
-
end
|
18
|
-
|
19
|
-
test "alias add to <<" do
|
5
|
+
test "default config is set" do
|
20
6
|
config = Jabbot::Config.new
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
test "mirror method_missing as config getters" do
|
26
|
-
config = Jabbot::Config.default << Jabbot::Config.new
|
27
|
-
assert_equal Jabbot::Config::DEFAULT[:password], config.password
|
28
|
-
assert_equal Jabbot::Config::DEFAULT[:login], config.login
|
7
|
+
assert_equal Jabbot::DEFAULT_CONFIG[:password], config.password
|
8
|
+
assert_equal Jabbot::DEFAULT_CONFIG[:login], config.login
|
29
9
|
end
|
30
10
|
|
31
11
|
test "mirror missing methods as config setters" do
|
32
|
-
config = Jabbot::Config.
|
33
|
-
assert_equal Jabbot::
|
12
|
+
config = Jabbot::Config.new
|
13
|
+
assert_equal Jabbot::DEFAULT_CONFIG[:login], config.login
|
34
14
|
|
35
15
|
val = "jabbot"
|
36
16
|
config.login = val+'!'
|
37
|
-
assert_not_equal Jabbot::
|
17
|
+
assert_not_equal Jabbot::DEFAULT_CONFIG[:login], config.login
|
38
18
|
assert_equal val+'!', config.login
|
39
19
|
end
|
40
|
-
|
41
|
-
test "not override default hash" do
|
42
|
-
config = Jabbot::Config.default
|
43
|
-
hash = Jabbot::Config::DEFAULT
|
44
|
-
|
45
|
-
config.login = "jabbot"
|
46
|
-
config.password = "secret"
|
47
|
-
|
48
|
-
assert_hashes_not_equal Jabbot::Config::DEFAULT, config.to_hash
|
49
|
-
assert_hashes_equal hash, Jabbot::Config::DEFAULT
|
50
|
-
end
|
51
|
-
|
52
|
-
test "return merged configuration from to_hash" do
|
53
|
-
config = Jabbot::Config.new
|
54
|
-
config.login = "jabbot"
|
55
|
-
config.password = "secret"
|
56
|
-
|
57
|
-
config2 = Jabbot::Config.new({})
|
58
|
-
config2.login = "not_jabbot2"
|
59
|
-
config << config2
|
60
|
-
options = config.to_hash
|
61
|
-
|
62
|
-
assert_equal "secret", options[:password]
|
63
|
-
assert_equal "not_jabbot2", options[:login]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
context "FileConfig" do
|
68
|
-
test "subclass config for file config" do
|
69
|
-
assert Jabbot::FileConfig.new(StringIO.new).is_a?(Jabbot::Config)
|
70
|
-
end
|
71
|
-
|
72
|
-
test "read settings from stream" do
|
73
|
-
config = Jabbot::FileConfig.new(StringIO.new <<-YAML)
|
74
|
-
login: jabbot
|
75
|
-
password: secret
|
76
|
-
YAML
|
77
|
-
|
78
|
-
assert_equal "jabbot", config.login
|
79
|
-
assert_equal "secret", config.password
|
80
|
-
end
|
81
20
|
end
|
data/test/test_macros.rb
CHANGED
@@ -6,7 +6,7 @@ context "Macros" do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
test "yield configuration" do
|
9
|
-
Jabbot::Macros.bot = Jabbot::Bot.new
|
9
|
+
Jabbot::Macros.bot = Jabbot::Bot.new
|
10
10
|
|
11
11
|
conf = nil
|
12
12
|
assert_nothing_raised { configure { |c| conf = c } }
|
@@ -14,7 +14,7 @@ context "Macros" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
test "add handler" do
|
17
|
-
Jabbot::Macros.bot = Jabbot::Bot.new
|
17
|
+
Jabbot::Macros.bot = Jabbot::Bot.new
|
18
18
|
|
19
19
|
handler = add_handler(:message, ":command", :from => :cjno)
|
20
20
|
assert handler.is_a?(Jabbot::Handler)
|
metadata
CHANGED
@@ -1,102 +1,111 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: jabbot
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.3.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- badboy
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2014-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
17
14
|
name: xmpp4r
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: "0.4"
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
25
20
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: eventmachine
|
29
21
|
prerelease: false
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: eventmachine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.12'
|
36
34
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: shoulda
|
40
35
|
prerelease: false
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: shoulda
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
46
47
|
version: 2.10.1
|
47
48
|
type: :development
|
48
|
-
|
49
|
-
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.10.1
|
55
|
+
description: |2
|
56
|
+
Jabbot is a Ruby micro-framework for creating Jabber/MUC bots,
|
57
|
+
heavily inspired by Sinatra and Twibot.
|
58
|
+
|
59
|
+
I modified the code of Twibot to fit my needs.
|
60
|
+
The original Twibot code by Christian Johansen is located at:
|
61
|
+
http://github.com/cjohansen/twibot
|
62
|
+
|
63
|
+
It's as easy as definig a small message handler:
|
64
|
+
message {|message, params|
|
65
|
+
post message.text
|
66
|
+
}
|
50
67
|
email: badboy@archlinux.us
|
51
68
|
executables: []
|
52
|
-
|
53
69
|
extensions: []
|
54
|
-
|
55
70
|
extra_rdoc_files: []
|
56
|
-
|
57
|
-
|
71
|
+
files:
|
72
|
+
- LICENSE
|
58
73
|
- README.md
|
59
74
|
- Rakefile
|
60
|
-
- LICENSE
|
61
75
|
- lib/hash.rb
|
62
76
|
- lib/jabbot.rb
|
63
|
-
- lib/jabbot/
|
77
|
+
- lib/jabbot/bot.rb
|
64
78
|
- lib/jabbot/config.rb
|
65
79
|
- lib/jabbot/handlers.rb
|
66
|
-
- lib/jabbot/
|
67
|
-
-
|
68
|
-
- test/test_macros.rb
|
69
|
-
- test/test_bot.rb
|
80
|
+
- lib/jabbot/macros.rb
|
81
|
+
- lib/jabbot/version.rb
|
70
82
|
- test/helper.rb
|
83
|
+
- test/test_bot.rb
|
84
|
+
- test/test_config.rb
|
71
85
|
- test/test_handler.rb
|
72
86
|
- test/test_hash.rb
|
73
|
-
|
87
|
+
- test/test_macros.rb
|
74
88
|
homepage: http://github.com/badboy/jabbot
|
75
89
|
licenses: []
|
76
|
-
|
90
|
+
metadata: {}
|
77
91
|
post_install_message:
|
78
92
|
rdoc_options: []
|
79
|
-
|
80
|
-
require_paths:
|
93
|
+
require_paths:
|
81
94
|
- lib
|
82
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
-
|
84
|
-
requirements:
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
85
97
|
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version:
|
88
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
-
|
90
|
-
requirements:
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
91
102
|
- - ">="
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version:
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
94
105
|
requirements: []
|
95
|
-
|
96
106
|
rubyforge_project:
|
97
|
-
rubygems_version:
|
107
|
+
rubygems_version: 2.2.2
|
98
108
|
signing_key:
|
99
|
-
specification_version:
|
109
|
+
specification_version: 4
|
100
110
|
summary: Simple framework for creating Jabber/MUC bots, inspired by Sinatra and Twibot
|
101
111
|
test_files: []
|
102
|
-
|