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 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
- See http://rdoc.injekt.net/sponge/Sponge/IRC/Client.html for a quick example
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
- task :default => [:clean, :rdoc, :package]
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,11 @@
1
+ class Help < Sponge::Plugin
2
+
3
+ def reply(m, arg)
4
+ if @bot.plugins.has_plugin?(arg)
5
+ m.reply @bot.plugins.help(arg)
6
+ else
7
+ m.reply "Plugin unknown"
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,8 @@
1
+ class Log < Sponge::Plugin
2
+ listen_to :privmsg, :join, :part, :quit
3
+
4
+ def listen(message)
5
+ puts "<#{message.channel}/#{message.nick}> #{message.text}"
6
+ end
7
+
8
+ end
@@ -0,0 +1,14 @@
1
+ class Login < Sponge::Plugin
2
+
3
+ def reply(m, arg)
4
+ if @bot.auth.login(m.nick, arg.to_s)
5
+ m.answer "You're logged in"
6
+ else
7
+ m.answer "Unable to log in"
8
+ end
9
+ end
10
+
11
+ def help
12
+ "login <password>"
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ class Logout < Sponge::Plugin
2
+
3
+ def reply(m, arg)
4
+ if @bot.auth.logout(m.nick)
5
+ m.answer "You're now logged out"
6
+ else
7
+ m.answer "Unable to log you out"
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class Say < Sponge::Plugin
2
+
3
+ def reply(message, arg)
4
+ message.reply arg
5
+ end
6
+
7
+ def help
8
+ "say <text> - reply in current channel with <text>"
9
+ end
10
+
11
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'sponge'
3
+
4
+ bot = Sponge::Bot.new('irc.yourserver.net',
5
+ :channels => ['#yourchannel'],
6
+ :users => {'foo' => 'bar'},
7
+ )
8
+
9
+ bot.start
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
@@ -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
+
@@ -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
- if @list.key?(message.command)
64
- @list[message.command].call(client.irc, message)
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
 
@@ -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,5 @@
1
+ on(376) do |irc, message|
2
+ @channels.each do |chan|
3
+ irc.join chan
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ on(:JOIN) do |irc, message|
2
+
3
+ register(:JOIN, message)
4
+ end
@@ -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
@@ -1,7 +1,7 @@
1
1
  module Sponge
2
2
  MAJOR = 0
3
- MINOR = 2
4
- TINY = 9
3
+ MINOR = 3
4
+ TINY = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join('.')
7
7
 
@@ -9,4 +9,4 @@ module Sponge
9
9
  def self.version
10
10
  VERSION
11
11
  end
12
- end
12
+ end
data/spec/helper.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  require File.expand_path('../../lib/sponge.rb', __FILE__)
2
2
  require 'bacon'
3
3
 
4
+ BaseClient = Sponge::IRC::Client.new do
5
+ server 'irc.freenode.org'
6
+ end unless defined?(BaseClient)
7
+
4
8
  class Sponge::IRC::Socket
5
9
  def write(data)
6
10
  nil
@@ -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
@@ -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
- - 2
8
- - 9
9
- version: 0.2.9
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-05 00:00:00 +01:00
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
- - examples/client.rb
46
- - examples/socket.rb
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://rdoc.injekt.net/sponge
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
@@ -1,9 +0,0 @@
1
- require 'sponge'
2
-
3
- sock = Sponge::IRC::Socket.open('irc.freenode.org')
4
- sock.nick "SpongeBot"
5
- sock.user "SpongeBot", "sponge", "sponge", "Sponge IRC bot"
6
- sock.join "#mychan"
7
- sock.privmsg "#mychan", "Hello!"
8
- sock.part "#mychan"
9
- sock.quit "Quitting.."