ircparser 0.6.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b3ba0c73061105629280badf2eda78d434a53c09bca59f77f73397740a6f062
4
- data.tar.gz: b49d3de744a1fec6d9c9fabb17ca2df3c4416dc38f8d0afe953e9d0f4587d7b9
3
+ metadata.gz: f2e712b24986a96105f7fc722698814542a077966bef240ffe6d4c3fcad6859f
4
+ data.tar.gz: 07d2480c650b4327ceba4e8b98c828846daf0e948210e4ed71bae33ffdada24d
5
5
  SHA512:
6
- metadata.gz: 04633fd5973f4b80cfdfa50b7c01c75683e9ecea0fe4e087c9d410d3a6cce649158eecc57e4902909fee8900031ebe50c3b5a6c9f070363120b711d762d29de8
7
- data.tar.gz: fc2a8e5cadb156963f16743d857703c3bdf4900da0f86a18a9814e13ef52532282d7eee4ba7d1ee761439d46ee7107a62a5da1eb833de330ddc8bf7e33c22762
6
+ metadata.gz: 725749ad9026c5873708b0586e5dc9c86822549476c0d0fd0883cda9c98100f7584d62142c3ce1b0cec06f83aea623ad40f9c567d5fce673fdeb1bb44eed9db5
7
+ data.tar.gz: e7a127efc3c55e5aee09c33b6782aa4d5b79d398ae6ea296d589bbf941461d452d1afcc6e8feef0b800b8d5e6b5bf070595f9486dd3f7f50c649a93eae2d791c
data/lib/ircparser.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -16,11 +16,12 @@
16
16
  module IRCParser
17
17
 
18
18
  # Public: The version of IRCParser in use.
19
- VERSION = '0.6.0'
19
+ VERSION = '0.6.1'
20
20
  end
21
21
 
22
22
  require_relative 'ircparser/error'
23
23
  require_relative 'ircparser/message'
24
24
  require_relative 'ircparser/prefix'
25
25
  require_relative 'ircparser/stream'
26
+ require_relative 'ircparser/wire/json'
26
27
  require_relative 'ircparser/wire/rfc'
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -47,12 +47,12 @@ module IRCParser
47
47
  #
48
48
  # line - The line to attempt to parse.
49
49
  def self.parse line
50
- return IRCParser::RFCWireFormat.objectify line.clone
50
+ return IRCParser::RFCWireFormat.objectify line
51
51
  end
52
52
 
53
53
  # Public: Serializes the message to a string.
54
54
  def to_s
55
- return IRCParser::RFCWireFormat.stringify self.clone
55
+ return IRCParser::RFCWireFormat.stringify self
56
56
  end
57
57
  end
