rims-rfc822 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3721bb4e1b0e4865de80a3756bc313a910180b207c76bbe4e25de30c2bb14f0b
4
+ data.tar.gz: f1d6f3b4b1bc84d32644beeb89628c814be2b4674bc3e5c334ce2adcc8889a11
5
+ SHA512:
6
+ metadata.gz: cb1a1894bed18cfc81da85627620de46d1754b8dc50145cc40de4af0c2ed9d5a75ea7cff508b889442b06c6a513c2d607824be15ec470e3718d203d150092c61
7
+ data.tar.gz: 42a2832fd4e246525c3e8932a7b7a1890b258862bb7adfd4077610cc8cf85fc05e277dfea02ecb93dea20f0b7894f31757a6ab5808fe626832f208099cefd453
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /vendor/
10
+ /Gemfile.lock
11
+ /README.html
12
+ *~
13
+ *.log
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in rims-rfc822.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 TOKI Yoshinori
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ RIMS::RFC822
2
+ ============
3
+
4
+ Fast parser for a RFC822 formatted message.
5
+ This gem is a component of RIMS (Ruby IMap Server), but can be used
6
+ independently of RIMS.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'rims-rfc822'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install rims-rfc822
24
+
25
+ Usage
26
+ -----
27
+
28
+ ```ruby
29
+ require 'rims/rfc822'
30
+
31
+ msg = RIMS::RFC822::Message.new(your_rfc822_text)
32
+
33
+ p msg.header
34
+ p msg.body
35
+
36
+ # source text attributes
37
+ p msg.raw_source
38
+ p msg.header.raw_source
39
+ p msg.body.raw_source
40
+
41
+ # type attributes
42
+ p msg.media_main_type
43
+ p msg.media_sub_type
44
+ p msg.content_type
45
+ p msg.content_type_parameters
46
+ p msg.charset
47
+ p msg.boundary
48
+
49
+ # headear attributes
50
+ p msg.date
51
+ p msg.from
52
+ p msg.sender
53
+ p msg.reply_to
54
+ p msg.to
55
+ p msg.cc
56
+ p msg.bcc
57
+
58
+ # content attributes
59
+ p msg.text?
60
+ p msg.multipart?
61
+ p msg.message?
62
+ p msg.parts
63
+ p msg.message
64
+ ```
65
+
66
+ Contributing
67
+ ------------
68
+
69
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/y10k/rims-rfc822>.
70
+
71
+ License
72
+ -------
73
+
74
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'rdoc/task'
6
+
7
+ Rake::TestTask.new do |task|
8
+ if ((ENV.key? 'RUBY_DEBUG') && (! ENV['RUBY_DEBUG'].empty?)) then
9
+ task.ruby_opts << '-d'
10
+ end
11
+ end
12
+
13
+ Rake::RDocTask.new do |rd|
14
+ rd.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ desc 'Build README.html from markdown source'
18
+ task :readme => %w[ README.html ]
19
+
20
+ file 'README.html' => [ 'README.md' ] do
21
+ sh "pandoc --from=markdown --to=html5 --standalone --self-contained --css=$HOME/.pandoc/github.css --output=README.html README.md"
22
+ end
23
+ CLOBBER.include 'README.html'
24
+
25
+ # Local Variables:
26
+ # mode: Ruby
27
+ # indent-tabs-mode: nil
28
+ # End:
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rims/rfc822"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,12 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RIMS
4
+ module RFC822
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
8
+
9
+ # Local Variables:
10
+ # mode: Ruby
11
+ # indent-tabs-mode: nil
12
+ # End:
@@ -0,0 +1,464 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rims/rfc822/version'
4
+ require 'time'
5
+
6
+ module RIMS
7
+ module RFC822
8
+ def split_message(msg_txt)
9
+ header_txt, body_txt = msg_txt.lstrip.split(/\r?\n\r?\n/, 2)
10
+ header_txt << $& if $&
11
+ [ header_txt, body_txt ]
12
+ end
13
+ module_function :split_message
14
+
15
+ def parse_header(header_txt)
16
+ field_pair_list = header_txt.scan(%r{
17
+ ^
18
+ ((?#name) \S+? )
19
+ \s* : \s*
20
+ (
21
+ (?#value)
22
+ .*? (?: \n|\z)
23
+ (?: ^\s .*? (?: \n|\z) )*
24
+ )
25
+ }x)
26
+
27
+ for _name, value in field_pair_list
28
+ value.strip!
29
+ name.freeze
30
+ value.freeze
31
+ end
32
+
33
+ field_pair_list.freeze
34
+ end
35
+ module_function :parse_header
36
+
37
+ def parse_content_type(content_type_txt)
38
+ src_txt = content_type_txt.dup
39
+ if (src_txt.sub!(%r"\A \s* (?<main_type>\S+?) \s* / \s* (?<sub_type>\S+?) \s* (?:;|\Z)"x, '')) then
40
+ main_type = $~[:main_type]
41
+ sub_type = $~[:sub_type]
42
+
43
+ params = {}
44
+ src_txt.scan(%r'(?<name>\S+?) \s* = \s* (?: (?<quoted_string>".*?") | (?<token>\S+?) ) \s* (?:;|\Z)'x) do
45
+ name = $~[:name]
46
+ if ($~[:quoted_string]) then
47
+ quoted_value = $~[:quoted_string]
48
+ value = unquote_phrase(quoted_value)
49
+ else
50
+ value = $~[:token]
51
+ end
52
+ params[name.downcase] = [ name.freeze, value.freeze ].freeze
53
+ end
54
+
55
+ [ main_type.freeze, sub_type.freeze, params.freeze ].freeze
56
+ else
57
+ [ 'application'.freeze, 'octet-stream'.freeze, {}.freeze ].freeze
58
+ end
59
+ end
60
+ module_function :parse_content_type
61
+
62
+ def parse_multipart_body(boundary, body_txt)
63
+ delim = '--' + boundary
64
+ term = delim + '--'
65
+ body_txt2, _body_epilogue_txt = body_txt.split(term, 2)
66
+ if (body_txt2) then
67
+ _body_preamble_txt, body_parts_txt = body_txt2.split(delim, 2)
68
+ if (body_parts_txt) then
69
+ part_list = body_parts_txt.split(delim, -1)
70
+ for part_txt in part_list
71
+ part_txt.lstrip!
72
+ part_txt.chomp!("\n")
73
+ part_txt.chomp!("\r")
74
+ part_txt.freeze
75
+ end
76
+ return part_list.freeze
77
+ end
78
+ end
79
+
80
+ [].freeze
81
+ end
82
+ module_function :parse_multipart_body
83
+
84
+ def unquote_phrase(phrase_txt)
85
+ state = :raw
86
+ src_txt = phrase_txt.dup
87
+ dst_txt = ''.encode(phrase_txt.encoding)
88
+
89
+ while (src_txt.sub!(/\A(:? " | \( | \) | \\ | [^"\(\)\\]+ )/x, ''))
90
+ match_txt = $&
91
+ case (state)
92
+ when :raw
93
+ case (match_txt)
94
+ when '"'
95
+ state = :quote
96
+ when '('
97
+ state = :comment
98
+ when "\\"
99
+ src_txt.sub!(/\A./, '') and dst_txt << $&
100
+ else
101
+ dst_txt << match_txt
102
+ end
103
+ when :quote
104
+ case (match_txt)
105
+ when '"'
106
+ state = :raw
107
+ when "\\"
108
+ src_txt.sub!(/\A./, '') && dst_txt << $&
109
+ else
110
+ dst_txt << match_txt
111
+ end
112
+ when :comment
113
+ case (match_txt)
114
+ when ')'
115
+ state = :raw
116
+ when "\\"
117
+ src_txt.sub!(/\A./, '')
118
+ else
119
+ # ignore comment text.
120
+ end
121
+ else
122
+ raise "internal error: unknown state #{state}"
123
+ end
124
+ end
125
+
126
+ dst_txt.freeze
127
+ end
128
+ module_function :unquote_phrase
129
+
130
+ def parse_mail_address_list(address_list_txt)
131
+ addr_list = []
132
+ src_txt = address_list_txt.dup
133
+
134
+ while (true)
135
+ if (src_txt.sub!(%r{
136
+ \A
137
+ \s*
138
+ (?<display_name>\S.*?) \s* : (?<group_list>.*?) ;
139
+ \s*
140
+ ,?
141
+ }x, ''))
142
+ then
143
+ display_name = $~[:display_name]
144
+ group_list = $~[:group_list]
145
+ addr_list << [ nil, nil, unquote_phrase(display_name), nil ].freeze
146
+ addr_list.concat(parse_mail_address_list(group_list))
147
+ addr_list << [ nil, nil, nil, nil ].freeze
148
+ elsif (src_txt.sub!(%r{
149
+ \A
150
+ \s*
151
+ (?<local_part>[^<>@",\s]+) \s* @ \s* (?<domain>[^<>@",\s]+)
152
+ \s*
153
+ ,?
154
+ }x, ''))
155
+ then
156
+ addr_list << [ nil, nil, $~[:local_part].freeze, $~[:domain].freeze ].freeze
157
+ elsif (src_txt.sub!(%r{
158
+ \A
159
+ \s*
160
+ (?<display_name>\S.*?)
161
+ \s*
162
+ <
163
+ \s*
164
+ (?:
165
+ (?<route>@[^<>@",]* (?:, \s* @[^<>@",]*)*)
166
+ \s*
167
+ :
168
+ )?
169
+ \s*
170
+ (?<local_part>[^<>@",\s]+) \s* @ \s* (?<domain>[^<>@",\s]+)
171
+ \s*
172
+ >
173
+ \s*
174
+ ,?
175
+ }x, ''))
176
+ then
177
+ display_name = $~[:display_name]
178
+ route = $~[:route]
179
+ local_part = $~[:local_part]
180
+ domain = $~[:domain]
181
+ addr_list << [ unquote_phrase(display_name), route.freeze, local_part.freeze, domain.freeze ].freeze
182
+ else
183
+ break
184
+ end
185
+ end
186
+
187
+ addr_list.freeze
188
+ end
189
+ module_function :parse_mail_address_list
190
+
191
+ class Header
192
+ include Enumerable
193
+
194
+ def initialize(header_txt)
195
+ @raw_source = header_txt.freeze
196
+ @field_list = nil
197
+ @field_map = nil
198
+ end
199
+
200
+ attr_reader :raw_source
201
+
202
+ def setup_header
203
+ if (@field_list.nil? || @field_map.nil?) then
204
+ @field_list = RFC822.parse_header(@raw_source)
205
+ @field_map = {}
206
+ for name, value in @field_list
207
+ key = name.downcase
208
+ @field_map[key] = [] unless (@field_map.key? key)
209
+ @field_map[key] << value
210
+ end
211
+ @field_map.each_value do |value_list|
212
+ value_list.freeze
213
+ end
214
+ @field_map.freeze
215
+ self
216
+ end
217
+ end
218
+ private :setup_header
219
+
220
+ def each
221
+ setup_header
222
+ return enum_for(:each) unless block_given?
223
+ for name, value in @field_list
224
+ yield(name, value)
225
+ end
226
+ self
227
+ end
228
+
229
+ def key?(name)
230
+ setup_header
231
+ @field_map.key? name.downcase
232
+ end
233
+
234
+ def [](name)
235
+ setup_header
236
+ if (value_list = @field_map[name.downcase]) then
237
+ value_list[0]
238
+ end
239
+ end
240
+
241
+ def fetch_upcase(name)
242
+ setup_header
243
+ if (value_list = @field_map[name.downcase]) then
244
+ if (value = value_list[0]) then
245
+ value.upcase
246
+ end
247
+ end
248
+ end
249
+
250
+ def field_value_list(name)
251
+ setup_header
252
+ @field_map[name.downcase]
253
+ end
254
+ end
255
+
256
+ class Body
257
+ def initialize(body_txt)
258
+ @raw_source = body_txt.freeze
259
+ end
260
+
261
+ attr_reader :raw_source
262
+ end
263
+
264
+ class Message
265
+ def initialize(msg_txt)
266
+ @raw_source = msg_txt.freeze
267
+ @header = nil
268
+ @body = nil
269
+ @content_type = nil
270
+ @is_multipart = nil
271
+ @parts = nil
272
+ @is_message = nil
273
+ @message = nil
274
+ @date = nil
275
+ @from = nil
276
+ @sender = nil
277
+ @reply_to = nil
278
+ @to = nil
279
+ @cc = nil
280
+ @bcc = nil
281
+ end
282
+
283
+ attr_reader :raw_source
284
+
285
+ def setup_message
286
+ if (@header.nil? || @body.nil?) then
287
+ header_txt, body_txt = RFC822.split_message(@raw_source)
288
+ @header = Header.new(header_txt || '')
289
+ @body = Body.new(body_txt || '')
290
+ self
291
+ end
292
+ end
293
+ private :setup_message
294
+
295
+ def header
296
+ setup_message
297
+ @header
298
+ end
299
+
300
+ def body
301
+ setup_message
302
+ @body
303
+ end
304
+
305
+ def setup_content_type
306
+ if (@content_type.nil?) then
307
+ @content_type = RFC822.parse_content_type(header['content-type'] || '')
308
+ self
309
+ end
310
+ end
311
+ private :setup_content_type
312
+
313
+ def to_upper(text_or_nil)
314
+ text_or_nil.upcase if text_or_nil
315
+ end
316
+ private :to_upper
317
+
318
+ def media_main_type
319
+ setup_content_type
320
+ @content_type[0]
321
+ end
322
+
323
+ def media_main_type_upcase
324
+ setup_content_type
325
+ to_upper(@content_type[0])
326
+ end
327
+
328
+ def media_sub_type
329
+ setup_content_type
330
+ @content_type[1]
331
+ end
332
+
333
+ def media_sub_type_upcase
334
+ setup_content_type
335
+ to_upper(@content_type[1])
336
+ end
337
+
338
+ def content_type
339
+ "#{media_main_type}/#{media_sub_type}"
340
+ end
341
+
342
+ def content_type_upcase
343
+ to_upper("#{media_main_type}/#{media_sub_type}")
344
+ end
345
+
346
+ def content_type_parameters
347
+ setup_content_type
348
+ @content_type[2].each_value.map{|name, value| [ name, value ] }
349
+ end
350
+
351
+ def charset
352
+ setup_content_type
353
+ if (name_value_pair = @content_type[2]['charset']) then
354
+ name_value_pair[1]
355
+ end
356
+ end
357
+
358
+ def boundary
359
+ setup_content_type
360
+ if (name_value_pair = @content_type[2]['boundary']) then
361
+ name_value_pair[1]
362
+ end
363
+ end
364
+
365
+ def text?
366
+ media_main_type_upcase == 'TEXT'
367
+ end
368
+
369
+ def multipart?
370
+ if (@is_multipart.nil?) then
371
+ @is_multipart = (media_main_type_upcase == 'MULTIPART')
372
+ end
373
+ @is_multipart
374
+ end
375
+
376
+ def parts
377
+ if (multipart?) then
378
+ if (@parts.nil?) then
379
+ if (boundary = self.boundary) then
380
+ part_list = RFC822.parse_multipart_body(boundary, body.raw_source)
381
+ @parts = part_list.map{|msg_txt| Message.new(msg_txt) }.freeze
382
+ else
383
+ @parts = [].freeze
384
+ end
385
+ end
386
+ @parts
387
+ end
388
+ end
389
+
390
+ def message?
391
+ if (@is_message.nil?) then
392
+ @is_message = (media_main_type_upcase == 'MESSAGE')
393
+ end
394
+ @is_message
395
+ end
396
+
397
+ def message
398
+ if (message?) then
399
+ if (@message.nil?) then
400
+ @message = Message.new(body.raw_source)
401
+ end
402
+ @message
403
+ end
404
+ end
405
+
406
+ def date
407
+ if (header.key? 'Date') then
408
+ if (@date.nil?) then
409
+ begin
410
+ @date = Time.parse(header['Date'])
411
+ rescue ArgumentError
412
+ @date = Time.at(0)
413
+ end
414
+ end
415
+
416
+ @date.freeze
417
+ end
418
+ end
419
+
420
+ def mail_address_header_field(field_name)
421
+ if (header.key? field_name) then
422
+ ivar_name = '@' + field_name.downcase.gsub('-', '_')
423
+ addr_list = instance_variable_get(ivar_name)
424
+ if (addr_list.nil?) then
425
+ addr_list = header.field_value_list(field_name).map{|addr_list_str| RFC822.parse_mail_address_list(addr_list_str) }.inject(:+)
426
+ addr_list.freeze
427
+ instance_variable_set(ivar_name, addr_list)
428
+ end
429
+ addr_list
430
+ end
431
+ end
432
+ private :mail_address_header_field
433
+
434
+ def from
435
+ mail_address_header_field('from')
436
+ end
437
+
438
+ def sender
439
+ mail_address_header_field('sender')
440
+ end
441
+
442
+ def reply_to
443
+ mail_address_header_field('reply-to')
444
+ end
445
+
446
+ def to
447
+ mail_address_header_field('to')
448
+ end
449
+
450
+ def cc
451
+ mail_address_header_field('cc')
452
+ end
453
+
454
+ def bcc
455
+ mail_address_header_field('bcc')
456
+ end
457
+ end
458
+ end
459
+ end
460
+
461
+ # Local Variables:
462
+ # mode: Ruby
463
+ # indent-tabs-mode: nil
464
+ # End:
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rims/rfc822/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'rims-rfc822'
9
+ spec.version = RIMS::RFC822::VERSION
10
+ spec.authors = ['TOKI Yoshinori']
11
+ spec.email = ['toki@freedom.ne.jp']
12
+
13
+ spec.summary = %q{Fast parser for a RFC822 formatted message.}
14
+ spec.description = <<-'EOF'
15
+ Fast parser for a RFC822 formatted message.
16
+ This gem is a component of RIMS (Ruby IMap Server), but can be
17
+ used independently of RIMS.
18
+ EOF
19
+ spec.homepage = 'https://github.com/y10k/rims-rfc822'
20
+ spec.license = 'MIT'
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_development_dependency 'bundler', '~> 1.17'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rdoc'
34
+ spec.add_development_dependency 'test-unit'
35
+ end
36
+
37
+ # Local Variables:
38
+ # mode: Ruby
39
+ # indent-tabs-mode: nil
40
+ # End:
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rims-rfc822
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - TOKI Yoshinori
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: |2
70
+ Fast parser for a RFC822 formatted message.
71
+ This gem is a component of RIMS (Ruby IMap Server), but can be
72
+ used independently of RIMS.
73
+ email:
74
+ - toki@freedom.ne.jp
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - lib/rims/rfc822.rb
87
+ - lib/rims/rfc822/version.rb
88
+ - rims-rfc822.gemspec
89
+ homepage: https://github.com/y10k/rims-rfc822
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubygems_version: 3.0.3
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Fast parser for a RFC822 formatted message.
112
+ test_files: []