Module: Flexr::Unicode::Property
- Defined in:
- lib/flexr/unicode/property.rb
Constant Summary collapse
- ALIASES =
{ "L" => "L", "Letter" => "L", "N" => "N", "Number" => "N", "Nd" => "Nd", "Hiragana" => "Hiragana", "Greek" => "Greek", "ASCII" => "ASCII", "Any" => "Any", "Assigned" => "Assigned", "Cased_Letter" => "LC", "digit" => "Nd", "alpha" => "Alphabetic", "alnum" => "Alnum", "word" => "Word", "space" => "Space", "Alnum" => "Alnum", "Word" => "Word", "Space" => "Space", "XDigit" => "XDigit", "Cntrl" => "Cntrl", "Lower" => "Lowercase", "Lowercase" => "Lowercase", "Upper" => "Uppercase", "Uppercase" => "Uppercase" }.freeze
- CACHE =
rubocop:disable Style/MutableConstant
{}
Class Method Summary collapse
- .canonical_name(name) ⇒ Object
- .complement(ranges) ⇒ Object
- .merge_ranges(ranges) ⇒ Object
- .normalize_name(name) ⇒ Object
- .posix_ranges(name) ⇒ Object
- .property_ranges(canonical, original_name) ⇒ Object
- .ranges(name, negate: false) ⇒ Object
Class Method Details
.canonical_name(name) ⇒ Object
35 36 37 38 39 40 41 42 43 |
# File 'lib/flexr/unicode/property.rb', line 35 def canonical_name(name) raw = name.to_s.strip raw = raw.split("=", 2).last if raw.include?("=") normalized = normalize_name(raw) alias_entry = ALIASES.find { |candidate, _canonical| normalize_name(candidate) == normalized } return alias_entry.last if alias_entry Data::PROPERTIES.keys.find { |candidate| normalize_name(candidate) == normalized } || raw end |
.complement(ranges) ⇒ Object
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/flexr/unicode/property.rb', line 62 def complement(ranges) result = [] cursor = 0 ranges.each do |lo, hi| result << [cursor, lo - 1] if cursor < lo cursor = hi + 1 end result << [cursor, 0x10ffff] if cursor <= 0x10ffff result end |
.merge_ranges(ranges) ⇒ Object
94 95 96 97 98 99 100 101 102 |
# File 'lib/flexr/unicode/property.rb', line 94 def merge_ranges(ranges) ranges.sort_by(&:first).each_with_object([]) do |range, merged| if merged.empty? || range.first > merged.last.last + 1 merged << range.dup else merged.last[1] = [merged.last.last, range.last].max end end end |
.normalize_name(name) ⇒ Object
45 46 47 |
# File 'lib/flexr/unicode/property.rb', line 45 def normalize_name(name) name.to_s.delete("-_ ").downcase end |
.posix_ranges(name) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/flexr/unicode/property.rb', line 73 def posix_ranges(name) alpha = Data::PROPERTIES.fetch("Alphabetic") case name when "alnum" then merge_ranges(Data::PROPERTIES.fetch("Alnum") + alpha) when "alpha" then alpha when "blank" [[0x09, 0x09], [0x20, 0x20], [0xa0, 0xa0], [0x1680, 0x1680], [0x2000, 0x200a], [0x202f, 0x202f], [0x205f, 0x205f], [0x3000, 0x3000]] when "cntrl" then Data::PROPERTIES.fetch("Cntrl") when "digit" then Data::PROPERTIES.fetch("Nd") when "graph" then complement(merge_ranges(Data::PROPERTIES.fetch("Space") + Data::PROPERTIES.fetch("Cntrl"))) when "lower" then merge_ranges(Data::PROPERTIES.fetch("Ll") + Data::PROPERTIES.fetch("Lowercase")) when "print" then complement(Data::PROPERTIES.fetch("Cntrl")) when "punct" then Data::PROPERTIES.fetch("P") when "space" then Data::PROPERTIES.fetch("Space") when "upper" then merge_ranges(Data::PROPERTIES.fetch("Lu") + Data::PROPERTIES.fetch("Uppercase")) when "xdigit" then [[0x30, 0x39], [0x41, 0x46], [0x61, 0x66]] else raise CompileError, "unknown POSIX character class: #{name}" end end |
.property_ranges(canonical, original_name) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/flexr/unicode/property.rb', line 49 def property_ranges(canonical, original_name) case canonical when "Alnum" merge_ranges(Data::PROPERTIES.fetch("Alnum") + Data::PROPERTIES.fetch("Other_Alphabetic")) when "Word" merge_ranges(Data::PROPERTIES.fetch("Alnum") + Data::PROPERTIES.fetch("Other_Alphabetic") + [[0x5f, 0x5f]]) else Data::PROPERTIES.fetch(canonical) end rescue KeyError raise CompileError, "unknown Unicode property: #{original_name}" end |
.ranges(name, negate: false) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/flexr/unicode/property.rb', line 21 def ranges(name, negate: false) canonical = canonical_name(name) key = [canonical, negate] return CACHE[key] if CACHE.key?(key) ranges = if canonical.start_with?("POSIX_") posix_ranges(canonical.delete_prefix("POSIX_")) else property_ranges(canonical, name) end ranges = complement(ranges) if negate CACHE[key] = ranges.map { |range| range.dup.freeze }.freeze end |