lib/annotate/annotate_models.rb in annotate-2.7.4 vs lib/annotate/annotate_models.rb in annotate-2.7.5

- old
+ new

@@ -60,11 +60,11 @@ # Helper files HELPER_DIR = File.join('app', "helpers") # Don't show limit (#) on these column types # Example: show "integer" instead of "integer(4)" - NO_LIMIT_COL_TYPES = %w(integer boolean).freeze + NO_LIMIT_COL_TYPES = %w(integer bigint boolean).freeze # Don't show default value for these column types NO_DEFAULT_COL_TYPES = %w(json jsonb hstore).freeze INDEX_CLAUSES = { @@ -299,11 +299,11 @@ elsif options[:format_markdown] name_remainder = max_size - col_name.length 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 if options[:show_indexes] && klass.table_exists? info << get_index_info(klass, options) @@ -360,11 +360,11 @@ index_info end def get_col_type(col) - if col.respond_to?(:bigint?) && col.bigint? + if (col.respond_to?(:bigint?) && col.bigint?) || /\Abigint\b/ =~ col.sql_type 'bigint' else (col.type || col.sql_type).to_s end end @@ -496,68 +496,71 @@ # :force<Symbol>:: whether to update the file even if it doesn't seem to need it. # :position_in_*<Symbol>:: where to place the annotated section in fixture or model file, # :before, :top, :after or :bottom. Default is :before. # def annotate_one_file(file_name, info_block, position, options = {}) - if File.exist?(file_name) - old_content = File.read(file_name) - return false if old_content =~ /#{SKIP_ANNOTATION_PREFIX}.*\n/ + return false unless File.exist?(file_name) + old_content = File.read(file_name) + return false if old_content =~ /#{SKIP_ANNOTATION_PREFIX}.*\n/ - # Ignore the Schema version line because it changes with each migration - header_pattern = /(^# Table name:.*?\n(#.*[\r]?\n)*[\r]?)/ - old_header = old_content.match(header_pattern).to_s - new_header = info_block.match(header_pattern).to_s + # Ignore the Schema version line because it changes with each migration + header_pattern = /(^# Table name:.*?\n(#.*[\r]?\n)*[\r]?)/ + old_header = old_content.match(header_pattern).to_s + new_header = info_block.match(header_pattern).to_s - column_pattern = /^#[\t ]+[\w\*`]+[\t ]+.+$/ - old_columns = old_header && old_header.scan(column_pattern).sort - new_columns = new_header && new_header.scan(column_pattern).sort + column_pattern = /^#[\t ]+[\w\*`]+[\t ]+.+$/ + old_columns = old_header && old_header.scan(column_pattern).sort + new_columns = new_header && new_header.scan(column_pattern).sort - magic_comments_block = magic_comments_as_string(old_content) + return false if old_columns == new_columns && !options[:force] - if old_columns == new_columns && !options[:force] - return false - else - # Replace inline the old schema info with the new schema info - new_content = old_content.sub(annotate_pattern(options), info_block + "\n") + abort "annotate error. #{file_name} needs to be updated, but annotate was run with `--frozen`." if options[:frozen] - if new_content.end_with?(info_block + "\n") - new_content = old_content.sub(annotate_pattern(options), "\n" + info_block) - end + # Replace inline the old schema info with the new schema info + wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" : "" + wrapper_close = options[:wrapper_close] ? "# #{options[:wrapper_close]}\n" : "" + wrapped_info_block = "#{wrapper_open}#{info_block}#{wrapper_close}" - wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" : "" - wrapper_close = options[:wrapper_close] ? "# #{options[:wrapper_close]}\n" : "" - wrapped_info_block = "#{wrapper_open}#{info_block}#{wrapper_close}" - # if there *was* no old schema info (no substitution happened) or :force was passed, - # we simply need to insert it in correct position - if new_content == old_content || options[:force] - old_content.gsub!(magic_comment_matcher, '') - old_content.sub!(annotate_pattern(options), '') + old_annotation = old_content.match(annotate_pattern(options)).to_s - new_content = if %w(after bottom).include?(options[position].to_s) - magic_comments_block + (old_content.rstrip + "\n\n" + wrapped_info_block) - else - magic_comments_block + wrapped_info_block + "\n" + old_content - end - end + # if there *was* no old schema info or :force was passed, we simply + # need to insert it in correct position + if old_annotation.empty? || options[:force] + magic_comments_block = magic_comments_as_string(old_content) + old_content.gsub!(magic_comment_matcher, '') + old_content.sub!(annotate_pattern(options), '') - File.open(file_name, 'wb') { |f| f.puts new_content } - return true - end + new_content = if %w(after bottom).include?(options[position].to_s) + magic_comments_block + (old_content.rstrip + "\n\n" + wrapped_info_block) + elsif magic_comments_block.empty? + magic_comments_block + wrapped_info_block + "\n" + old_content + else + magic_comments_block + "\n" + wrapped_info_block + "\n" + old_content + end else - false + # replace the old annotation with the new one + + # keep the surrounding whitespace the same + space_match = old_annotation.match(/\A(?<start>\s*).*?\n(?<end>\s*)\z/m) + new_annotation = space_match[:start] + wrapped_info_block + space_match[:end] + + new_content = old_content.sub(annotate_pattern(options), new_annotation) end + + File.open(file_name, 'wb') { |f| f.puts new_content } + true end def magic_comment_matcher Regexp.new(/(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/) end def magic_comments_as_string(content) magic_comments = content.scan(magic_comment_matcher).flatten.compact if magic_comments.any? - magic_comments.join + "\n" + magic_comments.join else '' end end @@ -883,18 +886,32 @@ end 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 max_size = klass.column_names.map(&:size).max end max_size += options[:format_rdoc] ? 5 : 1 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 def to_s