sponge 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +13 -3
- data/Rakefile +23 -9
- data/bin/sponge +38 -0
- data/lib/proto/plugins/help.rb +11 -0
- data/lib/proto/plugins/log.rb +8 -0
- data/lib/proto/plugins/login.rb +14 -0
- data/lib/proto/plugins/logout.rb +11 -0
- data/lib/proto/plugins/say.rb +11 -0
- data/lib/proto/plugins/seen.rb +20 -0
- data/lib/proto/sponge.rb +9 -0
- data/lib/sponge.rb +8 -3
- data/lib/sponge/auth.rb +41 -0
- data/lib/sponge/bot.rb +64 -0
- data/lib/sponge/irc/listeners.rb +13 -6
- data/lib/sponge/irc/parser.rb +3 -1
- data/lib/sponge/listeners/376.rb +5 -0
- data/lib/sponge/listeners/join.rb +4 -0
- data/lib/sponge/listeners/privmsg.rb +14 -0
- data/lib/sponge/plugin.rb +109 -0
- data/lib/sponge/plugins.rb +79 -0
- data/lib/sponge/version.rb +3 -3
- data/spec/helper.rb +4 -0
- data/spec/sponge/auth.rb +67 -0
- data/spec/sponge/irc/client.rb +6 -0
- data/spec/sponge/irc/listeners.rb +65 -0
- data/spec/sponge/irc/parser.rb +37 -0
- metadata +28 -13
- data/examples/client.rb +0 -20
- data/examples/socket.rb +0 -9
data/README.rdoc
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
== Sponge
|
2
2
|
|
3
|
-
Sponge is a simple, lightweight IRC library for Ruby.
|
3
|
+
Sponge is a simple, lightweight plugin based IRC bot and IRC library for Ruby.
|
4
|
+
See the {wiki}[http://wiki.github.com/injekt/sponge] for more information.
|
4
5
|
|
5
6
|
|
6
7
|
== Example
|
8
|
+
|
9
|
+
client = Sponge::IRC::Client.new do
|
10
|
+
server "irc.freenode.org"
|
11
|
+
nickname "MyNick"
|
12
|
+
end
|
7
13
|
|
8
|
-
|
14
|
+
client.run
|
15
|
+
|
16
|
+
|
17
|
+
See {Sponge::IRC::Client}[http://rdoc.injekt.net/sponge/Sponge/IRC/Client.html] for more
|
9
18
|
|
10
19
|
|
11
20
|
== Notes
|
@@ -16,7 +25,8 @@ are no specs and it lacks documenation. These will be added soon.
|
|
16
25
|
== Installation
|
17
26
|
|
18
27
|
gem install sponge
|
19
|
-
|
28
|
+
|
29
|
+
|
20
30
|
or alternatively you can checkout the latest revision from github
|
21
31
|
|
22
32
|
git clone git://github.com/injekt/sponge
|
data/Rakefile
CHANGED
@@ -3,11 +3,12 @@ require "rake/clean"
|
|
3
3
|
require "rake/gempackagetask"
|
4
4
|
require "find"
|
5
5
|
require "rake/rdoctask"
|
6
|
+
require 'spec/rake/spectask'
|
6
7
|
require "lib/sponge/version"
|
7
8
|
|
8
9
|
NAME = 'sponge'
|
9
10
|
VERSION = Sponge::VERSION
|
10
|
-
TITLE = "Sponge: The simple IRC library"
|
11
|
+
TITLE = "Sponge: The simple plugin based IRC bot/library"
|
11
12
|
CLEAN.include ["*.gem", "doc"]
|
12
13
|
RDOC_OPTS = [
|
13
14
|
"-U", "--title", TITLE,
|
@@ -20,23 +21,28 @@ Rake::RDocTask.new do |rdoc|
|
|
20
21
|
rdoc.rdoc_files.add %w(README.rdoc lib/**/*.rb)
|
21
22
|
end
|
22
23
|
|
24
|
+
desc "Run all specs"
|
25
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
26
|
+
t.spec_files = Dir['spec/**/*.rb']
|
27
|
+
end
|
28
|
+
|
23
29
|
desc "Package sponge"
|
24
|
-
task :package=>[:clean] do |p|
|
30
|
+
task :package => [:clean] do |p|
|
25
31
|
sh "gem build #{NAME}.gemspec"
|
26
32
|
end
|
27
33
|
|
28
34
|
desc "Install gem"
|
29
|
-
task :install=>[:package] do
|
35
|
+
task :install => [:package] do
|
30
36
|
sh "sudo gem install ./#{NAME}-#{VERSION} --local"
|
31
37
|
end
|
32
|
-
|
38
|
+
|
33
39
|
desc "Uninstall gem"
|
34
|
-
task :uninstall=>[:clean] do
|
40
|
+
task :uninstall => [:clean] do
|
35
41
|
sh "sudo gem uninstall #{NAME}"
|
36
42
|
end
|
37
|
-
|
43
|
+
|
38
44
|
desc "Upload gem to gemcutter"
|
39
|
-
task :release=>[:package] do
|
45
|
+
task :release => [:package] do
|
40
46
|
sh "gem push ./#{NAME}-#{VERSION}.gem"
|
41
47
|
end
|
42
48
|
|
@@ -46,8 +52,16 @@ task :version do
|
|
46
52
|
end
|
47
53
|
|
48
54
|
desc "Upload rdoc to injekt.net"
|
49
|
-
task :upload do
|
55
|
+
task :upload => [:clean, :rdoc] do
|
50
56
|
sh("scp -rP 2295 doc/* injekt@injekt.net:/var/www/localhost/rdoc.injekt.net/sponge")
|
51
57
|
end
|
52
58
|
|
53
|
-
|
59
|
+
desc "Report code statistics (KLOCs, etc) from the application"
|
60
|
+
task :stats do
|
61
|
+
STATS_DIRECTORIES = [%w(Code lib/), %w(Spec spec)].map{|name, dir| [ name, "./#{dir}" ] }.select { |name, dir| File.directory?(dir)}
|
62
|
+
require "extra/stats"
|
63
|
+
verbose = true
|
64
|
+
CodeStatistics.new(*STATS_DIRECTORIES).to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
task :default => [:spec]
|
data/bin/sponge
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'sponge'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rubygems'
|
7
|
+
require 'sponge'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'optparse'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
# This doesn't really do much at the moment
|
14
|
+
# At some point it should handling running bots
|
15
|
+
# but until then... bah
|
16
|
+
OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: sponge [options]"
|
18
|
+
|
19
|
+
opts.separator ""
|
20
|
+
|
21
|
+
opts.on("--init NAME", "Create a new directory with NAME and copy the default Sponge proto") do |n|
|
22
|
+
if File.exists?(n)
|
23
|
+
puts "Unable to create proto, file exists.."
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
FileUtils.mkdir(n)
|
27
|
+
path = File.expand_path(n)
|
28
|
+
proto = File.expand_path(Sponge::BASE + '/proto')
|
29
|
+
FileUtils.cp_r Dir[proto + '/**'], path
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-v", "--version", "Return the current version of Sponge") do
|
33
|
+
puts Sponge.version
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end.parse!
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class SeenPlugin < Sponge::Plugin
|
2
|
+
listen_to :privmsg
|
3
|
+
|
4
|
+
def initialize(bot)
|
5
|
+
@users = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def listen(message)
|
9
|
+
@users[message.nick] = message
|
10
|
+
end
|
11
|
+
|
12
|
+
def reply(m, arg)
|
13
|
+
if @users.include?(arg)
|
14
|
+
m.reply "I have seen #{arg}"
|
15
|
+
else
|
16
|
+
m.reply "I haven't seen #{arg}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/proto/sponge.rb
ADDED
data/lib/sponge.rb
CHANGED
@@ -9,9 +9,7 @@ module Sponge
|
|
9
9
|
require 'socket'
|
10
10
|
require 'pp'
|
11
11
|
require 'ostruct'
|
12
|
-
|
13
|
-
# Sponge core
|
14
|
-
require 'sponge/version'
|
12
|
+
require 'set'
|
15
13
|
|
16
14
|
# IRC library
|
17
15
|
require 'sponge/irc/socket'
|
@@ -20,4 +18,11 @@ module Sponge
|
|
20
18
|
require 'sponge/irc/user'
|
21
19
|
require 'sponge/irc/client'
|
22
20
|
require 'sponge/irc/listeners'
|
21
|
+
|
22
|
+
# Sponge core
|
23
|
+
require 'sponge/version'
|
24
|
+
require 'sponge/plugins'
|
25
|
+
require 'sponge/plugin'
|
26
|
+
require 'sponge/auth'
|
27
|
+
require 'sponge/bot'
|
23
28
|
end
|
data/lib/sponge/auth.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sponge
|
2
|
+
class Auth
|
3
|
+
|
4
|
+
def initialize(client, users)
|
5
|
+
@client = client
|
6
|
+
@users = users
|
7
|
+
@logged = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Log a user in, returns the user if the user has successfully
|
11
|
+
# logged in, and nil otherwise
|
12
|
+
def login(user, pass)
|
13
|
+
return unless @users.key?(user) && @users[user] == pass
|
14
|
+
@logged.push(user).uniq!
|
15
|
+
user
|
16
|
+
end
|
17
|
+
|
18
|
+
# Log a user out, returns nil if the user isn't logged in
|
19
|
+
def logout(user)
|
20
|
+
return unless logged_in?(user)
|
21
|
+
@logged.delete(user)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
# Check if a user is logged in
|
26
|
+
def logged_in?(user)
|
27
|
+
@logged.include?(user)
|
28
|
+
end
|
29
|
+
|
30
|
+
# How many users we have logged in
|
31
|
+
def count
|
32
|
+
@logged.size
|
33
|
+
end
|
34
|
+
|
35
|
+
# Log all users out
|
36
|
+
def clear
|
37
|
+
@logged.clear
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/sponge/bot.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Sponge
|
2
|
+
class Bot < IRC::Client
|
3
|
+
|
4
|
+
attr_reader :plugins
|
5
|
+
|
6
|
+
attr_reader :auth
|
7
|
+
|
8
|
+
def initialize(server=nil, options={}, &blk)
|
9
|
+
@plugins = Plugins.new(self)
|
10
|
+
@auth = Auth.new(self, options[:users] || {})
|
11
|
+
|
12
|
+
@command_prefix = options[:prefix] || '!'
|
13
|
+
@channels = options[:channels] || []
|
14
|
+
|
15
|
+
setup_plugins
|
16
|
+
|
17
|
+
super(server, options, &blk)
|
18
|
+
init_listeners
|
19
|
+
end
|
20
|
+
|
21
|
+
# This probably isn't a good idea, I generally don't like seeing any
|
22
|
+
# eval lines, as it's a nightmare to debug. It'll do for now, though.
|
23
|
+
def init_listeners
|
24
|
+
path = File.expand_path('../listeners', __FILE__)
|
25
|
+
Dir[path + '/*.rb'].each do |listener|
|
26
|
+
instance_eval(File.read(listener))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Looks through the 'plugins' directory, require all plugins
|
31
|
+
# found, and add them into Sponge::Plugins
|
32
|
+
def setup_plugins
|
33
|
+
unless File.directory?(@plugins.path)
|
34
|
+
raise(LoadError, "No plugins directory found. Did you run `sponge init'?")
|
35
|
+
end
|
36
|
+
|
37
|
+
Dir[@plugins.path + '/*.rb'].each do |plugin|
|
38
|
+
require plugin
|
39
|
+
end
|
40
|
+
|
41
|
+
Plugin::LIST.each do |plugin|
|
42
|
+
add_plugin(plugin)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Should only be used by #setup_plugins (for now..)
|
47
|
+
# Sugar for Sponge::Plugins#add
|
48
|
+
def add_plugin(plugin)
|
49
|
+
plugins.add(plugin)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Registers an IRC command ready to dispatch to any
|
53
|
+
# plugin who are listening
|
54
|
+
def register(command, message)
|
55
|
+
if Plugin.has_listener?(command)
|
56
|
+
Plugin::LISTENERS[command.to_s.downcase].each do |cmd|
|
57
|
+
plugins.dispatch_listen(cmd, message)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
data/lib/sponge/irc/listeners.rb
CHANGED
@@ -22,6 +22,8 @@ module Sponge
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
class ListenerExistsError < RuntimeError; end
|
26
|
+
|
25
27
|
# The IRC::Client using this Listener List
|
26
28
|
attr_reader :client
|
27
29
|
|
@@ -37,8 +39,8 @@ module Sponge
|
|
37
39
|
# * See IRC::Client#on
|
38
40
|
def add(*commands, &blk)
|
39
41
|
commands.each do |command|
|
40
|
-
command = command.to_s
|
41
|
-
raise "listener for #{command} already exists" if @list.key?(command)
|
42
|
+
command = command.to_s.downcase
|
43
|
+
raise ListenerExistsError, "listener for #{command} already exists" if @list.key?(command)
|
42
44
|
@list[command] = Listener.new(command, &blk)
|
43
45
|
end
|
44
46
|
commands
|
@@ -46,7 +48,7 @@ module Sponge
|
|
46
48
|
|
47
49
|
# Remove a listener from our list
|
48
50
|
def delete(command)
|
49
|
-
@list.delete(command)
|
51
|
+
@list.delete(command.to_s.downcase)
|
50
52
|
end
|
51
53
|
|
52
54
|
def [](command)
|
@@ -54,14 +56,19 @@ module Sponge
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def include?(k)
|
57
|
-
@list.key?(k)
|
59
|
+
@list.key?(k.to_s.downcase)
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear
|
63
|
+
@list.clear
|
58
64
|
end
|
59
65
|
|
60
66
|
# Invoke #call on a Listener if it exists passing an IRC::Message
|
61
67
|
def handle(message)
|
62
68
|
raise "Not a IRC::Message" unless message.is_a?(Sponge::IRC::Message)
|
63
|
-
|
64
|
-
|
69
|
+
command = message.command.to_s.downcase
|
70
|
+
if @list.key?(command)
|
71
|
+
@list[command].call(client.irc, message)
|
65
72
|
end
|
66
73
|
end
|
67
74
|
|
data/lib/sponge/irc/parser.rb
CHANGED
@@ -9,6 +9,8 @@ module Sponge
|
|
9
9
|
# == Synopsis
|
10
10
|
#
|
11
11
|
class Parser
|
12
|
+
|
13
|
+
class BadMessageFormat < RuntimeError; end
|
12
14
|
|
13
15
|
# Our IRC::Client instance
|
14
16
|
attr_reader :client
|
@@ -21,7 +23,7 @@ module Sponge
|
|
21
23
|
# for you to play with
|
22
24
|
def parse(data)
|
23
25
|
return unless data
|
24
|
-
raise "Unknown Message" unless matches = data.match(/\A(?:\:(\S+)\s)?([A-Z0-9]+?)\s(.+?)\Z/)
|
26
|
+
raise(BadMessageFormat, "Unknown Message") unless matches = data.match(/\A(?:\:(\S+)\s)?([A-Z0-9]+?)\s(.+?)\Z/)
|
25
27
|
prefix, command, params = matches.captures
|
26
28
|
|
27
29
|
message = IRC::Message.new(client, data, prefix, command, params)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
on(:PRIVMSG) do |irc, message|
|
2
|
+
|
3
|
+
prefix = Regexp.escape(@command_prefix)
|
4
|
+
|
5
|
+
if matches = message.text.match(/#{prefix}([a-zA-Z]+?)(\s*\Z|\s(.*))/)
|
6
|
+
command = matches[1]
|
7
|
+
arg = matches[3]
|
8
|
+
if @plugins.has_plugin?(command)
|
9
|
+
@plugins.dispatch_reply(command, message, arg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
register(:PRIVMSG, message)
|
14
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Sponge
|
2
|
+
|
3
|
+
# == Plugin Example
|
4
|
+
# class SayPlugin < Sponge::Plugin
|
5
|
+
# def reply(m, arg)
|
6
|
+
# m.reply arg
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# Simple as that, the reply method will get invoked when the say command is used.
|
11
|
+
# You can also have plugins 'listen' for stuff, for example if you'd like a plugin
|
12
|
+
# to print PRIVMSG's to your terminal you can have a plugin which listens for them.
|
13
|
+
#
|
14
|
+
# class ShowMessage < Sponge::Plugin
|
15
|
+
# listen_to :privmsg
|
16
|
+
#
|
17
|
+
# def listen(m)
|
18
|
+
# if m.public?
|
19
|
+
# puts "[#{m.channel}]<#{m.nick}> #{m.text}"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# And that's it, the listen method will be invoked whenever the bot see's a PRIVMSG
|
25
|
+
# and it'll send the Sponge::IRC::Message applicable for this command.
|
26
|
+
#
|
27
|
+
# All plugins should be placed into a 'plugins' directory. All plugins are loaded on start
|
28
|
+
# and cannot be 'unloaded' although im sure this feature will be implemented at some time.
|
29
|
+
class Plugin
|
30
|
+
|
31
|
+
# Our list of plugins
|
32
|
+
LIST = []
|
33
|
+
|
34
|
+
# For plugins which require authentication
|
35
|
+
AUTH = []
|
36
|
+
|
37
|
+
# A hash containing IRC commands as keys whose values are Arrays containing
|
38
|
+
# a list of commands who are interested in 'listening' to them
|
39
|
+
#
|
40
|
+
# :privmsg => ['log', 'memo', 'seen']
|
41
|
+
# :join => ['log']
|
42
|
+
LISTENERS = {}
|
43
|
+
|
44
|
+
# Throw our plugin straight into the LIST
|
45
|
+
def self.inherited(plugin)
|
46
|
+
LIST << plugin
|
47
|
+
end
|
48
|
+
|
49
|
+
# This works ok, but I should probably add a better way of checking
|
50
|
+
# at some point.. heh.
|
51
|
+
# Returns 'say' from SayPlugin, etc
|
52
|
+
def self.command
|
53
|
+
name.downcase.sub(/plugin$/, '')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check if an IRC command has any plugins 'listening' for it
|
57
|
+
def self.has_listener?(cmd)
|
58
|
+
LISTENERS.key?(cmd.to_s.downcase)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Plugin requires the nick to be authenticated
|
62
|
+
def self.requires_auth
|
63
|
+
AUTH << command
|
64
|
+
p AUTH
|
65
|
+
end
|
66
|
+
|
67
|
+
# Allows a specific plugin to 'listen' to irc messages
|
68
|
+
# making the plugins a little more interactive
|
69
|
+
def self.listen_to(*commands)
|
70
|
+
commands.each do |cmd|
|
71
|
+
cmd = cmd.to_s.downcase
|
72
|
+
if LISTENERS.key?(cmd)
|
73
|
+
LISTENERS[cmd] << command
|
74
|
+
else
|
75
|
+
LISTENERS[cmd] = [command]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create a new Plugin instance
|
81
|
+
# This is done for *every* command, if you want to reference the Sponge::Bot
|
82
|
+
# instance and also want to create add variables in your plugins constructor
|
83
|
+
# then make sure you either call super() or assign @bot in your plugins
|
84
|
+
#
|
85
|
+
# Probably a bad idea to use ::new on every Plugin, perhaps create a 'setup'
|
86
|
+
# method for controlling per plugin options and data in the future
|
87
|
+
#
|
88
|
+
# Need to implement a way of setting plugin specific options through class methods
|
89
|
+
# without using constants that just store the plugin name (ie AUTH)
|
90
|
+
def initialize(bot)
|
91
|
+
@bot = bot
|
92
|
+
end
|
93
|
+
|
94
|
+
# The default help if a specific plugin lacks it
|
95
|
+
def help
|
96
|
+
"No help for this plugin"
|
97
|
+
end
|
98
|
+
|
99
|
+
# The default usage if a specific plugin lacks it
|
100
|
+
def usage
|
101
|
+
"No usage for this plugin"
|
102
|
+
end
|
103
|
+
|
104
|
+
def requires_auth?
|
105
|
+
AUTH.include? self.class.command
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Sponge
|
2
|
+
class Plugins
|
3
|
+
|
4
|
+
attr_reader :bot
|
5
|
+
|
6
|
+
# The full path to our plugins directory
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(bot)
|
10
|
+
@bot = bot
|
11
|
+
@path = File.expand_path('plugins')
|
12
|
+
@list = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add a plugin, this method invokes Plugin::new and passes our Sponge::Bot instance
|
16
|
+
# so we can access it in all of our plugins
|
17
|
+
def add(plugin)
|
18
|
+
@list[plugin.command] = plugin.new(bot)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Grab a plugin
|
22
|
+
def get(plugin)
|
23
|
+
@list[plugin]
|
24
|
+
end
|
25
|
+
alias [] get
|
26
|
+
|
27
|
+
# Check if a plugin exists
|
28
|
+
def include?(command)
|
29
|
+
@list.key?(command)
|
30
|
+
end
|
31
|
+
alias has_plugin? include?
|
32
|
+
|
33
|
+
# Return a list of our plugin commands
|
34
|
+
def commands
|
35
|
+
@list.keys
|
36
|
+
end
|
37
|
+
|
38
|
+
def dispatch_listen(command, message)
|
39
|
+
if include?(command)
|
40
|
+
plugin = get(command)
|
41
|
+
|
42
|
+
if plugin.respond_to?(:listen)
|
43
|
+
plugin.send(:listen, message)
|
44
|
+
else
|
45
|
+
raise(ArgumentError, "Unable to dispatch to #{command}, does the #{plugin} plugin have a `listen' method?")
|
46
|
+
end
|
47
|
+
else
|
48
|
+
raise(ArgumentError, "Attempting to dispatch to unknown plugin")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def dispatch_reply(command, message, args)
|
53
|
+
if include?(command)
|
54
|
+
plugin = get(command)
|
55
|
+
|
56
|
+
# We don't raise if a plugin hasn't implemented a reply method
|
57
|
+
# as plugins can *just* be listeners
|
58
|
+
if plugin.respond_to?(:reply)
|
59
|
+
if plugin.requires_auth?
|
60
|
+
return unless bot.auth.logged_in?(message.nick)
|
61
|
+
end
|
62
|
+
plugin.send(:reply, message, args)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
raise(ArgumentError, "Attempting to dispatch to unknown plugin")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
alias :reply :dispatch_reply
|
69
|
+
|
70
|
+
def help(command)
|
71
|
+
if include?(command)
|
72
|
+
plugin = get(command)
|
73
|
+
|
74
|
+
plugin.help
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/sponge/version.rb
CHANGED
data/spec/helper.rb
CHANGED
data/spec/sponge/auth.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path('../../../lib/sponge/auth', __FILE__)
|
2
|
+
|
3
|
+
users = {
|
4
|
+
'injekt' => 'sekret',
|
5
|
+
'foo' => 'bar',
|
6
|
+
'lorem' => 'ipsum',
|
7
|
+
}
|
8
|
+
|
9
|
+
auth = Sponge::Auth.new(nil, users)
|
10
|
+
|
11
|
+
describe "Sponge::Auth" do
|
12
|
+
describe "#login" do
|
13
|
+
it "should log a user in" do
|
14
|
+
auth.login('injekt', 'sekret')
|
15
|
+
auth.logged_in?('injekt').should == true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return nil if given wrong credentials" do
|
19
|
+
resp = auth.login('injekt', 'wrongpass')
|
20
|
+
resp.should == nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#logout" do
|
25
|
+
it "should log a user out" do
|
26
|
+
auth.logout('injekt')
|
27
|
+
auth.logged_in?('injekt').should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return nil if a user is not logged in" do
|
31
|
+
resp = auth.logout('foo')
|
32
|
+
resp.should == nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#clear" do
|
37
|
+
it "should log all users out" do
|
38
|
+
auth.login('injekt', 'sekret')
|
39
|
+
auth.login('foo', 'bar')
|
40
|
+
auth.count.should == 2
|
41
|
+
auth.clear
|
42
|
+
auth.count.should == 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#logged_in?" do
|
47
|
+
it "should return true if a user is logged in" do
|
48
|
+
auth.login('injekt', 'sekret')
|
49
|
+
resp = auth.logged_in?('injekt')
|
50
|
+
resp.should == true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return false if a user is not logged in" do
|
54
|
+
auth.clear
|
55
|
+
resp = auth.logged_in?('injekt')
|
56
|
+
resp.should == false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#count" do
|
61
|
+
it "should display how many users are currently logged in" do
|
62
|
+
auth.login('injekt', 'sekret')
|
63
|
+
auth.login('foo', 'bar')
|
64
|
+
auth.count.should == 2
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/sponge/irc/client.rb
CHANGED
@@ -12,6 +12,12 @@ describe "Sponge::IRC::Client" do
|
|
12
12
|
client.config.nickname.should == 'Sponge'
|
13
13
|
end
|
14
14
|
|
15
|
+
it "should raise if no server is supplied" do
|
16
|
+
lambda { Sponge::IRC::Client.new }
|
17
|
+
.should.raise(ArgumentError)
|
18
|
+
.message.should == "No server supplied"
|
19
|
+
end
|
20
|
+
|
15
21
|
it "should use the default nickname if no username, hostname, or realname are supplied" do
|
16
22
|
c = Sponge::IRC::Client.new('', :nickname => 'foobot')
|
17
23
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path('../../../helper', __FILE__)
|
2
|
+
|
3
|
+
listeners = Sponge::IRC::Listeners.new(nil)
|
4
|
+
|
5
|
+
describe "Sponge::IRC::Listeners" do
|
6
|
+
|
7
|
+
it "is not case specific for keys" do
|
8
|
+
listeners.add('Case1', 'case2', 'CASE3')
|
9
|
+
3.times do |n|
|
10
|
+
str = "CaSe#{n+1}"
|
11
|
+
listeners.include?(str.upcase).should == true
|
12
|
+
listeners.include?(str.downcase).should == true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "::new" do
|
17
|
+
it "should add the default ping listener" do
|
18
|
+
listeners.include?('PING').should == true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#add" do
|
23
|
+
it "should add a listener" do
|
24
|
+
listeners.add('foo')
|
25
|
+
listeners.include?('foo').should == true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should add many listeners" do
|
29
|
+
listeners.add('lorem', 'ipsum')
|
30
|
+
listeners.include?('lorem').should == true
|
31
|
+
listeners.include?('ipsum').should == true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should convert Integers and Symbols to Strings" do
|
35
|
+
listeners.add(:blah)
|
36
|
+
listeners.include?('blah').should == true
|
37
|
+
|
38
|
+
listeners.add(376)
|
39
|
+
listeners.include?('376').should == true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should raise a ListenerExistsError if a listener already exists" do
|
43
|
+
lambda { listeners.add(:PING) }
|
44
|
+
.should.raise(Sponge::IRC::Listeners::ListenerExistsError)
|
45
|
+
.message.should =~ /listener for \w+ already exists/
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#delete" do
|
50
|
+
it "should remove a listener" do
|
51
|
+
listeners.add(:deleteme)
|
52
|
+
listeners.include?(:deleteme).should == true
|
53
|
+
listeners.delete(:deleteme)
|
54
|
+
listeners.include?(:deleteme).should == false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#clear" do
|
59
|
+
it "should remove all listeners" do
|
60
|
+
listeners.clear
|
61
|
+
listeners.all.empty?.should == true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path '../../../helper', __FILE__
|
2
|
+
|
3
|
+
lines = {
|
4
|
+
:ping => 'PING :1825672507',
|
5
|
+
:notice => ':injekt!~injekt@myhostname.com NOTICE Sponge :foo bar',
|
6
|
+
:privmsg => ':injekt!~injekt@myhostname.com PRIVMSG Sponge :foo bar',
|
7
|
+
:join => ':injekt!~injekt@myhostname.com JOIN #sponge',
|
8
|
+
:part => ':injekt!~injekt@myhostname.com PART #sponge :cya!',
|
9
|
+
:quit => ':injekt!~injekt@myhostname.com QUIT :bye',
|
10
|
+
# more commands
|
11
|
+
}
|
12
|
+
|
13
|
+
badline = "foobar"
|
14
|
+
|
15
|
+
parser = Sponge::IRC::Parser.new(BaseClient)
|
16
|
+
|
17
|
+
describe "Sponge::IRC::Parser#parse" do
|
18
|
+
|
19
|
+
it "should return an IRC::Message" do
|
20
|
+
m = parser.parse(lines[:privmsg])
|
21
|
+
m.class.should == Sponge::IRC::Message
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise BadMessageFormat if string is bad formatting" do
|
25
|
+
lambda { parser.parse(badline) }
|
26
|
+
.should.raise(Sponge::IRC::Parser::BadMessageFormat)
|
27
|
+
.message.should == "Unknown Message"
|
28
|
+
end
|
29
|
+
|
30
|
+
lines.each do |c, d|
|
31
|
+
it "should parse a #{c} message" do
|
32
|
+
m = parser.parse(d)
|
33
|
+
m.command.downcase.should == c.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Lee 'injekt' Jarvis
|
@@ -14,8 +14,8 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
18
|
-
default_executable:
|
17
|
+
date: 2010-04-07 00:00:00 +01:00
|
18
|
+
default_executable: sponge
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bacon
|
@@ -31,10 +31,10 @@ dependencies:
|
|
31
31
|
version: 1.1.0
|
32
32
|
type: :development
|
33
33
|
version_requirements: *id001
|
34
|
-
description: A simple IRC library
|
34
|
+
description: A simple plugin based IRC bot/library
|
35
35
|
email: ljjarvis@gmail.com
|
36
|
-
executables:
|
37
|
-
|
36
|
+
executables:
|
37
|
+
- sponge
|
38
38
|
extensions: []
|
39
39
|
|
40
40
|
extra_rdoc_files:
|
@@ -42,27 +42,42 @@ extra_rdoc_files:
|
|
42
42
|
files:
|
43
43
|
- README.rdoc
|
44
44
|
- Rakefile
|
45
|
-
-
|
46
|
-
-
|
45
|
+
- spec/sponge/auth.rb
|
46
|
+
- spec/sponge/irc/listeners.rb
|
47
47
|
- spec/sponge/irc/client.rb
|
48
|
+
- spec/sponge/irc/parser.rb
|
48
49
|
- spec/helper.rb
|
50
|
+
- lib/proto/plugins/log.rb
|
51
|
+
- lib/proto/plugins/logout.rb
|
52
|
+
- lib/proto/plugins/login.rb
|
53
|
+
- lib/proto/plugins/seen.rb
|
54
|
+
- lib/proto/plugins/help.rb
|
55
|
+
- lib/proto/plugins/say.rb
|
56
|
+
- lib/proto/sponge.rb
|
49
57
|
- lib/sponge/version.rb
|
58
|
+
- lib/sponge/plugins.rb
|
59
|
+
- lib/sponge/auth.rb
|
60
|
+
- lib/sponge/bot.rb
|
61
|
+
- lib/sponge/listeners/privmsg.rb
|
62
|
+
- lib/sponge/listeners/376.rb
|
63
|
+
- lib/sponge/listeners/join.rb
|
50
64
|
- lib/sponge/irc/listeners.rb
|
51
65
|
- lib/sponge/irc/client.rb
|
52
66
|
- lib/sponge/irc/message.rb
|
53
67
|
- lib/sponge/irc/socket.rb
|
54
68
|
- lib/sponge/irc/user.rb
|
55
69
|
- lib/sponge/irc/parser.rb
|
70
|
+
- lib/sponge/plugin.rb
|
56
71
|
- lib/sponge.rb
|
57
72
|
has_rdoc: true
|
58
|
-
homepage: http://
|
73
|
+
homepage: http://wiki.github.com/injekt/sponge
|
59
74
|
licenses: []
|
60
75
|
|
61
76
|
post_install_message:
|
62
77
|
rdoc_options:
|
63
78
|
- --quiet
|
64
79
|
- --title
|
65
|
-
- "Sponge: The Simple IRC library"
|
80
|
+
- "Sponge: The Simple plugin based IRC bot/library"
|
66
81
|
- --main
|
67
82
|
- README.rdoc
|
68
83
|
require_paths:
|
@@ -89,6 +104,6 @@ rubyforge_project:
|
|
89
104
|
rubygems_version: 1.3.6
|
90
105
|
signing_key:
|
91
106
|
specification_version: 3
|
92
|
-
summary: A simple IRC library
|
107
|
+
summary: A simple plugin based IRC bot/library
|
93
108
|
test_files: []
|
94
109
|
|
data/examples/client.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'sponge'
|
2
|
-
|
3
|
-
client = Sponge::IRC::Client.new do
|
4
|
-
server "irc.freenode.org"
|
5
|
-
nickname "Sponge"
|
6
|
-
end
|
7
|
-
|
8
|
-
# 376 is the command for end of motd
|
9
|
-
client.on "376" do |irc, message|
|
10
|
-
irc.join "#mychannel"
|
11
|
-
end
|
12
|
-
|
13
|
-
# Add a callback for when someone (including ourselves) joins a channel
|
14
|
-
client.on "JOIN" do |irc, message|
|
15
|
-
unless message.nick == 'Sponge'
|
16
|
-
message.reply "Hi there #{message.nick}, welcome to #{message.channel}!"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
client.run
|
data/examples/socket.rb
DELETED