mail 2.7.0.rc1 → 2.7.0.rc2

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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -98
  3. data/lib/mail.rb +1 -6
  4. data/lib/mail/attachments_list.rb +5 -2
  5. data/lib/mail/body.rb +39 -33
  6. data/lib/mail/check_delivery_params.rb +8 -6
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/elements/address.rb +19 -18
  9. data/lib/mail/encodings.rb +89 -31
  10. data/lib/mail/encodings/7bit.rb +5 -15
  11. data/lib/mail/encodings/8bit.rb +2 -21
  12. data/lib/mail/encodings/base64.rb +11 -12
  13. data/lib/mail/encodings/binary.rb +3 -22
  14. data/lib/mail/encodings/identity.rb +24 -0
  15. data/lib/mail/encodings/quoted_printable.rb +6 -6
  16. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  17. data/lib/mail/encodings/unix_to_unix.rb +2 -1
  18. data/lib/mail/envelope.rb +1 -1
  19. data/lib/mail/field.rb +93 -61
  20. data/lib/mail/fields/bcc_field.rb +2 -2
  21. data/lib/mail/fields/cc_field.rb +1 -1
  22. data/lib/mail/fields/comments_field.rb +1 -1
  23. data/lib/mail/fields/common/common_address.rb +32 -7
  24. data/lib/mail/fields/common/common_field.rb +1 -10
  25. data/lib/mail/fields/content_description_field.rb +1 -1
  26. data/lib/mail/fields/content_disposition_field.rb +3 -3
  27. data/lib/mail/fields/content_id_field.rb +2 -2
  28. data/lib/mail/fields/content_location_field.rb +1 -1
  29. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  30. data/lib/mail/fields/content_type_field.rb +1 -1
  31. data/lib/mail/fields/date_field.rb +2 -3
  32. data/lib/mail/fields/from_field.rb +1 -1
  33. data/lib/mail/fields/in_reply_to_field.rb +1 -1
  34. data/lib/mail/fields/keywords_field.rb +1 -1
  35. data/lib/mail/fields/message_id_field.rb +1 -1
  36. data/lib/mail/fields/mime_version_field.rb +1 -1
  37. data/lib/mail/fields/optional_field.rb +4 -1
  38. data/lib/mail/fields/received_field.rb +1 -1
  39. data/lib/mail/fields/references_field.rb +1 -1
  40. data/lib/mail/fields/reply_to_field.rb +1 -1
  41. data/lib/mail/fields/resent_bcc_field.rb +1 -1
  42. data/lib/mail/fields/resent_cc_field.rb +1 -1
  43. data/lib/mail/fields/resent_date_field.rb +0 -1
  44. data/lib/mail/fields/resent_from_field.rb +1 -1
  45. data/lib/mail/fields/resent_message_id_field.rb +1 -1
  46. data/lib/mail/fields/resent_sender_field.rb +1 -1
  47. data/lib/mail/fields/resent_to_field.rb +1 -1
  48. data/lib/mail/fields/return_path_field.rb +1 -1
  49. data/lib/mail/fields/sender_field.rb +1 -1
  50. data/lib/mail/fields/subject_field.rb +1 -1
  51. data/lib/mail/fields/to_field.rb +1 -1
  52. data/lib/mail/fields/unstructured_field.rb +19 -2
  53. data/lib/mail/header.rb +9 -8
  54. data/lib/mail/mail.rb +2 -10
  55. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  56. data/lib/mail/message.rb +64 -51
  57. data/lib/mail/multibyte.rb +14 -16
  58. data/lib/mail/multibyte/chars.rb +2 -1
  59. data/lib/mail/network.rb +1 -0
  60. data/lib/mail/network/delivery_methods/exim.rb +6 -10
  61. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  62. data/lib/mail/network/delivery_methods/sendmail.rb +8 -4
  63. data/lib/mail/network/delivery_methods/smtp.rb +56 -55
  64. data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -1
  65. data/lib/mail/network/retriever_methods/imap.rb +18 -5
  66. data/lib/mail/network/retriever_methods/pop3.rb +3 -1
  67. data/lib/mail/parser_tools.rb +15 -0
  68. data/lib/mail/parsers/address_lists_parser.rb +30462 -12597
  69. data/lib/mail/parsers/address_lists_parser.rl +18 -12
  70. data/lib/mail/parsers/content_disposition_parser.rb +405 -215
  71. data/lib/mail/parsers/content_disposition_parser.rl +11 -5
  72. data/lib/mail/parsers/content_location_parser.rb +443 -208
  73. data/lib/mail/parsers/content_location_parser.rl +9 -3
  74. data/lib/mail/parsers/content_transfer_encoding_parser.rb +180 -80
  75. data/lib/mail/parsers/content_transfer_encoding_parser.rl +8 -2
  76. data/lib/mail/parsers/content_type_parser.rb +436 -245
  77. data/lib/mail/parsers/content_type_parser.rl +12 -6
  78. data/lib/mail/parsers/date_time_parser.rb +172 -72
  79. data/lib/mail/parsers/date_time_parser.rl +10 -4
  80. data/lib/mail/parsers/envelope_from_parser.rb +2833 -1320
  81. data/lib/mail/parsers/envelope_from_parser.rl +9 -3
  82. data/lib/mail/parsers/message_ids_parser.rb +2325 -976
  83. data/lib/mail/parsers/message_ids_parser.rl +9 -3
  84. data/lib/mail/parsers/mime_version_parser.rb +164 -64
  85. data/lib/mail/parsers/mime_version_parser.rl +9 -3
  86. data/lib/mail/parsers/phrase_lists_parser.rb +582 -237
  87. data/lib/mail/parsers/phrase_lists_parser.rl +9 -3
  88. data/lib/mail/parsers/received_parser.rb +7036 -3004
  89. data/lib/mail/parsers/received_parser.rl +11 -5
  90. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +1 -0
  91. data/lib/mail/parsers/rfc2045_content_type.rl +1 -0
  92. data/lib/mail/parsers/rfc2045_mime.rl +1 -0
  93. data/lib/mail/parsers/rfc2183_content_disposition.rl +1 -0
  94. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  95. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +7 -1
  96. data/lib/mail/parsers/rfc5322.rl +3 -1
  97. data/lib/mail/parsers/rfc5322_address.rl +3 -1
  98. data/lib/mail/parsers/rfc5322_date_time.rl +1 -0
  99. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +9 -5
  100. data/lib/mail/part.rb +1 -1
  101. data/lib/mail/utilities.rb +44 -15
  102. data/lib/mail/version.rb +1 -1
  103. data/lib/mail/version_specific/ruby_1_8.rb +12 -1
  104. data/lib/mail/version_specific/ruby_1_9.rb +13 -1
  105. metadata +7 -13
  106. data/CHANGELOG.rdoc +0 -822
  107. data/CONTRIBUTING.md +0 -60
  108. data/Dependencies.txt +0 -1
  109. data/Gemfile +0 -11
  110. data/Rakefile +0 -23
  111. data/TODO.rdoc +0 -9
  112. data/lib/mail/multibyte/exceptions.rb +0 -9
