Skip to content

Commit bfdd0a7

Browse files
committed
Merge branch 'develop' into add-table-comment
2 parents 033e123 + e60a666 commit bfdd0a7

File tree

7 files changed

+198
-7
lines changed

7 files changed

+198
-7
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ you can do so with a simple environment variable, instead of editing the
250250
don't show default for given column types, separated by commas (e.g. `json,jsonb,hstore`)
251251
--ignore-unknown-models don't display warnings for bad model files
252252
--with-comment include database comments in model annotations
253+
--with-comment-column include database comments in model annotations, as its own column, after all others
253254

254255
### Option: `additional_file_patterns`
255256

lib/annotate/annotate_models.rb

+40-6
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,37 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho
146146

147147
if options[:format_markdown]
148148
info << sprintf( "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' )
149+
149150
info << "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n"
150151
end
151152

152153
cols = columns(klass, options)
153-
cols.each do |col|
154+
with_comments = with_comments?(klass, options)
155+
with_comments_column = with_comments_column?(klass, options)
156+
157+
# Precalculate Values
158+
cols_meta = cols.map do |col|
159+
col_comment = with_comments || with_comments_column ? col.comment&.gsub(/\n/, "\\n") : nil
154160
col_type = get_col_type(col)
155161
attrs = get_attributes(col, col_type, klass, options)
156-
col_name = if with_comments?(klass, options) && col.comment
157-
"#{col.name}(#{col.comment.gsub(/\n/, "\\n")})"
162+
col_name = if with_comments && col_comment
163+
"#{col.name}(#{col_comment})"
158164
else
159165
col.name
160166
end
167+
simple_formatted_attrs = attrs.join(", ")
168+
[col.name, { col_type: col_type, attrs: attrs, col_name: col_name, simple_formatted_attrs: simple_formatted_attrs, col_comment: col_comment }]
169+
end.to_h
170+
171+
# Output annotation
172+
bare_max_attrs_length = cols_meta.map { |_, m| m[:simple_formatted_attrs].length }.max
173+
174+
cols.each do |col|
175+
col_type = cols_meta[col.name][:col_type]
176+
attrs = cols_meta[col.name][:attrs]
177+
col_name = cols_meta[col.name][:col_name]
178+
simple_formatted_attrs = cols_meta[col.name][:simple_formatted_attrs]
179+
col_comment = cols_meta[col.name][:col_comment]
161180

162181
if options[:format_rdoc]
163182
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
@@ -169,8 +188,10 @@ def get_schema_info(klass, header, options = {}) # rubocop:disable Metrics/Metho
169188
name_remainder = max_size - col_name.length - non_ascii_length(col_name)
170189
type_remainder = (md_type_allowance - 2) - col_type.length
171190
info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n"
191+
elsif with_comments_column
192+
info << format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, bare_max_attrs_length, col_comment)
172193
else
173-
info << format_default(col_name, max_size, col_type, bare_type_allowance, attrs)
194+
info << format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs)
174195
end
175196
end
176197

@@ -801,6 +822,12 @@ def with_comments?(klass, options)
801822
klass.columns.any? { |col| !col.comment.nil? }
802823
end
803824

825+
def with_comments_column?(klass, options)
826+
options[:with_comment_column] &&
827+
klass.columns.first.respond_to?(:comment) &&
828+
klass.columns.any? { |col| !col.comment.nil? }
829+
end
830+
804831
def with_table_comment?(klass, options)
805832
options[:with_comment] &&
806833
klass.connection.respond_to?(:table_comment) &&
@@ -823,8 +850,15 @@ def max_schema_info_width(klass, options)
823850
max_size
824851
end
825852

