annotaterb 4.4.1 → 4.6.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 +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +29 -0
- data/VERSION +1 -1
- data/lib/annotate_rb/config_generator.rb +28 -0
- data/lib/annotate_rb/eager_loader.rb +6 -2
- data/lib/annotate_rb/model_annotator/annotated_file/generator.rb +92 -0
- data/lib/annotate_rb/model_annotator/annotated_file/updater.rb +46 -0
- data/lib/annotate_rb/model_annotator/annotated_file.rb +10 -0
- data/lib/annotate_rb/model_annotator/annotator.rb +2 -2
- data/lib/annotate_rb/model_annotator/file_name_resolver.rb +5 -0
- data/lib/annotate_rb/model_annotator/file_parser/annotation_finder.rb +103 -0
- data/lib/annotate_rb/model_annotator/file_parser/custom_parser.rb +217 -0
- data/lib/annotate_rb/model_annotator/file_parser/parsed_file.rb +94 -0
- data/lib/annotate_rb/model_annotator/file_parser/parsed_file_result.rb +54 -0
- data/lib/annotate_rb/model_annotator/file_parser.rb +12 -0
- data/lib/annotate_rb/model_annotator/model_class_getter.rb +7 -0
- data/lib/annotate_rb/model_annotator/model_files_getter.rb +4 -8
- data/lib/annotate_rb/model_annotator/model_wrapper.rb +11 -2
- data/lib/annotate_rb/model_annotator/pattern_getter.rb +2 -0
- data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +3 -3
- data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +10 -12
- data/lib/annotate_rb/model_annotator/single_file_annotator.rb +15 -8
- data/lib/annotate_rb/model_annotator/single_file_annotator_instruction.rb +1 -1
- data/lib/annotate_rb/model_annotator/single_file_remove_annotation_instruction.rb +1 -1
- data/lib/annotate_rb/model_annotator/zeitwerk_class_getter.rb +113 -0
- data/lib/annotate_rb/model_annotator.rb +3 -4
- data/lib/annotate_rb/options.rb +4 -0
- data/lib/annotate_rb/parser.rb +9 -3
- data/lib/annotate_rb/runner.rb +5 -4
- data/lib/annotate_rb/tasks/annotate_models_migrate.rake +5 -0
- data/lib/annotate_rb.rb +1 -0
- data/lib/generators/annotate_rb/config/USAGE +6 -0
- data/lib/generators/annotate_rb/config/config_generator.rb +15 -0
- data/lib/generators/annotate_rb/hook/USAGE +7 -0
- data/lib/generators/annotate_rb/hook/hook_generator.rb +15 -0
- data/lib/generators/annotate_rb/install/install_generator.rb +3 -4
- data/lib/generators/annotate_rb/update_config/USAGE +6 -0
- data/lib/generators/annotate_rb/update_config/update_config_generator.rb +15 -0
- metadata +20 -8
- data/lib/annotate_rb/model_annotator/annotation_pattern_generator.rb +0 -19
- data/lib/annotate_rb/model_annotator/file_builder.rb +0 -57
- data/lib/annotate_rb/model_annotator/file_components.rb +0 -81
- data/lib/annotate_rb/model_annotator/magic_comment_parser.rb +0 -32
- /data/lib/generators/annotate_rb/{install → hook}/templates/annotate_rb.rake +0 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
module FileParser
|
6
|
+
class ParsedFile
|
7
|
+
SKIP_ANNOTATION_STRING = "# -*- SkipSchemaAnnotations"
|
8
|
+
|
9
|
+
def initialize(file_content, new_annotations, options)
|
10
|
+
@file_content = file_content
|
11
|
+
@file_lines = @file_content.lines
|
12
|
+
@new_annotations = new_annotations
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse
|
17
|
+
@finder = AnnotationFinder.new(@file_content, @options[:wrapper_open], @options[:wrapper_close])
|
18
|
+
has_annotations = false
|
19
|
+
|
20
|
+
begin
|
21
|
+
@finder.run
|
22
|
+
has_annotations = @finder.annotated?
|
23
|
+
rescue AnnotationFinder::NoAnnotationFound => _e
|
24
|
+
end
|
25
|
+
|
26
|
+
annotations = if has_annotations
|
27
|
+
@file_lines[(@finder.annotation_start)..(@finder.annotation_end)].join
|
28
|
+
else
|
29
|
+
""
|
30
|
+
end
|
31
|
+
|
32
|
+
@diff = AnnotationDiffGenerator.new(annotations, @new_annotations).generate
|
33
|
+
@file_parser = @finder.parser
|
34
|
+
|
35
|
+
has_skip_string = @file_parser.comments.any? { |comment, _lineno| comment.include?(SKIP_ANNOTATION_STRING) }
|
36
|
+
annotations_changed = @diff.changed?
|
37
|
+
|
38
|
+
has_leading_whitespace = false
|
39
|
+
has_trailing_whitespace = false
|
40
|
+
|
41
|
+
annotations_with_whitespace = if has_annotations
|
42
|
+
begin
|
43
|
+
annotation_start = @finder.annotation_start
|
44
|
+
annotation_end = @finder.annotation_end
|
45
|
+
|
46
|
+
if @file_lines[annotation_start - 1]&.strip&.empty?
|
47
|
+
annotation_start -= 1
|
48
|
+
has_leading_whitespace = true
|
49
|
+
end
|
50
|
+
|
51
|
+
if @file_lines[annotation_end + 1]&.strip&.empty?
|
52
|
+
annotation_end += 1
|
53
|
+
has_trailing_whitespace = true
|
54
|
+
end
|
55
|
+
|
56
|
+
@file_lines[annotation_start..annotation_end].join
|
57
|
+
end
|
58
|
+
else
|
59
|
+
""
|
60
|
+
end
|
61
|
+
|
62
|
+
# :before or :after when it's set
|
63
|
+
annotation_position = nil
|
64
|
+
|
65
|
+
if has_annotations
|
66
|
+
const_declaration = @file_parser.starts.first
|
67
|
+
|
68
|
+
# If the file does not have any class or module declaration then const_declaration can be nil
|
69
|
+
_const, line_number = const_declaration
|
70
|
+
|
71
|
+
if line_number
|
72
|
+
annotation_position = if @finder.annotation_start < line_number
|
73
|
+
:before
|
74
|
+
else
|
75
|
+
:after
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
_result = ParsedFileResult.new(
|
81
|
+
has_annotations: has_annotations,
|
82
|
+
has_skip_string: has_skip_string,
|
83
|
+
annotations_changed: annotations_changed,
|
84
|
+
annotations: annotations,
|
85
|
+
annotations_with_whitespace: annotations_with_whitespace,
|
86
|
+
has_leading_whitespace: has_leading_whitespace,
|
87
|
+
has_trailing_whitespace: has_trailing_whitespace,
|
88
|
+
annotation_position: annotation_position
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
module FileParser
|
6
|
+
class ParsedFileResult
|
7
|
+
def initialize(
|
8
|
+
has_annotations:,
|
9
|
+
has_skip_string:,
|
10
|
+
annotations_changed:,
|
11
|
+
annotations:,
|
12
|
+
annotations_with_whitespace:,
|
13
|
+
has_leading_whitespace:,
|
14
|
+
has_trailing_whitespace:,
|
15
|
+
annotation_position:
|
16
|
+
)
|
17
|
+
@has_annotations = has_annotations
|
18
|
+
@has_skip_string = has_skip_string
|
19
|
+
@annotations_changed = annotations_changed
|
20
|
+
@annotations = annotations
|
21
|
+
@annotations_with_whitespace = annotations_with_whitespace
|
22
|
+
@has_leading_whitespace = has_leading_whitespace
|
23
|
+
@has_trailing_whitespace = has_trailing_whitespace
|
24
|
+
@annotation_position = annotation_position
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :annotations, :annotation_position
|
28
|
+
|
29
|
+
# Returns annotations with new line before and after if they exist
|
30
|
+
attr_reader :annotations_with_whitespace
|
31
|
+
|
32
|
+
def annotations_changed?
|
33
|
+
@annotations_changed
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_annotations?
|
37
|
+
@has_annotations
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_skip_string?
|
41
|
+
@has_skip_string
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_leading_whitespace?
|
45
|
+
@has_leading_whitespace
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_trailing_whitespace?
|
49
|
+
@has_trailing_whitespace
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
module FileParser
|
6
|
+
autoload :AnnotationFinder, "annotate_rb/model_annotator/file_parser/annotation_finder"
|
7
|
+
autoload :CustomParser, "annotate_rb/model_annotator/file_parser/custom_parser"
|
8
|
+
autoload :ParsedFile, "annotate_rb/model_annotator/file_parser/parsed_file"
|
9
|
+
autoload :ParsedFileResult, "annotate_rb/model_annotator/file_parser/parsed_file_result"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -8,6 +8,13 @@ module AnnotateRb
|
|
8
8
|
# Check for namespaced models in subdirectories as well as models
|
9
9
|
# in subdirectories without namespacing.
|
10
10
|
def call(file, options)
|
11
|
+
use_zeitwerk = defined?(::Rails) && ::Rails.try(:autoloaders).try(:zeitwerk_enabled?)
|
12
|
+
|
13
|
+
if use_zeitwerk
|
14
|
+
klass = ZeitwerkClassGetter.call(file, options)
|
15
|
+
return klass if klass
|
16
|
+
end
|
17
|
+
|
11
18
|
model_path = file.gsub(/\.rb$/, "")
|
12
19
|
options[:model_dir].each { |dir| model_path = model_path.gsub(/^#{dir}/, "").gsub(/^\//, "") }
|
13
20
|
|
@@ -9,13 +9,9 @@ module AnnotateRb
|
|
9
9
|
# of model files from root dir. Otherwise we take all the model files
|
10
10
|
# in the model_dir directory.
|
11
11
|
def call(options)
|
12
|
-
model_files =
|
12
|
+
model_files = list_model_files_from_argument(options)
|
13
13
|
|
14
|
-
|
15
|
-
# It's an artifact from the old Annotate gem and how it did control flow.
|
16
|
-
model_files = list_model_files_from_argument(options) if !options[:is_rake]
|
17
|
-
|
18
|
-
return model_files if !model_files.empty?
|
14
|
+
return model_files if model_files.any?
|
19
15
|
|
20
16
|
options[:model_dir].each do |dir|
|
21
17
|
Dir.chdir(dir) do
|
@@ -41,9 +37,9 @@ module AnnotateRb
|
|
41
37
|
private
|
42
38
|
|
43
39
|
def list_model_files_from_argument(options)
|
44
|
-
return [] if
|
40
|
+
return [] if options.get_state(:working_args).empty?
|
45
41
|
|
46
|
-
specified_files =
|
42
|
+
specified_files = options.get_state(:working_args).map { |file| File.expand_path(file) }
|
47
43
|
|
48
44
|
model_files = options[:model_dir].flat_map do |dir|
|
49
45
|
absolute_dir_path = File.expand_path(dir)
|
@@ -6,7 +6,7 @@ module AnnotateRb
|
|
6
6
|
# Should be the wrapper for an ActiveRecord model that serves as the source of truth of the model
|
7
7
|
# of the model that we're annotating
|
8
8
|
|
9
|
-
def initialize(klass, options
|
9
|
+
def initialize(klass, options)
|
10
10
|
@klass = klass
|
11
11
|
@options = options
|
12
12
|
end
|
@@ -115,7 +115,16 @@ module AnnotateRb
|
|
115
115
|
|
116
116
|
# Try to search the table without prefix
|
117
117
|
table_name_without_prefix = table_name.to_s.sub(@klass.table_name_prefix, "")
|
118
|
-
|
118
|
+
begin
|
119
|
+
@klass.connection.indexes(table_name_without_prefix)
|
120
|
+
rescue ActiveRecord::StatementInvalid => _e
|
121
|
+
# Mysql2 adapter behaves differently than Sqlite3 and Postgres adapter.
|
122
|
+
# If `table_name_without_prefix` does not exist, Mysql2 will raise,
|
123
|
+
# the other adapters will return an empty array.
|
124
|
+
#
|
125
|
+
# See: https://github.com/rails/rails/issues/51205
|
126
|
+
[]
|
127
|
+
end
|
119
128
|
end
|
120
129
|
|
121
130
|
def with_comments?
|
@@ -142,6 +142,8 @@ module AnnotateRb
|
|
142
142
|
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
|
143
143
|
File.join(root_directory, FilePatterns::FACTORY_BOT_TEST_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
144
144
|
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
145
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_TEST_DIR, "%PLURALIZED_MODEL_NAME%_factory.rb"), # (new style)
|
146
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_factory.rb"), # (new style)
|
145
147
|
File.join(root_directory, FilePatterns::FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
|
146
148
|
File.join(root_directory, FilePatterns::FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
|
147
149
|
]
|
@@ -24,10 +24,10 @@ module AnnotateRb
|
|
24
24
|
add_related_scaffold_files if !@options[:exclude_scaffolds]
|
25
25
|
add_related_controller_files if !@options[:exclude_controllers]
|
26
26
|
add_related_helper_files if !@options[:exclude_helpers]
|
27
|
-
add_related_admin_files if
|
28
|
-
add_additional_file_patterns if
|
27
|
+
add_related_admin_files if @options[:active_admin]
|
28
|
+
add_additional_file_patterns if @options[:additional_file_patterns].present?
|
29
29
|
|
30
|
-
@list
|
30
|
+
@list.uniq
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -12,20 +12,18 @@ module AnnotateRb
|
|
12
12
|
return false unless File.exist?(file_name)
|
13
13
|
old_content = File.read(file_name)
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
wrapper_open = if options[:wrapper_open]
|
22
|
-
"# #{options[:wrapper_open]}\n"
|
23
|
-
else
|
24
|
-
""
|
15
|
+
begin
|
16
|
+
parsed_file = FileParser::ParsedFile.new(old_content, "", options).parse
|
17
|
+
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
18
|
+
warn "Unable to process #{file_name}: #{e.message}"
|
19
|
+
warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
|
20
|
+
return false
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
return false if !parsed_file.has_annotations?
|
24
|
+
return false if parsed_file.has_skip_string?
|
25
|
+
|
26
|
+
updated_file_content = old_content.sub(parsed_file.annotations_with_whitespace, "")
|
29
27
|
|
30
28
|
File.open(file_name, "wb") { |f| f.puts updated_file_content }
|
31
29
|
|
@@ -21,22 +21,29 @@ module AnnotateRb
|
|
21
21
|
# :position_in_*<Symbol>:: where to place the annotated section in fixture or model file,
|
22
22
|
# :before, :top, :after or :bottom. Default is :before.
|
23
23
|
#
|
24
|
-
def call(file_name, annotation, annotation_position, options
|
24
|
+
def call(file_name, annotation, annotation_position, options)
|
25
25
|
return false unless File.exist?(file_name)
|
26
26
|
old_content = File.read(file_name)
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
begin
|
29
|
+
parsed_file = FileParser::ParsedFile.new(old_content, annotation, options).parse
|
30
|
+
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
31
|
+
warn "Unable to process #{file_name}: #{e.message}"
|
32
|
+
warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
|
33
|
+
return false
|
34
|
+
end
|
30
35
|
|
31
|
-
return false if
|
32
|
-
return false if !
|
36
|
+
return false if parsed_file.has_skip_string?
|
37
|
+
return false if !parsed_file.annotations_changed? && !options[:force]
|
33
38
|
|
34
39
|
abort "AnnotateRb error. #{file_name} needs to be updated, but annotaterb was run with `--frozen`." if options[:frozen]
|
35
40
|
|
36
|
-
updated_file_content = if !
|
37
|
-
|
41
|
+
updated_file_content = if !parsed_file.has_annotations?
|
42
|
+
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, options).generate
|
43
|
+
elsif options[:force]
|
44
|
+
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, options).generate
|
38
45
|
else
|
39
|
-
|
46
|
+
AnnotatedFile::Updater.new(old_content, annotation, annotation_position, options).update
|
40
47
|
end
|
41
48
|
|
42
49
|
File.open(file_name, "wb") { |f| f.puts updated_file_content }
|
@@ -4,7 +4,7 @@ module AnnotateRb
|
|
4
4
|
module ModelAnnotator
|
5
5
|
# A plain old Ruby object (PORO) that contains all necessary information for SingleFileAnnotator
|
6
6
|
class SingleFileAnnotatorInstruction
|
7
|
-
def initialize(file, annotation, position, options
|
7
|
+
def initialize(file, annotation, position, options)
|
8
8
|
@file = file # Path to file
|
9
9
|
@annotation = annotation # Annotation string
|
10
10
|
@position = position # Position in the file where to write the annotation to
|
@@ -4,7 +4,7 @@ module AnnotateRb
|
|
4
4
|
module ModelAnnotator
|
5
5
|
# A plain old Ruby object (PORO) that contains all necessary information for SingleFileAnnotationRemover
|
6
6
|
class SingleFileRemoveAnnotationInstruction
|
7
|
-
def initialize(file, options
|
7
|
+
def initialize(file, options)
|
8
8
|
@file = file # Path to file
|
9
9
|
@options = options
|
10
10
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ZeitwerkClassGetter
|
6
|
+
class << self
|
7
|
+
def call(file, options)
|
8
|
+
new(file, options).call
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(file, options)
|
13
|
+
@file = file
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Constant, nil] Attempts to return the model class constant (e.g. User) defined in the model file
|
18
|
+
# can return `nil` if the file does not define the constant.
|
19
|
+
def call
|
20
|
+
return unless defined?(::Zeitwerk)
|
21
|
+
|
22
|
+
@absolute_file_path = File.expand_path(@file)
|
23
|
+
loader = ::Rails.autoloaders.main
|
24
|
+
|
25
|
+
if supports_cpath?
|
26
|
+
constant_using_cpath(loader)
|
27
|
+
else
|
28
|
+
constant(loader)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def constant(loader)
|
35
|
+
root_dirs = loader.dirs(namespaces: true) # or `root_dirs = loader.root_dirs` with zeitwerk < 2.6.1
|
36
|
+
expanded_file = @absolute_file_path
|
37
|
+
|
38
|
+
# root_dir: "/home/dummyapp/app/models"
|
39
|
+
root_dir, namespace = root_dirs.find do |dir, _namespace|
|
40
|
+
expanded_file.start_with?(dir)
|
41
|
+
end
|
42
|
+
|
43
|
+
# expanded_file: "/home/dummyapp/app/models/collapsed/example/test_model.rb"
|
44
|
+
# filepath_relative_to_root_dir: "/collapsed/example/test_model.rb"
|
45
|
+
_, filepath_relative_to_root_dir = expanded_file.split(root_dir)
|
46
|
+
|
47
|
+
# Remove leading / and the .rb extension
|
48
|
+
filepath_relative_to_root_dir = filepath_relative_to_root_dir[1..].sub(/\.rb$/, "")
|
49
|
+
|
50
|
+
# once we have the filepath_relative_to_root_dir, we need to see if it
|
51
|
+
# falls within one of our Zeitwerk "collapsed" paths.
|
52
|
+
if loader.collapse.any? { |path| path.include?(root_dir) && file.include?(path.split(root_dir)[1]) }
|
53
|
+
# if the file is within a collapsed path, we then need to, for each
|
54
|
+
# collapsed path, remove the root dir
|
55
|
+
collapsed = loader.collapse.map { |path| path.split(root_dir)[1].sub(/^\//, "") }.to_set
|
56
|
+
|
57
|
+
collapsed.each do |collapse|
|
58
|
+
# next, we split the collapsed directory, e.g. `domain_name/models`, by
|
59
|
+
# slash, and discard the domain_name
|
60
|
+
_, *collapsed_namespace = collapse.split("/")
|
61
|
+
|
62
|
+
# if there are any collapsed namespaces, e.g. `models`, we then remove
|
63
|
+
# that from `filepath_relative_to_root_dir`.
|
64
|
+
#
|
65
|
+
# This would result in:
|
66
|
+
#
|
67
|
+
# previous filepath_relative_to_root_dir: domain_name/models/model_name
|
68
|
+
# new filepath_relative_to_root_dir: domain_name/model_name
|
69
|
+
if collapsed_namespace.any?
|
70
|
+
filepath_relative_to_root_dir.sub!("/#{collapsed_namespace.last}", "")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
camelize = loader.inflector.camelize(filepath_relative_to_root_dir, nil)
|
76
|
+
namespace.const_get(camelize)
|
77
|
+
rescue NameError => e
|
78
|
+
warn e
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def constant_using_cpath(loader)
|
83
|
+
begin
|
84
|
+
constant = loader.cpath_expected_at(@absolute_file_path)
|
85
|
+
rescue ::Zeitwerk::Error => e
|
86
|
+
# Raises when file does not exist
|
87
|
+
warn "Zeitwerk unable to find file #{@file}, error:\n#{e.message}"
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
# This uses ActiveSupport::Inflector.constantize
|
93
|
+
klass = constant.constantize
|
94
|
+
rescue NameError => e
|
95
|
+
warn e
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
klass
|
100
|
+
end
|
101
|
+
|
102
|
+
def supports_cpath?
|
103
|
+
@supports_cpath ||=
|
104
|
+
begin
|
105
|
+
current_version = ::Gem::Version.new(::Zeitwerk::VERSION)
|
106
|
+
required_version = ::Gem::Version.new("2.6.9")
|
107
|
+
|
108
|
+
current_version >= required_version
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -7,7 +7,6 @@ module AnnotateRb
|
|
7
7
|
autoload :BadModelFileError, "annotate_rb/model_annotator/bad_model_file_error"
|
8
8
|
autoload :FileNameResolver, "annotate_rb/model_annotator/file_name_resolver"
|
9
9
|
autoload :SingleFileAnnotationRemover, "annotate_rb/model_annotator/single_file_annotation_remover"
|
10
|
-
autoload :AnnotationPatternGenerator, "annotate_rb/model_annotator/annotation_pattern_generator"
|
11
10
|
autoload :ModelClassGetter, "annotate_rb/model_annotator/model_class_getter"
|
12
11
|
autoload :ModelFilesGetter, "annotate_rb/model_annotator/model_files_getter"
|
13
12
|
autoload :SingleFileAnnotator, "annotate_rb/model_annotator/single_file_annotator"
|
@@ -22,10 +21,10 @@ module AnnotateRb
|
|
22
21
|
autoload :SingleFileRemoveAnnotationInstruction, "annotate_rb/model_annotator/single_file_remove_annotation_instruction"
|
23
22
|
autoload :AnnotationDiffGenerator, "annotate_rb/model_annotator/annotation_diff_generator"
|
24
23
|
autoload :AnnotationDiff, "annotate_rb/model_annotator/annotation_diff"
|
25
|
-
autoload :FileBuilder, "annotate_rb/model_annotator/file_builder"
|
26
|
-
autoload :MagicCommentParser, "annotate_rb/model_annotator/magic_comment_parser"
|
27
|
-
autoload :FileComponents, "annotate_rb/model_annotator/file_components"
|
28
24
|
autoload :ProjectAnnotator, "annotate_rb/model_annotator/project_annotator"
|
29
25
|
autoload :ProjectAnnotationRemover, "annotate_rb/model_annotator/project_annotation_remover"
|
26
|
+
autoload :AnnotatedFile, "annotate_rb/model_annotator/annotated_file"
|
27
|
+
autoload :FileParser, "annotate_rb/model_annotator/file_parser"
|
28
|
+
autoload :ZeitwerkClassGetter, "annotate_rb/model_annotator/zeitwerk_class_getter"
|
30
29
|
end
|
31
30
|
end
|
data/lib/annotate_rb/options.rb
CHANGED
data/lib/annotate_rb/parser.rb
CHANGED
@@ -3,7 +3,7 @@ require "optparse"
|
|
3
3
|
module AnnotateRb
|
4
4
|
# Class for handling command line arguments
|
5
5
|
class Parser # rubocop:disable Metrics/ClassLength
|
6
|
-
def self.parse(args, existing_options
|
6
|
+
def self.parse(args, existing_options)
|
7
7
|
new(args, existing_options).parse
|
8
8
|
end
|
9
9
|
|
@@ -35,11 +35,11 @@ module AnnotateRb
|
|
35
35
|
}.freeze
|
36
36
|
|
37
37
|
def initialize(args, existing_options)
|
38
|
-
@args = args
|
38
|
+
@args = args.clone
|
39
39
|
base_options = DEFAULT_OPTIONS.dup
|
40
40
|
@options = base_options.merge(existing_options)
|
41
41
|
@commands = []
|
42
|
-
@options[:original_args] = args.
|
42
|
+
@options[:original_args] = args.clone
|
43
43
|
end
|
44
44
|
|
45
45
|
def parse
|
@@ -52,6 +52,12 @@ module AnnotateRb
|
|
52
52
|
@options
|
53
53
|
end
|
54
54
|
|
55
|
+
def remaining_args
|
56
|
+
# `@args` gets modified throughout the lifecycle of this class.
|
57
|
+
# It starts as a shallow clone of ARGV, then arguments matching commands and options are removed in #parse
|
58
|
+
@args
|
59
|
+
end
|
60
|
+
|
55
61
|
private
|
56
62
|
|
57
63
|
def parse_command(args)
|
data/lib/annotate_rb/runner.rb
CHANGED
@@ -9,14 +9,15 @@ module AnnotateRb
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def run(args)
|
12
|
-
_original_args = args.dup
|
13
|
-
|
14
12
|
config_file_options = ConfigLoader.load_config
|
15
|
-
|
13
|
+
parser = Parser.new(args, {})
|
14
|
+
|
15
|
+
parsed_options = parser.parse
|
16
|
+
remaining_args = parser.remaining_args
|
16
17
|
|
17
18
|
options = config_file_options.merge(parsed_options)
|
18
19
|
|
19
|
-
@options = Options.from(options, {})
|
20
|
+
@options = Options.from(options, {working_args: remaining_args})
|
20
21
|
AnnotateRb::RakeBootstrapper.call(@options)
|
21
22
|
|
22
23
|
if @options[:command]
|
@@ -6,6 +6,11 @@
|
|
6
6
|
|
7
7
|
# Migration tasks are tasks that we'll "hook" into
|
8
8
|
migration_tasks = %w[db:migrate db:migrate:up db:migrate:down db:migrate:reset db:migrate:redo db:rollback]
|
9
|
+
|
10
|
+
# Support for data_migrate gem (https://github.com/ilyakatz/data-migrate)
|
11
|
+
migration_tasks_with_data = migration_tasks.map { |task| "#{task}:with_data" }
|
12
|
+
migration_tasks += migration_tasks_with_data
|
13
|
+
|
9
14
|
if defined?(Rails::Application) && Rails.version.split(".").first.to_i >= 6
|
10
15
|
require "active_record"
|
11
16
|
|
data/lib/annotate_rb.rb
CHANGED
@@ -22,6 +22,7 @@ require_relative "annotate_rb/eager_loader"
|
|
22
22
|
require_relative "annotate_rb/rake_bootstrapper"
|
23
23
|
require_relative "annotate_rb/config_finder"
|
24
24
|
require_relative "annotate_rb/config_loader"
|
25
|
+
require_relative "annotate_rb/config_generator"
|
25
26
|
|
26
27
|
module AnnotateRb
|
27
28
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "annotate_rb"
|
4
|
+
|
5
|
+
module AnnotateRb
|
6
|
+
module Generators
|
7
|
+
class ConfigGenerator < ::Rails::Generators::Base
|
8
|
+
def generate_config
|
9
|
+
create_file ::AnnotateRb::ConfigFinder::DOTFILE do
|
10
|
+
::AnnotateRb::ConfigGenerator.default_config_yml
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "annotate_rb"
|
4
|
+
|
5
|
+
module AnnotateRb
|
6
|
+
module Generators
|
7
|
+
class HookGenerator < ::Rails::Generators::Base
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def copy_hook_file
|
11
|
+
copy_file "annotate_rb.rake", "lib/tasks/annotate_rb.rake"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,10 +5,9 @@ require "annotate_rb"
|
|
5
5
|
module AnnotateRb
|
6
6
|
module Generators
|
7
7
|
class InstallGenerator < ::Rails::Generators::Base
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
copy_file "annotate_rb.rake", "lib/tasks/annotate_rb.rake"
|
8
|
+
def install_hook_and_generate_defaults
|
9
|
+
generate "annotate_rb:hook"
|
10
|
+
generate "annotate_rb:config"
|
12
11
|
end
|
13
12
|
end
|
14
13
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "annotate_rb"
|
4
|
+
|
5
|
+
module AnnotateRb
|
6
|
+
module Generators
|
7
|
+
class UpdateConfigGenerator < ::Rails::Generators::Base
|
8
|
+
def generate_config
|
9
|
+
insert_into_file ::AnnotateRb::ConfigFinder::DOTFILE do
|
10
|
+
::AnnotateRb::ConfigGenerator.unset_config_defaults
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|