annotaterb 4.15.0 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a31463c338bd23299c7249e3c444d8c1b630157bf9905cfeb203dfafb1a4d16a
4
- data.tar.gz: ad12fccdeeb0186d6627ba237c417c637b1b6136f354313e81f09de90cef4665
3
+ metadata.gz: 8789a11055d7fe2e2631a4c8ca0b3e05e20e365c16a31a2ea21ba6c1f90eda60
4
+ data.tar.gz: cbd50d2e0be48c2ffc55c600b5e1a5d6ae5864224d04180924a473395c1543eb
5
5
  SHA512:
6
- metadata.gz: af6ec6a16d36b65b00eb28f4736c46682aa0d47da4869503eaecb8a58a8ff34f783ac3986c09200f125279666a8b30658af1ba91a9ad5829d789846c1c9e82dd
7
- data.tar.gz: ad7fbd08360072a24c2fbea2808c180806ae89da5775689d1f7cc2824fead770b771ac41667056e68da0921ae13948a6f3da48883ab2f0328506cbf7158a63c0
6
+ metadata.gz: a51864d58bb429fd7166c16c98e179c926b5d2cf06b294f7b476f36e6dce5662d5f3ea20881ef0ac773535f3ccd3ddf4e26d35d833ba813bbc955a38191a2ea5
7
+ data.tar.gz: 78349c0ac08e212a9c6c0d40315d4bb18eba61e0dea77a580c133b76235a04cd3e78072c6d85814d3081de3e7c53eaa19e7297f9148e3c45bfe8567cbe7ce559
data/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## [v4.16.0](https://github.com/drwl/annotaterb/tree/v4.16.0) (2025-06-18)
4
+
5
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.15.0...v4.16.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Feature Request: Add Option to Place Annotations Above Nested Classes or Modules. [\#186](https://github.com/drwl/annotaterb/issues/186)
10
+
11
+ **Closed issues:**
12
+
13
+ - Misleading pattern examples in documentation for `additional_file_patterns` [\#221](https://github.com/drwl/annotaterb/issues/221)
14
+ - Permission denied for table pg\_index [\#209](https://github.com/drwl/annotaterb/issues/209)
15
+ - Performance regression relative to pre-fork? [\#205](https://github.com/drwl/annotaterb/issues/205)
16
+ - Add back ruby configuration option? [\#203](https://github.com/drwl/annotaterb/issues/203)
17
+ - Enable frozen mode when CI environment variable is set [\#171](https://github.com/drwl/annotaterb/issues/171)
18
+
19
+ **Merged pull requests:**
20
+
21
+ - Bump version to v4.16.0 [\#228](https://github.com/drwl/annotaterb/pull/228) ([drwl](https://github.com/drwl))
22
+ - chore: add --with-column-comments readme documentation [\#227](https://github.com/drwl/annotaterb/pull/227) ([jonmcelroy-appfolio](https://github.com/jonmcelroy-appfolio))
23
+ - Drop Ruby 2.7 support and improve CI [\#226](https://github.com/drwl/annotaterb/pull/226) ([drwl](https://github.com/drwl))
24
+ - Pass .annotaterb.yml through ERB [\#225](https://github.com/drwl/annotaterb/pull/225) ([fxn](https://github.com/fxn))
25
+ - feat: Add `--nested-position` option for placing annotations above nested classes. [\#223](https://github.com/drwl/annotaterb/pull/223) ([yamat47](https://github.com/yamat47))
26
+ - Fix for: Misleading pattern examples in documentation for additional\_file\_patterns [\#222](https://github.com/drwl/annotaterb/pull/222) ([skliarov](https://github.com/skliarov))
27
+ - Move activerecord dependency into gemspec [\#220](https://github.com/drwl/annotaterb/pull/220) ([drwl](https://github.com/drwl))
28
+ - Generate changelog for v4.15.0 [\#219](https://github.com/drwl/annotaterb/pull/219) ([drwl](https://github.com/drwl))
29
+ - chore: add rake task to automatically deploy to rubygems [\#183](https://github.com/drwl/annotaterb/pull/183) ([OdenTakashi](https://github.com/OdenTakashi))
30
+
31
+ ## [v4.15.0](https://github.com/drwl/annotaterb/tree/v4.15.0) (2025-05-30)
32
+
33
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.14.1...v4.15.0)
34
+
35
+ **Closed issues:**
36
+
37
+ - Feature request: packs-rails support [\#99](https://github.com/drwl/annotaterb/issues/99)
38
+ - Annotate models using Zeitwerk namespaces [\#82](https://github.com/drwl/annotaterb/issues/82)
39
+
40
+ **Merged pull requests:**
41
+
42
+ - Bump version to v4.15.0 [\#218](https://github.com/drwl/annotaterb/pull/218) ([drwl](https://github.com/drwl))
43
+ - Add debug logs for model annotation [\#217](https://github.com/drwl/annotaterb/pull/217) ([jarredhawkins](https://github.com/jarredhawkins))
44
+ - Cache retrieved indexes in ModelWrapper [\#215](https://github.com/drwl/annotaterb/pull/215) ([tr4b4nt](https://github.com/tr4b4nt))
45
+ - feat: identify unique indexes in simple\_indexes option [\#214](https://github.com/drwl/annotaterb/pull/214) ([amerritt14](https://github.com/amerritt14))
46
+ - fix: Handle case when table\_name\_prefix specified as symbol [\#208](https://github.com/drwl/annotaterb/pull/208) ([gururuby](https://github.com/gururuby))
47
+ - Support the glob pattern in `root_dir` and `model_dir` [\#198](https://github.com/drwl/annotaterb/pull/198) ([sinsoku](https://github.com/sinsoku))
48
+ - Fix `changelog_uri` in gemspec [\#192](https://github.com/drwl/annotaterb/pull/192) ([y-yagi](https://github.com/y-yagi))
49
+ - Generate changelog for v4.14.0 [\#191](https://github.com/drwl/annotaterb/pull/191) ([drwl](https://github.com/drwl))
50
+ - feat: add `timestamp_columns` config option [\#173](https://github.com/drwl/annotaterb/pull/173) ([pbernays](https://github.com/pbernays))
51
+
52
+ ## [v4.14.1](https://github.com/drwl/annotaterb/tree/v4.14.1) (2025-03-31)
53
+
54
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.14.0...v4.14.1)
55
+
56
+ **Closed issues:**
57
+
58
+ - Sort by database order [\#194](https://github.com/drwl/annotaterb/issues/194)
59
+ - “wrong number of arguments \(given 0, expected 1..2\)” when using enum in a Rails 8 model [\#184](https://github.com/drwl/annotaterb/issues/184)
60
+
3
61
  ## [v4.14.0](https://github.com/drwl/annotaterb/tree/v4.14.0) (2025-02-17)
4
62
 
5
63
  [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.13.0...v4.14.0)
data/README.md CHANGED
@@ -134,6 +134,7 @@ Annotate model options:
134
134
  --ignore-unknown-models don't display warnings for bad model files
135
135
  -I, --ignore-columns REGEX don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`
136
136
  --with-comment include database comments in model annotations
137
+ --with-column-comments include column comments in model annotations
137
138
 
138
139
  Annotate routes options:
139
140
  Usage: annotaterb routes [options]
@@ -149,7 +150,7 @@ Command options:
149
150
  Additional options that work for annotating models and routes
150
151
 
151
152
  --additional-file-patterns path1,path2,path3
152
- Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)
153
+ Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%MODEL_NAME%/*.rb,/baz/%MODEL_NAME%.rb`)
153
154
  -d, --delete Remove annotations from all model files or the routes.rb file
154
155
  --model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with commas
155
156
  --root-dir dir Annotate files stored within root dir projects, separate multiple dirs with commas
@@ -192,7 +193,7 @@ Previously in the [Annotate](https://github.com/ctran/annotate_models) you could
192
193
  position: after
193
194
  ```
194
195
 
195
- Annotaterb reads first from the configuration file, if it exists, then merges it with any options passed into the CLI.
196
+ Annotaterb reads first the configuration file, if it exists, passes its content through ERB, and merges the result with any options passed into the CLI.
196
197
 
197
198
  For further details visit the [section in the migration guide](MIGRATION_GUIDE.md#automatic-annotations-after-running-database-migration-commands).
198
199
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.15.0
1
+ 4.17.0
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "erb"
4
+
3
5
  module AnnotateRb
4
6
  # Raised when a configuration file is not found.
5
7
  class ConfigNotFoundError < StandardError
@@ -20,8 +22,9 @@ module AnnotateRb
20
22
  # Method from Rubocop::ConfigLoader
21
23
  def load_yaml_configuration(absolute_path)
22
24
  file_contents = read_file(absolute_path)
25
+ yaml_code = ERB.new(file_contents).result
23
26
 
24
- hash = yaml_safe_load(file_contents, absolute_path) || {}
27
+ hash = yaml_safe_load(yaml_code, absolute_path) || {}
25
28
 
26
29
  # TODO: Print config if debug flag/option is set
27
30
 
@@ -47,22 +47,63 @@ module AnnotateRb
47
47
  def content_annotated_before(parsed, content_without_annotations, write_position)
48
48
  same_write_position = @parsed_file.has_annotations? && @parsed_file.annotation_position.to_s == write_position
49
49
 
50
- # Could error if there's no class or module declaration
51
- _constant_name, line_number_before = parsed.starts.first
50
+ _constant_name, line_number_before = determine_annotation_position(parsed)
52
51
 
53
52
  content_with_annotations_written_before = []
54
53
  content_with_annotations_written_before << content_without_annotations.lines[0...line_number_before]
55
54
  content_with_annotations_written_before << $/ if @parsed_file.has_leading_whitespace? && same_write_position
56
- content_with_annotations_written_before << @new_wrapped_annotations.lines
55
+ content_with_annotations_written_before << formatted_annotations(content_without_annotations, line_number_before)
57
56
  content_with_annotations_written_before << $/ if @parsed_file.has_trailing_whitespace? && same_write_position
58
57
  content_with_annotations_written_before << content_without_annotations.lines[line_number_before..]
59
58
 
60
59
  content_with_annotations_written_before.join
61
60
  end
62
61
 
62
+ # Determines where to place the annotation based on the nested_position option.
63
+ # When nested_position is enabled, finds the most deeply nested class declaration
64
+ # to place annotations directly above nested classes instead of at the file top.
65
+ def determine_annotation_position(parsed)
66
+ # Handle empty files where no classes/modules are found
67
+ return [nil, 0] if parsed.starts.empty?
68
+
69
+ return parsed.starts.first unless @options[:nested_position]
70
+
71
+ class_entries = parsed.starts.select { |name, _line| parsed.type_map[name] == :class }
72
+ class_entries.last || parsed.starts.first
73
+ end
74
+
75
+ # Formats annotations with appropriate indentation for consistent code structure.
76
+ # Applies the same indentation level as the target line to maintain proper
77
+ # code alignment when using nested positioning.
78
+ def formatted_annotations(content_without_annotations, line_number_before)
79
+ indentation = determine_indentation(content_without_annotations, line_number_before)
80
+ @new_wrapped_annotations.lines.map { |line| "#{indentation}#{line}" }
81
+ end
82
+
83
+ # Calculates the indentation string to apply to annotations for nested positioning.
84
+ # Extracts leading whitespace from the target line to preserve visual hierarchy
85
+ # and readability of nested code structures.
86
+ def determine_indentation(content_without_annotations, line_number_before)
87
+ return "" unless @options[:nested_position] && line_number_before > 0
88
+
89
+ target_line = content_without_annotations.lines[line_number_before]
90
+ target_line&.match(/^(\s*)/)&.[](1) || ""
91
+ end
92
+
63
93
  def content_annotated_after(parsed, content_without_annotations)
64
94
  _constant_name, line_number_after = parsed.ends.last
65
95
 
96
+ # Handle empty files where no classes/modules are found
97
+ if line_number_after.nil?
98
+ content_lines = content_without_annotations.lines
99
+ # For empty files, append annotations at the end
100
+ content_with_annotations_written_after = []
101
+ content_with_annotations_written_after << content_lines
102
+ content_with_annotations_written_after << $/ unless content_lines.empty?
103
+ content_with_annotations_written_after << @new_wrapped_annotations.lines
104
+ return content_with_annotations_written_after.join
105
+ end
106
+
66
107
  content_with_annotations_written_after = []
67
108
  content_with_annotations_written_after << content_without_annotations.lines[0..line_number_after]
68
109
  content_with_annotations_written_after << $/
@@ -12,42 +12,23 @@ module AnnotateRb
12
12
  end
13
13
 
14
14
  def build
15
- is_primary_key = is_column_primary_key?(@model, @column.name)
16
-
17
- table_indices = @model.retrieve_indexes_from_table
18
- column_indices = table_indices.select { |ind| ind.columns.include?(@column.name) }
19
- column_defaults = @model.column_defaults
20
-
21
- column_attributes = AttributesBuilder.new(@column, @options, is_primary_key, column_indices, column_defaults).build
22
- formatted_column_type = TypeBuilder.new(@column, @options, column_defaults).build
15
+ column_attributes = @model.built_attributes[@column.name]
16
+ formatted_column_type = TypeBuilder.new(@column, @options, @model.column_defaults).build
23
17
 
24
18
  display_column_comments = @options[:with_comment] && @options[:with_column_comments]
25
- col_name = if display_column_comments && @model.with_comments? && @column.comment
26
- "#{@column.name}(#{@column.comment.gsub(/\n/, '\\n')})"
27
- else
28
- @column.name
29
- end
30
-
31
- _component = ColumnComponent.new(col_name, @max_size, formatted_column_type, column_attributes)
32
- end
33
-
34
- private
35
-
36
- # TODO: Simplify this conditional
37
- def is_column_primary_key?(model, column_name)
38
- if model.primary_key
39
- if model.primary_key.is_a?(Array)
40
- # If the model has multiple primary keys, check if this column is one of them
41
- if model.primary_key.collect(&:to_sym).include?(column_name.to_sym)
42
- return true
43
- end
44
- elsif column_name.to_sym == model.primary_key.to_sym
45
- # If model has 1 primary key, check if this column is it
46
- return true
47
- end
48
- end
49
-
50
- false
19
+ display_column_comments &&= @model.with_comments? && @column.comment
20
+ position_of_column_comment = @options[:position_of_column_comment] || Options::FLAG_OPTIONS[:position_of_column_comment] if display_column_comments
21
+
22
+ max_attributes_size = @model.built_attributes.values.map { |v| v.join(", ").length }.max
23
+
24
+ _component = ColumnComponent.new(
25
+ column: @column,
26
+ max_name_size: @max_size,
27
+ type: formatted_column_type,
28
+ attributes: column_attributes,
29
+ position_of_column_comment: position_of_column_comment,
30
+ max_attributes_size: max_attributes_size
31
+ )
51
32
  end
52
33
  end
53
34
  end
@@ -6,19 +6,31 @@ module AnnotateRb
6
6
  class ColumnComponent < Components::Base
7
7
  MD_TYPE_ALLOWANCE = 18
8
8
  BARE_TYPE_ALLOWANCE = 16
9
+ MIN_SPACES_BEFORE_COMMENT = 4
9
10
 
10
- attr_reader :name, :max_size, :type, :attributes
11
+ attr_reader :column, :max_name_size, :type, :attributes, :position_of_column_comment, :max_attributes_size
11
12
 
12
- def initialize(name, max_size, type, attributes)
13
- @name = name
14
- @max_size = max_size
13
+ def initialize(column:, max_name_size:, type:, attributes:, position_of_column_comment:, max_attributes_size:)
14
+ @column = column
15
+ @max_name_size = max_name_size
15
16
  @type = type
16
17
  @attributes = attributes
18
+ @position_of_column_comment = position_of_column_comment
19
+ @max_attributes_size = max_attributes_size
20
+ end
21
+
22
+ def name
23
+ case position_of_column_comment
24
+ when :with_name
25
+ "#{column.name}(#{column.comment.gsub(/\n/, '\\n')})"
26
+ else
27
+ column.name
28
+ end
17
29
  end
18
30
 
19
31
  def to_rdoc
20
32
  # standard:disable Lint/FormatParameterMismatch
21
- format("# %-#{max_size}.#{max_size}s<tt>%s</tt>",
33
+ format("# %-#{max_name_size}.#{max_name_size}s<tt>%s</tt>",
22
34
  "*#{name}*::",
23
35
  attributes.unshift(type).join(", ")).rstrip
24
36
  # standard:enable Lint/FormatParameterMismatch
@@ -40,24 +52,35 @@ module AnnotateRb
40
52
  end
41
53
 
42
54
  def to_markdown
43
- name_remainder = max_size - name.length - non_ascii_length(name)
55
+ joined_attributes = attributes.join(", ").rstrip
56
+ name_remainder = max_name_size - name.length - non_ascii_length(name)
44
57
  type_remainder = (MD_TYPE_ALLOWANCE - 2) - type.length
58
+ attributes_remainder = max_attributes_size + 1 - joined_attributes.length
59
+ comment_rightmost = (position_of_column_comment != :rightmost_column) ? "" : " | `#{@column.comment}`"
45
60
 
46
61
  # standard:disable Lint/FormatParameterMismatch
47
- format("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`",
62
+ format(
63
+ "# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`%#{attributes_remainder}s", # %s",
48
64
  name,
49
65
  " ",
50
66
  type,
51
67
  " ",
52
- attributes.join(", ").rstrip).gsub("``", " ").rstrip
68
+ joined_attributes,
69
+ comment_rightmost.to_s
70
+ ).gsub("``", " ").rstrip
53
71
  # standard:enable Lint/FormatParameterMismatch
54
72
  end
55
73
 
56
74
  def to_default
57
- format("# %s:%s %s",
58
- mb_chars_ljust(name, max_size),
75
+ comment_rightmost = (position_of_column_comment == :rightmost_column) ? @column.comment : ""
76
+ joined_attributes = attributes.join(", ")
77
+ format(
78
+ "# %s:%s %s %s",
79
+ mb_chars_ljust(name, max_name_size),
59
80
  mb_chars_ljust(type, BARE_TYPE_ALLOWANCE),
60
- attributes.join(", ")).rstrip
81
+ mb_chars_ljust(joined_attributes, max_attributes_size.to_i + MIN_SPACES_BEFORE_COMMENT),
82
+ comment_rightmost
83
+ ).rstrip
61
84
  end
62
85
 
63
86
  private
@@ -18,7 +18,7 @@ module AnnotateRb
18
18
  max_size = indexes.map { |index| index.name.size }.max + 1
19
19
 
20
20
  indexes = indexes.sort_by(&:name).map do |index|
21
- IndexComponent.new(index, max_size)
21
+ IndexComponent.new(index, max_size, @options)
22
22
  end
23
23
 
24
24
  _annotation = Annotation.new(indexes)
@@ -4,11 +4,12 @@ module AnnotateRb
4
4
  module ModelAnnotator
5
5
  module IndexAnnotation
6
6
  class IndexComponent < Components::Base
7
- attr_reader :index, :max_size
7
+ attr_reader :index, :max_size, :options
8
8
 
9
- def initialize(index, max_size)
9
+ def initialize(index, max_size, options)
10
10
  @index = index
11
11
  @max_size = max_size
12
+ @options = options
12
13
  end
13
14
 
14
15
  def to_default
@@ -34,11 +35,22 @@ module AnnotateRb
34
35
  ""
35
36
  end
36
37
 
38
+ include_info = ""
39
+ if options[:show_indexes_include]
40
+ value = index.try(:include)
41
+ include_info = if value.present? && value.any?
42
+ " INCLUDE (#{value.join(",")})"
43
+ else
44
+ ""
45
+ end
46
+ end
47
+
37
48
  # standard:disable Lint/FormatParameterMismatch
38
49
  sprintf(
39
- "# %-#{max_size}.#{max_size}s %s%s%s%s%s",
50
+ "# %-#{max_size}.#{max_size}s %s%s%s%s%s%s",
40
51
  index.name,
41
52
  "(#{columns_info.join(",")})",
53
+ include_info,
42
54
  unique_info,
43
55
  nulls_not_distinct_info,
44
56
  where_info,
@@ -70,8 +82,19 @@ module AnnotateRb
70
82
  ""
71
83
  end
72
84
 
85
+ include_info = ""
86
+ if options[:show_indexes_include]
87
+ value = index.try(:include)
88
+ include_info = if value.present? && value.any?
89
+ " _include_ (#{value.join(",")})"
90
+ else
91
+ ""
92
+ end
93
+ end
94
+
73
95
  details = sprintf(
74
- "%s%s%s%s",
96
+ "%s%s%s%s%s",
97
+ include_info,
75
98
  unique_info,
76
99
  nulls_not_distinct_info,
77
100
  where_info,
@@ -23,7 +23,7 @@ module AnnotateRb
23
23
  ignore_columns = @options[:ignore_columns]
24
24
  if ignore_columns
25
25
  cols = cols.reject do |col|
26
- col.name.match(/#{ignore_columns}/)
26
+ col.name.match?(/#{ignore_columns}/)
27
27
  end
28
28
  end
29
29
 
@@ -91,7 +91,8 @@ module AnnotateRb
91
91
  begin
92
92
  cols = columns
93
93
 
94
- if with_comments?
94
+ position_of_column_comment = @options.with_default_fallback(:position_of_column_comment)
95
+ if with_comments? && position_of_column_comment == :with_name
95
96
  column_widths = cols.map do |column|
96
97
  column.name.size + (column.comment ? Helper.width(column.comment) : 0)
97
98
  end
@@ -108,6 +109,35 @@ module AnnotateRb
108
109
  end
109
110
  end
110
111
 
112
+ # TODO: Simplify this conditional
113
+ def is_column_primary_key?(column_name)
114
+ if primary_key
115
+ if primary_key.is_a?(Array)
116
+ # If the model has multiple primary keys, check if this column is one of them
117
+ if primary_key.collect(&:to_sym).include?(column_name.to_sym)
118
+ return true
119
+ end
120
+ elsif column_name.to_sym == primary_key.to_sym
121
+ # If model has 1 primary key, check if this column is it
122
+ return true
123
+ end
124
+ end
125
+
126
+ false
127
+ end
128
+
129
+ def built_attributes
130
+ @built_attributes ||= begin
131
+ table_indices = retrieve_indexes_from_table
132
+ columns.map do |column|
133
+ is_primary_key = is_column_primary_key?(column.name)
134
+ column_indices = table_indices.select { |ind| ind.columns.include?(column.name) }
135
+ built = ColumnAnnotation::AttributesBuilder.new(column, @options, is_primary_key, column_indices, column_defaults).build
136
+ [column.name, built]
137
+ end.to_h
138
+ end
139
+ end
140
+
111
141
  def retrieve_indexes_from_table
112
142
  @indexes_from_table ||= _retrieve_indexes_from_table
113
143
  end
@@ -143,6 +173,10 @@ module AnnotateRb
143
173
  raw_columns.map(&:comment).any? { |comment| !comment.nil? }
144
174
  end
145
175
 
176
+ def position_of_column_comment
177
+ @position_of_column_comment ||= @options[:position_of_column_comment]
178
+ end
179
+
146
180
  def classified_sort(cols)
147
181
  rest_cols = []
148
182
  timestamps = []
@@ -42,7 +42,11 @@ module AnnotateRb
42
42
  klass.reset_column_information
43
43
  annotation = Annotation::AnnotationBuilder.new(klass, @options).build
44
44
  model_name = klass.name.underscore
45
- table_name = klass.table_name
45
+
46
+ # In multi-database configurations, it is possible for different models to have the same table name but live
47
+ # in different databases. Here we are opting to use the table name to find related files only when the model
48
+ # is using the primary connection.
49
+ table_name = klass.table_name if klass.connection_specification_name == ActiveRecord::Base.name
46
50
 
47
51
  model_instruction = SingleFileAnnotatorInstruction.new(file, annotation, :position_in_class, @options)
48
52
  instructions << model_instruction
@@ -48,6 +48,7 @@ module AnnotateRb
48
48
  show_check_constraints: false, # ModelAnnotator
49
49
  show_foreign_keys: true, # ModelAnnotator
50
50
  show_indexes: true, # ModelAnnotator
51
+ show_indexes_include: false, # ModelAnnotator
51
52
  show_virtual_columns: false, # ModelAnnotator
52
53
  simple_indexes: false, # ModelAnnotator
53
54
  sort: false, # ModelAnnotator
@@ -55,7 +56,8 @@ module AnnotateRb
55
56
  trace: false, # ModelAnnotator, but is part of Core
56
57
  with_comment: true, # ModelAnnotator
57
58
  with_column_comments: nil, # ModelAnnotator
58
- with_table_comments: nil # ModelAnnotator
59
+ with_table_comments: nil, # ModelAnnotator
60
+ position_of_column_comment: :with_name # ModelAnnotator
59
61
  }.freeze
60
62
 
61
63
  OTHER_OPTIONS = {
@@ -118,13 +120,15 @@ module AnnotateRb
118
120
  :show_complete_foreign_keys,
119
121
  :show_foreign_keys,
120
122
  :show_indexes,
123
+ :show_indexes_include,
121
124
  :simple_indexes,
122
125
  :sort,
123
126
  :timestamp,
124
127
  :trace,
125
128
  :with_comment,
126
129
  :with_column_comments,
127
- :with_table_comments
130
+ :with_table_comments,
131
+ :position_of_column_comment
128
132
  ].freeze
129
133
 
130
134
  OTHER_OPTION_KEYS = [
@@ -205,10 +209,15 @@ module AnnotateRb
205
209
  # Set column and table comments to default to :with_comment, if not set
206
210
  @options[:with_column_comments] = @options[:with_comment] if @options[:with_column_comments].nil?
207
211
  @options[:with_table_comments] = @options[:with_comment] if @options[:with_table_comments].nil?
212
+ @options[:position_of_column_comment] = @options[:position_of_column_comment].to_sym
208
213
 
209
214
  self
210
215
  end
211
216
 
217
+ def with_default_fallback(key)
218
+ @options[key] || DEFAULT_OPTIONS[key]
219
+ end
220
+
212
221
  def set_state(key, value, overwrite = false)
213
222
  if @state.key?(key) && !overwrite
214
223
  val = @state[key]
@@ -246,6 +246,11 @@ module AnnotateRb
246
246
  @options[:with_column_comments] = false
247
247
  end
248
248
 
249
+ option_parser.on("--position-of-column-comments VALUE",
250
+ "set the position, in the annotation block, of the column comment") do |value|
251
+ @options[:position_of_column_comments] = value.to_sym
252
+ end
253
+
249
254
  option_parser.on("--with-table-comments",
250
255
  "include table comments in model annotations") do
251
256
  @options[:with_table_comments] = true
@@ -264,6 +269,11 @@ module AnnotateRb
264
269
  [klass]
265
270
  end
266
271
  end
272
+
273
+ option_parser.on("--nested-position",
274
+ "Place annotations directly above nested classes or modules instead of at the top of the file.") do
275
+ @options[:nested_position] = true
276
+ end
267
277
  end
268
278
 
269
279
  def add_route_options_to_parser(option_parser)
@@ -362,7 +372,7 @@ module AnnotateRb
362
372
 
363
373
  option_parser.on("--additional-file-patterns path1,path2,path3",
364
374
  Array,
365
- "Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)") do |additional_file_patterns|
375
+ "Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%MODEL_NAME%/*.rb,/baz/%MODEL_NAME%.rb`)") do |additional_file_patterns|
366
376
  @options[:additional_file_patterns] = additional_file_patterns
367
377
  end
368
378
 
@@ -3,7 +3,7 @@
3
3
  module AnnotateRb
4
4
  module RouteAnnotator
5
5
  module Helper
6
- MAGIC_COMMENT_MATCHER = /(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/.freeze
6
+ MAGIC_COMMENT_MATCHER = /(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/
7
7
 
8
8
  class << self
9
9
  def routes_file_exist?
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: annotaterb
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.15.0
4
+ version: 4.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew W. Lee
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-30 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2025-07-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 6.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 6.0.0
13
41
  description: Annotates Rails/ActiveRecord Models, routes, fixtures, and others based
14
42
  on the database schema.
15
43
  email:
@@ -131,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
159
  requirements:
132
160
  - - ">="
133
161
  - !ruby/object:Gem::Version
134
- version: 2.7.0
162
+ version: 3.0.0
135
163
  required_rubygems_version: !ruby/object:Gem::Requirement
136
164
  requirements:
137
165
  - - ">="