ircsupport 0.1.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/.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