ircsupport 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ coverage/
2
+ .yardoc/
3
+ doc/
4
+ pkg/
5
+ Gemfile.lock
6
+ .rbx/
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ruby-head
6
+ - jruby-19mode
7
+ - jruby-head
8
+ - rbx-19mode
data/CHANGES.md ADDED
@@ -0,0 +1,3 @@
1
+ 0.1.0
2
+ -----
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Hinrik Örn Sigurðsson
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.md ADDED
@@ -0,0 +1,134 @@
1
+ IRCSupport
2
+ ==========
3
+
4
+ [![Build Status](https://secure.travis-ci.org/hinrik/ircsupport.png?branch=master)](http://travis-ci.org/hinrik/ircsupport)
5
+
6
+ IRCSupport provides everything you need to work with the IRC protocol and its
7
+ widely-used extensions. It is meant to be a building block for higher-level
8
+ libraries that use IRC (clients or servers). There are a bunch of IRC
9
+ client/bot libraries for Ruby out there, and they all implement their own
10
+ stuff for dealing with the IRC protocol. Why not keep it in one place?
11
+
12
+ Features
13
+ --------
14
+
15
+ * __Complete:__ Includes support for all protocol standards used by modern
16
+ IRC clients and servers, including:
17
+ * RFC1459
18
+ * RFC2812 & RFC2813
19
+ * CTCP
20
+ * DCC (CHAT, SEND, ACCEPT, RESUME)
21
+ * RPL\_ISUPPORT (draft-brocklesby-irc-isupport-03)
22
+ * CAP capabilities extension (draft-mitchell-irc-capabilities-02)
23
+ * mIRC/ECMA-48/RGB color and formatting codes
24
+ * __Tested:__ A heavy emphasis is placed on testing the code. It generally
25
+ has 100% test coverage.
26
+ * __Flexible:__ The tools provided by IRCSupport are flexible and modular,
27
+ and should encourage reuse.
28
+
29
+ Usage
30
+ -----
31
+
32
+ Here are some examples of using IRCSupport:
33
+
34
+ ```ruby
35
+ require 'ircsupport'
36
+
37
+ line = ':foo!bar@baz.com PRIVMSG #the_room :Greetings, everyone!'
38
+ irc_parser = IRCSupport::Parser.new
39
+ msg = irc_parser.parse(line)
40
+
41
+ msg.channel
42
+ # => '#the_room'
43
+
44
+ msg.sender
45
+ # => 'foo!bar@baz'
46
+
47
+ msg.is_action?
48
+ # => false
49
+
50
+ msg.type
51
+ # => 'private_msg'
52
+
53
+ IRCSupport::Validations.valid_nick_name?("Foo{}Bar[]")
54
+ # => true
55
+
56
+ IRCSupport::Validations.valid_nick_name?("123FooBar")
57
+ # => false
58
+
59
+ IRCSupport::Numerics.numeric_to_name('005')
60
+ # => 'RPL_ISUPPORT'
61
+
62
+ # any module can also be mixed into your class
63
+ include IRCSupport::Numerics
64
+ numeric_to_name('001')
65
+ # => 'RPL_WELCOME'
66
+ ```
67
+
68
+ Components
69
+ ----------
70
+
71
+ ### `IRCSupport::Parser`
72
+
73
+ This class is a complete parser for the IRC protocol. It can provide you with
74
+ rich objects which encapsulate all the information of a message in handy
75
+ methods.
76
+
77
+ ### `IRCSupport::Case`
78
+
79
+ A module that provides functions that conversion between various IRC
80
+ casemappings.
81
+
82
+ ### `IRCSupport::Encoding`
83
+
84
+ A module that provides functions to encode or decode IRC messages.
85
+
86
+ ### `IRCSupport::Formatting`
87
+
88
+ A module that provides functions for detecting, stripping, and constructing
89
+ strings with IRC color and formatting codes.
90
+
91
+ ### `IRCSupport::Masks`
92
+
93
+ A module that provides functions to deal with IRC masks.
94
+
95
+ ### `IRCSupport::Modes`
96
+
97
+ A module that provides functions to work with mode strings.
98
+
99
+ ### `IRCSupport::Numerics`
100
+
101
+ A module that provides functions to look up the names of IRC numerics and
102
+ vice versa.
103
+
104
+ ### `IRCSupport::Validations`
105
+
106
+ A module that provides functions to validate various IRC strings.
107
+
108
+ Supported platforms
109
+ -------------------
110
+
111
+ IRCSupport works on any Ruby 1.9-compatible VM. As of this writing, Rubinius'
112
+ and JRuby's encoding support is not complete, so some of the functions in
113
+ `IRCSupport::Encoding` will not work on those platforms.
114
+
115
+ Contributing
116
+ ------------
117
+
118
+ * Fork this repository on github
119
+ * Make your changes and send me a pull request
120
+ * If I like them I'll merge them
121
+ * If I've accepted a patch, feel free to ask for commit access
122
+
123
+ Kudos
124
+ -----
125
+ Those go to the authors of the [`IRC::Utils`](https://metacpan.org/module/IRC::Utils)
126
+ Perl module, on which much of this library's functionality is based. Same for
127
+ the authors of [`cinch`](https://github.com/cinchrb/cinch), from which a few
128
+ functions were borrowed.
129
+
130
+ License
131
+ -------
132
+
133
+ Copyright (c) 2012 Hinrik Örn Sigurðsson. Distributed under the MIT License.
134
+ See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'yard'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new(:test) do |task|
8
+ task.libs << "test"
9
+ task.test_files = FileList['test/test_coverage.rb', 'test/*_test.rb']
10
+ task.verbose = true
11
+ end
12
+
13
+ YARD::Rake::YardocTask.new do |task|
14
+ task.files = ['lib/**/*.rb', '-', 'CHANGES.md', 'LICENSE.txt']
15
+ task.options = ['--no-private', '--markup=markdown']
16
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'ircsupport/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "ircsupport"
7
+ gem.version = IRCSupport::VERSION
8
+ gem.authors = ["Hinrik Örn Sigurðsson"]
9
+ gem.email = ["hinrik.sig@gmail.com"]
10
+ gem.homepage = "https://github.com/hinrik/ircsupport"
11
+ gem.summary = "An IRC protocol library"
12
+ gem.description = "IRCSupport provides tools for dealing with the IRC protocol."
13
+ gem.licenses = ['MIT']
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- test/*`.split("\n")
17
+ gem.require_path = "lib"
18
+ gem.has_rdoc = "yard"
19
+ gem.required_ruby_version = '>= 1.9.1'
20
+
21
+ gem.add_development_dependency "rake"
22
+ gem.add_development_dependency "simplecov"
23
+ gem.add_development_dependency "yard", ">= 0.7.5"
24
+ gem.add_development_dependency "minitest", ">= 2.11.4"
25
+ gem.add_development_dependency "turn"
26
+ end
data/lib/ircsupport.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'ircsupport/version'
2
+ require 'ircsupport/case'
3
+ require 'ircsupport/encoding'
4
+ require 'ircsupport/formatting'
5
+ require 'ircsupport/masks'
6
+ require 'ircsupport/message'
7
+ require 'ircsupport/modes'
8
+ require 'ircsupport/numerics'
9
+ require 'ircsupport/parser'
10
+ require 'ircsupport/validations'
@@ -0,0 +1,84 @@
1
+ module IRCSupport
2
+ module Case
3
+ # @private
4
+ @@ascii_map = ['a-z', 'A-Z']
5
+ # @private
6
+ @@rfc1459_map = ['a-z{}^|', 'A-Z[]~\\']
7
+ # @private
8
+ @@strict_rfc1459_map = ['a-z{}|', 'A-Z[]\\']
9
+
10
+ # @param [String] irc_string An IRC string (nickname, channel, etc).
11
+ # @param [Symbol] casemapping An IRC casemapping.
12
+ # Like {#irc_upcase}, but modifies the string in place.
13
+ # @return [String] An upper case version of the IRC string according to
14
+ # the casemapping.
15
+ def irc_upcase!(irc_string, casemapping = :rfc1459)
16
+ case casemapping
17
+ when :ascii
18
+ irc_string.tr!(*@@ascii_map)
19
+ when :rfc1459
20
+ irc_string.tr!(*@@rfc1459_map)
21
+ when :'strict-rfc1459'
22
+ # the backslash must be last, otherwise it causes issues
23
+ irc_string.tr!(*@@strict_rfc1459_map)
24
+ else
25
+ raise ArgumentError, "Unsupported casemapping #{casemapping}"
26
+ end
27
+
28
+ return irc_string
29
+ end
30
+
31
+ # @param [String] irc_string An IRC string (nickname, channel, etc)
32
+ # @param [Symbol] casemapping An IRC casemapping
33
+ # @return [String] An upper case version of the IRC string according to
34
+ # the casemapping.
35
+ def irc_upcase(irc_string, casemapping = :rfc1459)
36
+ result = irc_string.dup
37
+ irc_upcase!(result, casemapping)
38
+ return result
39
+ end
40
+
41
+ # @param [String] irc_string An IRC string (nickname, channel, etc)
42
+ # @param [Symbol] casemapping An IRC casemapping
43
+ # Like {#irc_downcase}, but modifies the string in place.
44
+ # @return [String] A lower case version of the IRC string according to
45
+ # the casemapping
46
+ def irc_downcase!(irc_string, casemapping = :rfc1459)
47
+ case casemapping
48
+ when :ascii
49
+ irc_string.tr!(*@@ascii_map.reverse)
50
+ when :rfc1459
51
+ irc_string.tr!(*@@rfc1459_map.reverse)
52
+ when :'strict-rfc1459'
53
+ # the backslash must be last, otherwise it causes issues
54
+ irc_string.tr!(*@@strict_rfc1459_map.reverse)
55
+ else
56
+ raise ArgumentError, "Unsupported casemapping #{casemapping}"
57
+ end
58
+
59
+ return irc_string
60
+ end
61
+
62
+ # @param [String] irc_string An IRC string (nickname, channel, etc).
63
+ # @param [Symbol] casemapping An IRC casemapping.
64
+ # @return [String] A lower case version of the IRC string according to
65
+ # the casemapping
66
+ def irc_downcase(irc_string, casemapping = :rfc1459)
67
+ result = irc_string.dup
68
+ irc_downcase!(result, casemapping)
69
+ return result
70
+ end
71
+
72
+ # @param [String] first The first IRC string to compare.
73
+ # @param [String] second The second IRC string to compare.
74
+ # @param [Symbol] casemapping The IRC casemappig to use for the comparison.
75
+ # @return [Boolean] Will be `true` if the strings only differ in case or
76
+ # not all, but `false` otherwise.
77
+ def irc_eql?(first, second, casemapping = :rfc1459)
78
+ return irc_upcase(first, casemapping) == irc_upcase(second, casemapping)
79
+ end
80
+
81
+ module_function :irc_upcase, :irc_upcase!, :irc_downcase,
82
+ :irc_downcase!, :irc_eql?
83
+ end
84
+ end
@@ -0,0 +1,74 @@
1
+ module IRCSupport
2
+ module Encoding
3
+ # @param [String] string The IRC string you want to decode.
4
+ # @param [Symbol] encoding The source encoding.
5
+ # @return [String] A UTF-8 Ruby string.
6
+ def decode_irc(string, encoding = :irc)
7
+ string = string.dup
8
+ decode_irc!(string, encoding)
9
+ end
10
+
11
+ # @param [String] string The string you want to encode.
12
+ # @param [Symbol] encoding The target encoding.
13
+ # @return [String] A string encoded in the encoding you specified.
14
+ def encode_irc(string, encoding = :irc)
15
+ string = string.dup
16
+ encode_irc!(string, encoding)
17
+ end
18
+
19
+ # @param [String] string The IRC string you want to decode.
20
+ # @param [Symbol] encoding The source encoding.
21
+ # Like {#decode_irc}, but modifies the string in place.
22
+ # @return [String] A UTF-8 Ruby string.
23
+ def decode_irc!(string, encoding = :irc)
24
+ if encoding == :irc
25
+ # If incoming text is valid UTF-8, it will be interpreted as
26
+ # such. If it fails validation, a CP1252 -&gt; UTF-8 conversion
27
+ # is performed. This allows you to see non-ASCII from mIRC
28
+ # users (non-UTF-8) and other users sending you UTF-8.
29
+ #
30
+ # (from http://xchat.org/encoding/#hybrid)
31
+ string.force_encoding("UTF-8")
32
+ if !string.valid_encoding?
33
+ string.force_encoding("CP1252").encode!("UTF-8", {:invalid => :replace, :undef => :replace})
34
+ end
35
+ else
36
+ string.force_encoding(encoding).encode!({:invalid => :replace, :undef => :replace})
37
+ string = string.chars.select { |c| c.valid_encoding? }.join
38
+ end
39
+
40
+ return string
41
+ end
42
+
43
+ # @param [String] string The string you want to encode.
44
+ # @param [Symbol] encoding The target encoding.
45
+ # Like {#encode_irc}, but modifies the string in place.
46
+ # @return [String] A string encoded in the encoding you specified.
47
+ def encode_irc!(string, encoding = :irc)
48
+ if encoding == :irc
49
+ # If your text contains only characters that fit inside the CP1252
50
+ # code page (aka Windows Latin-1), the entire line will be sent
51
+ # that way. mIRC users should see it correctly. XChat users who
52
+ # are using UTF-8 will also see it correctly, because it will fail
53
+ # UTF-8 validation and will be assumed to be CP1252, even by older
54
+ # XChat versions.
55
+ #
56
+ # If the text doesn't fit inside the CP1252 code page, (for example if you
57
+ # type Eastern European characters, or Russian) it will be sent as UTF-8. Only
58
+ # UTF-8 capable clients will be able to see these characters correctly
59
+ #
60
+ # (from http://xchat.org/encoding/#hybrid)
61
+ begin
62
+ string.encode!("CP1252")
63
+ rescue ::Encoding::UndefinedConversionError
64
+ end
65
+ else
66
+ string.encode!(encoding, {:invalid => :replace, :undef => :replace}).force_encoding("ASCII-8BIT")
67
+ end
68
+
69
+ return string
70
+ end
71
+
72
+ module_function :decode_irc, :decode_irc!, :encode_irc, :encode_irc!
73
+ end
74
+ end
@@ -0,0 +1,149 @@
1
+ module IRCSupport
2
+ module Formatting
3
+ # @private
4
+ @@color = /[\x03\x04\x1b]/
5
+ # @private
6
+ @@formatting = /[\x02\x06\x11\x16\x1d\x1f]/
7
+ # @private
8
+ @@mirc_color = / \x03 (?: ,\d{1,2} | \d{1,2} (?: ,\d{1,2})? )? /x
9
+ # @private
10
+ @@rgb_color = /\x04[0-9a-fA-F]{0,6}/
11
+ # @private
12
+ @@ecma48_color = /\x1b\[.*?[\x00-\x1f\x40-\x7e]/
13
+ # @private
14
+ @@normal = /\x0f/
15
+
16
+ # @private
17
+ @@attributes = {
18
+ reset: 15.chr,
19
+ bold: 2.chr,
20
+ underline: 31.chr,
21
+ underlined: 31.chr,
22
+ inverse: 22.chr,
23
+ reverse: 22.chr,
24
+ reversed: 22.chr,
25
+ italic: 29.chr,
26
+ fixed: 17.chr,
27
+ blink: 6.chr,
28
+ }
29
+
30
+ # @private
31
+ @@colors = {
32
+ white: "00",
33
+ black: "01",
34
+ blue: "02",
35
+ green: "03",
36
+ red: "04",
37
+ brown: "05",
38
+ purple: "06",
39
+ orange: "07",
40
+ yellow: "08",
41
+ lime: "09",
42
+ teal: "10",
43
+ aqua: "11",
44
+ royal: "12",
45
+ pink: "13",
46
+ grey: "14",
47
+ silver: "15",
48
+ }
49
+
50
+ # @param [String] string The string you want to check.
51
+ # @return [Boolean] Will be true if the string contains IRC color codes.
52
+ def has_color?(string)
53
+ return true if string =~ @@color
54
+ return false
55
+ end
56
+
57
+ # @param [String] string The string you want to check.
58
+ # @return [Boolean] Will be true if the string contains IRC formatting codes.
59
+ def has_formatting?(string)
60
+ return true if string =~ @@formatting
61
+ return false
62
+ end
63
+
64
+ # @param [String] string The string you want to strip.
65
+ # Like {#strip_color}, but modifies the string in place.
66
+ # @return [String] A string stripped of all IRC color codes.
67
+ def strip_color!(string)
68
+ [@@mirc_color, @@rgb_color, @@ecma48_color].each do |pattern|
69
+ string.gsub!(pattern, '')
70
+ end
71
+ # strip cancellation codes too if there are no formatting codes
72
+ string.gsub!(@@normal) if !has_color?(string)
73
+ return string
74
+ end
75
+
76
+ # @param [String] string The string you want to strip.
77
+ # @return [String] A string stripped of all IRC color codes.
78
+ def strip_color(string)
79
+ string = string.dup
80
+ return strip_color!(string)
81
+ end
82
+
83
+ # @param [String] string The string you want to strip.
84
+ # Like {#strip_formatting}, but modifies the string in place.
85
+ # @return [String] A string stripped of all IRC formatting codes.
86
+ def strip_formatting!(string)
87
+ string.gsub!(@@formatting, '')
88
+ # strip cancellation codes too if there are no color codes
89
+ string.gsub!(@@normal) if !has_color?(string)
90
+ return string
91
+ end
92
+
93
+ # @param [String] string The string you want to strip.
94
+ # @return [String] A string stripped of all IRC formatting codes.
95
+ def strip_formatting(string)
96
+ string = string.dup
97
+ return strip_formatting!(string)
98
+ end
99
+
100
+ # @param [*Array] settings A list of color and formatting attributes you
101
+ # want to apply.
102
+ # Like {#irc_format}, but modifies the string in place.
103
+ # @param [String] string A string you want to format.
104
+ # @return [String] A formatted string.
105
+ def irc_format!(*settings, string)
106
+ string = string.dup
107
+
108
+ attributes = settings.select {|k| @@attributes.has_key?(k)}.map {|k| @@attributes[k]}
109
+ colors = settings.select {|k| @@colors.has_key?(k)}.map {|k| @@colors[k]}
110
+ if colors.size > 2
111
+ raise ArgumentError, "At most two colors (foreground and background) might be specified"
112
+ end
113
+
114
+ attribute_string = attributes.join
115
+ color_string = if colors.empty?
116
+ ""
117
+ else
118
+ "\x03#{colors.join(",")}"
119
+ end
120
+
121
+ prepend = attribute_string + color_string
122
+ append = @@attributes[:reset]
123
+
124
+ # attributes act as toggles, so e.g. underline+underline = no
125
+ # underline. We thus have to delete all duplicate attributes
126
+ # from nested strings.
127
+ string.delete!(attribute_string)
128
+
129
+ # Replace the reset code of nested strings to continue the
130
+ # formattings of the outer string.
131
+ string.gsub!(/#{@@attributes[:reset]}/, @@attributes[:reset] + prepend)
132
+ string.insert(0, prepend)
133
+ string << append
134
+ return string
135
+ end
136
+
137
+ # @param [*Array] settings A list of color and formatting attributes you
138
+ # want to apply.
139
+ # @param [String] string A string you want to format.
140
+ # @return [String] A formatted string.
141
+ def irc_format(*settings, string)
142
+ string = string.dup
143
+ return irc_format!(*settings, string)
144
+ end
145
+
146
+ module_function :has_color?, :has_formatting?, :strip_color, :strip_color!,
147
+ :strip_formatting, :strip_formatting!, :irc_format
148
+ end
149
+ end