dball-mail 2.2.9.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.
Files changed (122) hide show
  1. data/CHANGELOG.rdoc +459 -0
  2. data/README.rdoc +582 -0
  3. data/Rakefile +66 -0
  4. data/TODO.rdoc +9 -0
  5. data/lib/VERSION +4 -0
  6. data/lib/mail/attachments_list.rb +105 -0
  7. data/lib/mail/body.rb +286 -0
  8. data/lib/mail/configuration.rb +71 -0
  9. data/lib/mail/core_extensions/nil.rb +11 -0
  10. data/lib/mail/core_extensions/string.rb +27 -0
  11. data/lib/mail/elements/address.rb +306 -0
  12. data/lib/mail/elements/address_list.rb +74 -0
  13. data/lib/mail/elements/content_disposition_element.rb +30 -0
  14. data/lib/mail/elements/content_location_element.rb +25 -0
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +24 -0
  16. data/lib/mail/elements/content_type_element.rb +35 -0
  17. data/lib/mail/elements/date_time_element.rb +26 -0
  18. data/lib/mail/elements/envelope_from_element.rb +34 -0
  19. data/lib/mail/elements/message_ids_element.rb +29 -0
  20. data/lib/mail/elements/mime_version_element.rb +26 -0
  21. data/lib/mail/elements/phrase_list.rb +21 -0
  22. data/lib/mail/elements/received_element.rb +30 -0
  23. data/lib/mail/elements.rb +14 -0
  24. data/lib/mail/encodings/7bit.rb +31 -0
  25. data/lib/mail/encodings/8bit.rb +31 -0
  26. data/lib/mail/encodings/base64.rb +33 -0
  27. data/lib/mail/encodings/binary.rb +31 -0
  28. data/lib/mail/encodings/quoted_printable.rb +38 -0
  29. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  30. data/lib/mail/encodings.rb +268 -0
  31. data/lib/mail/envelope.rb +35 -0
  32. data/lib/mail/field.rb +223 -0
  33. data/lib/mail/field_list.rb +33 -0
  34. data/lib/mail/fields/bcc_field.rb +56 -0
  35. data/lib/mail/fields/cc_field.rb +55 -0
  36. data/lib/mail/fields/comments_field.rb +41 -0
  37. data/lib/mail/fields/common/address_container.rb +16 -0
  38. data/lib/mail/fields/common/common_address.rb +125 -0
  39. data/lib/mail/fields/common/common_date.rb +42 -0
  40. data/lib/mail/fields/common/common_field.rb +50 -0
  41. data/lib/mail/fields/common/common_message_id.rb +44 -0
  42. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  43. data/lib/mail/fields/content_description_field.rb +19 -0
  44. data/lib/mail/fields/content_disposition_field.rb +69 -0
  45. data/lib/mail/fields/content_id_field.rb +63 -0
  46. data/lib/mail/fields/content_location_field.rb +42 -0
  47. data/lib/mail/fields/content_transfer_encoding_field.rb +50 -0
  48. data/lib/mail/fields/content_type_field.rb +198 -0
  49. data/lib/mail/fields/date_field.rb +55 -0
  50. data/lib/mail/fields/from_field.rb +55 -0
  51. data/lib/mail/fields/in_reply_to_field.rb +55 -0
  52. data/lib/mail/fields/keywords_field.rb +44 -0
  53. data/lib/mail/fields/message_id_field.rb +83 -0
  54. data/lib/mail/fields/mime_version_field.rb +53 -0
  55. data/lib/mail/fields/optional_field.rb +13 -0
  56. data/lib/mail/fields/received_field.rb +67 -0
  57. data/lib/mail/fields/references_field.rb +55 -0
  58. data/lib/mail/fields/reply_to_field.rb +55 -0
  59. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  60. data/lib/mail/fields/resent_cc_field.rb +55 -0
  61. data/lib/mail/fields/resent_date_field.rb +35 -0
  62. data/lib/mail/fields/resent_from_field.rb +55 -0
  63. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  64. data/lib/mail/fields/resent_sender_field.rb +62 -0
  65. data/lib/mail/fields/resent_to_field.rb +55 -0
  66. data/lib/mail/fields/return_path_field.rb +64 -0
  67. data/lib/mail/fields/sender_field.rb +67 -0
  68. data/lib/mail/fields/structured_field.rb +51 -0
  69. data/lib/mail/fields/subject_field.rb +16 -0
  70. data/lib/mail/fields/to_field.rb +55 -0
  71. data/lib/mail/fields/unstructured_field.rb +179 -0
  72. data/lib/mail/fields.rb +35 -0
  73. data/lib/mail/header.rb +264 -0
  74. data/lib/mail/mail.rb +255 -0
  75. data/lib/mail/message.rb +1972 -0
  76. data/lib/mail/network/delivery_methods/file_delivery.rb +40 -0
  77. data/lib/mail/network/delivery_methods/sendmail.rb +62 -0
  78. data/lib/mail/network/delivery_methods/smtp.rb +136 -0
  79. data/lib/mail/network/delivery_methods/test_mailer.rb +40 -0
  80. data/lib/mail/network/retriever_methods/imap.rb +213 -0
  81. data/lib/mail/network/retriever_methods/pop3.rb +194 -0
  82. data/lib/mail/network/retriever_methods/test_retriever.rb +31 -0
  83. data/lib/mail/network.rb +10 -0
  84. data/lib/mail/parsers/address_lists.rb +64 -0
  85. data/lib/mail/parsers/address_lists.treetop +19 -0
  86. data/lib/mail/parsers/content_disposition.rb +535 -0
  87. data/lib/mail/parsers/content_disposition.treetop +46 -0
  88. data/lib/mail/parsers/content_location.rb +139 -0
  89. data/lib/mail/parsers/content_location.treetop +20 -0
  90. data/lib/mail/parsers/content_transfer_encoding.rb +162 -0
  91. data/lib/mail/parsers/content_transfer_encoding.treetop +20 -0
  92. data/lib/mail/parsers/content_type.rb +967 -0
  93. data/lib/mail/parsers/content_type.treetop +68 -0
  94. data/lib/mail/parsers/date_time.rb +114 -0
  95. data/lib/mail/parsers/date_time.treetop +11 -0
  96. data/lib/mail/parsers/envelope_from.rb +194 -0
  97. data/lib/mail/parsers/envelope_from.treetop +32 -0
  98. data/lib/mail/parsers/message_ids.rb +45 -0
  99. data/lib/mail/parsers/message_ids.treetop +15 -0
  100. data/lib/mail/parsers/mime_version.rb +144 -0
  101. data/lib/mail/parsers/mime_version.treetop +19 -0
  102. data/lib/mail/parsers/phrase_lists.rb +45 -0
  103. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  104. data/lib/mail/parsers/received.rb +71 -0
  105. data/lib/mail/parsers/received.treetop +11 -0
  106. data/lib/mail/parsers/rfc2045.rb +464 -0
  107. data/lib/mail/parsers/rfc2045.treetop +36 -0
  108. data/lib/mail/parsers/rfc2822.rb +5318 -0
  109. data/lib/mail/parsers/rfc2822.treetop +410 -0
  110. data/lib/mail/parsers/rfc2822_obsolete.rb +3757 -0
  111. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  112. data/lib/mail/part.rb +116 -0
  113. data/lib/mail/parts_list.rb +43 -0
  114. data/lib/mail/patterns.rb +34 -0
  115. data/lib/mail/utilities.rb +211 -0
  116. data/lib/mail/version.rb +24 -0
  117. data/lib/mail/version_specific/ruby_1_8.rb +97 -0
  118. data/lib/mail/version_specific/ruby_1_9.rb +87 -0
  119. data/lib/mail.rb +80 -0
  120. data/lib/tasks/corpus.rake +125 -0
  121. data/lib/tasks/treetop.rake +10 -0
  122. metadata +255 -0