58
58
  end
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -0,0 +1,265 @@
1
+ # IRCParser - Internet Relay Chat Message Parser
2
+ #
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
+ #
5
+ # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
+ # fee is hereby granted, provided that the above copyright notice and this permission notice appear
7
+ # in all copies.
8
+ #
9
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
10
+ # SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
11
+ # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
13
+ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
14
+ # OF THIS SOFTWARE.
15
+
16
+ require 'json'
17
+
18
+ module IRCParser
19
+
20
+ # Internal: Implements objectification and stringification for the JSON wire format.
21
+ module JSONWireFormat
22
+
23
+ # Internal: Objectifies a message from the JSON wire format to an IRCParser::Message.
24
+ #
25
+ # str - A String containing a message in the JSON wire format.
26
+ def self.objectify str
27
+
28
+ # Ruby really needs some kind of basic type checking.
29
+ unless str.is_a? String
30
+ raise IRCParser::Error.new(str), "message is not a String"
31
+ end
32
+
33
+ # Parse and validate the JSON object.
34
+ message = JSON.parse str.lstrip, max_nesting: 6 rescue nil
35
+ unless message.is_a? Hash
36
+ raise IRCParser::Error.new(str), 'message is not a JSON object'
37
+ end
38
+
39
+ { tags: Hash.new, parameters: Array.new }
40
+
41
+ # Have we encountered IRCv3 message tags?
42
+ components = Hash.new
43
+ components[:tags] = if message.include? 'tags'
44
+ raise IRCParser::Error.new(str), 'message tags are not a JSON object' unless message[:tags].is_a? Hash
45
+ message[:tags]
46
+ else
47
+ Hash.new
48
+ end
49
+
50
+ components[:prefix] = if message.include? 'source'
51
+
52
+ end
53
+
54
+ if current_token != nil && current_token[0] == '@'
55
+ components[:tags] = self.__objectify_tags current_token
56
+ current_token = self.__get_token message
57
+ end
58
+
59
+ # Have we encountered the prefix of this message?
60
+ if current_token != nil && current_token[0] == ':'
61
+ components[:prefix] = self.__objectify_prefix current_token
62
+ current_token = self.__get_token message
63
+ end
64
+
65
+ # The command parameter is mandatory.
66
+ if current_token != nil
67
+ components[:command] = current_token.upcase
68
+ current_token = self.__get_final_token message
69
+ else
70
+ raise IRCParser::Error.new(str), 'message is missing the command name'
71
+ end
72
+
73
+ # Try to parse all of the remaining parameters.
74
+ components[:parameters] = Array.new
75
+ while current_token != nil
76
+ components[:parameters] << current_token
77
+ current_token = self.__get_final_token message
78
+ end
79
+
80
+ return IRCParser::Message.new components
81
+ end
82
+
83
+ # Internal: Stringifies a message from an IRCParser::Message to the JSON wire format.
84
+ #
85
+ # obj - An IRCParser::Message to stringify to the JSON wire format.
86
+ def self.stringify obj
87
+
88
+ # Ruby really needs some kind of basic type checking.
89
+ unless obj.is_a? IRCParser::Message
90
+ raise IRCParser::Error.new(obj), "message is not an IRCParser::Message"
91
+ end
92
+
93
+ # Stringify the tags.
94
+ buffer = String.new
95
+ unless obj.tags.empty?
96
+ buffer += '@'
97
+ buffer += self.__stringify_tags obj.tags
98
+ buffer += ' '
99
+ end
100
+
101
+ # Stringify the prefix.
102
+ unless obj.prefix.nil?
103
+ buffer += ':'
104
+ buffer += self.__stringify_prefix obj.prefix
105
+ buffer += ' '
106
+ end
107
+
108
+ # Stringify the command.
109
+ buffer += obj.command
110
+
111
+ # Stringify the parameters
112
+ buffer += self.__stringify_parameters obj.parameters
113
+
114
+ # We're done!
115
+ return buffer
116
+ end
117
+
118
+ private
119
+
120
+ # Internal: A regular expression which matches a n!u@h mask.
121
+ MATCH_PREFIX = /^:(?<nick>[^@!]+) (?:!(?<user>[^@]+))? (?:@(?<host>.+))?$/x
122
+
123
+ # Internal: A regular expression which matches a tag.
124
+ MATCH_TAG = /^(?<name>[^\s=]+?)(?:=(?<value>[^\s;]+))?$/
125
+
126
+ # Internal: The characters which need to be escaped in tag values.
127
+ TAG_ESCAPES = {
128
+ '\\\\' => '\\',
129
+ '\:' => ';',
130
+ '\s' => "\s",
131
+ '\r' => "\r",
132
+ '\n' => "\n",
133
+ }
134
+
135
+ # Internal: Retrieves a space delimited token from the buffer.
136
+ #
137
+ # buffer - The buffer to retrieve the token from.
138
+ def self.__get_token buffer
139
+ return nil if buffer.empty?
140
+ position = buffer.index ' '
141
+ if position == nil
142
+ token = buffer.clone
143
+ buffer.clear
144
+ return token
145
+ end
146
+ token = buffer.slice! 0...position
147
+ position = buffer.index /\S+/
148
+ if position == nil
149
+ buffer.clear
150
+ else
151
+ buffer.slice! 0...position
152
+ end
153
+ return token
154
+ end
155
+
156
+ # Internal: Retrieves a space delimited token that may be a <trailing> parameter.
157
+ #
158
+ # buffer - The buffer to retrieve the token from.
159
+ def self.__get_final_token buffer
160
+ return nil if buffer.empty?
161
+ if buffer[0] == ':'
162
+ token = buffer[1..-1]
163
+ buffer.clear
164
+ return token
165
+ end
166
+ return self.__get_token buffer
167
+ end
168
+
169
+ # Internal: Objectifies the prefix from the JSON wire format to an IRCParser::Prefix.
170
+ #
171
+ # token - A String containing the prefix in the JSON wire format.
172
+ def self.__objectify_prefix prefix
173
+ unless MATCH_PREFIX =~ prefix
174
+ raise IRCParser::Error.new(prefix), 'prefix is not a user mask or server name'
175
+ end
176
+ return IRCParser::Prefix.new nick: $~[:nick], user: $~[:user], host: $~[:host]
177
+ end
178
+
179
+ # Internal: Objectifies tags from the JSON wire format to a Hash.
180
+ #
181
+ # token - A String containing tags in the JSON wire format.
182
+ def self.__objectify_tags token
183
+ tags = Hash.new
184
+ token[1..-1].split(';').each do |tag|
185
+ if tag =~ MATCH_TAG
186
+ value = nil
187
+ value_index = 0
188
+ while $~['value'] != nil && value_index < $~['value'].size
189
+ value ||= String.new
190
+ if $~['value'][value_index] == '\\'
191
+ escape = $~['value'].slice(value_index, 2)
192
+ if TAG_ESCAPES.include? escape
193
+ value += TAG_ESCAPES[escape]
194
+ value_index += 1
195
+ end
196
+ else
197
+ value += $~['value'][value_index]
198
+ end
199
+ value_index += 1
200
+ end
201
+ tags[$~['name']] = value
202
+ else
203
+ raise IRCParser::Error.new(tag), 'tag is malformed'
204
+ end
205
+ end
206
+ return tags
207
+ end
208
+
209
+ # Internal: Stringifies parameters from an Array to the JSON wire format.
210
+ #
211
+ # parameters - An Array to stringify to the JSON wire format.
212
+ def self.__stringify_parameters parameters
213
+ buffer = String.new
214
+ parameters.each_with_index do |parameter, index|
215
+ trailing = parameter.include? ' '
216
+ if trailing && index != parameters.size-1
217
+ raise IRCParser::Error.new(parameter), 'only the last parameter may contain spaces'
218
+ end
219
+
220
+ buffer += ' '
221
+ if trailing || parameter.empty?
222
+ buffer += ':'
223
+ buffer += parameter
224
+ break
225
+ end
226
+ buffer += parameter
227
+ end
228
+ return buffer
229
+ end
230
+
231
+ # Internal: Stringifies the prefix from an IRCParser::Prefix to the JSON wire format.
232
+ #
233
+ # tags - An IRCParser::Prefix to stringify to the JSON wire format.
234
+ def self.__stringify_prefix prefix
235
+ buffer = prefix.nick
236
+ buffer += "!#{prefix.user}" unless prefix.user.nil?
237
+ buffer += "@#{prefix.host}" unless prefix.host.nil?
238
+ return buffer
239
+ end
240
+
241
+ # Internal: Stringifies tags from a Hash to the JSON wire format.
242
+ #
243
+ # tags - A Hash of tags to stringify to the JSON wire format.
244
+ def self.__stringify_tags tags
245
+ buffer = String.new
246
+ tags.each.with_index do |tag, idx|
247
+ key, value = tag
248
+ buffer += key
249
+ unless value.nil?
250
+ buffer += '='
251
+ value.each_char do |chr|
252
+ if TAG_ESCAPES.has_value? chr
253
+ buffer += TAG_ESCAPES.key chr
254
+ else
255
+ buffer += chr
256
+ end
257
+ end
258
+ end
259
+ buffer += ';' if idx < tags.size - 1
260
+ end
261
+ return buffer
262
+ end
263
+
264
+ end
265
+ end
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -25,39 +25,43 @@ module IRCParser
25
25
 
