irc_socket 1.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e4c693a95c5ee11f00d4801bbb01747635a2fb134858dd9312a96224e1e31180
4
+ data.tar.gz: f512fa98cb41980cdb6006f243f701f961c6c3f025addb4f50014b65b3987cd1
5
+ SHA512:
6
+ metadata.gz: 49476fa472445c39e051f50528e211af8103669a6545bfb5f4500d96c347c5a5b066801bf89fc158459816f2dcb08de249e92bb5df542d221492bcefe5251370
7
+ data.tar.gz: 8c7cfca56dbb7b0570f893307fae06c7f200f64d4e0a318fe1ba36fd3165aa144fba9620b82dbf61a51398ce245bf561d8ae2ff26253fa5f9889933d1b5dfa01
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Lee Jarvis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,35 @@
1
+ == Description
2
+
3
+ IRCSocket is an IRC wrapper around a TCPSocket. It implements all of the major
4
+ commands laid out in {RFC 2812}[http://irchelp.org/irchelp/rfc/rfc2812.txt].
5
+ All these commands are available as instance methods of an IRCSocket Object.
6
+
7
+ API documentation is available {here}[http://rdoc.injekt.net/irc-socket]
8
+
9
+ == Example
10
+ irc = IRCSocket.new('irc.freenode.org')
11
+ irc.connect
12
+
13
+ if irc.connected?
14
+ irc.nick "HulkHogan"
15
+ irc.user "Hulk", 0, "*", "I am Hulk Hogan"
16
+
17
+ while line = irc.read
18
+
19
+ # Join a channel after MOTD
20
+ if line.split[1] == '376'
21
+ irc.join "#mychannel"
22
+ end
23
+
24
+ puts "Received: #{line}"
25
+ end
26
+ end
27
+
28
+ == Installation
29
+ gem install irc-socket
30
+
31
+ Or alternatively you can clone the Github repository
32
+ git clone https://github.com/injekt/irc-socket
33
+
34
+ == Notes
35
+ I may have missed something in the RFC. Patches welcome.
data/lib/irc_socket.rb ADDED
@@ -0,0 +1,300 @@
1
+ require 'socket'
2
+
3
+ # == Author
4
+ # * Lee Jarvis - ljjarvis@gmail.com
5
+ #
6
+ # == Description
7
+ # IRCSocket is an IRC wrapper around a TCPSocket. It implements all of the major
8
+ # commands laid out in {RFC 2812}[http://irchelp.org/irchelp/rfc/rfc2812.txt].
9
+ # All these commands are available as instance methods of an IRCSocket Object.
10
+ #
11
+ # == Example
12
+ # irc = IRCSocket.new('irc.freenode.org')
13
+ # irc.connect
14
+ #
15
+ # if irc.connected?
16
+ # irc.nick "HulkHogan"
17
+ # irc.user "Hulk", 0, "*", "I am Hulk Hogan"
18
+ #
19
+ # while line = irc.read
20
+ #
21
+ # # Join a channel after MOTD
22
+ # if line.split[1] == '376'
23
+ # irc.join "#mychannel"
24
+ # end
25
+ #
26
+ # puts "Received: #{line}"
27
+ # end
28
+ # end
29
+ #
30
+ # === Block Form
31
+ # IRCSocket.new('irc.freenode.org') do |irc|
32
+ # irc.nick "SpongeBob"
33
+ # irc.user "Spongey", 0, "*", "Square Pants"
34
+ #
35
+ # puts irc.read
36
+ # end
37
+ class IRCSocket
38
+
39
+ # The server our socket is connected to
40
+ attr_reader :server
41
+
42
+ # The port our socket is connected on
43
+ attr_reader :port
44
+
45
+ # The TCPSocket instance
46
+ attr_reader :socket
47
+
48
+ # Creates a new IRCSocket and automatically connects
49
+ #
50
+ # === Example
51
+ # irc = IRCSocket.open('irc.freenode.org')
52
+ #
53
+ # while data = irc.read
54
+ # puts data
55
+ # end
56
+ def self.open(server, port=6667, ssl=false)
57
+ irc = new(server, port, ssl)
58
+ irc.connect
59
+ irc
60
+ end
61
+
62
+ # Create a new IRCSocket to connect to +server+ on +port+. Defaults to port 6667.
63
+ # If an optional code block is given, it will be passed an instance of the IRCSocket.
64
+ #
65
+ # NOTE: Using the block form does not mean the socket will send the applicable QUIT
66
+ # command to leave the IRC server. You must send this yourself.
67
+ def initialize(server, port=6667, ssl=false)
68
+ @server = server
69
+ @port = port
70
+ @ssl = ssl
71
+
72
+ @socket = nil
73
+ @connected = false
74
+
75
+ if block_given?
76
+ connect
77
+ yield self
78
+ end
79
+ end
80
+
81
+ # Check if our socket is alive and connected to an IRC server
82
+ def connected?
83
+ @connected
84
+ end
85
+ alias connected connected?
86
+
87
+ # Connect to an IRC server, returns true on a successful connection, or
88
+ # raises otherwise
89
+ def connect
90
+ socket = TCPSocket.new(server, port)
91
+
92
+ if @ssl
93
+ require 'openssl'
94
+
95
+ ssl = OpenSSL::SSL::SSLContext.new
96
+ ssl.verify_mode = OpenSSL::SSL::VERIFY_NONE
97
+ @socket = OpenSSL::SSL::SSLSocket.new(socket, ssl)
98
+ @socket.sync = true
99
+ @socket.connect
100
+ else
101
+ @socket = socket
102
+ end
103
+ rescue Interrupt
104
+ raise
105
+ rescue Exception
106
+ raise
107
+ else
108
+ @connected = true
109
+ end
110
+
111
+ # Read the next line in from the server. If no arguments are passed
112
+ # the line will have the CRLF chomp'ed. Returns nil if no data could be read
113
+ def read(chompstr="\r\n")
114
+ if data = @socket.gets("\r\n")
115
+ data.chomp!(chompstr) if chompstr
116
+ data
117
+ else
118
+ nil
119
+ end
120
+ rescue IOError
121
+ nil
122
+ end
123
+
124
+ # Write to our Socket and append CRLF
125
+ def write(data)
126
+ @socket.write(data + "\r\n")
127
+ rescue IOError
128
+ raise
129
+ end
130
+
131
+ # Sugar for #write
132
+ def raw(*args) # :nodoc:
133
+ args.last.insert(0, ':') unless args.last.nil?
134
+ write args.join(' ').strip
135
+ end
136
+
137
+ # More sugar
138
+ def write_optional(command, *optional) # :nodoc:
139
+ command = "#{command} #{optional.join(' ')}" if optional
140
+ write(command.strip)
141
+ end
142
+ private :raw, :write_optional
143
+
144
+ # Send PASS command
145
+ def pass(password)
146
+ write("PASS #{password}")
147
+ end
148
+
149
+ # Send NICK command
150
+ def nick(nickname)
151
+ write("NICK #{nickname}")
152
+ end
153
+
154
+ # Send USER command
155
+ def user(user, mode, unused, realname)
156
+ write("USER #{user} #{mode} #{unused} :#{realname}")
157
+ end
158
+
159
+ # Send OPER command
160
+ def oper(name, password)
161
+ write("OPER #{name} #{password}")
162
+ end
163
+
164
+ # Send the MODE command.
165
+ # Should probably implement a better way of doing this
166
+ def mode(channel, *modes)
167
+ write("MODE #{channel} #{modes.join(' ')}")
168
+ end
169
+
170
+ # Send QUIT command
171
+ def quit(message=nil)
172
+ raw("QUIT", message)
173
+ end
174
+
175
+ # Send JOIN command - Join a channel with given password
176
+ def join(channel, password=nil)
177
+ write_optional("JOIN #{channel}", password)
178
+ end
179
+
180
+ # Send PART command
181
+ def part(channel, message=nil)
182
+ raw("PART", channel, message)
183
+ end
184
+
185
+ # Send TOPIC command
186
+ def topic(channel, topic=nil)
187
+ raw("TOPIC", channel, topic)
188
+ end
189
+
190
+ # Send NAMES command
191
+ def names(*channels)
192
+ write("NAMES #{channels.join(',') unless channels.empty?}")
193
+ end
194
+
195
+ # Send LIST command
196
+ def list(*channels)
197
+ write("LIST #{channels.join(',') unless channels.empty?}")
198
+ end
199
+
200
+ # Send INVITE command
201
+ def invite(nickname, channel)
202
+ write("INVITE #{nickname} #{channel}")
203
+ end
204
+
205
+ # Send KICK command
206
+ def kick(channel, user, comment=nil)
207
+ raw("KICK", channel, user, comment)
208
+ end
209
+
210
+ # Send PRIVMSG command
211
+ def privmsg(target, message)
212
+ write("PRIVMSG #{target} :#{message}")
213
+ end
214
+
215
+ # Send NOTICE command
216
+ def notice(target, message)
217
+ write("NOTICE #{target} :#{message}")
218
+ end
219
+
220
+ # Send MOTD command
221
+ def motd(target=nil)
222
+ write_optional("MOTD", target)
223
+ end
224
+
225
+ # Send VERSION command
226
+ def version(target=nil)
227
+ write_optional("VERSION", target)
228
+ end
229
+
230
+ # Send STATS command
231
+ def stats(*params)
232
+ write_optional("STATS", params)
233
+ end
234
+
235
+ # Send TIME command
236
+ def time(target=nil)
237
+ write_optional("TIME", target)
238
+ end
239
+
240
+ # Send INFO command
241
+ def info(target=nil)
242
+ write_optional("INFO", target)
243
+ end
244
+
245
+ # Send SQUERY command
246
+ def squery(target, message)
247
+ write("SQUERY #{target} :#{message}")
248
+ end
249
+
250
+ # Send WHO command
251
+ def who(*params)
252
+ write_optional("WHO", params)
253
+ end
254
+
255
+ # Send WHOIS command
256
+ def whois(*params)
257
+ write_optional("WHOIS", params)
258
+ end
259
+
260
+ # Send WHOWAS command
261
+ def whowas(*params)
262
+ write_optional("WHOWAS", params)
263
+ end
264
+
265
+ # Send KILL command
266
+ def kill(user, message)
267
+ write("KILL #{user} :#{message}")
268
+ end
269
+
270
+ # Send PING command
271
+ def ping(server)
272
+ write("PING #{server}")
273
+ end
274
+
275
+ # Send PONG command
276
+ def pong(server)
277
+ write("PONG #{server}")
278
+ end
279
+
280
+ # Send AWAY command
281
+ def away(message=nil)
282
+ raw("AWAY", message)
283
+ end
284
+
285
+ # Send USERS command
286
+ def users(target=nil)
287
+ write_optional("USERS", target)
288
+ end
289
+
290
+ # Send USERHOST command
291
+ def userhost(*users)
292
+ write("USERHOST #{users.join(' ')}")
293
+ end
294
+
295
+ # Close our socket instance
296
+ def close
297
+ @socket.close if connected?
298
+ end
299
+ end
300
+
@@ -0,0 +1,92 @@
1
+ require File.expand_path('../../lib/irc-socket', __FILE__)
2
+
3
+ class IRCSocket
4
+ def write(data)
5
+ return data
6
+ end
7
+
8
+ def read(chompstr="\r\n")
9
+ str = "foo bar baz\r\n"
10
+ str.chomp!(chompstr) if chompstr
11
+ end
12
+ end
13
+
14
+ commands = [
15
+ [:pass, %w(foobar), "PASS foobar"],
16
+ [:nick, %(ipsum), "NICK ipsum"],
17
+ [:user, ["guest", 0, '*', "real name"], "USER guest 0 * :real name"],
18
+ [:oper, %w(foo bar), "OPER foo bar"],
19
+ [:mode, %w(#foo +v bar), "MODE #foo +v bar"],
20
+ [:quit, %w(goodbye), "QUIT :goodbye"],
21
+ [:join, %w(#mychan), "JOIN #mychan"],
22
+ [:part, %w(#mychan), "PART #mychan"],
23
+ [:part, %w(#mychan cya!), "PART #mychan :cya!", "with part message"],
24
+ [:topic, %w(#mychan newtopic), "TOPIC #mychan :newtopic"],
25
+ [:names, %w(#foo #bar), "NAMES #foo,#bar"],
26
+ [:list, %w(#foo #bar), "LIST #foo,#bar"],
27
+ [:invite, %w(foo #mychan), "INVITE foo #mychan"],
28
+ [:kick, %w(#chan villian), "KICK #chan villian"],
29
+ [:kick, %w(#chan villian gtfo!), "KICK #chan villian :gtfo!", "with kick reason"],
30
+ [:privmsg, ['#chan', 'foo bar baz'], "PRIVMSG #chan :foo bar baz"],
31
+ [:notice, ['#chan', 'foo bar baz'], "NOTICE #chan :foo bar baz"],
32
+ [:motd, %w(someserver), "MOTD someserver"],
33
+ [:version, %w(anotherserver), "VERSION anotherserver"],
34
+ [:stats, %w(m server), "STATS m server"],
35
+ [:time, %w(irc.someserver.net), "TIME irc.someserver.net"],
36
+ [:info, %w(foobar), "INFO foobar"],
37
+ [:squery, %w(irchelp HELPME), "SQUERY irchelp :HELPME"],
38
+ [:who, %w(*.com o), "WHO *.com o"],
39
+ [:whois, %w(foo.org user), "WHOIS foo.org user"],
40
+ [:whowas, %w(foo.org user), "WHOWAS foo.org user"],
41
+ [:kill, ['badperson', 'get out!'], "KILL badperson :get out!"],
42
+ [:ping, %w(010123444), "PING 010123444"],
43
+ [:pong, %w(irc.foobar.org), "PONG irc.foobar.org"],
44
+ [:away, [], "AWAY"],
45
+ [:away, ['gone for lunch'], "AWAY :gone for lunch"],
46
+ [:users, %w(irc.foobar.org), "USERS irc.foobar.org"],
47
+ [:userhost, %w(foo bar baz), "USERHOST foo bar baz"],
48
+ ]
49
+
50
+ describe "IRCSocket" do
51
+ before do
52
+ @irc = IRCSocket.new('irc.myserver.net')
53
+ end
54
+
55
+ describe "::new" do
56
+ it "should return an IRCSocket" do
57
+ @irc.class.should == IRCSocket
58
+ end
59
+
60
+ it "should default to port 6667" do
61
+ @irc.port.should == 6667
62
+ end
63
+
64
+ it "should not automatically connect" do
65
+ @irc.connected.should == false
66
+ end
67
+
68
+ it "should set socket instance as nil" do
69
+ @irc.socket.should == nil
70
+ end
71
+ end
72
+
73
+ describe "#read" do
74
+ it "should chomp CRLF by default" do
75
+ @irc.read.should == "foo bar baz"
76
+ @irc.read.should_not == "foo bar baz\r\n"
77
+ end
78
+ end
79
+
80
+ describe "IRC commands as per rfc2812" do
81
+ commands.each do |requirements|
82
+ meth, params, pass, extra = *requirements
83
+ describe "##{meth}" do
84
+ it "should send a #{meth.to_s.upcase} command #{extra if extra}" do
85
+ @irc.send(meth, *params).should == pass
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: irc_socket
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Lee Jarvis
8
+ - Ken Spencer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-11-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 2.1.0
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 2.1.0
28
+ description: An IRC wrapper around TCPSocket
29
+ email: me+irc_socket@iotaspencer.me
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.rdoc
36
+ - lib/irc_socket.rb
37
+ - spec/irc_socket_spec.rb
38
+ homepage: http://rubydoc.info/github/IotaSpencer/irc_socket
39
+ licenses: []
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.8.6
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 2.7.6
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: An IRC wrapper around TCPSocket
61
+ test_files: []