nano-fast-tool 0.0.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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/mail-2.9.1/MIT-LICENSE +20 -0
  3. data/mail-2.9.1/README.md +771 -0
  4. data/mail-2.9.1/lib/mail/attachments_list.rb +109 -0
  5. data/mail-2.9.1/lib/mail/body.rb +305 -0
  6. data/mail-2.9.1/lib/mail/configuration.rb +78 -0
  7. data/mail-2.9.1/lib/mail/constants.rb +79 -0
  8. data/mail-2.9.1/lib/mail/elements/address.rb +258 -0
  9. data/mail-2.9.1/lib/mail/elements/address_list.rb +34 -0
  10. data/mail-2.9.1/lib/mail/elements/content_disposition_element.rb +20 -0
  11. data/mail-2.9.1/lib/mail/elements/content_location_element.rb +17 -0
  12. data/mail-2.9.1/lib/mail/elements/content_transfer_encoding_element.rb +13 -0
  13. data/mail-2.9.1/lib/mail/elements/content_type_element.rb +25 -0
  14. data/mail-2.9.1/lib/mail/elements/date_time_element.rb +15 -0
  15. data/mail-2.9.1/lib/mail/elements/envelope_from_element.rb +39 -0
  16. data/mail-2.9.1/lib/mail/elements/message_ids_element.rb +31 -0
  17. data/mail-2.9.1/lib/mail/elements/mime_version_element.rb +15 -0
  18. data/mail-2.9.1/lib/mail/elements/phrase_list.rb +19 -0
  19. data/mail-2.9.1/lib/mail/elements/received_element.rb +35 -0
  20. data/mail-2.9.1/lib/mail/elements.rb +15 -0
  21. data/mail-2.9.1/lib/mail/encodings/7bit.rb +27 -0
  22. data/mail-2.9.1/lib/mail/encodings/8bit.rb +18 -0
  23. data/mail-2.9.1/lib/mail/encodings/base64.rb +38 -0
  24. data/mail-2.9.1/lib/mail/encodings/binary.rb +13 -0
  25. data/mail-2.9.1/lib/mail/encodings/identity.rb +24 -0
  26. data/mail-2.9.1/lib/mail/encodings/quoted_printable.rb +45 -0
  27. data/mail-2.9.1/lib/mail/encodings/transfer_encoding.rb +77 -0
  28. data/mail-2.9.1/lib/mail/encodings/unix_to_unix.rb +20 -0
  29. data/mail-2.9.1/lib/mail/encodings.rb +314 -0
  30. data/mail-2.9.1/lib/mail/envelope.rb +28 -0
  31. data/mail-2.9.1/lib/mail/field.rb +313 -0
  32. data/mail-2.9.1/lib/mail/field_list.rb +87 -0
  33. data/mail-2.9.1/lib/mail/fields/bcc_field.rb +49 -0
  34. data/mail-2.9.1/lib/mail/fields/cc_field.rb +33 -0
  35. data/mail-2.9.1/lib/mail/fields/comments_field.rb +31 -0
  36. data/mail-2.9.1/lib/mail/fields/common_address_field.rb +162 -0
  37. data/mail-2.9.1/lib/mail/fields/common_date_field.rb +56 -0
  38. data/mail-2.9.1/lib/mail/fields/common_field.rb +77 -0
  39. data/mail-2.9.1/lib/mail/fields/common_message_id_field.rb +41 -0
  40. data/mail-2.9.1/lib/mail/fields/content_description_field.rb +12 -0
  41. data/mail-2.9.1/lib/mail/fields/content_disposition_field.rb +44 -0
  42. data/mail-2.9.1/lib/mail/fields/content_id_field.rb +35 -0
  43. data/mail-2.9.1/lib/mail/fields/content_location_field.rb +28 -0
  44. data/mail-2.9.1/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  45. data/mail-2.9.1/lib/mail/fields/content_type_field.rb +171 -0
  46. data/mail-2.9.1/lib/mail/fields/date_field.rb +28 -0
  47. data/mail-2.9.1/lib/mail/fields/from_field.rb +33 -0
  48. data/mail-2.9.1/lib/mail/fields/in_reply_to_field.rb +45 -0
  49. data/mail-2.9.1/lib/mail/fields/keywords_field.rb +30 -0
  50. data/mail-2.9.1/lib/mail/fields/message_id_field.rb +36 -0
  51. data/mail-2.9.1/lib/mail/fields/mime_version_field.rb +42 -0
  52. data/mail-2.9.1/lib/mail/fields/named_structured_field.rb +10 -0
  53. data/mail-2.9.1/lib/mail/fields/named_unstructured_field.rb +10 -0
  54. data/mail-2.9.1/lib/mail/fields/optional_field.rb +15 -0
  55. data/mail-2.9.1/lib/mail/fields/parameter_hash.rb +61 -0
  56. data/mail-2.9.1/lib/mail/fields/received_field.rb +61 -0
  57. data/mail-2.9.1/lib/mail/fields/references_field.rb +42 -0
  58. data/mail-2.9.1/lib/mail/fields/reply_to_field.rb +33 -0
  59. data/mail-2.9.1/lib/mail/fields/resent_bcc_field.rb +33 -0
  60. data/mail-2.9.1/lib/mail/fields/resent_cc_field.rb +33 -0
  61. data/mail-2.9.1/lib/mail/fields/resent_date_field.rb +10 -0
  62. data/mail-2.9.1/lib/mail/fields/resent_from_field.rb +33 -0
  63. data/mail-2.9.1/lib/mail/fields/resent_message_id_field.rb +10 -0
  64. data/mail-2.9.1/lib/mail/fields/resent_sender_field.rb +32 -0
  65. data/mail-2.9.1/lib/mail/fields/resent_to_field.rb +33 -0
  66. data/mail-2.9.1/lib/mail/fields/return_path_field.rb +60 -0
  67. data/mail-2.9.1/lib/mail/fields/sender_field.rb +45 -0
  68. data/mail-2.9.1/lib/mail/fields/structured_field.rb +24 -0
  69. data/mail-2.9.1/lib/mail/fields/subject_field.rb +14 -0
  70. data/mail-2.9.1/lib/mail/fields/to_field.rb +33 -0
  71. data/mail-2.9.1/lib/mail/fields/unstructured_field.rb +189 -0
  72. data/mail-2.9.1/lib/mail/fields.rb +45 -0
  73. data/mail-2.9.1/lib/mail/header.rb +237 -0
  74. data/mail-2.9.1/lib/mail/indifferent_hash.rb +147 -0
  75. data/mail-2.9.1/lib/mail/mail.rb +267 -0
  76. data/mail-2.9.1/lib/mail/matchers/attachment_matchers.rb +44 -0
  77. data/mail-2.9.1/lib/mail/matchers/has_sent_mail.rb +201 -0
  78. data/mail-2.9.1/lib/mail/message.rb +2159 -0
  79. data/mail-2.9.1/lib/mail/multibyte/chars.rb +318 -0
  80. data/mail-2.9.1/lib/mail/multibyte/unicode.rb +405 -0
  81. data/mail-2.9.1/lib/mail/multibyte/utils.rb +44 -0
  82. data/mail-2.9.1/lib/mail/multibyte.rb +82 -0
  83. data/mail-2.9.1/lib/mail/network/delivery_methods/exim.rb +50 -0
  84. data/mail-2.9.1/lib/mail/network/delivery_methods/file_delivery.rb +43 -0
  85. data/mail-2.9.1/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  86. data/mail-2.9.1/lib/mail/network/delivery_methods/sendmail.rb +87 -0
  87. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp.rb +200 -0
  88. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp_connection.rb +57 -0
  89. data/mail-2.9.1/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  90. data/mail-2.9.1/lib/mail/network/retriever_methods/base.rb +64 -0
  91. data/mail-2.9.1/lib/mail/network/retriever_methods/imap.rb +190 -0
  92. data/mail-2.9.1/lib/mail/network/retriever_methods/pop3.rb +143 -0
  93. data/mail-2.9.1/lib/mail/network/retriever_methods/test_retriever.rb +45 -0
  94. data/mail-2.9.1/lib/mail/network.rb +16 -0
  95. data/mail-2.9.1/lib/mail/parser_tools.rb +15 -0
  96. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rb +33245 -0
  97. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rl +183 -0
  98. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rb +904 -0
  99. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rl +93 -0
  100. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rb +825 -0
  101. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rl +82 -0
  102. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rb +525 -0
  103. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
  104. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rb +1051 -0
  105. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rl +94 -0
  106. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rb +894 -0
  107. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rl +73 -0
  108. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rb +3678 -0
  109. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rl +93 -0
  110. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rb +5164 -0
  111. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rl +97 -0
  112. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rb +516 -0
  113. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rl +72 -0
  114. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rb +887 -0
  115. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rl +94 -0
  116. data/mail-2.9.1/lib/mail/parsers/received_parser.rb +8785 -0
  117. data/mail-2.9.1/lib/mail/parsers/received_parser.rl +95 -0
  118. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  119. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  120. data/mail-2.9.1/lib/mail/parsers/rfc2045_mime.rl +16 -0
  121. data/mail-2.9.1/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  122. data/mail-2.9.1/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  123. data/mail-2.9.1/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  124. data/mail-2.9.1/lib/mail/parsers/rfc5322.rl +74 -0
  125. data/mail-2.9.1/lib/mail/parsers/rfc5322_address.rl +72 -0
  126. data/mail-2.9.1/lib/mail/parsers/rfc5322_date_time.rl +37 -0
  127. data/mail-2.9.1/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  128. data/mail-2.9.1/lib/mail/parsers.rb +13 -0
  129. data/mail-2.9.1/lib/mail/part.rb +119 -0
  130. data/mail-2.9.1/lib/mail/parts_list.rb +131 -0
  131. data/mail-2.9.1/lib/mail/smtp_envelope.rb +57 -0
  132. data/mail-2.9.1/lib/mail/utilities.rb +576 -0
  133. data/mail-2.9.1/lib/mail/values/unicode_tables.dat +0 -0
  134. data/mail-2.9.1/lib/mail/version.rb +17 -0
  135. data/mail-2.9.1/lib/mail/yaml.rb +30 -0
  136. data/mail-2.9.1/lib/mail.rb +65 -0
  137. data/nano-fast-tool.gemspec +12 -0
  138. metadata +177 -0