26
26
  # Ruby really needs some kind of basic type checking.
27
27
  unless str.is_a? String
28
- raise IRCParser::Error.new(line), "message is not a string"
28
+ raise IRCParser::Error.new(str), "message is not a String"
29
29
  end
30
30
 
31
+ # Skip any preceding whitespace. This is technically invalid but
32
+ # is implemented by several servers in the wild.
33
+ message = str.lstrip
34
+
31
35
  # Split the message up into an array of tokens.
32
- current_token = self.__get_token str
36
+ current_token = self.__get_token message
33
37
  components = Hash.new
34
38
 
35
39
  # Have we encountered IRCv3 message tags?
36
40
  components[:tags] = Hash.new
37
41
  if current_token != nil && current_token[0] == '@'
38
42
  components[:tags] = self.__objectify_tags current_token
39
- current_token = self.__get_token str
43
+ current_token = self.__get_token message
40
44
  end
41
45
 
42
46
  # Have we encountered the prefix of this message?
43
47
  if current_token != nil && current_token[0] == ':'
44
48
  components[:prefix] = self.__objectify_prefix current_token
45
- current_token = self.__get_token str
49
+ current_token = self.__get_token message
46
50
  end
47
51
 
48
52
  # The command parameter is mandatory.
49
53
  if current_token != nil
50
54
  components[:command] = current_token.upcase
51
- current_token = self.__get_final_token str
55
+ current_token = self.__get_final_token message
52
56
  else
53
- raise IRCParser::Error.new(line), 'message is missing the command name'
57
+ raise IRCParser::Error.new(str), 'message is missing the command name'
54
58
  end
55
59
 
