From 26142667a1da560e681fc0621857a160edf26007 Mon Sep 17 00:00:00 2001 From: oieioi Date: Sun, 9 Sep 2018 18:27:24 +0900 Subject: [PATCH] Fix alignment of multi-byte fullwidth character comments (#575) This fixes alignment of Japanese, Korean and Chinese fullwidth character comments. The displayed widths of multi-byte fullwidth characters are generally twice as large as the ASCII characters, but String#size returns only the number of characters. So if the column comment contains fullwidth multibyte characters, the alignment is broken. --- lib/annotate/annotate_models.rb | 18 ++++++++++++++++-- spec/annotate/annotate_models_spec.rb | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/annotate/annotate_models.rb b/lib/annotate/annotate_models.rb index 575acd888..fa33f9083 100644 --- a/lib/annotate/annotate_models.rb +++ b/lib/annotate/annotate_models.rb @@ -301,7 +301,7 @@ def get_schema_info(klass, header, options = {}) type_remainder = (md_type_allowance - 2) - col_type.length info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n" else - info << sprintf("# %-#{max_size}.#{max_size}s:%-#{bare_type_allowance}.#{bare_type_allowance}s %s", col_name, col_type, attrs.join(", ")).rstrip + "\n" + info << format_default(col_name, max_size, col_type, bare_type_allowance, attrs) end end @@ -884,7 +884,7 @@ def with_comments?(klass, options) def max_schema_info_width(klass, options) if with_comments?(klass, options) max_size = klass.columns.map do |column| - column.name.size + (column.comment ? column.comment.size : 0) + column.name.size + (column.comment ? width(column.comment) : 0) end.max || 0 max_size += 2 else @@ -894,6 +894,20 @@ def max_schema_info_width(klass, options) max_size end + + def format_default(col_name, max_size, col_type, bare_type_allowance, attrs) + sprintf("# %s:%s %s", mb_chars_ljust(col_name, max_size), mb_chars_ljust(col_type, bare_type_allowance), attrs.join(", ")).rstrip + "\n" + end + + def width(string) + string.chars.inject(0) { |acc, elem| acc + (elem.bytesize == 1 ? 1 : 2) } + end + + def mb_chars_ljust(string, length) + string = string.to_s + padding = length - width(string) + string + (' ' * padding) + end end class BadModelFileError < LoadError diff --git a/spec/annotate/annotate_models_spec.rb b/spec/annotate/annotate_models_spec.rb index 9326e5ec7..39458c2e5 100644 --- a/spec/annotate/annotate_models_spec.rb +++ b/spec/annotate/annotate_models_spec.rb @@ -936,6 +936,29 @@ def self.when_called_with(options = {}) # notes(Notes) :text(55) not null # no_comment :text(20) not null # + EOS + + mocked_columns_with_multibyte_comment = [ + [:id, :integer, { limit: 8, comment: 'ID' }], + [:active, :boolean, { limit: 1, comment: 'ACTIVE' }], + [:name, :string, { limit: 50, comment: 'NAME' }], + [:notes, :text, { limit: 55, comment: 'NOTES' }], + [:no_comment, :text, { limit: 20, comment: nil }] + ] + + when_called_with with_comment: 'yes', + with_columns: mocked_columns_with_multibyte_comment, returns: + <<-EOS.strip_heredoc + # Schema Info + # + # Table name: users + # + # id(ID) :integer not null, primary key + # active(ACTIVE) :boolean not null + # name(NAME) :string(50) not null + # notes(NOTES) :text(55) not null + # no_comment :text(20) not null + # EOS it 'should get schema info as RDoc' do