@@ -0,0 +1,318 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/multibyte/unicode'
4
+
5
+ module Mail #:nodoc:
6
+ module Multibyte #:nodoc:
7
+ # Chars enables you to work transparently with UTF-8 encoding in the Ruby String class without having extensive
8
+ # knowledge about the encoding. A Chars object accepts a string upon initialization and proxies String methods in an
9
+ # encoding safe manner. All the normal String methods are also implemented on the proxy.
10
+ #
11
+ # String methods are proxied through the Chars object, and can be accessed through the +mb_chars+ method. Methods
12
+ # which would normally return a String object now return a Chars object so methods can be chained.
13
+ #
14
+ # "The Perfect String ".mb_chars.downcase.strip.normalize # => "the perfect string"
15
+ #
16
+ # Chars objects are perfectly interchangeable with String objects as long as no explicit class checks are made.
17
+ # If certain methods do explicitly check the class, call +to_s+ before you pass chars objects to them.
18
+ #
19
+ # bad.explicit_checking_method "T".mb_chars.downcase.to_s
20
+ #
21
+ # The default Chars implementation assumes that the encoding of the string is UTF-8, if you want to handle different
22
+ # encodings you can write your own multibyte string handler and configure it through
23
+ # Mail::Multibyte.proxy_class.
24
+ #
25
+ # class CharsForUTF32
26
+ # def size
27
+ # @wrapped_string.size / 4
28
+ # end
29
+ #
30
+ # def self.accepts?(string)
31
+ # string.length % 4 == 0
32
+ # end
33
+ # end
34
+ #
35
+ # Mail::Multibyte.proxy_class = CharsForUTF32
36
+ class Chars
37
+ attr_reader :wrapped_string
38
+ alias to_s wrapped_string
39
+ alias to_str wrapped_string
40
+
41
+ # Creates a new Chars instance by wrapping _string_.
42
+ def initialize(string)
43
+ @wrapped_string = string.dup
44
+ @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
45
+ end
46
+
47
+ # Forward all undefined methods to the wrapped string.
48
+ def method_missing(method, *args, &block)
49
+ if method.to_s.end_with?('!')
50
+ @wrapped_string.__send__(method, *args, &block)
51
+ self
52
+ else
53
+ result = @wrapped_string.__send__(method, *args, &block)
54
+ result.kind_of?(String) ? chars(result) : result
55
+ end
56
+ end
57
+
58
+ # Returns +true+ if _obj_ responds to the given method. Private methods are included in the search
59
+ # only if the optional second parameter evaluates to +true+.
60
+ def respond_to?(method, include_private=false)
61
+ super || @wrapped_string.respond_to?(method, include_private) || false
62
+ end
63
+
64
+ # Enable more predictable duck-typing on String-like classes. See Object#acts_like?.
65
+ def acts_like_string?
66
+ true
67
+ end
68
+
69
+ include Comparable
70
+
71
+ # Returns -1, 0, or 1, depending on whether the Chars object is to be sorted before,
72
+ # equal or after the object on the right side of the operation. It accepts any object
73
+ # that implements +to_s+:
74
+ #
75
+ # 'é'.mb_chars <=> 'ü'.mb_chars # => -1
76
+ #
77
+ # See <tt>String#<=></tt> for more details.
78
+ def <=>(other)
79
+ @wrapped_string <=> other.to_s
80
+ end
81
+
82
+ def =~(other)
83
+ @wrapped_string =~ other
84
+ end
85
+
86
+ # Works just like <tt>String#split</tt>, with the exception that the items in the resulting list are Chars
87
+ # instances instead of String. This makes chaining methods easier.
88
+ #
89
+ # Example:
90
+ # Mail::Multibyte.mb_chars('Café périferôl').split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
91
+ def split(*args)
92
+ @wrapped_string.split(*args).map { |i| i.mb_chars }
93
+ end
94
+
95
+ # Like <tt>String#[]=</tt>, except instead of byte offsets you specify character offsets.
96
+ #
97
+ # Example:
98
+ #
99
+ # s = "Müller"
100
+ # s.mb_chars[2] = "e" # Replace character with offset 2
101
+ # s
102
+ # # => "Müeler"
103
+ #
104
+ # s = "Müller"
105
+ # s.mb_chars[1, 2] = "ö" # Replace 2 characters at character offset 1
106
+ # s
107
+ # # => "Möler"
108
+ def []=(*args)
109
+ replace_by = args.pop
110
+ # Indexed replace with regular expressions already works
111
+ if args.first.is_a?(Regexp)
112
+ @wrapped_string[*args] = replace_by
113
+ else
114
+ result = Unicode.u_unpack(@wrapped_string)
115
+ if args[0].is_a?(Integer)
116
+ raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
117
+ min = args[0]
118
+ max = args[1].nil? ? min : (min + args[1] - 1)
119
+ range = Range.new(min, max)
120
+ replace_by = [replace_by].pack('U') if replace_by.is_a?(Integer)
121
+ elsif args.first.is_a?(Range)
122
+ raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
123
+ range = args[0]
124
+ else
125
+ needle = args[0].to_s
126
+ min = index(needle)
127
+ max = min + Unicode.u_unpack(needle).length - 1
128
+ range = Range.new(min, max)
129
+ end
130
+ result[range] = Unicode.u_unpack(replace_by)
131
+ @wrapped_string.replace(result.pack('U*'))
132
+ end
133
+ end
134
+
135
+ # Reverses all characters in the string.
136
+ #
137
+ # Example:
138
+ # Mail::Multibyte.mb_chars('Café').reverse.to_s # => 'éfaC'
139
+ def reverse
140
+ chars(Unicode.g_unpack(@wrapped_string).reverse.flatten.pack('U*'))
141
+ end
142
+
143
+ # Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that
144
+ # character.
145
+ #
146
+ # Example:
147
+ # Mail::Multibyte.mb_chars('こんにちは').slice(2..3).to_s # => "にち"
148
+ def slice(*args)
149
+ if args.size > 2
150
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
151
+ elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp)))
152
+ raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native
153
+ elsif (args.size == 2 && !args[1].is_a?(Numeric))
154
+ raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native
155
+ elsif args[0].kind_of? Range
156
+ cps = Unicode.u_unpack(@wrapped_string).slice(*args)
157
+ result = cps.nil? ? nil : cps.pack('U*')
158
+ elsif args[0].kind_of? Regexp
159
+ result = @wrapped_string.slice(*args)
160
+ elsif args.size == 1 && args[0].kind_of?(Numeric)
161
+ character = Unicode.u_unpack(@wrapped_string)[args[0]]
162
+ result = character && [character].pack('U')
163
+ else
164
+ cps = Unicode.u_unpack(@wrapped_string).slice(*args)
165
+ result = cps && cps.pack('U*')
166
+ end
167
+ result && chars(result)
168
+ end
169
+ alias_method :[], :slice
170
+
171
+ # Limit the byte size of the string to a number of bytes without breaking characters. Usable
172
+ # when the storage for a string is limited for some reason.
173
+ #
174
+ # Example:
175
+ # s = 'こんにちは'
176
+ # s.mb_chars.limit(7) # => "こん"
177
+ def limit(limit)
178
+ slice(0...translate_offset(limit))
179
+ end
180
+
181
+ # Convert characters in the string to uppercase.
182
+ #
183
+ # Example:
184
+ # Mail::Multibyte.mb_chars('Laurent, où sont les tests ?').upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
185
+ def upcase
186
+ chars(Unicode.apply_mapping(@wrapped_string, :uppercase_mapping))
187
+ end
188
+
189
+ # Convert characters in the string to lowercase.
190
+ #
191
+ # Example:
192
+ # Mail::Multibyte.mb_chars('VĚDA A VÝZKUM').downcase.to_s # => "věda a výzkum"
193
+ def downcase
194
+ chars(Unicode.apply_mapping(@wrapped_string, :lowercase_mapping))
195
+ end
196
+
197
+ # Converts the first character to uppercase and the remainder to lowercase.
198
+ #
199
+ # Example:
200
+ # Mail::Multibyte.mb_chars('über').capitalize.to_s # => "Über"
201
+ def capitalize
202
+ (slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
203
+ end
204
+
205
+ # Capitalizes the first letter of every word, when possible.
206
+ #
207
+ # Example:
208
+ # Mail::Multibyte.mb_chars("ÉL QUE SE ENTERÓ").titleize # => "Él Que Se Enteró"
209
+ # Mail::Multibyte.mb_chars("日本語").titleize # => "日本語"
210
+ def titleize
211
+ chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
212
+ end
213
+ alias_method :titlecase, :titleize
214
+
215
+ # Returns the KC normalization of the string by default. NFKC is considered the best normalization form for
216
+ # passing strings to databases and validations.
217
+ #
218
+ # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
219
+ # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
220
+ # Mail::Multibyte::Unicode.default_normalization_form
221
+ def normalize(form = nil)
222
+ chars(Unicode.normalize(@wrapped_string, form))
223
+ end
224
+
225
+ # Performs canonical decomposition on all the characters.
226
+ #
227
+ # Example:
228
+ # 'é'.length # => 2
229
+ # Mail::Multibyte.mb_chars('é').decompose.to_s.length # => 3
230
+ def decompose
231
+ chars(Unicode.decompose_codepoints(:canonical, Unicode.u_unpack(@wrapped_string)).pack('U*'))
232
+ end
233
+
234
+ # Performs composition on all the characters.
235
+ #
236
+ # Example:
237
+ # 'é'.length # => 3
238
+ # Mail::Multibyte.mb_chars('é').compose.to_s.length # => 2
239
+ def compose
240
+ chars(Unicode.compose_codepoints(Unicode.u_unpack(@wrapped_string)).pack('U*'))
241
+ end
242
+
243
+ # Returns the number of grapheme clusters in the string.
244
+ #
245
+ # Example:
246
+ # Mail::Multibyte.mb_chars('क्षि').length # => 4
247
+ # Mail::Multibyte.mb_chars('क्षि').g_length # => 3
248
+ def g_length
249
+ Unicode.g_unpack(@wrapped_string).length
250
+ end
251
+
252
+ # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
253
+ #
254
+ # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1.
255
+ def tidy_bytes(force = false)
256
+ chars(Unicode.tidy_bytes(@wrapped_string, force))
257
+ end
258
+
259
+ %w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
260
+ # Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will
261
+ # exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
262
+ if public_method_defined?(method)
263
+ define_method("#{method}!") do |*args|
264
+ @wrapped_string = send(method, *args).to_s
265
+ self
266
+ end
267
+ end
268
+ end
269
+
270
+ protected
271
+
272
+ def translate_offset(byte_offset) #:nodoc:
273
+ return nil if byte_offset.nil?
274
+ return 0 if @wrapped_string == ''
275
+
276
+ if @wrapped_string.respond_to?(:force_encoding)
277
+ @wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT)
278
+ end
279
+
280
+ begin
281
+ @wrapped_string[0...byte_offset].unpack('U*').length
282
+ rescue ArgumentError
283
+ byte_offset -= 1
284
+ retry
285
+ end
286
+ end
287
+
288
+ def justify(integer, way, padstr=' ') #:nodoc:
289
+ raise ArgumentError, "zero width padding" if padstr.length == 0
290
+ padsize = integer - size
291
+ padsize = padsize > 0 ? padsize : 0
292
+ case way
293
+ when :right
294
+ result = @wrapped_string.dup.insert(0, padding(padsize, padstr))
295
+ when :left
296
+ result = @wrapped_string.dup.insert(-1, padding(padsize, padstr))
297
+ when :center
298
+ lpad = padding((padsize / 2.0).floor, padstr)
299
+ rpad = padding((padsize / 2.0).ceil, padstr)
300
+ result = @wrapped_string.dup.insert(0, lpad).insert(-1, rpad)
301
+ end
302
+ chars(result)
303
+ end
304
+
305
+ def padding(padsize, padstr=' ') #:nodoc:
306
+ if padsize != 0
307
+ chars(padstr * ((padsize / Unicode.u_unpack(padstr).size) + 1)).slice(0, padsize)
308
+ else
309
+ ''
310
+ end
311
+ end
312
+
313
+ def chars(string) #:nodoc:
314
+ self.class.new(string)
315
+ end
316
+ end
317
+ end
318
+ end