sponge 0.2.9 → 0.3.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.
- 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