annotaterb 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/VERSION +1 -1
  4. data/exe/annotaterb +7 -7
  5. data/lib/annotate_rb/active_record_patch.rb +2 -0
  6. data/lib/annotate_rb/commands/annotate_models.rb +0 -1
  7. data/lib/annotate_rb/commands/annotate_routes.rb +0 -1
  8. data/lib/annotate_rb/commands/print_help.rb +0 -1
  9. data/lib/annotate_rb/commands/print_version.rb +0 -1
  10. data/lib/annotate_rb/commands.rb +4 -4
  11. data/lib/annotate_rb/config_finder.rb +1 -1
  12. data/lib/annotate_rb/config_loader.rb +2 -2
  13. data/lib/annotate_rb/core.rb +3 -3
  14. data/lib/annotate_rb/helper.rb +16 -0
  15. data/lib/annotate_rb/model_annotator/{annotation_generator.rb → annotation_builder.rb} +18 -14
  16. data/lib/annotate_rb/model_annotator/annotation_decider.rb +10 -12
  17. data/lib/annotate_rb/model_annotator/annotation_diff.rb +1 -1
  18. data/lib/annotate_rb/model_annotator/annotation_diff_generator.rb +9 -9
  19. data/lib/annotate_rb/model_annotator/annotation_pattern_generator.rb +3 -3
  20. data/lib/annotate_rb/model_annotator/annotator.rb +12 -53
  21. data/lib/annotate_rb/model_annotator/column_annotation/annotation_builder.rb +135 -0
  22. data/lib/annotate_rb/model_annotator/column_annotation/attributes_builder.rb +104 -0
  23. data/lib/annotate_rb/model_annotator/column_annotation/column_wrapper.rb +103 -0
  24. data/lib/annotate_rb/model_annotator/column_annotation/type_builder.rb +54 -0
  25. data/lib/annotate_rb/model_annotator/column_annotation.rb +12 -0
  26. data/lib/annotate_rb/model_annotator/file_builder.rb +58 -0
  27. data/lib/annotate_rb/model_annotator/file_components.rb +78 -0
  28. data/lib/annotate_rb/model_annotator/file_name_resolver.rb +3 -3
  29. data/lib/annotate_rb/model_annotator/foreign_key_annotation/annotation_builder.rb +57 -0
  30. data/lib/annotate_rb/model_annotator/foreign_key_annotation.rb +9 -0
  31. data/lib/annotate_rb/model_annotator/index_annotation/annotation_builder.rb +113 -0
  32. data/lib/annotate_rb/model_annotator/index_annotation.rb +9 -0
  33. data/lib/annotate_rb/model_annotator/magic_comment_parser.rb +32 -0
  34. data/lib/annotate_rb/model_annotator/model_class_getter.rb +6 -6
  35. data/lib/annotate_rb/model_annotator/model_files_getter.rb +12 -10
  36. data/lib/annotate_rb/model_annotator/model_wrapper.rb +44 -37
  37. data/lib/annotate_rb/model_annotator/pattern_getter.rb +142 -10
  38. data/lib/annotate_rb/model_annotator/project_annotation_remover.rb +65 -0
  39. data/lib/annotate_rb/model_annotator/project_annotator.rb +63 -0
  40. data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +16 -18
  41. data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +37 -0
  42. data/lib/annotate_rb/model_annotator/single_file_annotator.rb +49 -0
  43. data/lib/annotate_rb/model_annotator/{file_annotator_instruction.rb → single_file_annotator_instruction.rb} +2 -2
  44. data/lib/annotate_rb/model_annotator/single_file_remove_annotation_instruction.rb +15 -0
  45. data/lib/annotate_rb/model_annotator.rb +25 -26
  46. data/lib/annotate_rb/options.rb +20 -25
  47. data/lib/annotate_rb/parser.rb +150 -142
  48. data/lib/annotate_rb/rake_bootstrapper.rb +8 -8
  49. data/lib/annotate_rb/route_annotator/annotation_processor.rb +7 -8
  50. data/lib/annotate_rb/route_annotator/annotator.rb +2 -2
  51. data/lib/annotate_rb/route_annotator/base_processor.rb +3 -3
  52. data/lib/annotate_rb/route_annotator/header_generator.rb +15 -15
  53. data/lib/annotate_rb/route_annotator/helper.rb +9 -9
  54. data/lib/annotate_rb/route_annotator/removal_processor.rb +4 -4
  55. data/lib/annotate_rb/route_annotator.rb +6 -6
  56. data/lib/annotate_rb/runner.rb +0 -4
  57. data/lib/annotate_rb/tasks/annotate_models_migrate.rake +5 -5
  58. data/lib/annotate_rb.rb +19 -19
  59. data/lib/generators/annotate_rb/install/install_generator.rb +3 -2
  60. data/lib/generators/annotate_rb/install/templates/annotate_rb.rake +1 -1
  61. metadata +22 -16
  62. data/lib/annotate_rb/model_annotator/column_annotation_builder.rb +0 -92
  63. data/lib/annotate_rb/model_annotator/column_attributes_builder.rb +0 -102
  64. data/lib/annotate_rb/model_annotator/column_type_builder.rb +0 -51
  65. data/lib/annotate_rb/model_annotator/column_wrapper.rb +0 -84
  66. data/lib/annotate_rb/model_annotator/constants.rb +0 -22
  67. data/lib/annotate_rb/model_annotator/file_annotation_remover.rb +0 -25
  68. data/lib/annotate_rb/model_annotator/file_annotator.rb +0 -77
  69. data/lib/annotate_rb/model_annotator/file_patterns.rb +0 -129
  70. data/lib/annotate_rb/model_annotator/foreign_key_annotation_builder.rb +0 -55
  71. data/lib/annotate_rb/model_annotator/helper.rb +0 -107
  72. data/lib/annotate_rb/model_annotator/index_annotation_builder.rb +0 -74
  73. data/lib/annotate_rb/model_annotator/model_file_annotator.rb +0 -55
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8888511eb71e6d0c45eadf9f562767868adf7cb9f2c5c58d6eb3458a65dfdc31
4
- data.tar.gz: 51d25d56e5068979a09d4562e7018b0272f8f73e952941a4f66faece7408cc11
3
+ metadata.gz: 5864a6030a7b4cfbf7751761c07136690ebafe15393d67147789f70319036205
4
+ data.tar.gz: a1dc2b99206b342bbd0dbc66795db4156abddfee307acecf6c2c383e8dbe89b1
5
5
  SHA512:
