vendor/rails/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb in radiant-0.6.4 vs vendor/rails/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb in radiant-0.6.5
- old
+ new
@@ -138,10 +138,87 @@
def index(str, *args)
bidx = str.index(*args)
bidx ? (u_unpack(str.slice(0...bidx)).size) : nil
end
+ # Works just like the indexed replace method on string, except instead of byte offsets you specify
+ # character offsets.
+ #
+ # Example:
+ #
+ # s = "Müller"
+ # s.chars[2] = "e" # Replace character with offset 2
+ # s
+ # #=> "Müeler"
+ #
+ # s = "Müller"
+ # s.chars[1, 2] = "ö" # Replace 2 characters at character offset 1
+ # s
+ # #=> "Möler"
+ def []=(str, *args)
+ replace_by = args.pop
+ # Indexed replace with regular expressions already works
+ return str[*args] = replace_by if args.first.is_a?(Regexp)
+ result = u_unpack(str)
+ if args[0].is_a?(Fixnum)
+ raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
+ min = args[0]
+ max = args[1].nil? ? min : (min + args[1] - 1)
+ range = Range.new(min, max)
+ replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
+ elsif args.first.is_a?(Range)
+ raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
+ range = args[0]
+ else
+ needle = args[0].to_s
+ min = index(str, needle)
+ max = min + length(needle) - 1
+ range = Range.new(min, max)
+ end
+ result[range] = u_unpack(replace_by)
+ str.replace(result.pack('U*'))
+ end
+
+ # Works just like String#rjust, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.rjust(8).to_s
+ # #=> " ¾ cup"
+ #
+ # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
+ # #=> " ¾ cup"
+ def rjust(str, integer, padstr=' ')
+ justify(str, integer, :right, padstr)
+ end
+
+ # Works just like String#ljust, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.rjust(8).to_s
+ # #=> "¾ cup "
+ #
+ # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
+ # #=> "¾ cup "
+ def ljust(str, integer, padstr=' ')
+ justify(str, integer, :left, padstr)
+ end
+
+ # Works just like String#center, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.center(8).to_s
+ # #=> " ¾ cup "
+ #
+ # "¾ cup".chars.center(8, " ").to_s # Use non-breaking whitespace
+ # #=> " ¾ cup "
+ def center(str, integer, padstr=' ')
+ justify(str, integer, :center, padstr)
+ end
+
# Does Unicode-aware rstrip
def rstrip(str)
str.gsub(UNICODE_TRAILERS_PAT, '')
end
@@ -167,15 +244,21 @@
end
# Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that
# character.
def slice(str, *args)
- if (args.size == 2 && args.first.is_a?(Range))
- raise TypeError, 'cannot convert Range into Integer' # Do as if we were native
+ if args.size > 2
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
+ elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp)))
+ raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native
+ elsif (args.size == 2 && !args[1].is_a?(Numeric))
+ raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native
elsif args[0].kind_of? Range
cps = u_unpack(str).slice(*args)
cps.nil? ? nil : cps.pack('U*')
+ elsif args[0].kind_of? Regexp
+ str.slice(*args)
elsif args.size == 1 && args[0].kind_of?(Numeric)
u_unpack(str)[args[0]]
else
u_unpack(str).slice(*args).pack('U*')
end
@@ -198,12 +281,12 @@
# ///
# Returns the KC normalization of the string by default. NFKC is considered the best normalization form for
# passing strings to databases and validations.
#
- # * <tt>str</tt>: The string to perform normalization on.
- # * <tt>form</tt>: The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd.
+ # * <tt>str</tt> - The string to perform normalization on.
+ # * <tt>form</tt> - The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd.
def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM)
# See http://www.unicode.org/reports/tr15, Table 1
codepoints = u_unpack(str)
case form
when :d
@@ -233,12 +316,12 @@
# /// BEGIN Helper methods for unicode operation
# ///
# Used to translate an offset from bytes to characters, for instance one received from a regular expression match
def translate_offset(str, byte_offset)
- return 0 if str == ''
return nil if byte_offset.nil?
+ return 0 if str == ''
chunk = str[0..byte_offset]
begin
begin
chunk.unpack('U*').length - 1
rescue ArgumentError => e
@@ -334,9 +417,36 @@
end
# Reverse operation of g_unpack
def g_pack(unpacked)
unpacked.flatten
+ end
+
+ # Justifies a string in a certain way. Valid values for <tt>way</tt> are <tt>:right</tt>, <tt>:left</tt> and
+ # <tt>:center</tt>. Is primarily used as a helper method by <tt>rjust</tt>, <tt>ljust</tt> and <tt>center</tt>.
+ def justify(str, integer, way, padstr=' ')
+ raise ArgumentError, "zero width padding" if padstr.length == 0
+ padsize = integer - size(str)
+ padsize = padsize > 0 ? padsize : 0
+ case way
+ when :right
+ str.dup.insert(0, padding(padsize, padstr))
+ when :left
+ str.dup.insert(-1, padding(padsize, padstr))
+ when :center
+ lpad = padding((padsize / 2.0).floor, padstr)
+ rpad = padding((padsize / 2.0).ceil, padstr)
+ str.dup.insert(0, lpad).insert(-1, rpad)
+ end
+ end
+
+ # Generates a padding string of a certain size.
+ def padding(padsize, padstr=' ')
+ if padsize != 0
+ slice(padstr * ((padsize / size(padstr)) + 1), 0, padsize)
+ else
+ ''
+ end
end
# Convert characters to a different case
def to_case(way, str)
u_unpack(str).map do |codepoint|