@@ -33,12 +33,14 @@ module Mail
33
33
  end
34
34
 
35
35
  def validate_smtp_addr(addr)
36
- if addr.bytesize > 2048
37
- yield 'may not exceed 2kB'
38
- end
39
-
40
- if /[\r\n]/ =~ addr
41
- yield 'may not contain CR or LF line breaks'
36
+ if addr
37
+ if addr.bytesize > 2048
38
+ yield 'may not exceed 2kB'
39
+ end
40
+
41
+ if /[\r\n]/ =~ addr
42
+ yield 'may not contain CR or LF line breaks'
43
+ end
42
44
  end
43
45
 
44
46
  addr
@@ -42,6 +42,8 @@ module Mail
42
42
  Mail::SMTPConnection
43
43
  when :test
44
44
  Mail::TestMailer
45
+ when :logger
46
+ Mail::LoggerDelivery
45
47
  else
46
48
  method
47
49
  end
@@ -23,7 +23,6 @@ module Mail
23
23
  # a.comments #=> ['My email address']
24
24
  # a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
25
25
  def initialize(value = nil)
26
- @output_type = :decode
27
26
  if value.nil?
28
27
  @parsed = false
29
28
  @data = nil
@@ -45,14 +44,14 @@ module Mail
45
44
  #