@@ -0,0 +1,105 @@
1
+ module Mail
2
+ class AttachmentsList < Array
3
+
4
+ def initialize(parts_list)
5
+ @parts_list = parts_list
6
+ @content_disposition_type = 'attachment'
7
+ parts_list.map { |p|
8
+ if p.content_type == "message/rfc822"
9
+ Mail.new(p.body).attachments
10
+ elsif p.parts.empty?
11
+ p if p.attachment?
12
+ else
13
+ p.attachments
14
+ end
15
+ }.flatten.compact.each { |a| self << a }
16
+ self
17
+ end
18
+
19
+ def inline
20
+ @content_disposition_type = 'inline'
21
+ self
22
+ end
23
+
24
+ # Returns the attachment by filename or at index.
25
+ #
26
+ # mail.attachments['test.png'] = File.read('test.png')
27
+ # mail.attachments['test.jpg'] = File.read('test.jpg')
28
+ #
29
+ # mail.attachments['test.png'].filename #=> 'test.png'
30
+ # mail.attachments[1].filename #=> 'test.jpg'
31
+ def [](index_value)
32
+ if index_value.is_a?(Fixnum)
33
+ self.fetch(index_value)
34
+ else
35
+ self.select { |a| a.filename == index_value }.first
36
+ end
37
+ end
38
+
39
+ def []=(name, value)
40
+ default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{name}\"",
41
+ :content_transfer_encoding => "#{guess_encoding}",
42
+ :content_disposition => "#{@content_disposition_type}; filename=\"#{name}\"" }
43
+
44
+ if value.is_a?(Hash)
45
+
46
+ default_values[:body] = value.delete(:content) if value[:content]
47
+
48
+ default_values[:body] = value.delete(:data) if value[:data]
49
+
50
+ encoding = value.delete(:transfer_encoding) || value.delete(:encoding)
51
+ if encoding
52
+ if Mail::Encodings.defined? encoding
53
+ default_values[:content_transfer_encoding] = encoding
54
+ else
55
+ raise "Do not know how to handle Content Transfer Encoding #{encoding}, please choose either quoted-printable or base64"
56
+ end
57
+ end
58
+
59
+ if value[:mime_type]
60
+ default_values[:content_type] = value.delete(:mime_type)
61
+ @mime_type = MIME::Types[default_values[:content_type]].first
62
+ default_values[:content_transfer_encoding] = guess_encoding
63
+ end
64
+
65
+ hash = default_values.merge(value)
66
+ else
67
+ default_values[:body] = value
68
+ hash = default_values
69
+ end
70
+
71
+ if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
72
+ if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary"
73
+ hash[:body].force_encoding("BINARY")
74
+ end
75
+ end
76
+
77
+ attachment = Part.new(hash)
78
+ attachment.add_content_id(hash[:content_id])
79
+
80
+ @parts_list << attachment
81
+ end
82
+
83
+ # Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
84
+ # set it to binary, otherwise as set to plain text
85
+ def guess_encoding
86
+ if @mime_type && !@mime_type.binary?
87
+ "7bit"
88
+ else
89
+ "binary"
90
+ end
91
+ end
92
+
93
+ def set_mime_type(filename)
94
+ # Have to do this because MIME::Types is not Ruby 1.9 safe yet
95
+ if RUBY_VERSION >= '1.9'
96
+ new_file = String.new(filename).force_encoding(Encoding::BINARY)
97
+ ext = new_file.split('.'.force_encoding(Encoding::BINARY)).last
98
+ filename = "file.#{ext}".force_encoding('US-ASCII')
99
+ end
100
+ @mime_type = MIME::Types.type_for(filename).first
101
+ end
102
+
103
+ end
104
+ end
105
+
data/lib/mail/body.rb ADDED
@@ -0,0 +1,286 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+
4
+ # = Body
5
+ #
6
+ # The body is where the text of the email is stored. Mail treats the body
7
+ # as a single object. The body itself has no information about boundaries
8
+ # used in the MIME standard, it just looks at it's content as either a single
9
+ # block of text, or (if it is a multipart message) as an array of blocks o text.
10
+ #
11
+ # A body has to be told to split itself up into a multipart message by calling
12
+ # #split with the correct boundary. This is because the body object has no way
13
+ # of knowing what the correct boundary is for itself (there could be many
14
+ # boundaries in a body in the case of a nested MIME text).
15
+ #
16
+ # Once split is called, Mail::Body will slice itself up on this boundary,
17
+ # assigning anything that appears before the first part to the preamble, and
18
+ # anything that appears after the closing boundary to the epilogue, then
19
+ # each part gets initialized into a Mail::Part object.
20
+ #
21
+ # The boundary that is used to split up the Body is also stored in the Body
22
+ # object for use on encoding itself back out to a string. You can
23
+ # overwrite this if it needs to be changed.
24
+ #
25
+ # On encoding, the body will return the preamble, then each part joined by
26
+ # the boundary, followed by a closing boundary string and then the epilogue.
27
+ class Body
28
+
29
+ def initialize(string = '')
30
+ @boundary = nil
31
+ @preamble = nil
32
+ @epilogue = nil
33
+ @charset = nil
34
+ @part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
35
+ @parts = Mail::PartsList.new
36
+ if string.blank?
37
+ @raw_source = ''
38
+ else
39
+ # Do join first incase we have been given an Array in Ruby 1.9
40
+ if string.respond_to?(:join)
41
+ @raw_source = string.join('')
42
+ elsif string.respond_to?(:to_s)
43
+ @raw_source = string.to_s
44
+ else
45
+ raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
46
+ end
47
+ end
48
+ @encoding = (only_us_ascii? ? '7bit' : '8bit')
49
+ set_charset
50
+ end
51
+
52
+ # Matches this body with another body. Also matches the decoded value of this
53
+ # body with a string.
54
+ #
55
+ # Examples:
56
+ #
57
+ # body = Mail::Body.new('The body')
58
+ # body == body #=> true
59
+ #
60
+ # body = Mail::Body.new('The body')
61
+ # body == 'The body' #=> true
62
+ #
63
+ # body = Mail::Body.new("VGhlIGJvZHk=\n")
64
+ # body.encoding = 'base64'
65
+ # body == "The body" #=> true
66
+ def ==(other)
67
+ if other.class == String
68
+ self.decoded == other
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ # Accepts a string and performs a regular expression against the decoded text
75
+ #
76
+ # Examples:
77
+ #
78
+ # body = Mail::Body.new('The body')
79
+ # body =~ /The/ #=> 0
80
+ #
81
+ # body = Mail::Body.new("VGhlIGJvZHk=\n")
82
+ # body.encoding = 'base64'
83
+ # body =~ /The/ #=> 0
84
+ def =~(regexp)
85
+ self.decoded =~ regexp
86
+ end
87
+
88
+ # Accepts a string and performs a regular expression against the decoded text
89
+ #
90
+ # Examples:
91
+ #
92
+ # body = Mail::Body.new('The body')
93
+ # body.match(/The/) #=> #<MatchData "The">
94
+ #
95
+ # body = Mail::Body.new("VGhlIGJvZHk=\n")
96
+ # body.encoding = 'base64'
97
+ # body.match(/The/) #=> #<MatchData "The">
98
+ def match(regexp)
99
+ self.decoded.match(regexp)
100
+ end
101
+
102
+ # Accepts anything that responds to #to_s and checks if it's a substring of the decoded text
103
+ #
104
+ # Examples:
105
+ #
106
+ # body = Mail::Body.new('The body')
107
+ # body.include?('The') #=> true
108
+ #
109
+ # body = Mail::Body.new("VGhlIGJvZHk=\n")
110
+ # body.encoding = 'base64'
111
+ # body.include?('The') #=> true
112
+ def include?(other)
113
+ self.decoded.include?(other.to_s)
114
+ end
115
+
116
+ # Allows you to set the sort order of the parts, overriding the default sort order.
117
+ # Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content
118
+ # type coming after.
119
+ def set_sort_order(order)
120
+ @part_sort_order = order
121
+ end
122
+
123
+ # Allows you to sort the parts according to the default sort order, or the sort order you
124
+ # set with :set_sort_order.
125
+ #
126
+ # sort_parts! is also called from :encode, so there is no need for you to call this explicitly
127
+ def sort_parts!
128
+ @parts.each do |p|
129
+ p.body.set_sort_order(@part_sort_order)
130
+ @parts.sort!(@part_sort_order)
131
+ p.body.sort_parts!
132
+ end
133
+ end
134
+
135
+ # Returns the raw source that the body was initialized with, without
136
+ # any tampering
137
+ def raw_source
138
+ @raw_source
139
+ end
140
+
141
+ def get_best_encoding(target)
142
+ target_encoding = Mail::Encodings.get_encoding(target)
143
+ target_encoding.get_best_compatible(encoding, raw_source)
144
+ end
145
+
146
+ # Returns a body encoded using transfer_encoding. Multipart always uses an
147
+ # identiy encoding (i.e. no encoding).
148
+ # Calling this directly is not a good idea, but supported for compatibility
149
+ # TODO: Validate that preamble and epilogue are valid for requested encoding
150
+ def encoded(transfer_encoding = '8bit')
151
+ if multipart?
152
+ self.sort_parts!
153
+ encoded_parts = parts.map { |p| p.encoded }
154
+ ([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
155
+ else
156
+ be = get_best_encoding(transfer_encoding)
157
+ dec = Mail::Encodings::get_encoding(encoding)
158
+ enc = Mail::Encodings::get_encoding(be)
159
+ if transfer_encoding == encoding and dec.nil?
160
+ # Cannot decode, so skip normalization
161
+ raw_source
162
+ else
163
+ # Decode then encode to normalize and allow transforming
164
+ # from base64 to Q-P and vice versa
165
+ enc.encode(dec.decode(raw_source))
166
+ end
167
+ end
168
+ end
169
+
170
+ def decoded
171
+ if !Encodings.defined?(encoding)
172
+ raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
173
+ else
174
+ Encodings.get_encoding(encoding).decode(raw_source)
175
+ end
176
+ end
177
+
178
+ def to_s
179
+ decoded
180
+ end
181
+
182
+ def charset
183
+ @charset
184
+ end
185
+
186
+ def charset=( val )
187
+ @charset = val
188
+ end
189
+
190
+ def encoding(val = nil)
191
+ if val
192
+ self.encoding = val
193
+ else
194
+ @encoding
195
+ end
196
+ end
197
+
198
+ def encoding=( val )
199
+ if val == "text" || val.blank? then
200
+ val = "8bit"
201
+ end
202
+ @encoding = (val == "text") ? "8bit" : val
203
+ end
204
+
205
+ # Returns the preamble (any text that is before the first MIME boundary)
206
+ def preamble
207
+ @preamble
208
+ end
209
+
210
+ # Sets the preamble to a string (adds text before the first MIME boundary)
211
+ def preamble=( val )
212
+ @preamble = val
213
+ end
214
+
215
+ # Returns the epilogue (any text that is after the last MIME boundary)
216
+ def epilogue
217
+ @epilogue
218
+ end
219
+
220
+ # Sets the epilogue to a string (adds text after the last MIME boundary)
221
+ def epilogue=( val )
222
+ @epilogue = val
223
+ end
224
+
225
+ # Returns true if there are parts defined in the body
226
+ def multipart?
227
+ true unless parts.empty?
228
+ end
229
+
230
+ # Returns the boundary used by the body
231
+ def boundary
232
+ @boundary
233
+ end
234
+
235
+ # Allows you to change the boundary of this Body object
236
+ def boundary=( val )
237
+ @boundary = val
238
+ end
239
+
240
+ def parts
241
+ @parts
242
+ end
243
+
244
+ def <<( val )
245
+ if @parts
246
+ @parts << val
247
+ else
248
+ @parts = Mail::PartsList.new[val]
249
+ end
250
+ end
251
+
252
+ def split!(boundary)
253
+ self.boundary = boundary
254
+ parts = raw_source.split("--#{boundary}")
255
+ # Make the preamble equal to the preamble (if any)
256
+ self.preamble = parts[0].to_s.strip
257
+ # Make the epilogue equal to the epilogue (if any)
258
+ self.epilogue = parts[-1].to_s.sub('--', '').strip
259
+ parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
260
+ self
261
+ end
262
+
263
+ def only_us_ascii?
264
+ raw_source.each_byte {|b| return false if (b == 0 || b > 127)}
265
+ true
266
+ end
267
+
268
+ def empty?
269
+ !!raw_source.to_s.empty?
270
+ end
271
+
272
+ private
273
+
274
+ def crlf_boundary
275
+ "\r\n\r\n--#{boundary}\r\n"
276
+ end
277
+
278
+ def end_boundary
279
+ "\r\n\r\n--#{boundary}--\r\n"
280
+ end
281
+
282
+ def set_charset
283
+ only_us_ascii? ? @charset = 'US-ASCII' : @charset = nil
284
+ end
285
+ end
286
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Thanks to Nicolas Fouché for this wrapper
4
+ #
5
+ require 'singleton'
6
+
7
+ module Mail
8
+
9
+ # The Configuration class is a Singleton used to hold the default
10
+ # configuration for all Mail objects.
11
+ #
12
+ # Each new mail object gets a copy of these values at initialization
13
+ # which can be overwritten on a per mail object basis.
14
+ class Configuration
15
+ include Singleton
16
+
17
+ def initialize
18
+ @delivery_method = nil
19
+ @retriever_method = nil
20
+ super
21
+ end
22
+
23
+ def delivery_method(method = nil, settings = {})
24
+ return @delivery_method if @delivery_method && method.nil?
25
+ @delivery_method = lookup_delivery_method(method).new(settings)
26
+ end
27
+
28
+ def lookup_delivery_method(method)
29
+ case method
30
+ when nil
31
+ Mail::SMTP
32
+ when :smtp
33
+ Mail::SMTP
34
+ when :sendmail
35
+ Mail::Sendmail
36
+ when :file
37
+ Mail::FileDelivery
38
+ when :test
39
+ Mail::TestMailer
40
+ else
41
+ method
42
+ end
43
+ end
44
+
45
+ def retriever_method(method = nil, settings = {})
46
+ return @retriever_method if @retriever_method && method.nil?
47
+ @retriever_method = lookup_retriever_method(method).new(settings)
48
+ end
49
+
50
+ def lookup_retriever_method(method)
51
+ case method
52
+ when nil
53
+ Mail::POP3
54
+ when :pop3
55
+ Mail::POP3
56
+ when :imap
57
+ Mail::IMAP
58
+ when :test
59
+ Mail::TestRetriever
60
+ else
61
+ method
62
+ end
63
+ end
64
+
65
+ def param_encode_language(value = nil)
66
+ value ? @encode_language = value : @encode_language ||= 'en'
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ class NilClass #:nodoc:
4
+ def to_crlf
5
+ ''
6
+ end
7
+
8
+ def to_lf
9
+ ''
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ class String #:nodoc:
3
+ def to_crlf
4
+ gsub(/\n|\r\n|\r/) { "\r\n" }
5
+ end
6
+
7
+ def to_lf
8
+ gsub(/\n|\r\n|\r/) { "\n" }
9
+ end
10
+
11
+ unless method_defined?(:ascii_only?)
12
+ # Provides all strings with the Ruby 1.9 method of .ascii_only? and
13
+ # returns true or false
14
+ US_ASCII_REGEXP = %Q{\x00-\x7f}
15
+ def ascii_only?
16
+ !(self =~ /[^#{US_ASCII_REGEXP}]/)
17
+ end
18
+ end
19
+
20
+ def not_ascii_only?
21
+ !ascii_only?
22
+ end
23
+
24
+ unless method_defined?(:bytesize)
25
+ alias :bytesize :length
26
+ end
27
+ end