class ActiveSupport::Multibyte::Chars

ActiveSupport::Multibyte.proxy_class = CharsForUTF32
end
end
string.length % 4 == 0
def self.accepts?(string)
end
@wrapped_string.size / 4
def size
class CharsForUTF32
ActiveSupport::Multibyte.proxy_class.
multibyte string handler and configure it through
is UTF-8, if you want to handle different encodings you can write your own
The default Chars implementation assumes that the encoding of the string
bad.explicit_checking_method ‘T’.mb_chars.downcase.to_s
the class, call to_s before you pass chars objects to them.
no explicit class checks are made. If certain methods do explicitly check
Chars objects are perfectly interchangeable with String objects as long as
# => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string=“the perfect string”>
‘The Perfect String ’.mb_chars.downcase.strip
String object now return a Chars object so methods can be chained.
through the mb_chars method. Methods which would normally return a
String methods are proxied through the Chars object, and can be accessed
implemented on the proxy.
methods in an encoding safe manner. All the normal String methods are also
Chars object accepts a string upon initialization and proxies String
String class without having extensive knowledge about the encoding. A
Chars enables you to work transparently with UTF-8 encoding in the Ruby
:nodoc:
:nodoc:

def as_json(options = nil) # :nodoc:

:nodoc:
def as_json(options = nil) # :nodoc:
  to_s.as_json(options)
end

def chars(string)

def chars(string)
  self.class.new(string)
end

def compose

'é'.mb_chars.compose.to_s.length # => 1
'é'.length # => 1

Performs composition on all the characters.
def compose
  chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
end

def decompose

'é'.mb_chars.decompose.to_s.length # => 2
'é'.length # => 1

Performs canonical decomposition on all the characters.
def decompose
  chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
end

def grapheme_length

'क्षि'.mb_chars.grapheme_length # => 2
'क्षि'.mb_chars.length # => 4

Returns the number of grapheme clusters in the string.
def grapheme_length
  @wrapped_string.grapheme_clusters.length
end

def initialize(string)

Creates a new Chars instance by wrapping _string_.
def initialize(string)
  @wrapped_string = string
  @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
end

def limit(limit)

'こんにちは'.mb_chars.limit(7).to_s # => "こん"

reason.
characters. Usable when the storage for a string is limited for some
Limits the byte size of the string to a number of bytes without breaking
def limit(limit)
  chars(@wrapped_string.truncate_bytes(limit, omission: nil))
end

def method_missing(method, *args, &block)

Forward all undefined methods to the wrapped string.
def method_missing(method, *args, &block)
  result = @wrapped_string.__send__(method, *args, &block)
  if method.end_with?("!")
    self if result
  else
    result.kind_of?(String) ? chars(result) : result
  end
end

def respond_to_missing?(method, include_private)

evaluates to +true+.
are included in the search only if the optional second parameter
Returns +true+ if _obj_ responds to the given method. Private methods
def respond_to_missing?(method, include_private)
  @wrapped_string.respond_to?(method, include_private)
end

def reverse

'Café'.mb_chars.reverse.to_s # => 'éfaC'

Reverses all characters in the string.
def reverse
  chars(@wrapped_string.grapheme_clusters.reverse.join)
end

def slice!(*args)

string # => 'me'
string.mb_chars.slice!(0..3) # => #
string # => 'Welome'
string.mb_chars.slice!(3) # => #
string = 'Welcome'

modified if the range given is out of bounds
Chars, or +nil+ if the string was not modified. The string will not be
Works like String#slice!, but returns an instance of
def slice!(*args)
  string_sliced = @wrapped_string.slice!(*args)
  if string_sliced
    chars(string_sliced)
  end
end

def split(*args)

'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]

chaining methods easier.
in the resulting list are Chars instances instead of String. This makes
Works just like String#split, with the exception that the items
def split(*args)
  @wrapped_string.split(*args).map { |i| self.class.new(i) }
end

def tidy_bytes(force = false)

encoding is entirely CP1252 or ISO-8859-1.
Passing +true+ will forcibly tidy all bytes, assuming that the string's

resulting in a valid UTF-8 string.
Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
def tidy_bytes(force = false)
  chars(Unicode.tidy_bytes(@wrapped_string, force))
end

def titleize

"日本語".mb_chars.titleize.to_s # => "日本語"
"ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"

Capitalizes the first letter of every word, when possible.
def titleize
  chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
end