annotaterb 4.7.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -4
- data/VERSION +1 -1
- data/lib/annotate_rb/model_annotator/annotated_file/generator.rb +4 -3
- data/lib/annotate_rb/model_annotator/annotated_file/updater.rb +2 -2
- data/lib/annotate_rb/model_annotator/annotation_builder.rb +15 -4
- data/lib/annotate_rb/model_annotator/annotation_decider.rb +4 -0
- data/lib/annotate_rb/model_annotator/check_constraint_annotation/annotation_builder.rb +57 -0
- data/lib/annotate_rb/model_annotator/check_constraint_annotation.rb +9 -0
- data/lib/annotate_rb/model_annotator/file_parser/annotation_finder.rb +2 -4
- data/lib/annotate_rb/model_annotator/file_parser/parsed_file.rb +7 -4
- data/lib/annotate_rb/model_annotator/file_parser/parsed_file_result.rb +6 -2
- data/lib/annotate_rb/model_annotator/file_parser/yml_parser.rb +67 -0
- data/lib/annotate_rb/model_annotator/file_parser.rb +1 -0
- data/lib/annotate_rb/model_annotator/file_to_parser_mapper.rb +25 -0
- data/lib/annotate_rb/model_annotator/pattern_getter.rb +56 -15
- data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +86 -5
- data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +3 -1
- data/lib/annotate_rb/model_annotator/single_file_annotator.rb +6 -4
- data/lib/annotate_rb/model_annotator.rb +2 -0
- data/lib/annotate_rb/options.rb +20 -0
- data/lib/annotate_rb/parser.rb +6 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 255fdc09fbc3848ba6d9306ec84d07c2471491ffbfde2440dc502bc35432a702
|
4
|
+
data.tar.gz: 004c6df59a13ec89bca83190fcb4de77c88435b0a091cd0385e1bc2a1c3f9ae8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff01eaa95eda26cd5a14d30fb93bd2da5cabde3dc2da12cac718c40349a4228963e162162db017461942aa01cffba5ef59ca7c43344c01549a11ee2d6ba189b1
|
7
|
+
data.tar.gz: 4ee46c7c044938e98a883f72daa023ed89f3c2d13548d1986d2353b0f5f034a8eccab3cd8ea4032c80c3d7e3b3f8f093deccc92ef494c81f1c5631be5261d720
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,41 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v4.7.1](https://github.com/drwl/annotaterb/tree/v4.7.1) (2024-05-09)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/drwl/annotaterb/compare/v4.7.0...v4.7.1)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- Check constraint support [\#104](https://github.com/drwl/annotaterb/issues/104)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Bump version to v4.7.1 [\#113](https://github.com/drwl/annotaterb/pull/113) ([drwl](https://github.com/drwl))
|
14
|
+
- Change AnnotationDecider to return false early [\#112](https://github.com/drwl/annotaterb/pull/112) ([drwl](https://github.com/drwl))
|
15
|
+
- Memoize ActiveRecord migrator version calls [\#111](https://github.com/drwl/annotaterb/pull/111) ([drwl](https://github.com/drwl))
|
16
|
+
- Fix misspelling in migration guide [\#109](https://github.com/drwl/annotaterb/pull/109) ([RobinDaugherty](https://github.com/RobinDaugherty))
|
17
|
+
- Annotate model check constraints [\#105](https://github.com/drwl/annotaterb/pull/105) ([drwl](https://github.com/drwl))
|
18
|
+
- Fix CHANGELOG.md [\#102](https://github.com/drwl/annotaterb/pull/102) ([drwl](https://github.com/drwl))
|
19
|
+
- Generate changelog for v4.7.0 [\#101](https://github.com/drwl/annotaterb/pull/101) ([drwl](https://github.com/drwl))
|
20
|
+
|
21
|
+
## [v4.7.0](https://github.com/drwl/annotaterb/tree/v4.7.0) (2024-03-27)
|
22
|
+
|
23
|
+
[Full Changelog](https://github.com/drwl/annotaterb/compare/v4.6.0...v4.7.0)
|
24
|
+
|
25
|
+
**Closed issues:**
|
26
|
+
|
27
|
+
- Feature request: better custom type representation [\#97](https://github.com/drwl/annotaterb/issues/97)
|
28
|
+
|
29
|
+
**Merged pull requests:**
|
30
|
+
|
31
|
+
- Bump version to v4.7.0 [\#100](https://github.com/drwl/annotaterb/pull/100) ([drwl](https://github.com/drwl))
|
32
|
+
- Add configurable classes list with `to_s` representation [\#98](https://github.com/drwl/annotaterb/pull/98) ([viralpraxis](https://github.com/viralpraxis))
|
33
|
+
- Generate changelog for v4.6.0 [\#96](https://github.com/drwl/annotaterb/pull/96) ([drwl](https://github.com/drwl))
|
34
|
+
|
3
35
|
## [v4.6.0](https://github.com/drwl/annotaterb/tree/v4.6.0) (2024-02-27)
|
4
36
|
|
5
37
|
[Full Changelog](https://github.com/drwl/annotaterb/compare/v4.5.0...v4.6.0)
|
6
38
|
|
7
|
-
Adds two big changes: Fix annotations swallowing comments [\#72](https://github.com/drwl/annotaterb/pull/72) and
|
8
|
-
Add Zeitwerk support [\#85](https://github.com/drwl/annotaterb/pull/85).
|
9
|
-
Please report any issues you encounter.
|
10
|
-
|
11
39
|
**Closed issues:**
|
12
40
|
|
13
41
|
- Add support for `data_migrate` gem [\#89](https://github.com/drwl/annotaterb/issues/89)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.
|
1
|
+
4.8.0
|
@@ -5,7 +5,7 @@ module AnnotateRb
|
|
5
5
|
module AnnotatedFile
|
6
6
|
# Generates the file with fresh annotations
|
7
7
|
class Generator
|
8
|
-
def initialize(file_content, new_annotations, annotation_position, options)
|
8
|
+
def initialize(file_content, new_annotations, annotation_position, parser_klass, parsed_file, options)
|
9
9
|
@annotation_position = annotation_position
|
10
10
|
@options = options
|
11
11
|
|
@@ -14,7 +14,8 @@ module AnnotateRb
|
|
14
14
|
@new_annotations = new_annotations
|
15
15
|
@file_content = file_content
|
16
16
|
|
17
|
-
@
|
17
|
+
@parser = parser_klass
|
18
|
+
@parsed_file = parsed_file
|
18
19
|
end
|
19
20
|
|
20
21
|
# @return [String] Returns the annotated file content to be written back to a file
|
@@ -32,7 +33,7 @@ module AnnotateRb
|
|
32
33
|
end
|
33
34
|
|
34
35
|
# We need to get class start and class end depending on the position
|
35
|
-
parsed =
|
36
|
+
parsed = @parser.parse(content_without_annotations)
|
36
37
|
|
37
38
|
_content = if %w[after bottom].include?(annotation_write_position)
|
38
39
|
content_annotated_after(parsed, content_without_annotations)
|
@@ -5,13 +5,13 @@ module AnnotateRb
|
|
5
5
|
module AnnotatedFile
|
6
6
|
# Updates existing annotations
|
7
7
|
class Updater
|
8
|
-
def initialize(file_content, new_annotations, _annotation_position, options)
|
8
|
+
def initialize(file_content, new_annotations, _annotation_position, parsed_file, options)
|
9
9
|
@options = options
|
10
10
|
|
11
11
|
@new_annotations = new_annotations
|
12
12
|
@file_content = file_content
|
13
13
|
|
14
|
-
@parsed_file =
|
14
|
+
@parsed_file = parsed_file
|
15
15
|
end
|
16
16
|
|
17
17
|
# @return [String] Returns the annotated file content to be written back to a file
|
@@ -44,6 +44,10 @@ module AnnotateRb
|
|
44
44
|
@info += ForeignKeyAnnotation::AnnotationBuilder.new(@model, @options).build
|
45
45
|
end
|
46
46
|
|
47
|
+
if @options[:show_check_constraints] && @model.table_exists?
|
48
|
+
@info += CheckConstraintAnnotation::AnnotationBuilder.new(@model, @options).build
|
49
|
+
end
|
50
|
+
|
47
51
|
@info += schema_footer_text
|
48
52
|
|
49
53
|
@info
|
@@ -52,12 +56,19 @@ module AnnotateRb
|
|
52
56
|
def header
|
53
57
|
header = @options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
|
54
58
|
header = "# #{header}"
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
|
60
|
+
if @options.get_state(:current_version).nil?
|
61
|
+
migration_version = begin
|
62
|
+
ActiveRecord::Migrator.current_version
|
63
|
+
rescue
|
64
|
+
0
|
65
|
+
end
|
66
|
+
|
67
|
+
@options.set_state(:current_version, migration_version)
|
59
68
|
end
|
60
69
|
|
70
|
+
version = @options.get_state(:current_version)
|
71
|
+
|
61
72
|
if @options[:include_version] && version > 0
|
62
73
|
header += "\n# Schema version: #{version}"
|
63
74
|
end
|
@@ -18,6 +18,10 @@ module AnnotateRb
|
|
18
18
|
klass = ModelClassGetter.call(@file, @options)
|
19
19
|
|
20
20
|
klass_is_a_class = klass.is_a?(Class)
|
21
|
+
# Methods such as #superclass only exist on a class. Because of how the code is structured, `klass` could be a
|
22
|
+
# module that does not support the #superclass method, so we want to return early.
|
23
|
+
return false if !klass_is_a_class
|
24
|
+
|
21
25
|
klass_inherits_active_record_base = klass < ActiveRecord::Base
|
22
26
|
klass_is_not_abstract = klass.respond_to?(:abstract_class) && !klass.abstract_class?
|
23
27
|
klass_table_exists = klass.respond_to?(:abstract_class) && klass.table_exists?
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
module CheckConstraintAnnotation
|
6
|
+
class AnnotationBuilder
|
7
|
+
def initialize(model, options)
|
8
|
+
@model = model
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
constraint_info = if @options[:format_markdown]
|
14
|
+
"#\n# ### Check Constraints\n#\n"
|
15
|
+
else
|
16
|
+
"#\n# Check Constraints\n#\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
return "" unless @model.connection.respond_to?(:supports_check_constraints?) &&
|
20
|
+
@model.connection.supports_check_constraints? && @model.connection.respond_to?(:check_constraints)
|
21
|
+
|
22
|
+
check_constraints = @model.connection.check_constraints(@model.table_name)
|
23
|
+
return "" if check_constraints.empty?
|
24
|
+
|
25
|
+
max_size = check_constraints.map { |check_constraint| check_constraint.name.size }.max + 1
|
26
|
+
check_constraints.sort_by(&:name).each do |check_constraint|
|
27
|
+
expression = check_constraint.expression ? "(#{check_constraint.expression.squish})" : nil
|
28
|
+
|
29
|
+
constraint_info += if @options[:format_markdown]
|
30
|
+
cc_info_in_markdown(check_constraint.name, expression)
|
31
|
+
else
|
32
|
+
cc_info_string(check_constraint.name, expression, max_size)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
constraint_info
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def cc_info_in_markdown(name, expression)
|
42
|
+
cc_info_markdown = sprintf("# * `%s`", name)
|
43
|
+
cc_info_markdown += sprintf(": `%s`", expression) if expression
|
44
|
+
cc_info_markdown += "\n"
|
45
|
+
|
46
|
+
cc_info_markdown
|
47
|
+
end
|
48
|
+
|
49
|
+
def cc_info_string(name, expression, max_size)
|
50
|
+
# standard:disable Lint/FormatParameterMismatch
|
51
|
+
sprintf("# %-#{max_size}.#{max_size}s %s", name, expression).rstrip + "\n"
|
52
|
+
# standard:enable Lint/FormatParameterMismatch
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -19,19 +19,17 @@ module AnnotateRb
|
|
19
19
|
|
20
20
|
attr_reader :parser
|
21
21
|
|
22
|
-
def initialize(content, wrapper_open, wrapper_close)
|
22
|
+
def initialize(content, wrapper_open, wrapper_close, parser)
|
23
23
|
@content = content
|
24
24
|
@wrapper_open = wrapper_open
|
25
25
|
@wrapper_close = wrapper_close
|
26
26
|
@annotation_start = nil
|
27
27
|
@annotation_end = nil
|
28
|
-
@parser =
|
28
|
+
@parser = parser
|
29
29
|
end
|
30
30
|
|
31
31
|
# Find the annotation's line start and line end
|
32
32
|
def run
|
33
|
-
# CustomParser returns line numbers as 0-indexed
|
34
|
-
@parser = FileParser::CustomParser.new(@content, "", 0).tap(&:parse)
|
35
33
|
comments = @parser.comments
|
36
34
|
|
37
35
|
start = comments.find_index { |comment, _| comment.include?(COMPAT_PREFIX) || comment.include?(COMPAT_PREFIX_MD) }
|
@@ -6,15 +6,17 @@ module AnnotateRb
|
|
6
6
|
class ParsedFile
|
7
7
|
SKIP_ANNOTATION_STRING = "# -*- SkipSchemaAnnotations"
|
8
8
|
|
9
|
-
def initialize(file_content, new_annotations, options)
|
9
|
+
def initialize(file_content, new_annotations, parser_klass, options)
|
10
10
|
@file_content = file_content
|
11
11
|
@file_lines = @file_content.lines
|
12
12
|
@new_annotations = new_annotations
|
13
|
+
@parser_klass = parser_klass
|
13
14
|
@options = options
|
14
15
|
end
|
15
16
|
|
16
17
|
def parse
|
17
|
-
@
|
18
|
+
@file_parser = @parser_klass.parse(@file_content)
|
19
|
+
@finder = AnnotationFinder.new(@file_content, @options[:wrapper_open], @options[:wrapper_close], @file_parser)
|
18
20
|
has_annotations = false
|
19
21
|
|
20
22
|
begin
|
@@ -30,7 +32,6 @@ module AnnotateRb
|
|
30
32
|
end
|
31
33
|
|
32
34
|
@diff = AnnotationDiffGenerator.new(annotations, @new_annotations).generate
|
33
|
-
@file_parser = @finder.parser
|
34
35
|
|
35
36
|
has_skip_string = @file_parser.comments.any? { |comment, _lineno| comment.include?(SKIP_ANNOTATION_STRING) }
|
36
37
|
annotations_changed = @diff.changed?
|
@@ -85,7 +86,9 @@ module AnnotateRb
|
|
85
86
|
annotations_with_whitespace: annotations_with_whitespace,
|
86
87
|
has_leading_whitespace: has_leading_whitespace,
|
87
88
|
has_trailing_whitespace: has_trailing_whitespace,
|
88
|
-
annotation_position: annotation_position
|
89
|
+
annotation_position: annotation_position,
|
90
|
+
starts: @file_parser.starts,
|
91
|
+
ends: @file_parser.ends
|
89
92
|
)
|
90
93
|
end
|
91
94
|
end
|
@@ -12,7 +12,9 @@ module AnnotateRb
|
|
12
12
|
annotations_with_whitespace:,
|
13
13
|
has_leading_whitespace:,
|
14
14
|
has_trailing_whitespace:,
|
15
|
-
annotation_position
|
15
|
+
annotation_position:,
|
16
|
+
starts:,
|
17
|
+
ends:
|
16
18
|
)
|
17
19
|
@has_annotations = has_annotations
|
18
20
|
@has_skip_string = has_skip_string
|
@@ -22,9 +24,11 @@ module AnnotateRb
|
|
22
24
|
@has_leading_whitespace = has_leading_whitespace
|
23
25
|
@has_trailing_whitespace = has_trailing_whitespace
|
24
26
|
@annotation_position = annotation_position
|
27
|
+
@starts = starts
|
28
|
+
@ends = ends
|
25
29
|
end
|
26
30
|
|
27
|
-
attr_reader :annotations, :annotation_position
|
31
|
+
attr_reader :annotations, :annotation_position, :starts, :ends
|
28
32
|
|
29
33
|
# Returns annotations with new line before and after if they exist
|
30
34
|
attr_reader :annotations_with_whitespace
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "psych"
|
4
|
+
|
5
|
+
module AnnotateRb
|
6
|
+
module ModelAnnotator
|
7
|
+
module FileParser
|
8
|
+
class YmlParser
|
9
|
+
class << self
|
10
|
+
def parse(string)
|
11
|
+
_parser = new(string).tap(&:parse)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :comments, :starts, :ends
|
16
|
+
|
17
|
+
def initialize(input)
|
18
|
+
@input = input
|
19
|
+
@comments = []
|
20
|
+
@starts = []
|
21
|
+
@ends = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse
|
25
|
+
parse_comments
|
26
|
+
parse_yml
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_comments
|
32
|
+
# Adds 0-indexed line numbers
|
33
|
+
@input.split($/).each_with_index do |line, line_no|
|
34
|
+
if line.strip.starts_with?("#")
|
35
|
+
@comments << [line, line_no]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_yml
|
41
|
+
# https://docs.ruby-lang.org/en/master/Psych.html#module-Psych-label-Reading+to+Psych-3A-3ANodes-3A-3AStream+structure
|
42
|
+
parser = Psych.parser
|
43
|
+
parser.parse(@input)
|
44
|
+
|
45
|
+
stream = parser.handler.root
|
46
|
+
|
47
|
+
if stream.children.any?
|
48
|
+
doc = stream.children.first
|
49
|
+
@starts << [nil, doc.start_line]
|
50
|
+
@ends << [nil, doc.end_line]
|
51
|
+
else
|
52
|
+
# When parsing a yml file, streamer returns an instance of `Psych::Nodes::Stream` which is a subclass of
|
53
|
+
# `Psych::Nodes::Node`. It along with children nodes, implement #start_line and #end_line.
|
54
|
+
#
|
55
|
+
# When parsing input that is only comments, the parser counts #start_line as the start of the file being
|
56
|
+
# line 0.
|
57
|
+
#
|
58
|
+
# What we really want is where the "start" of the yml file would happen, which would be after comments.
|
59
|
+
# This is stream#end_line.
|
60
|
+
@starts << [nil, stream.end_line]
|
61
|
+
@ends << [nil, stream.end_line]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -7,6 +7,7 @@ module AnnotateRb
|
|
7
7
|
autoload :CustomParser, "annotate_rb/model_annotator/file_parser/custom_parser"
|
8
8
|
autoload :ParsedFile, "annotate_rb/model_annotator/file_parser/parsed_file"
|
9
9
|
autoload :ParsedFileResult, "annotate_rb/model_annotator/file_parser/parsed_file_result"
|
10
|
+
autoload :YmlParser, "annotate_rb/model_annotator/file_parser/yml_parser"
|
10
11
|
end
|
11
12
|
end
|
12
13
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class FileToParserMapper
|
6
|
+
class UnsupportedFileTypeError < StandardError; end
|
7
|
+
|
8
|
+
MAP = {
|
9
|
+
".rb" => FileParser::CustomParser,
|
10
|
+
".yml" => FileParser::YmlParser
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def map(file_name)
|
15
|
+
extension = File.extname(file_name).downcase
|
16
|
+
parser = MAP[extension]
|
17
|
+
|
18
|
+
raise UnsupportedFileTypeError, "File '#{file_name}' does not have a supported file type." if parser.nil?
|
19
|
+
|
20
|
+
parser
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -88,22 +88,51 @@ module AnnotateRb
|
|
88
88
|
when "scaffold" then scaffold_files(root_directory)
|
89
89
|
when "factory" then factory_files(root_directory)
|
90
90
|
when "serializer" then serialize_files(root_directory)
|
91
|
-
when "
|
92
|
-
|
93
|
-
when "controller"
|
94
|
-
|
95
|
-
when "admin"
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
]
|
100
|
-
when "helper"
|
101
|
-
[File.join(root_directory, FilePatterns::HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")]
|
91
|
+
when "serializer_test" then serializer_test_files(root_directory)
|
92
|
+
when "additional_file_patterns" then additional_file_patterns
|
93
|
+
when "controller" then controller_files(root_directory)
|
94
|
+
when "controller_test" then controller_test_files(root_directory)
|
95
|
+
when "admin" then active_admin_files(root_directory)
|
96
|
+
when "helper" then helper_files(root_directory)
|
97
|
+
when "request_spec" then request_spec_files(root_directory)
|
98
|
+
when "routing_spec" then routing_spec_files(root_directory)
|
102
99
|
else
|
103
100
|
[]
|
104
101
|
end
|
105
102
|
end
|
106
103
|
|
104
|
+
def controller_files(root_directory)
|
105
|
+
[
|
106
|
+
File.join(root_directory, FilePatterns::CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")
|
107
|
+
]
|
108
|
+
end
|
109
|
+
|
110
|
+
def controller_test_files(root_directory)
|
111
|
+
[
|
112
|
+
File.join(root_directory, FilePatterns::CONTROLLER_TEST_DIR, "%PLURALIZED_MODEL_NAME%_controller_test.rb"),
|
113
|
+
File.join(root_directory, FilePatterns::CONTROLLER_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_controller_spec.rb")
|
114
|
+
]
|
115
|
+
end
|
116
|
+
|
117
|
+
def additional_file_patterns
|
118
|
+
[
|
119
|
+
@options[:additional_file_patterns] || []
|
120
|
+
].flatten
|
121
|
+
end
|
122
|
+
|
123
|
+
def active_admin_files(root_directory)
|
124
|
+
[
|
125
|
+
File.join(root_directory, FilePatterns::ACTIVEADMIN_DIR, "%MODEL_NAME%.rb"),
|
126
|
+
File.join(root_directory, FilePatterns::ACTIVEADMIN_DIR, "%PLURALIZED_MODEL_NAME%.rb")
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
def helper_files(root_directory)
|
131
|
+
[
|
132
|
+
File.join(root_directory, FilePatterns::HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")
|
133
|
+
]
|
134
|
+
end
|
135
|
+
|
107
136
|
def test_files(root_directory)
|
108
137
|
[
|
109
138
|
File.join(root_directory, FilePatterns::UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
@@ -122,10 +151,17 @@ module AnnotateRb
|
|
122
151
|
end
|
123
152
|
|
124
153
|
def scaffold_files(root_directory)
|
154
|
+
controller_test_files(root_directory) + request_spec_files(root_directory) + routing_spec_files(root_directory)
|
155
|
+
end
|
156
|
+
|
157
|
+
def request_spec_files(root_directory)
|
158
|
+
[
|
159
|
+
File.join(root_directory, FilePatterns::REQUEST_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_spec.rb")
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
def routing_spec_files(root_directory)
|
125
164
|
[
|
126
|
-
File.join(root_directory, FilePatterns::CONTROLLER_TEST_DIR, "%PLURALIZED_MODEL_NAME%_controller_test.rb"),
|
127
|
-
File.join(root_directory, FilePatterns::CONTROLLER_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_controller_spec.rb"),
|
128
|
-
File.join(root_directory, FilePatterns::REQUEST_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_spec.rb"),
|
129
165
|
File.join(root_directory, FilePatterns::ROUTING_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_routing_spec.rb")
|
130
166
|
]
|
131
167
|
end
|
@@ -151,7 +187,12 @@ module AnnotateRb
|
|
151
187
|
|
152
188
|
def serialize_files(root_directory)
|
153
189
|
[
|
154
|
-
File.join(root_directory, FilePatterns::SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb")
|
190
|
+
File.join(root_directory, FilePatterns::SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb")
|
191
|
+
]
|
192
|
+
end
|
193
|
+
|
194
|
+
def serializer_test_files(root_directory)
|
195
|
+
[
|
155
196
|
File.join(root_directory, FilePatterns::SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_test.rb"),
|
156
197
|
File.join(root_directory, FilePatterns::SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
|
157
198
|
]
|
@@ -7,6 +7,9 @@ module AnnotateRb
|
|
7
7
|
class RelatedFilesListBuilder
|
8
8
|
RELATED_TYPES = %w[test fixture factory serializer scaffold controller helper].freeze
|
9
9
|
|
10
|
+
# Valid options when `:exclude_tests` is an Array, note that symbols are expected
|
11
|
+
EXCLUDE_TEST_OPTIONS = %i[model controller serializer request routing].freeze
|
12
|
+
|
10
13
|
def initialize(file, model_name, table_name, options)
|
11
14
|
@file = file
|
12
15
|
@model_name = model_name
|
@@ -17,11 +20,14 @@ module AnnotateRb
|
|
17
20
|
def build
|
18
21
|
@list = []
|
19
22
|
|
20
|
-
add_related_test_files if
|
23
|
+
add_related_test_files if !exclude_model_test_files?
|
21
24
|
add_related_fixture_files if !@options[:exclude_fixtures]
|
22
25
|
add_related_factory_files if !@options[:exclude_factories]
|
23
26
|
add_related_serializer_files if !@options[:exclude_serializers]
|
24
|
-
|
27
|
+
add_related_serializer_test_files if !exclude_serializer_tests?
|
28
|
+
add_related_controller_test_files if !exclude_controller_tests?
|
29
|
+
add_related_request_spec_files if !exclude_request_specs?
|
30
|
+
add_related_routing_spec_files if !exclude_routing_specs?
|
25
31
|
add_related_controller_files if !@options[:exclude_controllers]
|
26
32
|
add_related_helper_files if !@options[:exclude_helpers]
|
27
33
|
add_related_admin_files if @options[:active_admin]
|
@@ -32,6 +38,51 @@ module AnnotateRb
|
|
32
38
|
|
33
39
|
private
|
34
40
|
|
41
|
+
def exclude_model_test_files?
|
42
|
+
option = @options[:exclude_tests]
|
43
|
+
|
44
|
+
# If exclude_tests: [:model] then
|
45
|
+
# 1) we want to exclude model test files, and
|
46
|
+
# 2) we don't want to include model test files
|
47
|
+
if option.is_a?(Array)
|
48
|
+
option.include?(:model)
|
49
|
+
else
|
50
|
+
option
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def exclude_serializer_tests?
|
55
|
+
if @options[:exclude_tests].is_a?(Array)
|
56
|
+
@options[:exclude_tests].include?(:serializer)
|
57
|
+
else
|
58
|
+
@options[:exclude_serializers]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def exclude_controller_tests?
|
63
|
+
if @options[:exclude_tests].is_a?(Array)
|
64
|
+
@options[:exclude_tests].include?(:controller)
|
65
|
+
else
|
66
|
+
@options[:exclude_scaffolds]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def exclude_routing_specs?
|
71
|
+
if @options[:exclude_tests].is_a?(Array)
|
72
|
+
@options[:exclude_tests].include?(:routing)
|
73
|
+
else
|
74
|
+
@options[:exclude_scaffolds]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def exclude_request_specs?
|
79
|
+
if @options[:exclude_tests].is_a?(Array)
|
80
|
+
@options[:exclude_tests].include?(:request)
|
81
|
+
else
|
82
|
+
@options[:exclude_scaffolds]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
35
86
|
def related_files_for_pattern(pattern_type)
|
36
87
|
patterns = PatternGetter.call(@options, pattern_type)
|
37
88
|
|
@@ -81,9 +132,9 @@ module AnnotateRb
|
|
81
132
|
@list.concat(files_with_position_key)
|
82
133
|
end
|
83
134
|
|
84
|
-
def
|
85
|
-
position_key = :
|
86
|
-
pattern_type = "
|
135
|
+
def add_related_serializer_test_files
|
136
|
+
position_key = :position_in_serializer
|
137
|
+
pattern_type = "serializer_test"
|
87
138
|
|
88
139
|
related_files = related_files_for_pattern(pattern_type)
|
89
140
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -101,6 +152,36 @@ module AnnotateRb
|
|
101
152
|
@list.concat(files_with_position_key)
|
102
153
|
end
|
103
154
|
|
155
|
+
def add_related_controller_test_files
|
156
|
+
position_key = :position_in_scaffold # Key does not exist
|
157
|
+
pattern_type = "controller_test"
|
158
|
+
|
159
|
+
related_files = related_files_for_pattern(pattern_type)
|
160
|
+
files_with_position_key = related_files.map { |f| [f, position_key] }
|
161
|
+
|
162
|
+
@list.concat(files_with_position_key)
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_related_request_spec_files
|
166
|
+
position_key = :position_in_scaffold # Key does not exist
|
167
|
+
pattern_type = "request_spec"
|
168
|
+
|
169
|
+
related_files = related_files_for_pattern(pattern_type)
|
170
|
+
files_with_position_key = related_files.map { |f| [f, position_key] }
|
171
|
+
|
172
|
+
@list.concat(files_with_position_key)
|
173
|
+
end
|
174
|
+
|
175
|
+
def add_related_routing_spec_files
|
176
|
+
position_key = :position_in_scaffold # Key does not exist
|
177
|
+
pattern_type = "routing_spec"
|
178
|
+
|
179
|
+
related_files = related_files_for_pattern(pattern_type)
|
180
|
+
files_with_position_key = related_files.map { |f| [f, position_key] }
|
181
|
+
|
182
|
+
@list.concat(files_with_position_key)
|
183
|
+
end
|
184
|
+
|
104
185
|
def add_related_helper_files
|
105
186
|
position_key = :position_in_helper # Key does not exist
|
106
187
|
pattern_type = "helper"
|
@@ -12,8 +12,10 @@ module AnnotateRb
|
|
12
12
|
return false unless File.exist?(file_name)
|
13
13
|
old_content = File.read(file_name)
|
14
14
|
|
15
|
+
parser_klass = FileToParserMapper.map(file_name)
|
16
|
+
|
15
17
|
begin
|
16
|
-
parsed_file = FileParser::ParsedFile.new(old_content, "", options).parse
|
18
|
+
parsed_file = FileParser::ParsedFile.new(old_content, "", parser_klass, options).parse
|
17
19
|
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
18
20
|
warn "Unable to process #{file_name}: #{e.message}"
|
19
21
|
warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
|
@@ -25,8 +25,10 @@ module AnnotateRb
|
|
25
25
|
return false unless File.exist?(file_name)
|
26
26
|
old_content = File.read(file_name)
|
27
27
|
|
28
|
+
parser_klass = FileToParserMapper.map(file_name)
|
29
|
+
|
28
30
|
begin
|
29
|
-
parsed_file = FileParser::ParsedFile.new(old_content, annotation, options).parse
|
31
|
+
parsed_file = FileParser::ParsedFile.new(old_content, annotation, parser_klass, options).parse
|
30
32
|
rescue FileParser::AnnotationFinder::MalformedAnnotation => e
|
31
33
|
warn "Unable to process #{file_name}: #{e.message}"
|
32
34
|
warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
|
@@ -39,11 +41,11 @@ module AnnotateRb
|
|
39
41
|
abort "AnnotateRb error. #{file_name} needs to be updated, but annotaterb was run with `--frozen`." if options[:frozen]
|
40
42
|
|
41
43
|
updated_file_content = if !parsed_file.has_annotations?
|
42
|
-
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, options).generate
|
44
|
+
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, parser_klass, parsed_file, options).generate
|
43
45
|
elsif options[:force]
|
44
|
-
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, options).generate
|
46
|
+
AnnotatedFile::Generator.new(old_content, annotation, annotation_position, parser_klass, parsed_file, options).generate
|
45
47
|
else
|
46
|
-
AnnotatedFile::Updater.new(old_content, annotation, annotation_position, options).update
|
48
|
+
AnnotatedFile::Updater.new(old_content, annotation, annotation_position, parsed_file, options).update
|
47
49
|
end
|
48
50
|
|
49
51
|
File.open(file_name, "wb") { |f| f.puts updated_file_content }
|
@@ -26,5 +26,7 @@ module AnnotateRb
|
|
26
26
|
autoload :AnnotatedFile, "annotate_rb/model_annotator/annotated_file"
|
27
27
|
autoload :FileParser, "annotate_rb/model_annotator/file_parser"
|
28
28
|
autoload :ZeitwerkClassGetter, "annotate_rb/model_annotator/zeitwerk_class_getter"
|
29
|
+
autoload :CheckConstraintAnnotation, "annotate_rb/model_annotator/check_constraint_annotation"
|
30
|
+
autoload :FileToParserMapper, "annotate_rb/model_annotator/file_to_parser_mapper"
|
29
31
|
end
|
30
32
|
end
|
data/lib/annotate_rb/options.rb
CHANGED
@@ -45,6 +45,7 @@ module AnnotateRb
|
|
45
45
|
ignore_unknown_models: false, # ModelAnnotator
|
46
46
|
include_version: false, # ModelAnnotator
|
47
47
|
show_complete_foreign_keys: false, # ModelAnnotator
|
48
|
+
show_check_constraints: false, # ModelAnnotator
|
48
49
|
show_foreign_keys: true, # ModelAnnotator
|
49
50
|
show_indexes: true, # ModelAnnotator
|
50
51
|
simple_indexes: false, # ModelAnnotator
|
@@ -109,6 +110,7 @@ module AnnotateRb
|
|
109
110
|
:ignore_model_sub_dir,
|
110
111
|
:ignore_unknown_models,
|
111
112
|
:include_version,
|
113
|
+
:show_check_constraints,
|
112
114
|
:show_complete_foreign_keys,
|
113
115
|
:show_foreign_keys,
|
114
116
|
:show_indexes,
|
@@ -161,6 +163,8 @@ module AnnotateRb
|
|
161
163
|
|
162
164
|
# For now, state is a hash to store state that we need but is not a configuration option
|
163
165
|
@state = state
|
166
|
+
|
167
|
+
symbolize_exclude_tests
|
164
168
|
end
|
165
169
|
|
166
170
|
def to_h
|
@@ -216,5 +220,21 @@ module AnnotateRb
|
|
216
220
|
def print
|
217
221
|
# TODO: prints options and state
|
218
222
|
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
# Guard against user inputting strings instead of symbols
|
227
|
+
def symbolize_exclude_tests
|
228
|
+
# `:exclude_tests` option is being expanded to function as a boolean OR an array of symbols
|
229
|
+
# https://github.com/drwl/annotaterb/issues/103
|
230
|
+
|
231
|
+
if @options[:exclude_tests].is_a?(Array)
|
232
|
+
@options[:exclude_tests].map! do |item|
|
233
|
+
item = item.strip if item.respond_to?(:strip)
|
234
|
+
|
235
|
+
item.to_sym
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
219
239
|
end
|
220
240
|
end
|
data/lib/annotate_rb/parser.rb
CHANGED
@@ -198,6 +198,12 @@ module AnnotateRb
|
|
198
198
|
@options[:simple_indexes] = true
|
199
199
|
end
|
200
200
|
|
201
|
+
option_parser.on("-c",
|
202
|
+
"--show-check-constraints",
|
203
|
+
"List the table's check constraints in the annotation") do
|
204
|
+
@options[:show_check_constraints] = true
|
205
|
+
end
|
206
|
+
|
201
207
|
option_parser.on("--hide-limit-column-types VALUES",
|
202
208
|
"don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)") do |values|
|
203
209
|
@options[:hide_limit_column_types] = values.to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: annotaterb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.8.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: 2024-
|
11
|
+
date: 2024-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Annotates Rails/ActiveRecord Models, routes, fixtures, and others based
|
14
14
|
on the database schema.
|
@@ -46,6 +46,8 @@ files:
|
|
46
46
|
- lib/annotate_rb/model_annotator/annotation_diff_generator.rb
|
47
47
|
- lib/annotate_rb/model_annotator/annotator.rb
|
48
48
|
- lib/annotate_rb/model_annotator/bad_model_file_error.rb
|
49
|
+
- lib/annotate_rb/model_annotator/check_constraint_annotation.rb
|
50
|
+
- lib/annotate_rb/model_annotator/check_constraint_annotation/annotation_builder.rb
|
49
51
|
- lib/annotate_rb/model_annotator/column_annotation.rb
|
50
52
|
- lib/annotate_rb/model_annotator/column_annotation/annotation_builder.rb
|
51
53
|
- lib/annotate_rb/model_annotator/column_annotation/attributes_builder.rb
|
@@ -58,6 +60,8 @@ files:
|
|
58
60
|
- lib/annotate_rb/model_annotator/file_parser/custom_parser.rb
|
59
61
|
- lib/annotate_rb/model_annotator/file_parser/parsed_file.rb
|
60
62
|
- lib/annotate_rb/model_annotator/file_parser/parsed_file_result.rb
|
63
|
+
- lib/annotate_rb/model_annotator/file_parser/yml_parser.rb
|
64
|
+
- lib/annotate_rb/model_annotator/file_to_parser_mapper.rb
|
61
65
|
- lib/annotate_rb/model_annotator/foreign_key_annotation.rb
|
62
66
|
- lib/annotate_rb/model_annotator/foreign_key_annotation/annotation_builder.rb
|
63
67
|
- lib/annotate_rb/model_annotator/index_annotation.rb
|