6
- metadata.gz: 9b878bfc48836e52fe762c547870b67619427772e54efd28835e8699371dc60fdb5511649d9f2bf39431541a9b07f8e32188469526dd109553f71badedd6ec45
7
- data.tar.gz: df69b71c4c10cc046ebd6cf0a21391262b90e0bcffe19556b59214d7658623fa323a7adbf24e711726bb685377e47596d9b95fed9c2425f22f4877264eed97d8
6
+ metadata.gz: b7cbd03e31fdc24f27d23d700773c157eca461078cddcd87739605980d6f5f07887b59f345ef41d91994547d8efbc2b82595e454f9e4619a5fe4e0fb506d29cd
7
+ data.tar.gz: f162544608cce0746a92250287ca4a5c7d25d151fe5bfe8bf4d18075834e98ce68939dc8b176dbe97d16f1f039a1a001cbb71066b26280f9fb5e83df763ba158
data/CHANGELOG.md CHANGED
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased](https://github.com/drwl/annotaterb/tree/HEAD)
4
+
5
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.1.1...HEAD)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Specify `standard` gem version [\#39](https://github.com/drwl/annotaterb/pull/39) ([drwl](https://github.com/drwl))
10
+ - Bump version to v4.2.0 [\#37](https://github.com/drwl/annotaterb/pull/37) ([drwl](https://github.com/drwl))
11
+ - Generate changelog for 4.2 [\#36](https://github.com/drwl/annotaterb/pull/36) ([drwl](https://github.com/drwl))
12
+ - Improve tests for `ColumnAnnotation::*` [\#35](https://github.com/drwl/annotaterb/pull/35) ([drwl](https://github.com/drwl))
13
+ - Change instances of `Options.from` =\> `Options.new` in tests [\#34](https://github.com/drwl/annotaterb/pull/34) ([drwl](https://github.com/drwl))
14
+ - Add `Standard` linter to project [\#33](https://github.com/drwl/annotaterb/pull/33) ([drwl](https://github.com/drwl))
15
+ - Support Sorbet `typed` magic comment [\#32](https://github.com/drwl/annotaterb/pull/32) ([drwl](https://github.com/drwl))
16
+ - Add `position_in_additional_file_patterns` to Options and Parser [\#31](https://github.com/drwl/annotaterb/pull/31) ([drwl](https://github.com/drwl))
17
+ - Remove `Files` gem as a dependency [\#30](https://github.com/drwl/annotaterb/pull/30) ([drwl](https://github.com/drwl))
18
+ - Refactor `ModelAnnotator` again [\#28](https://github.com/drwl/annotaterb/pull/28) ([drwl](https://github.com/drwl))
19
+ - Add initial change log [\#27](https://github.com/drwl/annotaterb/pull/27) ([drwl](https://github.com/drwl))
20
+
21
+ ## [v4.1.1](https://github.com/drwl/annotaterb/tree/v4.1.1) (2023-05-20)
22
+
23
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.1.0...v4.1.1)
24
+
25
+ **Merged pull requests:**
26
+
27
+ - Bump version to v4.1.1 [\#26](https://github.com/drwl/annotaterb/pull/26) ([drwl](https://github.com/drwl))
28
+ - Tidy the github repo [\#25](https://github.com/drwl/annotaterb/pull/25) ([drwl](https://github.com/drwl))
29
+ - Add guide for migrating from Annotate gem [\#24](https://github.com/drwl/annotaterb/pull/24) ([drwl](https://github.com/drwl))
30
+ - Update column pattern regex to incorporate special column comments [\#23](https://github.com/drwl/annotaterb/pull/23) ([drwl](https://github.com/drwl))
31
+
32
+ ## [v4.1.0](https://github.com/drwl/annotaterb/tree/v4.1.0) (2023-05-17)
33
+
34
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/v4.0.0...v4.1.0)
35
+
36
+ **Merged pull requests:**
37
+
38
+ - Bump version to 4.1.0 [\#22](https://github.com/drwl/annotaterb/pull/22) ([drwl](https://github.com/drwl))
39
+ - Refactor ModelAnnotator; Fix instances of incorrect `exclude_*` keys [\#21](https://github.com/drwl/annotaterb/pull/21) ([drwl](https://github.com/drwl))
40
+ - Fix the default behavior for model annotator [\#20](https://github.com/drwl/annotaterb/pull/20) ([drwl](https://github.com/drwl))
41
+ - Refactor model annotator [\#19](https://github.com/drwl/annotaterb/pull/19) ([drwl](https://github.com/drwl))
42
+ - Removed unused helper methods and `Env` class [\#18](https://github.com/drwl/annotaterb/pull/18) ([drwl](https://github.com/drwl))
43
+ - Update dummy app depdencies [\#17](https://github.com/drwl/annotaterb/pull/17) ([drwl](https://github.com/drwl))
44
+
45
+ ## [v4.0.0](https://github.com/drwl/annotaterb/tree/v4.0.0) (2023-05-03)
46
+
47
+ [Full Changelog](https://github.com/drwl/annotaterb/compare/1da0386bf9e1ca3fbd0d9d3ae69cdc7a8cdc26fa...v4.0.0)
48
+
49
+ **Merged pull requests:**
50
+
51
+ - Last project polish for 4.0.0 release [\#14](https://github.com/drwl/annotaterb/pull/14) ([drwl](https://github.com/drwl))
52
+ - Add configuration instructions to README [\#13](https://github.com/drwl/annotaterb/pull/13) ([drwl](https://github.com/drwl))
53
+ - Prepare gem for beta release [\#12](https://github.com/drwl/annotaterb/pull/12) ([drwl](https://github.com/drwl))
54
+ - Make annotaterb usable [\#11](https://github.com/drwl/annotaterb/pull/11) ([drwl](https://github.com/drwl))
55
+ - Move old annotate code into AnnotateRb namespace [\#10](https://github.com/drwl/annotaterb/pull/10) ([drwl](https://github.com/drwl))
56
+ - Fix CodeQL action [\#9](https://github.com/drwl/annotaterb/pull/9) ([drwl](https://github.com/drwl))
57
+ - Regularly run CI [\#8](https://github.com/drwl/annotaterb/pull/8) ([drwl](https://github.com/drwl))
58
+ - Get CI consistently green [\#7](https://github.com/drwl/annotaterb/pull/7) ([drwl](https://github.com/drwl))
59
+ - More work [\#6](https://github.com/drwl/annotaterb/pull/6) ([drwl](https://github.com/drwl))
60
+ - Make CI green [\#5](https://github.com/drwl/annotaterb/pull/5) ([drwl](https://github.com/drwl))
61
+ - Make it work for Rails 7 [\#4](https://github.com/drwl/annotaterb/pull/4) ([drwl](https://github.com/drwl))
62
+ - Tidy up project [\#3](https://github.com/drwl/annotaterb/pull/3) ([drwl](https://github.com/drwl))
63
+ - Set spec run order to random [\#2](https://github.com/drwl/annotaterb/pull/2) ([drwl](https://github.com/drwl))
64
+ - Tidy rspec configuration [\#1](https://github.com/drwl/annotaterb/pull/1) ([drwl](https://github.com/drwl))
65
+
66
+
67
+
68
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.1.1
1
+ 4.2.0
data/exe/annotaterb CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- unless File.exist?('./Rakefile') || File.exist?('./Gemfile')
5
- abort 'Please run annotaterb from the root of the project.'
4
+ unless File.exist?("./Rakefile") || File.exist?("./Gemfile")
5
+ abort "Please run annotaterb from the root of the project."
6
6
  end
7
7
 
8
8
  begin
9
- require 'bundler'
9
+ require "bundler"
10
10
  Bundler.setup
11
- rescue StandardError
11
+ rescue
12
12
  end
13
13
 
14
14
  $LOAD_PATH.unshift("#{__dir__}/../lib")
15
15
 
16
- require 'annotate_rb'
16
+ require "annotate_rb"
17
17
 
18
- exit_status = ::AnnotateRb::Runner.run(ARGV)
18
+ _exit_status = ::AnnotateRb::Runner.run(ARGV)
19
19
 
20
20
  # TODO: Return exit status
21
- # exit exit_status
21
+ # exit exit_status
@@ -1,5 +1,6 @@
1
1
  # monkey patches
2
2
 
3
+ # standard:disable Style/MissingRespondToMissing
3
4
  module ::ActiveRecord
4
5
  class Base
5
6
  def self.method_missing(_name, *_args)
@@ -7,3 +8,4 @@ module ::ActiveRecord
7
8
  end
8
9
  end
9
10
  end
11
+ # standard:enable Style/MissingRespondToMissing
@@ -19,4 +19,3 @@ module AnnotateRb
19
19
  end
20
20
  end
21
21
  end
22
-
@@ -16,4 +16,3 @@ module AnnotateRb
16
16
  end
17
17
  end
18
18
  end
19
-
@@ -13,4 +13,3 @@ module AnnotateRb
13
13
  end
14
14
  end
15
15
  end
16
-
@@ -9,4 +9,3 @@ module AnnotateRb
9
9
  end
10
10
  end
11
11
  end
12
-
@@ -2,9 +2,9 @@
2
2
 
3
3
  module AnnotateRb
4
4
  module Commands
5
- autoload :PrintVersion, 'annotate_rb/commands/print_version'
6
- autoload :PrintHelp, 'annotate_rb/commands/print_help'
7
- autoload :AnnotateModels, 'annotate_rb/commands/annotate_models'
8
- autoload :AnnotateRoutes, 'annotate_rb/commands/annotate_routes'
5
+ autoload :PrintVersion, "annotate_rb/commands/print_version"
6
+ autoload :PrintHelp, "annotate_rb/commands/print_help"
7
+ autoload :AnnotateModels, "annotate_rb/commands/annotate_models"
8
+ autoload :AnnotateRoutes, "annotate_rb/commands/annotate_routes"
9
9
  end
10
10
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module AnnotateRb
4
4
  class ConfigFinder
5
- DOTFILE = '.annotaterb.yml'
5
+ DOTFILE = ".annotaterb.yml"
6
6
 
7
7
  class << self
8
8
  def find_project_root
@@ -44,9 +44,9 @@ module AnnotateRb
44
44
  # Method from Rubocop::ConfigLoader
45
45
  def yaml_safe_load(yaml_code, filename)
46
46
  yaml_safe_load!(yaml_code, filename)
47
- rescue ::StandardError
47
+ rescue
48
48
  if defined?(::SafeYAML)
49
- raise 'SafeYAML is unmaintained, no longer needed and should be removed'
49
+ raise "SafeYAML is unmaintained, no longer needed and should be removed"
50
50
  end
51
51
 
52
52
  raise
@@ -4,13 +4,13 @@ module AnnotateRb
4
4
  module Core
5
5
  class << self
6
6
  def version
7
- @version ||= File.read(File.expand_path('../../VERSION', __dir__)).strip
7
+ @version ||= File.read(File.expand_path("../../VERSION", __dir__)).strip
8
8
  end
9
9
 
10
10
  def load_rake_tasks
11
11
  return if @load_rake_tasks
12
12
 
13
- rake_tasks = Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')]
13
+ rake_tasks = Dir[File.join(File.dirname(__FILE__), "tasks", "**/*.rake")]
14
14
 
15
15
  rake_tasks.each do |task|
16
16
  load task
@@ -20,4 +20,4 @@ module AnnotateRb
20
20
  end
21
21
  end
22
22
  end
23
- end
23
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module Helper
5
+ class << self
6
+ def width(string)
7
+ string.chars.inject(0) { |acc, elem| acc + ((elem.bytesize == 3) ? 2 : 1) }
8
+ end
9
+
10
+ # TODO: Find another implementation that doesn't depend on ActiveSupport
11
+ def fallback(*args)
12
+ args.compact.detect(&:present?)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module AnnotateRb
4
4
  module ModelAnnotator
5
- class AnnotationGenerator
5
+ class AnnotationBuilder
6
6
  # Annotate Models plugin use this header
7
- PREFIX = '== Schema Information'.freeze
8
- PREFIX_MD = '## Schema Information'.freeze
7
+ PREFIX = "== Schema Information"
8
+ PREFIX_MD = "## Schema Information"
9
9
 
10
- END_MARK = '== Schema Information End'.freeze
10
+ END_MARK = "== Schema Information End"
11
11
 
12
12
  MD_NAMES_OVERHEAD = 6
13
13
  MD_TYPE_ALLOWANCE = 18
@@ -18,7 +18,7 @@ module AnnotateRb
18
18
  @info = "" # TODO: Make array and build string that way
19
19
  end
20
20
 
21
- def generate
21
+ def build
22
22
  @info = "# #{header}\n"
23
23
  @info += schema_header_text
24
24
 
@@ -26,22 +26,22 @@ module AnnotateRb
26
26
 
27
27
  if @options[:format_markdown]
28
28
  @info += format("# %-#{max_size + MD_NAMES_OVERHEAD}.#{max_size + MD_NAMES_OVERHEAD}s | %-#{MD_TYPE_ALLOWANCE}.#{MD_TYPE_ALLOWANCE}s | %s\n",
29
- 'Name',
30
- 'Type',
31
- 'Attributes')
32
- @info += "# #{'-' * (max_size + MD_NAMES_OVERHEAD)} | #{'-' * MD_TYPE_ALLOWANCE} | #{'-' * 27}\n"
29
+ "Name",
30
+ "Type",
31
+ "Attributes")
32
+ @info += "# #{"-" * (max_size + MD_NAMES_OVERHEAD)} | #{"-" * MD_TYPE_ALLOWANCE} | #{"-" * 27}\n"
33
33
  end
34
34
 
35
35
  @info += @model.columns.map do |col|
36
- ColumnAnnotationBuilder.new(col, @model, max_size, @options).build
36
+ ColumnAnnotation::AnnotationBuilder.new(col, @model, max_size, @options).build
37
37
  end.join
38
38
 
39
39
  if @options[:show_indexes] && @model.table_exists?
40
- @info += IndexAnnotationBuilder.new(@model, @options).build
40
+ @info += IndexAnnotation::AnnotationBuilder.new(@model, @options).build
41
41
  end
42
42
 
43
43
  if @options[:show_foreign_keys] && @model.table_exists?
44
- @info += ForeignKeyAnnotationBuilder.new(@model, @options).build
44
+ @info += ForeignKeyAnnotation::AnnotationBuilder.new(@model, @options).build
45
45
  end
46
46
 
47
47
  @info += schema_footer_text
@@ -51,7 +51,11 @@ module AnnotateRb
51
51
 
52
52
  def header
53
53
  header = @options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
54
- version = ActiveRecord::Migrator.current_version rescue 0
54
+ version = begin
55
+ ActiveRecord::Migrator.current_version
56
+ rescue
57
+ 0
58
+ end
55
59
 
56
60
  if @options[:include_version] && version > 0
57
61
  header += "\n# Schema version: #{version}"
@@ -91,4 +95,4 @@ module AnnotateRb
91
95
  end
92
96
  end
93
97
  end
94
- end
98
+ end
@@ -4,6 +4,8 @@ module AnnotateRb
4
4
  module ModelAnnotator
5
5
  # Class that encapsulates the logic to decide whether to annotate a model file and its related files or not.
6
6
  class AnnotationDecider
7
+ SKIP_ANNOTATION_PREFIX = '# -\*- SkipSchemaAnnotations'
8
+
7
9
  def initialize(file, options)
8
10
  @file = file
9
11
  @options = options
@@ -35,12 +37,12 @@ module AnnotateRb
35
37
  return to_annotate
36
38
  rescue BadModelFileError => e
37
39
  unless @options[:ignore_unknown_models]
38
- $stderr.puts "Unable to annotate #{@file}: #{e.message}"
39
- $stderr.puts "\t" + e.backtrace.join("\n\t") if @options[:trace]
40
+ warn "Unable to process #{@file}: #{e.message}"
41
+ warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
40
42
  end
41
- rescue StandardError => e
42
- $stderr.puts "Unable to annotate #{@file}: #{e.message}"
43
- $stderr.puts "\t" + e.backtrace.join("\n\t") if @options[:trace]
43
+ rescue => e
44
+ warn "Unable to process #{@file}: #{e.message}"
45
+ warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
44
46
  end
45
47
 
46
48
  false
@@ -49,14 +51,10 @@ module AnnotateRb
49
51
  private
50
52
 
51
53
  def file_contains_skip_annotation
52
- file_string = File.exist?(@file) ? File.read(@file) : ''
54
+ file_string = File.exist?(@file) ? File.read(@file) : ""
53
55
 
54
- if /#{Constants::SKIP_ANNOTATION_PREFIX}.*/ =~ file_string
55
- true
56
- else
57
- false
58
- end
56
+ /#{SKIP_ANNOTATION_PREFIX}.*/o.match?(file_string)
59
57
  end
60
58
  end
61
59
  end
62
- end
60
+ end
@@ -16,4 +16,4 @@ module AnnotateRb
16
16
  end
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -4,8 +4,8 @@ module AnnotateRb
4
4
  module ModelAnnotator
5
5
  # Compares the current file content and new annotation block and generates the column annotation differences
6
6
  class AnnotationDiffGenerator
7
- HEADER_PATTERN = /(^# Table name:.*?\n(#.*[\r]?\n)*[\r]?)/.freeze
8
- COLUMN_PATTERN = /^#[\t ]+[\w\*\.`\[\]():]+[\t ]+.+$/.freeze
7
+ HEADER_PATTERN = /(^# Table name:.*?\n(#.*\r?\n)*\r?)/
8
+ COLUMN_PATTERN = /^#[\t ]+[\w*.`\[\]():]+[\t ]+.+$/
9
9
 
10
10
  class << self
11
11
  def call(file_content, annotation_block)
@@ -25,20 +25,20 @@ module AnnotateRb
25
25
  current_annotations = @file_content.match(HEADER_PATTERN).to_s
26
26
  new_annotations = @annotation_block.match(HEADER_PATTERN).to_s
27
27
 
28
- if current_annotations.present?
29
- current_annotation_columns = current_annotations.scan(COLUMN_PATTERN).sort
28
+ current_annotation_columns = if current_annotations.present?
29
+ current_annotations.scan(COLUMN_PATTERN).sort
30
30
  else
31
- current_annotation_columns = []
31
+ []
32
32
  end
33
33
 
34
- if new_annotations.present?
35
- new_annotation_columns = new_annotations.scan(COLUMN_PATTERN).sort
34
+ new_annotation_columns = if new_annotations.present?
35
+ new_annotations.scan(COLUMN_PATTERN).sort
36
36
  else
37
- new_annotation_columns = []
37
+ []
38
38
  end
39
39
 
40
40
  _result = AnnotationDiff.new(current_annotation_columns, new_annotation_columns)
41
41
  end
42
42
  end
43
43
  end
44
- end
44
+ end
@@ -3,15 +3,15 @@
3
3
  module AnnotateRb
4
4
  module ModelAnnotator
5
5
  class AnnotationPatternGenerator
6
- COMPAT_PREFIX = '== Schema Info'.freeze
7
- COMPAT_PREFIX_MD = '## Schema Info'.freeze
6
+ COMPAT_PREFIX = "== Schema Info"
7
+ COMPAT_PREFIX_MD = "## Schema Info"
8
8
 
9
9
  class << self
10
10
  def call(options = Options.from({}))
11
11
  if options[:wrapper_open]
12
12
  return /(?:^(\n|\r\n)?# (?:#{options[:wrapper_open]}).*(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*)|^(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*/
13
13
  end
14
- /^(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*/
14
+ /^(\n|\r\n)?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?(\n|\r\n)(#.*(\n|\r\n))*(\n|\r\n)*/o
15
15
  end
16
16
  end
17
17
  end
@@ -5,66 +5,25 @@ module AnnotateRb
5
5
  class Annotator
6
6
  class << self
7
7
  def do_annotations(options = {})
8
- annotated = []
9
-
10
- model_files_to_consider = ModelFilesGetter.call(options)
11
-
12
- model_files_to_consider.each do |path, filename|
13
- file = File.join(path, filename)
14
-
15
- if AnnotationDecider.new(file, options).annotate?
16
- ModelFileAnnotator.call(annotated, file, options)
17
- end
18
- end
19
-
20
- if annotated.empty?
21
- puts 'Model files unchanged.'
22
- else
23
- puts "Annotated (#{annotated.length}): #{annotated.join(', ')}"
24
- end
8
+ new(options).do_annotations
25
9
  end
26
10
 
27
11
  def remove_annotations(options = {})
28
- deannotated = []
29
-
30
- model_files_to_consider = ModelFilesGetter.call(options)
31
-
32
- model_files_to_consider.each do |path, filename|
33
- deannotated_klass = false
34
- file = File.join(path, filename)
35
-
36
- begin
37
- klass = ModelClassGetter.call(file, options)
38
- if klass < ActiveRecord::Base && !klass.abstract_class?
39
- model_name = klass.name.underscore
40
- table_name = klass.table_name
41
-
42
- if FileAnnotationRemover.call(file, options)
43
- deannotated_klass = true
44
- end
45
-
46
- related_files = RelatedFilesListBuilder.new(file, model_name, table_name, options).build
12
+ new(options).remove_annotations
13
+ end
14
+ end
47
15
 
48
- related_files.each do |f, _position_key|
49
- if File.exist?(f)
50
- FileAnnotationRemover.call(f, options)
51
- end
52
- end
53
- end
16
+ def initialize(options)
17
+ @options = options
18
+ end
54
19
 
55
- if deannotated_klass
56
- deannotated << klass
57
- end
58
- rescue StandardError => e
59
- $stderr.puts "Unable to deannotate #{File.join(file)}: #{e.message}"
60
- $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
61
- end
62
- end
20
+ def do_annotations
21
+ ProjectAnnotator.new(@options).annotate
22
+ end
63
23
 
64
- puts "Removed annotations from: #{deannotated.join(', ')}"
65
- end
24
+ def remove_annotations
25
+ ProjectAnnotationRemover.new(@options).remove_annotations
66
26
  end
67
27
  end
68
28
  end
69
29
  end
70
-
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ module ColumnAnnotation
6
+ class AnnotationBuilder
7
+ BARE_TYPE_ALLOWANCE = 16
8
+ MD_TYPE_ALLOWANCE = 18
9
+
10
+ def initialize(column, model, max_size, options)
11
+ @column = column
12
+ @model = model
13
+ @max_size = max_size
14
+ @options = options
15
+ end
16
+
17
+ def build
18
+ result = ""
19
+
20
+ is_primary_key = is_column_primary_key?(@model, @column.name)
21
+
22
+ table_indices = @model.retrieve_indexes_from_table
23
+ column_indices = table_indices.select { |ind| ind.columns.include?(@column.name) }
24
+
25
+ column_attributes = AttributesBuilder.new(@column, @options, is_primary_key, column_indices).build
26
+ formatted_column_type = TypeBuilder.new(@column, @options).build
27
+
28
+ col_name = if @model.with_comments? && @column.comment
29
+ "#{@column.name}(#{@column.comment.gsub(/\n/, '\\n')})"
30
+ else
31
+ @column.name
32
+ end
33
+
34
+ result += if @options[:format_rdoc]
35
+ format_rdoc(col_name, @max_size, formatted_column_type, column_attributes)
36
+ elsif @options[:format_yard]
37
+ format_yard(col_name, @max_size, formatted_column_type, column_attributes)
38
+ elsif @options[:format_markdown]
39
+ format_markdown(col_name, @max_size, formatted_column_type, column_attributes)
40
+ else
41
+ format_default(col_name, @max_size, formatted_column_type, column_attributes)
42
+ end
43
+
44
+ result
45
+ end
46
+
47
+ private
48
+
49
+ def non_ascii_length(string)
50
+ string.to_s.chars.count { |element| !element.ascii_only? }
51
+ end
52
+
53
+ def mb_chars_ljust(string, length)
54
+ string = string.to_s
55
+ padding = length - Helper.width(string)
56
+ if padding.positive?
57
+ string + (" " * padding)
58
+ else
59
+ string[0..(length - 1)]
60
+ end
61
+ end
62
+
63
+ def map_col_type_to_ruby_classes(col_type)
64
+ case col_type
65
+ when "integer" then Integer.to_s
66
+ when "float" then Float.to_s
67
+ when "decimal" then BigDecimal.to_s
68
+ when "datetime", "timestamp", "time" then Time.to_s
69
+ when "date" then Date.to_s
70
+ when "text", "string", "binary", "inet", "uuid" then String.to_s
71
+ when "json", "jsonb" then Hash.to_s
72
+ when "boolean" then "Boolean"
73
+ end
74
+ end
75
+
76
+ def format_rdoc(col_name, max_size, formatted_column_type, column_attributes)
77
+ format("# %-#{max_size}.#{max_size}s<tt>%s</tt>",
78
+ "*#{col_name}*::",
79
+ column_attributes.unshift(formatted_column_type).join(", ")).rstrip + "\n"
80
+ end
81
+
82
+ def format_yard(col_name, _max_size, formatted_column_type, _column_attributes)
83
+ res = ""
84
+ res += sprintf("# @!attribute #{col_name}") + "\n"
85
+
86
+ ruby_class = if @column.respond_to?(:array) && @column.array
87
+ "Array<#{map_col_type_to_ruby_classes(formatted_column_type)}>"
88
+ else
89
+ map_col_type_to_ruby_classes(formatted_column_type)
90
+ end
91
+
92
+ res += sprintf("# @return [#{ruby_class}]") + "\n"
93
+
94
+ res
95
+ end
96
+
97
+ def format_markdown(col_name, max_size, formatted_column_type, column_attributes)
98
+ name_remainder = max_size - col_name.length - non_ascii_length(col_name)
99
+ type_remainder = (MD_TYPE_ALLOWANCE - 2) - formatted_column_type.length
100
+
101
+ format("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`",
102
+ col_name,
103
+ " ",
104
+ formatted_column_type,
105
+ " ",
106
+ column_attributes.join(", ").rstrip).gsub("``", " ").rstrip + "\n"
107
+ end
108
+
109
+ def format_default(col_name, max_size, formatted_column_type, column_attributes)
110
+ format("# %s:%s %s",
111
+ mb_chars_ljust(col_name, max_size),
112
+ mb_chars_ljust(formatted_column_type, BARE_TYPE_ALLOWANCE),
113
+ column_attributes.join(", ")).rstrip + "\n"
114
+ end
115
+
116
+ # TODO: Simplify this conditional
117
+ def is_column_primary_key?(model, column_name)
118
+ if model.primary_key
119
+ if model.primary_key.is_a?(Array)
120
+ # If the model has multiple primary keys, check if this column is one of them
121
+ if model.primary_key.collect(&:to_sym).include?(column_name.to_sym)
122
+ return true
123
+ end
124
+ elsif column_name.to_sym == model.primary_key.to_sym
125
+ # If model has 1 primary key, check if this column is it
126
+ return true
127
+ end
128
+ end
129
+
130
+ false
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end