826-
def format_default(col_name, max_size, col_type, bare_type_allowance, attrs)
827-
sprintf("# %s:%s %s", mb_chars_ljust(col_name, max_size), mb_chars_ljust(col_type, bare_type_allowance), attrs.join(", ")).rstrip + "\n"
853+
# rubocop:disable Metrics/ParameterLists
854+
def format_default(col_name, max_size, col_type, bare_type_allowance, simple_formatted_attrs, bare_max_attrs_length = 0, col_comment = nil)
855+
sprintf(
856+
"# %s:%s %s %s",
857+
mb_chars_ljust(col_name, max_size),
858+
mb_chars_ljust(col_type, bare_type_allowance),
859+
mb_chars_ljust(simple_formatted_attrs, bare_max_attrs_length),
860+
col_comment
861+
).rstrip + "\n"
828862
end
829863

830864
def width(string)

lib/annotate/constants.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module Constants
1818
:trace, :timestamp, :exclude_serializers, :classified_sort,
1919
:show_foreign_keys, :show_complete_foreign_keys,
2020
:exclude_scaffolds, :exclude_controllers, :exclude_helpers,
21-
:exclude_sti_subclasses, :ignore_unknown_models, :with_comment,
21+
:exclude_sti_subclasses, :ignore_unknown_models, :with_comment, :with_comment_column,
2222
:show_check_constraints
2323
].freeze
2424

lib/annotate/parser.rb

+5
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ def add_options_to_parser(option_parser) # rubocop:disable Metrics/MethodLength,
304304
"include database comments in model annotations") do
305305
env['with_comment'] = 'true'
306306
end
307+
308+
option_parser.on('--with-comment-column',
309+
"include database comments in model annotations, as its own column, after all others") do
310+
env['with_comment_column'] = 'true'
311+
end
307312
end
308313
end
309314
end

spec/lib/annotate/annotate_models_spec.rb

