From 64b37c3f956e291c94e98a560b748eee8c2ef2f2 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Sun, 30 Aug 2026 05:05:19 +0200 Subject: [PATCH 1/2] Support documented Proc width overwrites --- lib/unicode/display_width.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/unicode/display_width.rb b/lib/unicode/display_width.rb index a95a77e..48381b8 100644 --- a/lib/unicode/display_width.rb +++ b/lib/unicode/display_width.rb @@ -61,8 +61,9 @@ def self.of(string, ambiguous = nil, overwrite = nil, old_options = {}, **option width = 0 - unless options[:overwrite].empty? - width, string = width_custom(string, options[:overwrite]) + overwrite = options[:overwrite] + unless overwrite.respond_to?(:empty?) && overwrite.empty? + width, string = width_custom(string, overwrite) end if string.ascii_only? @@ -118,8 +119,8 @@ def self.width_custom(string, overwrite) width = 0 string = string.each_codepoint.select{ |codepoint| - if overwrite[codepoint] - width += overwrite[codepoint] + if overwrite_width = overwrite[codepoint] + width += overwrite_width nil else codepoint @@ -211,7 +212,7 @@ def self.normalize_options(string, ambiguous = nil, overwrite = nil, old_options raise ArgumentError, "Unicode::DisplayWidth: Ambiguous width must be 1 or 2" end - if overwrite && !overwrite.empty? + if overwrite && (!overwrite.respond_to?(:empty?) || !overwrite.empty?) warn "Unicode::DisplayWidth: Please migrate to keyword arguments - overwrite: #{overwrite.inspect}" options[:overwrite] = overwrite end From cd0824a305d09c320f6695e8b8498462948a6606 Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Sun, 27 Sep 2026 12:14:26 +0700 Subject: [PATCH 2/2] Cover overwrite fast path and custom lookup forms --- spec/display_width_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/display_width_spec.rb b/spec/display_width_spec.rb index 067dd97..7afdfcc 100644 --- a/spec/display_width_spec.rb +++ b/spec/display_width_spec.rb @@ -3,6 +3,24 @@ require_relative '../lib/unicode/display_width/string_ext' describe 'Unicode::DisplayWidth.of' do + describe 'overwrite fast path' do + it 'skips custom processing for omitted, nil, false and empty overwrites' do + expect(Unicode::DisplayWidth).not_to receive(:width_custom) + expect(Unicode::DisplayWidth.of('ABC')).to eq 3 + [nil, false, {}, double(empty?: true)].each do |overwrite| + expect(Unicode::DisplayWidth.of('ABC', overwrite: overwrite)).to eq 3 + end + end + + it 'applies non-empty hashes, procs and lookup objects' do + lookup = double(empty?: false) + allow(lookup).to receive(:[]).with(65).and_return(4) + [{65 => 4}, ->(codepoint) { 4 if codepoint == 65 }, lookup].each do |overwrite| + expect(Unicode::DisplayWidth.of('A', overwrite: overwrite)).to eq 4 + end + end + end + describe '[east asian width]' do it 'returns 2 for F' do expect( '!'.display_width ).to eq 2