46
45
  # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
47
46
  # a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
48
- def format
47
+ def format(output_type = :decode)
49
48
  parse unless @parsed
50
49
  if @data.nil?
51
50
  EMPTY
52
- elsif display_name
53
- [quote_phrase(display_name), "<#{address}>", format_comments].compact.join(SPACE)
54
- elsif address
55
- [address, format_comments].compact.join(SPACE)
51
+ elsif name = display_name(output_type)
52
+ [quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(SPACE)
53
+ elsif a = address(output_type)
54
+ [a, format_comments].compact.join(SPACE)
56
55
  else
57
56
  raw
58
57
  end
@@ -63,9 +62,13 @@ module Mail
63
62
  #
64
63
  # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
65
64
  # a.address #=> 'mikel@test.lindsaar.net'
66
- def address
65
+ def address(output_type = :decode)
67
66
  parse unless @parsed
68
- domain ? "#{local}@#{domain}" : local
67
+ if d = domain(output_type)
68
+ "#{local(output_type)}@#{d}"
69
+ else
70
+ local(output_type)
71
+ end
69
72
  end
70
73
 
71
74
  # Provides a way to assign an address to an already made Mail::Address object.
@@ -81,10 +84,10 @@ module Mail
81
84
  #
82
85
  # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
83
86
  # a.display_name #=> 'Mikel Lindsaar'
84
- def display_name
87
+ def display_name(output_type = :decode)
85
88
  parse unless @parsed
86
89
  @display_name ||= get_display_name
87
- Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
90
+ Encodings.decode_encode(@display_name.to_s, output_type) if @display_name
88
91
  end
89
92
 
90
93
  # Provides a way to assign a display name to an already made Mail::Address object.
@@ -102,9 +105,9 @@ module Mail
102
105
  #
103
106
  # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
104
107
  # a.local #=> 'mikel'
105
- def local
108
+ def local(output_type = :decode)
106
109
  parse unless @parsed
107
- Encodings.decode_encode("#{@data.obs_domain_list}#{get_local.strip}", @output_type) if get_local
110
+ Encodings.decode_encode("#{@data.obs_domain_list}#{get_local.strip}", output_type) if get_local
108
111
  end
109
112
 
110
113
  # Returns the domain part (the right hand side of the @ sign in the email address) of
@@ -112,9 +115,9 @@ module Mail
112
115
  #
113
116
  # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
114
117
  # a.domain #=> 'test.lindsaar.net'
115
- def domain
118
+ def domain(output_type = :decode)
116
119
  parse unless @parsed
117
- Encodings.decode_encode(strip_all_comments(get_domain), @output_type) if get_domain
120
+ Encodings.decode_encode(strip_all_comments(get_domain), output_type) if get_domain
118
121
  end
119
122
 
120
123
  # Returns an array of comments that are in the email, or nil if there
@@ -164,13 +167,11 @@ module Mail
164
167
  end
165
168
 
166
169
  def encoded
167
- @output_type = :encode
168
- format
170
+ format :encode
169
171
  end
170
172
 
171
173
  def decoded
172
- @output_type = :decode
173
- format
174
+ format :decode
174
175
  end
175
176
 
176
177
  def group
@@ -7,7 +7,6 @@ module Mail
7
7
  end
8
8
 
9
9
  module Encodings
10
-
11
10
  include Mail::Constants
12
11
  extend Mail::Utilities
13
12
 
@@ -19,7 +18,7 @@ module Mail
19
18
  #
20
19
  # Encodings.register "base64", Mail::Encodings::Base64
21
20
  def Encodings.register(name, cls)
22
- @transfer_encodings[get_name(name)] = cls
21
+ @transfer_encodings[get_name(name)] = cls
23
22
  end
24
23
 
25
24
  # Is the encoding we want defined?
@@ -27,8 +26,8 @@ module Mail
27
26
  # Example:
28
27
  #
29
28
  # Encodings.defined?(:base64) #=> true
30
- def Encodings.defined?( str )
31
- @transfer_encodings.include? get_name(str)
29
+ def Encodings.defined?(name)
30
+ @transfer_encodings.include? get_name(name)
32
31
  end
33
32
 
34
33
  # Gets a defined encoding type, QuotedPrintable or Base64 for now.
@@ -39,16 +38,16 @@ module Mail
39
38
  # Example:
40
39
  #
41
40
  # Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64
42
- def Encodings.get_encoding( str )
43
- @transfer_encodings[get_name(str)]
41
+ def Encodings.get_encoding(name)
42
+ @transfer_encodings[get_name(name)]
44
43
  end
45
44
 
46
45
  def Encodings.get_all
47
46
  @transfer_encodings.values
48
47
  end
49
48
 
50
- def Encodings.get_name(enc)
51
- underscoreize(enc).downcase
49
+ def Encodings.get_name(name)
50
+ underscoreize(name).downcase
52
51
  end
53
52
 
54
53
  def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
@@ -168,31 +167,51 @@ module Mail
168
167
 
169
168
  def Encodings.address_encode(address, charset = 'utf-8')
170
169
  if address.is_a?(Array)
171
- # loop back through for each element
172
170
  address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
173
- else
174
- # find any word boundary that is not ascii and encode it
175
- encode_non_usascii(address, charset) if address
171
+ elsif address
172
+ encode_non_usascii(address, charset)
176
173
  end
177
174
  end
178
175
 
179
176
  def Encodings.encode_non_usascii(address, charset)
180
177
  return address if address.ascii_only? or charset.nil?
181
- # Encode all strings embedded inside of quotes
182
- address = address.gsub(/("[^"]*")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
183
- # Then loop through all remaining items and encode as needed
184
- tokens = address.split(/\s/)
185
- map_with_index(tokens) do |word, i|
186
- if word.ascii_only?
187
- word
188
- else
189
- previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
190
- if previous_non_ascii #why are we adding an extra space here?
191
- word = " #{word}"
178
+
179
+ # With KCODE=u we can't use regexps on other encodings. Go ASCII.
180
+ with_ascii_kcode do
181
+ # Encode all strings embedded inside of quotes
182
+ address = address.gsub(/("[^"]*[^\/]")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
183
+
184
+ # Then loop through all remaining items and encode as needed
185
+ tokens = address.split(/\s/)
186
+
187
+ map_with_index(tokens) do |word, i|
188
+ if word.ascii_only?
189
+ word
190
+ else
191
+ previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
192
+ if previous_non_ascii #why are we adding an extra space here?
193
+ word = " #{word}"
194
+ end
195
+ Encodings.b_value_encode(word, charset)
192
196
  end
193
- Encodings.b_value_encode(word, charset)
197
+ end.join(' ')
198
+ end
199
+ end
200
+
201
+ if RUBY_VERSION < '1.9'
202
+ # With KCODE=u we can't use regexps on other encodings. Go ASCII.
203
+ def Encodings.with_ascii_kcode #:nodoc:
204
+ if $KCODE
205
+ $KCODE, original_kcode = '', $KCODE
194
206
  end
195
- end.join(' ')
207
+ yield
208
+ ensure
209
+ $KCODE = original_kcode if original_kcode
210
+ end
211
+ else
212
+ def Encodings.with_ascii_kcode #:nodoc:
213
+ yield
214
+ end
196
215
  end
197
216
 
198
217
  # Encode a string with Base64 Encoding and returns it ready to be inserted
@@ -202,12 +221,15 @@ module Mail
202
221
  #
203
222
  # Encodings.b_value_encode('This is あ string', 'UTF-8')
204
223
  # #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="
205
- def Encodings.b_value_encode(encoded_str, encoding = nil)
206
- return encoded_str if encoded_str.to_s.ascii_only?
207
- string, encoding = RubyVer.b_value_encode(encoded_str, encoding)
208
- map_lines(string) do |str|
209
- "=?#{encoding}?B?#{str.chomp}?="
210
- end.join(" ")
224
+ def Encodings.b_value_encode(string, encoding = nil)
225
+ if string.to_s.ascii_only?
226
+ string
227
+ else
228
+ Encodings.each_base64_chunk_byterange(string, 60).map do |chunk|
229
+ str, encoding = RubyVer.b_value_encode(chunk, encoding)
230
+ "=?#{encoding}?B?#{str.chomp}?="
231
+ end.join(" ")
232
+ end
211
233
  end
212
234
 
213
235
  # Encode a string with Quoted-Printable Encoding and returns it ready to be inserted
@@ -281,5 +303,41 @@ module Mail
281
303
 
282
304
  results
283
305
  end
306
+
307
+ # Partition the string into bounded-size chunks without splitting
308
+ # multibyte characters.
309
+ def Encodings.each_base64_chunk_byterange(str, max_bytesize_per_base64_chunk, &block)
310
+ raise "size per chunk must be multiple of 4" if (max_bytesize_per_base64_chunk % 4).nonzero?
311
+
312
+ if block_given?
313
+ max_bytesize = ((3 * max_bytesize_per_base64_chunk) / 4.0).floor
314
+ each_chunk_byterange(str, max_bytesize, &block)
315
+ else
316
+ enum_for :each_base64_chunk_byterange, str, max_bytesize_per_base64_chunk
317
+ end
318
+ end
319
+
320
+ # Partition the string into bounded-size chunks without splitting
321
+ # multibyte characters.
322
+ def Encodings.each_chunk_byterange(str, max_bytesize_per_chunk)
323
+ return enum_for(:each_chunk_byterange, str, max_bytesize_per_chunk) unless block_given?
324
+
325
+ offset = 0
326
+ chunksize = 0
327
+
328
+ str.each_char do |chr|
329
+ charsize = chr.bytesize
330
+
331
+ if chunksize + charsize > max_bytesize_per_chunk
332
+ yield RubyVer.string_byteslice(str, offset, chunksize)
333
+ offset += chunksize
334
+ chunksize = charsize
335
+ else
336
+ chunksize += charsize
337
+ end
338
+ end
339
+
340
+ yield RubyVer.string_byteslice(str, offset, chunksize)
341
+ end
284
342
  end
285
343
  end
@@ -4,29 +4,19 @@ require 'mail/encodings/8bit'
4
4
 
5
5
  module Mail
6
6
  module Encodings
7
+ # 7bit and 8bit are equivalent. 7bit encoding is for text only.
7
8
  class SevenBit < EightBit
8
9
  NAME = '7bit'
9
-
10
10
  PRIORITY = 1
11
+ Encodings.register(NAME, self)
11
12
 
12
- # 7bit and 8bit operate the same
13
-
14
- # Decode the string
15
13
  def self.decode(str)
16
- super
14
+ ::Mail::Utilities.binary_unsafe_to_lf str
17
15
  end
18
-
19
- # Encode the string
16
+
20
17
  def self.encode(str)
21
- super
22
- end
23
-
24
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
25
- def self.cost(str)
26
- super
18
+ ::Mail::Utilities.binary_unsafe_to_crlf str
27
19
  end
28
-
29
- Encodings.register(NAME, self)
30
20
  end
31
21
  end
32
22
  end
@@ -6,32 +6,13 @@ module Mail
6
6
  module Encodings
7
7
  class EightBit < Binary
8
8
  NAME = '8bit'
9
-
10
9
  PRIORITY = 4
11
-
12
- # 8bit is an identiy encoding, meaning nothing to do
13
-
14
- # Decode the string
15
- def self.decode(str)
16
- ::Mail::Utilities.to_lf str
17
- end
18
-
19
- # Encode the string
20
- def self.encode(str)
21
- ::Mail::Utilities.to_crlf str
22
- end
23
-
24
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
25
- def self.cost(str)
26
- 1.0
27
- end
10
+ Encodings.register(NAME, self)
28
11
 
29
12
  # Per RFC 2821 4.5.3.1, SMTP lines may not be longer than 1000 octets including the <CRLF>.
30
13
  def self.compatible_input?(str)
31
- !str.lines.find { |line| line.length > 998 }
14
+ !str.lines.find { |line| line.bytesize > 998 }
32
15
  end
33
-
34
- Encodings.register(NAME, self)
35
16
  end
36
17
  end
37
18
  end
@@ -4,36 +4,35 @@ require 'mail/encodings/7bit'
4
4
 
5
5
  module Mail
6
6
  module Encodings
7
+ # Base64 encoding handles binary content at the cost of 4 output bytes
8
+ # per input byte.
7
9
  class Base64 < SevenBit
8
10
  NAME = 'base64'
9
-
10
11
  PRIORITY = 3
11
-
12
+ Encodings.register(NAME, self)
13
+
12
14
  def self.can_encode?(enc)
13
15
  true
14
16
  end
15
17
 
16
- # Decode the string from Base64
17
18
  def self.decode(str)
18
- RubyVer.decode_base64( str )
19
+ RubyVer.decode_base64(str)
19
20
  end
20
-
21
- # Encode the string to Base64
21
+
22
22
  def self.encode(str)
23
- ::Mail::Utilities.to_crlf(RubyVer.encode_base64( str ))
23
+ ::Mail::Utilities.binary_unsafe_to_crlf(RubyVer.encode_base64(str))
24
24
  end
25
25
 
26
- # Base64 has a fixed cost, 4 bytes out per 3 bytes in
26
+ # 3 bytes in -> 4 bytes out
27
27
  def self.cost(str)
28
- 4.0/3
28
+ 4.0 / 3
29
29
  end
30
30
 
31
- # Base64 inserts newlines automatically and cannot violate the SMTP spec.
31
+ # Ruby Base64 inserts newlines automatically, so it doesn't exceed
32
+ # SMTP line length limits.
32
33
  def self.compatible_input?(str)
33
34
  true
34
35
  end
35
-
36
- Encodings.register(NAME, self)
37
36
  end
38
37
  end
39
38
  end
@@ -1,32 +1,13 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- require 'mail/encodings/transfer_encoding'
3
+ require 'mail/encodings/identity'
4
4
 
5
5
  module Mail
6
6
  module Encodings
7
- class Binary < TransferEncoding
7
+ class Binary < Identity
8
8
  NAME = 'binary'
9
-
10
9
  PRIORITY = 5
11
-
12
- # Binary is an identiy encoding, meaning nothing to do
13
-
14
- # Decode the string
15
- def self.decode(str)
16
- str
17
- end
18
-
19
- # Encode the string
20
- def self.encode(str)
21
- str
22
- end
23
-
24
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
25
- def self.cost(str)
26
- 1.0
27
- end
28
-
29
- Encodings.register(NAME, self)
10
+ Encodings.register(NAME, self)
30
11
  end
31
12
  end
32
13
  end