sponge 0.2.8

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.
@@ -0,0 +1,30 @@
1
+ == Sponge
2
+
3
+ Sponge is a simple, lightweight IRC library for Ruby.
4
+
5
+
6
+ == Example
7
+
8
+ See http://rdoc.injekt.net/sponge/Sponge/IRC/Client.html for a quick example
9
+
10
+
11
+ == Notes
12
+
13
+ Please note that this is an early release. Though the code should work fine, there
14
+ are no specs and it lacks documenation. These will be added soon.
15
+
16
+ == Installation
17
+
18
+ gem install sponge
19
+
20
+ or alternatively you can checkout the latest revision from github
21
+
22
+ git clone git://github.com/injekt/sponge
23
+
24
+
25
+ == TODO
26
+
27
+ * Finish this README
28
+ * Create specs
29
+ * Complete documentation
30
+ * Create more rake tasks
@@ -0,0 +1,54 @@
1
+ require "rake"
2
+ require "rake/clean"
3
+ require "rake/gempackagetask"
4
+ require "find"
5
+ require "rake/rdoctask"
6
+ require "lib/sponge/version"
7
+
8
+ NAME = 'sponge'
9
+ VERSION = Sponge::VERSION
10
+ TITLE = "Sponge: The simple IRC library"
11
+ CLEAN.include ["*.gem", ".config", "rdoc"]
12
+ RDOC_OPTS = [
13
+ "--line-numbers", "--inline-source",
14
+ "--title", TITLE,
15
+ "--main", "README.rdoc"
16
+ ]
17
+
18
+ Rake::RDocTask.new do |rdoc|
19
+ rdoc.rdoc_dir = "rdoc"
20
+ rdoc.options += RDOC_OPTS
21
+ rdoc.rdoc_files.add %w(README.rdoc lib/**/*.rb)
22
+ end
23
+
24
+ desc "Package sponge"
25
+ task :package=>[:clean] do |p|
26
+ sh "gem build #{NAME}.gemspec"
27
+ end
28
+
29
+ desc "Install gem"
30
+ task :install=>[:package] do
31
+ sh "sudo gem install ./#{NAME}-#{VERSION} --local"
32
+ end
33
+
34
+ desc "Uninstall gem"
35
+ task :uninstall=>[:clean] do
36
+ sh "sudo gem uninstall #{NAME}"
37
+ end
38
+
39
+ desc "Upload gem to gemcutter"
40
+ task :release=>[:package] do
41
+ sh "gem push ./#{NAME}-#{VERSION}.gem"
42
+ end
43
+
44
+ desc "Print latest #{NAME} version"
45
+ task :version do
46
+ puts VERSION
47
+ end
48
+
49
+ desc "Upload rdoc to injekt.net"
50
+ task :upload do
51
+ sh("scp -rP 2295 rdoc/ injekt@injekt.net:/var/www/localhost/rdoc.injekt.net/sponge")
52
+ end
53
+
54
+ task :default => [:rdoc, :package]
@@ -0,0 +1,20 @@
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
@@ -0,0 +1,9 @@
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.."
@@ -0,0 +1,23 @@
1
+ # Copyright (c) 2010 Lee 'injekt' Jarvis <ljjarvis@gmail.com>
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ module Sponge
5
+ BASE = File.expand_path(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(BASE)
7
+
8
+ # Stdlib
9
+ require 'socket'
10
+ require 'pp'
11
+ require 'ostruct'
12
+
13
+ # Sponge core
14
+ require 'sponge/version'
15
+
16
+ # IRC library
17
+ require 'sponge/irc/socket'
18
+ require 'sponge/irc/parser'
19
+ require 'sponge/irc/message'
20
+ require 'sponge/irc/user'
21
+ require 'sponge/irc/client'
22
+ require 'sponge/irc/listeners'
23
+ end
@@ -0,0 +1,158 @@
1
+ module Sponge
2
+ module IRC
3
+
4
+ # == Author
5
+ # * Lee Jarvis - ljjarvis@gmail.com
6
+ #
7
+ # == Description
8
+ # TODO
9
+ #
10
+ # == Usage
11
+ #
12
+ # === Minimal Example
13
+ # client = Sponge::IRC::Client.new do
14
+ # server "irc.freenode.org"
15
+ # nickname "MyNick"
16
+ # end
17
+ #
18
+ # client.run
19
+ #
20
+ # === Mapping a Listener
21
+ # client = Sponge::IRC::Client.new do
22
+ # server "irc.freenode.org"
23
+ # nickname "MyNick"
24
+ # realname "Mr Sponge Bot"
25
+ # end
26
+ #
27
+ # # Join a channel once we've seen end of MOTD
28
+ # client.on(376) do |irc, message|
29
+ # irc.join "#mychan"
30
+ # end
31
+ #
32
+ # client.on(:JOIN) do |irc, message|
33
+ # message.reply "Hi #{message.nick}. Welcome to #{message.channel}!"
34
+ # end
35
+ #
36
+ # client.run
37
+ class Client
38
+ # The current IRC::Socket this Client is using
39
+ attr_reader :irc
40
+
41
+ # Client configuration options
42
+ attr_reader :config
43
+
44
+ def initialize(server=nil, opts={}, &blk)
45
+ @config = OpenStruct.new(opts.merge(OptionsDSL.new(server, &blk).options))
46
+ @config.port ||= 6667
47
+
48
+ @irc = IRC::Socket.new(config.server, config.port)
49
+ @irc.client = self
50
+ @parser = IRC::Parser.new(self)
51
+ @listeners = IRC::Listeners.new(self)
52
+
53
+ setup_username
54
+ end
55
+
56
+ # Start our connection
57
+ def connect
58
+ puts "Connecting to #{irc.server} on #{irc.port}"
59
+ irc.connect unless irc.connected?
60
+
61
+ irc.nick(config.nickname)
62
+ irc.user(config.username, config.hostname, "*", config.realname)
63
+
64
+ puts "Connected" if irc.connected?
65
+ end
66
+
67
+ # Map listeners to an IRC command. For example:
68
+ #
69
+ # client.on("376") do |irc, message|
70
+ # irc.join "#mychan"
71
+ # end
72
+ #
73
+ # client.on(:JOIN) do |irc, message|
74
+ # message.reply "Hi, #{message.nick}. Welcome to #{message.channel}"
75
+ # end
76
+ #
77
+ # * +irc+ - The Clients Sponge::IRC::Socket
78
+ # * +message+ - The current Sponge::IRC::Message
79
+ def on(*commands, &blk)
80
+ @listeners.add(*commands, &blk)
81
+ end
82
+
83
+ # Change clients nickname
84
+ def set_nick(new)
85
+ config.nickname = new
86
+ @irc.nick(new)
87
+ end
88
+
89
+ # Sugar for IRC::Parser#parse
90
+ def process(data)
91
+ message = @parser.parse(data)
92
+ @listeners.handle(message) if message
93
+ end
94
+
95
+ # Reads the next line from the IRC server whilst we're connected.
96
+ # Sends the line to #process
97
+ def run
98
+ connect unless irc.connected?
99
+ process(irc.read) while irc.connected?
100
+ end
101
+
102
+ # Quit our IRC socket and exit the Client
103
+ def quit
104
+ @irc.quit
105
+ exit
106
+ end
107
+
108
+ private
109
+
110
+ def setup_username
111
+ raise "You must set a nickname" unless nick = config.nickname
112
+ config.username ||= nick
113
+ config.hostname ||= nick
114
+ config.realname ||= nick
115
+ end
116
+
117
+ # == Author
118
+ # * Lee Jarvis - ljjarvis@gmail.com
119
+ #
120
+ # == Description
121
+ # TODO
122
+ class OptionsDSL
123
+ attr_reader :options
124
+
125
+ def initialize(server=nil, &blk)
126
+ @options = {}
127
+ server(server) if server
128
+ instance_eval(&blk)
129
+ end
130
+
131
+ def server(val)
132
+ @options[:server] = val
133
+ end
134
+
135
+ def port(val)
136
+ @options[:port] = val
137
+ end
138
+
139
+ def nickname(val)
140
+ @options[:nickname] = val
141
+ end
142
+
143
+ def username(val)
144
+ @options[:username] = val
145
+ end
146
+
147
+ def hostname(val)
148
+ @options[:hostname] = val
149
+ end
150
+
151
+ def realname(val)
152
+ @options[:realname] = val
153
+ end
154
+ end
155
+
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,69 @@
1
+ module Sponge
2
+ module IRC
3
+
4
+ # == Author
5
+ # * Lee Jarvis
6
+ #
7
+ #
8
+ #
9
+ class Listeners
10
+
11
+ # == Author
12
+ # * Lee Jarvis
13
+ #
14
+ #
15
+ class Listener
16
+ def initialize(command, &blk)
17
+ @callback = blk
18
+ end
19
+
20
+ def call(*args)
21
+ @callback.call(args)
22
+ end
23
+ end
24
+
25
+ # The IRC::Client using this Listener List
26
+ attr_reader :client
27
+
28
+ def initialize(client)
29
+ @client = client
30
+ @list = {}
31
+
32
+ # Add the default PING reply
33
+ add(:PING) {|i, m| i.pong(m.text) }
34
+ end
35
+
36
+ # Add a new Listener to the Listener List
37
+ # * See IRC::Client#on
38
+ def add(*commands, &blk)
39
+ commands.each do |command|
40
+ command = command.to_s
41
+ raise "listener for #{command} already exists" if @list.key?(command)
42
+ @list[command] = Listener.new(command, &blk)
43
+ end
44
+ end
45
+
46
+ # Remove a listener from our list
47
+ def delete(command)
48
+ @list.delete(command)
49
+ end
50
+
51
+ def [](command)
52
+ @list[command]
53
+ end
54
+
55
+ # Invoke #call on a Listener if it exists passing an IRC::Message
56
+ def handle(message)
57
+ raise "Not a IRC::Message" unless message.is_a?(Sponge::IRC::Message)
58
+ if @list.key?(message.command)
59
+ @list[message.command].call(client.irc, message)
60
+ end
61
+ end
62
+
63
+ def all
64
+ @list
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,90 @@
1
+ module Sponge
2
+ module IRC
3
+
4
+ # == Author
5
+ # * Lee Jarvis
6
+ #
7
+ # == Description
8
+ # This class should *only* be used by IRC::Parser
9
+ #
10
+ # == Synopsis
11
+ #
12
+ #
13
+ class Message
14
+
15
+ # Our IRC::Client
16
+ attr_reader :client
17
+
18
+ # Our IRC::Socket instance
19
+ attr_reader :irc
20
+
21
+ # The raw IRC string received from the server
22
+ attr_reader :raw
23
+
24
+ # The message prefix passed from IRC::Parser
25
+ attr_reader :prefix
26
+
27
+ # The IRC Command (PRIVMSG, MODE, 376, 372, etc)
28
+ attr_reader :command
29
+
30
+ # Channel the message is for
31
+ attr_accessor :channel
32
+
33
+ # The channel or the client name (if it's a private message)
34
+ attr_reader :for
35
+
36
+ # The IRC::User this message is from
37
+ attr_accessor :from
38
+
39
+ # The nick the message is from (sugar for IRC::User#nick)
40
+ attr_accessor :nick
41
+
42
+ # Message text
43
+ attr_accessor :text
44
+
45
+ # All params
46
+ attr_reader :params
47
+
48
+ def initialize(client, raw, prefix, command, params)
49
+ @client = client
50
+ @irc = client.irc
51
+ @raw = raw
52
+ @prefix = prefix
53
+ @command = command
54
+ @params = []
55
+ params.scan(/(?!:)(\S+)|:(.*)/) { @params << ($1 || $2) } if params
56
+
57
+ @channel = nil
58
+ @for = nil
59
+ @from = nil
60
+ @nick = nil
61
+ end
62
+
63
+ def for=(who)
64
+ @for = who
65
+ @channel = who if who =~ /^[\#&]+/
66
+ end
67
+
68
+ def private?
69
+ @channel
70
+ end
71
+
72
+ def public?
73
+ !@channel
74
+ end
75
+
76
+ # Reply to a message with a PRIVMSG back to the sender (channel or nick)
77
+ def reply(message)
78
+ who = channel || from
79
+ @irc.privmsg(who, message)
80
+ end
81
+
82
+ # Reply to a user with their nickname prefix'd
83
+ def answer(message)
84
+ return unless nick && channel
85
+ @irc.privmsg(channel, [nick, message].join(': '))
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,41 @@
1
+ module Sponge
2
+ module IRC
3
+
4
+ # == Author
5
+ # * Lee Jarvis - ljjarvis@gmail.com
6
+ #
7
+ # == Description
8
+ #
9
+ # == Synopsis
10
+ #
11
+ class Parser
12
+
13
+ # Our IRC::Client instance
14
+ attr_reader :client
15
+
16
+ def initialize(client)
17
+ @client = client
18
+ end
19
+
20
+ # Parses a raw IRC server message and returns a nicely encapsulated IRC::Message
21
+ # for you to play with
22
+ def parse(data)
23
+ return unless data
24
+ raise "Unknown Message" unless matches = data.match(/\A(?:\:(\S+)\s)?([A-Z0-9]+?)\s(.+?)\Z/)
25
+ prefix, command, params = matches.captures
26
+
27
+ message = IRC::Message.new(client, data, prefix, command, params)
28
+ message.for = message.params.first
29
+ message.text = message.params.last
30
+
31
+ if prefix && usermatch = prefix.match(/^(\S+?)!(\S+?)@(\S+?)$/)
32
+ message.from = IRC::User.new(client, *usermatch.captures)
33
+ message.nick = message.from.nick
34
+ end
35
+
36
+ message
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,165 @@
1
+ module Sponge
2
+ module IRC
3
+
4
+ # == Author
5
+ # * Lee Jarvis - ljjarvis@gmail.com
6
+ #
7
+ # == Description
8
+ # Sponge::IRC::Socket is a simple wrapper around TCPSocket. It provides simple
9
+ # functionality to interact with IRC servers.
10
+ #
11
+ # Note that when creating a new IRC::Socket, I generally assign the instance to a
12
+ # variable named <em>irc</em> throughout the documentation.
13
+ #
14
+ # == Synopsis
15
+ # irc = Sponge::IRC::Socket.open('irc.2600.net')
16
+ # irc.nick "SpongeBot"
17
+ # irc.user "SpongeBot", "sponge", "sponge", "Sponge IRC bot"
18
+ # irc.join "#mychan"
19
+ # irc.privmsg "#mychan", "Hello!"
20
+ # irc.part "#mychan"
21
+ # irc.quit "Quitting.."
22
+ #
23
+ class Socket
24
+
25
+ # The Client using this Socket (if one at all)
26
+ attr_accessor :client
27
+
28
+ # The server address we're connected to
29
+ attr_reader :server
30
+
31
+ # The port our socket is connected on
32
+ attr_reader :port
33
+
34
+ # Create a new IRC::Socket and connect to it
35
+ def self.open(server, port=6667)
36
+ sock = new(server, port)
37
+ sock.connect
38
+ sock
39
+ end
40
+
41
+ # Creates a new IRC::Socket. This doesn't automatically connect.
42
+ # If you want to do that use IRC::Socket.open
43
+ def initialize(server, port=6667)
44
+ @server = server
45
+ @port = port
46
+
47
+ @client = nil
48
+ @connected = false
49
+ end
50
+
51
+ # Connect to our IRC server if we haven't already connected
52
+ def connect
53
+ return if connected?
54
+
55
+ @socket = TCPSocket.new(server, port)
56
+ rescue Interrupt
57
+ raise
58
+ rescue Exception
59
+ raise
60
+ else
61
+ @connected = true
62
+ end
63
+
64
+ # Check if our Socket is currently connected to a server
65
+ def connected?
66
+ @connected
67
+ end
68
+
69
+ # Send a message to our server, appending CR-LF
70
+ def write(data)
71
+ @socket.print(data + "\r\n")
72
+ rescue IOError
73
+ raise
74
+ end
75
+
76
+ # Read the next line from the server. Chomps the trailing CR-LF
77
+ # Returns nil if there are issues with reading from the Socket.
78
+ # This method also safely shuts down our IRC::Socket by sending
79
+ # the QUIT command before exiting, it then closes the socket and exits
80
+ # the program.
81
+ def read
82
+ if data = @socket.gets
83
+ data.chomp("\r\n")
84
+ else
85
+ @connected = false
86
+ nil
87
+ end
88
+ rescue Interrupt
89
+ puts "\nInterrupted. Shutting down safely."
90
+ if connected?
91
+ quit("Client Interrupted")
92
+ close
93
+ exit 1
94
+ end
95
+ rescue IOError
96
+ @connected = false
97
+ nil
98
+ end
99
+
100
+ # Close our socket
101
+ def close
102
+ @socket.close
103
+ rescue IOError
104
+ end
105
+
106
+ # Send the USER command, usually to log into the server
107
+ def user(user, host, server, real)
108
+ write("USER #{user} #{host} #{server} :#{real}")
109
+ end
110
+
111
+ # Change our nickname
112
+ def nick(nick)
113
+ write("NICK #{nick}")
114
+ end
115
+
116
+ # Send a PRIVMSG to a specific user or channel
117
+ def privmsg(recipient, message)
118
+ write("PRIVMSG #{recipient} :#{message}")
119
+ end
120
+
121
+ # Send a NOTICE to a specific user or channel
122
+ def notice(recipient, message)
123
+ write("NOTICE #{recipient} :#{message}")
124
+ end
125
+
126
+ # Join a channel, using a password is necessary
127
+ def join(channel, password=nil)
128
+ write("JOIN #{channel}#{password ? password : ''}")
129
+ end
130
+
131
+ # Part a channel(s)
132
+ def part(*channels)
133
+ write("PART #{channels.join(',')}")
134
+ end
135
+
136
+ # Set the topic on a given channel
137
+ def topic(channel, topic)
138
+ write("TOPIC #{channel} :#{topic}")
139
+ end
140
+
141
+ # Kick nick from channel
142
+ def kick(channel, nick, reason="")
143
+ write("KICK #{channel} #{nick} :#{reason}")
144
+ end
145
+
146
+ # Send a PONG command
147
+ def pong(server)
148
+ write("PONG #{server}")
149
+ end
150
+
151
+ # Set ourselves as being away, (or not-away if a message is not given)
152
+ def away(message=nil)
153
+ write("AWAY#{message ? ':'+message : ''}")
154
+ end
155
+
156
+ # Send the QUIT command to our IRC server
157
+ # This also closes our IRC::Socket
158
+ def quit(reason="Cya!")
159
+ write("QUIT :#{reason}")
160
+ close
161
+ end
162
+
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,35 @@
1
+ module Sponge
2
+ module IRC
3
+ class User
4
+
5
+ # Our IRC::Client
6
+ attr_reader :client
7
+
8
+ # The nickname of this User
9
+ attr_reader :nick
10
+
11
+ # The username of this User
12
+ attr_reader :user
13
+
14
+ # The hostname of this User
15
+ attr_reader :host
16
+
17
+ def initialize(client, nick, user, host)
18
+ @client = client
19
+ @nick = nick
20
+ @user = user
21
+ @host = host
22
+ end
23
+
24
+ # Check if the User is us
25
+ def me?
26
+ client.config.nickname == nick
27
+ end
28
+
29
+ def to_s
30
+ @nick
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module Sponge
2
+ MAJOR = 0
3
+ MINOR = 2
4
+ TINY = 8
5
+
6
+ VERSION = [MAJOR, MINOR, TINY].join('.')
7
+
8
+ # The current Version of Sponge you're using
9
+ def self.version
10
+ VERSION
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sponge
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 8
9
+ version: 0.2.8
10
+ platform: ruby
11
+ authors:
12
+ - Lee 'injekt' Jarvis
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-05 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: A simple IRC library
22
+ email: ljjarvis@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.rdoc
29
+ files:
30
+ - README.rdoc
31
+ - Rakefile
32
+ - examples/client.rb
33
+ - examples/socket.rb
34
+ - lib/sponge/version.rb
35
+ - lib/sponge/irc/listeners.rb
36
+ - lib/sponge/irc/client.rb
37
+ - lib/sponge/irc/message.rb
38
+ - lib/sponge/irc/socket.rb
39
+ - lib/sponge/irc/user.rb
40
+ - lib/sponge/irc/parser.rb
41
+ - lib/sponge.rb
42
+ has_rdoc: true
43
+ homepage: http://rdoc.injekt.net/sponge
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --quiet
49
+ - --line-numbers
50
+ - --inline-source
51
+ - --title
52
+ - "Sponge: The Simple IRC library"
53
+ - --main
54
+ - README.rdoc
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 1
63
+ - 8
64
+ - 4
65
+ version: 1.8.4
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.6
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A simple IRC library
80
+ test_files: []
81
+