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 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.
@@ -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 'jeweler'
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
- puts "Jeweler not available. Install it with: sudo gem install jeweler"
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
-
@@ -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
- module Jabbot
10
-
11
- # :stopdoc:
12
- VERSION = '0.1.2'
13
- LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
14
- PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
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
@@ -9,7 +9,7 @@ module Jabbot
9
9
  class Bot
10
10
  include Jabbot::Handlers
11
11
  attr_reader :client
12
- attr_reader :user
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
- @user = []
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
- @user << config[:nick]
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 @user.include? nick
147
- @user << nick
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
- @user.delete(nick)
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
  #
@@ -27,7 +27,8 @@ module Jabbot
27
27
  :nick => 'jabbot',
28
28
  :channel => nil,
29
29
  :server => nil,
30
- :resource => nil
30
+ :resource => nil,
31
+ :debug => false
31
32
  }
32
33
 
33
34
  def initialize(settings = {})
@@ -1,54 +1,105 @@
1
1
  module Jabbot
2
- @@prompt = false
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
- def user
49
- bot.user
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
- private
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