56
60
  # Try to parse all of the remaining parameters.
57
61
  components[:parameters] = Array.new
58
62
  while current_token != nil
59
63
  components[:parameters] << current_token
60
- current_token = self.__get_final_token str
64
+ current_token = self.__get_final_token message
61
65
  end
62
66
 
63
67
  return IRCParser::Message.new components
data/test/test_message.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
@@ -144,12 +144,24 @@ describe IRCParser::Message do
144
144
  end
145
145
  end
146
146
 
147
+ describe 'when checking we can handle a space before the command' do
148
+ before do
149
+ @text = ' COMMAND'
150
+ @message = IRCParser::Message.parse @text
151
+ end
152
+ it 'should parse the message properly' do
153
+ @message.command.must_equal 'COMMAND'
154
+ @message.parameters.size.must_equal 0
155
+ end
156
+ end
157
+
147
158
  describe 'when checking we can handle a space after the command' do
148
159
  before do
149
160
  @text = 'COMMAND '
150
161
  @message = IRCParser::Message.parse @text
151
162
  end
152
163
  it 'should parse the message properly' do
164
+ @message.command.must_equal 'COMMAND'
153
165
  @message.parameters.size.must_equal 0
154
166
  end
155
167
  end
@@ -160,6 +172,7 @@ describe IRCParser::Message do
160
172
  @message = IRCParser::Message.parse @text
161
173
  end
162
174
  it 'should parse the trailing parameter properly' do
175
+ @message.command.must_equal 'COMMAND'
163
176
  @message.parameters.size.must_equal 1
164
177
  @message.parameters[0].must_equal ''
165
178
  end
@@ -202,4 +215,31 @@ describe IRCParser::Message do
202
215
  end
203
216
  end
204
217
 
218
+ describe 'when checking we handle parsing malformed messages properly' do
219
+ it 'should throw an IRCParser::Error when trying to parse an empty message' do
220
+ proc {
221
+ IRCParser::Message.parse ''
222
+ }.must_raise IRCParser::Error
223
+ end
224
+ it 'should throw an IRCParser::Error when trying to parse an whitespace message' do
225
+ proc {
226
+ IRCParser::Message.parse ' '
227
+ }.must_raise IRCParser::Error
228
+ end
229
+ it 'should throw an IRCParser::Error when trying to parse a message with tags and a prefix but no command' do
230
+ proc {
231
+ IRCParser::Message.parse '@foo;bar=baz :irc.example.com'
232
+ }.must_raise IRCParser::Error
233
+ end
234
+ it 'should throw an IRCParser::Error when trying to parse a message with tags but no command' do
235
+ proc {
236
+ IRCParser::Message.parse '@foo;bar=baz'
237
+ }.must_raise IRCParser::Error
238
+ end
239
+ it 'should throw an IRCParser::Error when trying to parse a message with a prefix but no command' do
240
+ proc {
241
+ IRCParser::Message.parse ':irc.example.com'
242
+ }.must_raise IRCParser::Error
243
+ end
244
+ end
205
245
  end
data/test/test_prefix.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # IRCParser - Internet Relay Chat Message Parser
2
2
  #
3
- # Copyright (C) 2015-2017 Peter "SaberUK" Powell <petpow@saberuk.com>
3
+ # Copyright (C) 2015-2019 Peter "SaberUK" Powell <petpow@saberuk.com>
4
4
  #
5
5
  # Permission to use, copy, modify, and/or distribute this software for any purpose with or without
6
6
  # fee is hereby granted, provided that the above copyright notice and this permission notice appear
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ircparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter "SaberUK" Powell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-12 00:00:00.000000000 Z
11
+ date: 2019-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -69,10 +69,11 @@ files:
69
69
  - lib/ircparser/message.rb
70
70
  - lib/ircparser/prefix.rb
71
71
  - lib/ircparser/stream.rb
72
+ - lib/ircparser/wire/json.rb
72
73
  - lib/ircparser/wire/rfc.rb
73
74
  - test/test_message.rb
74
75
  - test/test_prefix.rb
75
- homepage: https://github.com/SaberUK/ircparser
76
+ homepage: https://github.com/SaberUK/ircparser-ruby
76
77
  licenses:
77
78
  - ISC
78
79
  metadata: {}
@@ -91,8 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
92
  - !ruby/object:Gem::Version
92
93
  version: '0'
93
94
  requirements: []
94
- rubyforge_project:
95
- rubygems_version: 2.7.5
95
+ rubygems_version: 3.0.1
96
96
  signing_key:
97
97
  specification_version: 4
98
98
  summary: An IRCv3 message parser.