+140
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,146 @@ def mock_column(name, type, options = {})
13441344
end
13451345
end
13461346
end
1347+
1348+
context 'when "with_comment_column" is specified in options' do
1349+
let :options do
1350+
{ with_comment_column: 'yes' }
1351+
end
1352+
1353+
context 'when columns have comments' do
1354+
let :columns do
1355+
[
1356+
mock_column(:id, :integer, limit: 8, comment: 'ID'),
1357+
mock_column(:active, :boolean, limit: 1, comment: 'Active'),
1358+
mock_column(:name, :string, limit: 50, comment: 'Name'),
1359+
mock_column(:notes, :text, limit: 55, comment: 'Notes'),
1360+
mock_column(:no_comment, :text, limit: 20, comment: nil)
1361+
]
1362+
end
1363+
1364+
let :expected_result do
1365+
<<~EOS
1366+
# Schema Info
1367+
#
1368+
# Table name: users
1369+
#
1370+
# id :integer not null, primary key ID
1371+
# active :boolean not null Active
1372+
# name :string(50) not null Name
1373+
# notes :text(55) not null Notes
1374+
# no_comment :text(20) not null
1375+
#
1376+
EOS
1377+
end
1378+
1379+
it 'works with option "with_comment_column"' do
1380+
is_expected.to eq expected_result
1381+
end
1382+
end
1383+
1384+
context 'when columns have multibyte comments' do
1385+
let :columns do
1386+
[
1387+
mock_column(:id, :integer, limit: 8, comment: 'ID'),
1388+
mock_column(:active, :boolean, limit: 1, comment: 'ACTIVE'),
1389+
mock_column(:name, :string, limit: 50, comment: 'NAME'),
1390+
mock_column(:notes, :text, limit: 55, comment: 'NOTES'),
1391+
mock_column(:cyrillic, :text, limit: 30, comment: 'Кириллица'),
1392+
mock_column(:japanese, :text, limit: 60, comment: '熊本大学 イタリア 宝島'),
1393+
mock_column(:arabic, :text, limit: 20, comment: 'لغة'),
1394+
mock_column(:no_comment, :text, limit: 20, comment: nil),
1395+
mock_column(:location, :geometry_collection, limit: nil, comment: nil)
1396+
]
1397+
end
1398+
1399+
let :expected_result do
1400+
<<~EOS
1401+
# Schema Info
1402+
#
1403+
# Table name: users
1404+
#
1405+
# id :integer not null, primary key ID
1406+
# active :boolean not null ACTIVE
1407+
# name :string(50) not null NAME
1408+
# notes :text(55) not null NOTES
1409+
# cyrillic :text(30) not null Кириллица
1410+
# japanese :text(60) not null 熊本大学 イタリア 宝島
1411+
# arabic :text(20) not null لغة
1412+
# no_comment :text(20) not null
1413+
# location :geometry_collect not null
1414+
#
1415+
EOS
1416+
end
1417+
1418+
it 'works with option "with_comment_column"' do
1419+
is_expected.to eq expected_result
1420+
end
1421+
end
1422+
1423+
context 'when columns have multiline comments' do
1424+
let :columns do
1425+
[
1426+
mock_column(:id, :integer, limit: 8, comment: 'ID'),
1427+
mock_column(:notes, :text, limit: 55, comment: "Notes.\nMay include things like notes."),
1428+
mock_column(:no_comment, :text, limit: 20, comment: nil)
1429+
]
1430+
end
1431+
1432+
let :expected_result do
1433+
<<~EOS
1434+
# Schema Info
1435+
#
1436+
# Table name: users
1437+
#
1438+
# id :integer not null, primary key ID
1439+
# notes :text(55) not null Notes.\\nMay include things like notes.
1440+
# no_comment :text(20) not null
1441+
#
1442+
EOS
1443+
end
1444+
1445+
it 'works with option "with_comment_column"' do
1446+
is_expected.to eq expected_result
1447+
end
1448+
end
1449+
1450+
context 'when geometry columns are included' do
1451+
let :columns do
1452+
[
1453+
mock_column(:id, :integer, limit: 8),
1454+
mock_column(:active, :boolean, default: false, null: false),
1455+
mock_column(:geometry, :geometry,
1456+
geometric_type: 'Geometry', srid: 4326,
1457+
limit: { srid: 4326, type: 'geometry' }),
1458+
mock_column(:location, :geography,
1459+
geometric_type: 'Point', srid: 0,
1460+
limit: { srid: 0, type: 'geometry' }),
1461+
mock_column(:non_srid, :geography,
1462+
geometric_type: 'Point',
1463+
limit: { type: 'geometry' })
1464+
]
1465+
end
1466+
1467+
let :expected_result do
1468+
<<~EOS
1469+
# Schema Info
1470+
#
1471+
# Table name: users
1472+
#
1473+
# id :integer not null, primary key
1474+
# active :boolean default(FALSE), not null
1475+
# geometry :geometry not null, geometry, 4326
1476+
# location :geography not null, point, 0
1477+
# non_srid :geography not null, point
1478+
#
1479+
EOS
1480+
end
1481+
1482+
it 'works with option "with_comment_column"' do
1483+
is_expected.to eq expected_result
1484+
end
1485+
end
1486+
end
13471487
end
13481488
end
13491489
end

spec/lib/annotate/parser_spec.rb

+10
Original file line numberDiff line numberDiff line change
@@ -560,5 +560,15 @@ module Annotate # rubocop:disable Metrics/ModuleLength
560560
Parser.parse([option])
561561
end
562562
end
563+
564+
describe '--with-comment-column' do
565+
let(:option) { '--with-comment-column' }
566+
let(:env_key) { 'with_comment_column' }
567+
let(:set_value) { 'true' }
568+
it 'sets the ENV variable' do
569+
expect(ENV).to receive(:[]=).with(env_key, set_value)
570+
Parser.parse([option])
571+
end
572+
end
563573
end
564574
end

spec/spec_helper.rb

+1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@
3636

3737
RSpec.configure do |config|
3838
config.order = 'random'
39+
config.filter_run_when_matching :focus
3940
end

0 commit comments

Comments
 (0)