ircparser 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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.