1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
class CharacterSet
class Character
ENCODING = 'utf-8'.freeze
SAFELY_PRINTABLE = (0x21..0x7E).to_a - %w(- / [ \\ ] ^).map(&:ord)
attr_accessor :codepoint
def initialize(codepoint)
case codepoint
when Integer then self.codepoint = codepoint
when String then self.codepoint = codepoint.ord
else raise ArgumentError, 'pass an Integer or String'
end
end
def to_s
codepoint.chr(ENCODING)
end
def hex
codepoint.to_s(16).upcase
end
def escape(opts = {})
return to_s if SAFELY_PRINTABLE.include?(codepoint) && !opts[:escape_all]
return yield(self) if block_given?
# https://billposer.org/Software/ListOfRepresentations.html
case opts[:format].to_s.downcase.delete('-_ ')
when '', 'default', 'es6', 'esnext', 'rb', 'ruby'
default_escape(opts)
when 'java', 'javascript', 'js'
default_escape(opts, false)
when 'capitalizableu', 'c#', 'csharp', 'd', 'python'
capitalizable_u_escape
when 'u+', 'uplus'
u_plus_escape
when 'literal', 'raw'
to_s
else
raise ArgumentError, "unsupported format: #{opts[:format].inspect}"
end
end
def plane
codepoint / 0x10000
end
private
def default_escape(opts, support_wide_hex = true)
if hex.length <= 2
'\\x' + hex.rjust(2, '0')
elsif hex.length <= 4
'\\u' + hex.rjust(4, '0')
elsif support_wide_hex
'\\u{' + hex + '}'
else
raise "#{opts[:format]} does not support escaping astral value #{hex}"
end
end
def capitalizable_u_escape
if hex.length <= 4
'\\u' + hex.rjust(4, '0')
else
'\\U' + hex.rjust(8, '0')
end
end
def u_plus_escape
'U+' + hex.rjust(4, '0')
end
end
end
|