annotaterb 4.1.1 → 4.2.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 +68 -0
- data/VERSION +1 -1
- data/exe/annotaterb +7 -7
- data/lib/annotate_rb/active_record_patch.rb +2 -0
- data/lib/annotate_rb/commands/annotate_models.rb +0 -1
- data/lib/annotate_rb/commands/annotate_routes.rb +0 -1
- data/lib/annotate_rb/commands/print_help.rb +0 -1
- data/lib/annotate_rb/commands/print_version.rb +0 -1
- data/lib/annotate_rb/commands.rb +4 -4
- data/lib/annotate_rb/config_finder.rb +1 -1
- data/lib/annotate_rb/config_loader.rb +2 -2
- data/lib/annotate_rb/core.rb +3 -3
- data/lib/annotate_rb/helper.rb +16 -0
- data/lib/annotate_rb/model_annotator/{annotation_generator.rb → annotation_builder.rb} +18 -14
- data/lib/annotate_rb/model_annotator/annotation_decider.rb +10 -12
- data/lib/annotate_rb/model_annotator/annotation_diff.rb +1 -1
- data/lib/annotate_rb/model_annotator/annotation_diff_generator.rb +9 -9
- data/lib/annotate_rb/model_annotator/annotation_pattern_generator.rb +3 -3
- data/lib/annotate_rb/model_annotator/annotator.rb +12 -53
- data/lib/annotate_rb/model_annotator/column_annotation/annotation_builder.rb +135 -0
- data/lib/annotate_rb/model_annotator/column_annotation/attributes_builder.rb +104 -0
- data/lib/annotate_rb/model_annotator/column_annotation/column_wrapper.rb +103 -0
- data/lib/annotate_rb/model_annotator/column_annotation/type_builder.rb +54 -0
- data/lib/annotate_rb/model_annotator/column_annotation.rb +12 -0
- data/lib/annotate_rb/model_annotator/file_builder.rb +58 -0
- data/lib/annotate_rb/model_annotator/file_components.rb +78 -0
- data/lib/annotate_rb/model_annotator/file_name_resolver.rb +3 -3
- data/lib/annotate_rb/model_annotator/foreign_key_annotation/annotation_builder.rb +57 -0
- data/lib/annotate_rb/model_annotator/foreign_key_annotation.rb +9 -0
- data/lib/annotate_rb/model_annotator/index_annotation/annotation_builder.rb +113 -0
- data/lib/annotate_rb/model_annotator/index_annotation.rb +9 -0
- data/lib/annotate_rb/model_annotator/magic_comment_parser.rb +32 -0
- data/lib/annotate_rb/model_annotator/model_class_getter.rb +6 -6
- data/lib/annotate_rb/model_annotator/model_files_getter.rb +12 -10
- data/lib/annotate_rb/model_annotator/model_wrapper.rb +44 -37
- data/lib/annotate_rb/model_annotator/pattern_getter.rb +142 -10
- data/lib/annotate_rb/model_annotator/project_annotation_remover.rb +65 -0
- data/lib/annotate_rb/model_annotator/project_annotator.rb +63 -0
- data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +16 -18
- data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +37 -0
- data/lib/annotate_rb/model_annotator/single_file_annotator.rb +49 -0
- data/lib/annotate_rb/model_annotator/{file_annotator_instruction.rb → single_file_annotator_instruction.rb} +2 -2
- data/lib/annotate_rb/model_annotator/single_file_remove_annotation_instruction.rb +15 -0
- data/lib/annotate_rb/model_annotator.rb +25 -26
- data/lib/annotate_rb/options.rb +20 -25
- data/lib/annotate_rb/parser.rb +150 -142
- data/lib/annotate_rb/rake_bootstrapper.rb +8 -8
- data/lib/annotate_rb/route_annotator/annotation_processor.rb +7 -8
- data/lib/annotate_rb/route_annotator/annotator.rb +2 -2
- data/lib/annotate_rb/route_annotator/base_processor.rb +3 -3
- data/lib/annotate_rb/route_annotator/header_generator.rb +15 -15
- data/lib/annotate_rb/route_annotator/helper.rb +9 -9
- data/lib/annotate_rb/route_annotator/removal_processor.rb +4 -4
- data/lib/annotate_rb/route_annotator.rb +6 -6
- data/lib/annotate_rb/runner.rb +0 -4
- data/lib/annotate_rb/tasks/annotate_models_migrate.rake +5 -5
- data/lib/annotate_rb.rb +19 -19
- data/lib/generators/annotate_rb/install/install_generator.rb +3 -2
- data/lib/generators/annotate_rb/install/templates/annotate_rb.rake +1 -1
- metadata +22 -16
- data/lib/annotate_rb/model_annotator/column_annotation_builder.rb +0 -92
- data/lib/annotate_rb/model_annotator/column_attributes_builder.rb +0 -102
- data/lib/annotate_rb/model_annotator/column_type_builder.rb +0 -51
- data/lib/annotate_rb/model_annotator/column_wrapper.rb +0 -84
- data/lib/annotate_rb/model_annotator/constants.rb +0 -22
- data/lib/annotate_rb/model_annotator/file_annotation_remover.rb +0 -25
- data/lib/annotate_rb/model_annotator/file_annotator.rb +0 -77
- data/lib/annotate_rb/model_annotator/file_patterns.rb +0 -129
- data/lib/annotate_rb/model_annotator/foreign_key_annotation_builder.rb +0 -55
- data/lib/annotate_rb/model_annotator/helper.rb +0 -107
- data/lib/annotate_rb/model_annotator/index_annotation_builder.rb +0 -74
- data/lib/annotate_rb/model_annotator/model_file_annotator.rb +0 -55
@@ -20,19 +20,21 @@ module AnnotateRb
|
|
20
20
|
options[:model_dir].each do |dir|
|
21
21
|
Dir.chdir(dir) do
|
22
22
|
list = if options[:ignore_model_sub_dir]
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
Dir["*.rb"].map { |f| [dir, f] }
|
24
|
+
else
|
25
|
+
Dir["**/*.rb"]
|
26
|
+
.reject { |f| f["concerns/"] }
|
27
|
+
.map { |f| [dir, f] }
|
28
|
+
end
|
27
29
|
model_files.concat(list)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
33
|
model_files
|
32
34
|
rescue SystemCallError
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
warn "No models found in directory '#{options[:model_dir].join("', '")}'."
|
36
|
+
warn "Either specify models on the command line, or use the --model-dir option."
|
37
|
+
warn "Call 'annotaterb --help' for more info."
|
36
38
|
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
37
39
|
end
|
38
40
|
|
@@ -47,12 +49,12 @@ module AnnotateRb
|
|
47
49
|
absolute_dir_path = File.expand_path(dir)
|
48
50
|
specified_files
|
49
51
|
.find_all { |file| file.start_with?(absolute_dir_path) }
|
50
|
-
.map { |file| [dir, file.sub("#{absolute_dir_path}/",
|
52
|
+
.map { |file| [dir, file.sub("#{absolute_dir_path}/", "")] }
|
51
53
|
end
|
52
54
|
|
53
55
|
if model_files.size != specified_files.size
|
54
|
-
|
55
|
-
|
56
|
+
warn "The specified file could not be found in directory '#{options[:model_dir].join("', '")}'."
|
57
|
+
warn "Call 'annotaterb --help' for more info."
|
56
58
|
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
57
59
|
end
|
58
60
|
|
@@ -13,22 +13,23 @@ module AnnotateRb
|
|
13
13
|
|
14
14
|
# Gets the columns of the ActiveRecord model, processes them, and then returns them.
|
15
15
|
def columns
|
16
|
-
@columns ||=
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
16
|
+
@columns ||=
|
17
|
+
begin
|
18
|
+
cols = raw_columns
|
19
|
+
cols += translated_columns
|
20
|
+
|
21
|
+
ignore_columns = @options[:ignore_columns]
|
22
|
+
if ignore_columns
|
23
|
+
cols = cols.reject do |col|
|
24
|
+
col.name.match(/#{ignore_columns}/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
cols = cols.sort_by(&:name) if @options[:sort]
|
29
|
+
cols = classified_sort(cols) if @options[:classified_sort]
|
30
|
+
|
31
|
+
cols
|
32
|
+
end
|
32
33
|
end
|
33
34
|
|
34
35
|
def connection
|
@@ -75,19 +76,25 @@ module AnnotateRb
|
|
75
76
|
# Calculates the max width of the schema for the model by looking at the columns, schema comments, with respect
|
76
77
|
# to the options.
|
77
78
|
def max_schema_info_width
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
max_size = cols.map(&:name).map(&:size).max
|
87
|
-
end
|
88
|
-
max_size += @options[:format_rdoc] ? 5 : 1
|
79
|
+
@max_schema_info_width ||=
|
80
|
+
begin
|
81
|
+
cols = columns
|
82
|
+
|
83
|
+
if with_comments?
|
84
|
+
column_widths = cols.map do |column|
|
85
|
+
column.name.size + (column.comment ? Helper.width(column.comment) : 0)
|
86
|
+
end
|
89
87
|
|
90
|
-
|
88
|
+
max_size = column_widths.max || 0
|
89
|
+
max_size += 2
|
90
|
+
else
|
91
|
+
max_size = cols.map(&:name).map(&:size).max
|
92
|
+
end
|
93
|
+
|
94
|
+
max_size += @options[:format_rdoc] ? 5 : 1
|
95
|
+
|
96
|
+
max_size
|
97
|
+
end
|
91
98
|
end
|
92
99
|
|
93
100
|
def retrieve_indexes_from_table
|
@@ -98,12 +105,12 @@ module AnnotateRb
|
|
98
105
|
return indexes if indexes.any? || !@klass.table_name_prefix
|
99
106
|
|
100
107
|
# Try to search the table without prefix
|
101
|
-
table_name_without_prefix = table_name.to_s.sub(@klass.table_name_prefix,
|
108
|
+
table_name_without_prefix = table_name.to_s.sub(@klass.table_name_prefix, "")
|
102
109
|
@klass.connection.indexes(table_name_without_prefix)
|
103
110
|
end
|
104
111
|
|
105
112
|
def with_comments?
|
106
|
-
@options[:with_comment] &&
|
113
|
+
@with_comments ||= @options[:with_comment] &&
|
107
114
|
raw_columns.first.respond_to?(:comment) &&
|
108
115
|
raw_columns.map(&:comment).any? { |comment| !comment.nil? }
|
109
116
|
end
|
@@ -115,11 +122,11 @@ module AnnotateRb
|
|
115
122
|
id = nil
|
116
123
|
|
117
124
|
cols.each do |c|
|
118
|
-
if c.name.eql?(
|
125
|
+
if c.name.eql?("id")
|
119
126
|
id = c
|
120
|
-
elsif c.name.eql?(
|
127
|
+
elsif c.name.eql?("created_at") || c.name.eql?("updated_at")
|
121
128
|
timestamps << c
|
122
|
-
elsif c.name[-3, 3].eql?(
|
129
|
+
elsif c.name[-3, 3].eql?("_id")
|
123
130
|
associations << c
|
124
131
|
else
|
125
132
|
rest_cols << c
|
@@ -137,9 +144,9 @@ module AnnotateRb
|
|
137
144
|
# eg. Model: Car, foreign column name: car_id
|
138
145
|
foreign_column_name = [
|
139
146
|
@klass.translation_class.to_s
|
140
|
-
|
141
|
-
|
142
|
-
|
147
|
+
.gsub("::Translation", "").gsub("::", "_")
|
148
|
+
.downcase,
|
149
|
+
"_id"
|
143
150
|
].join.to_sym
|
144
151
|
|
145
152
|
[
|
@@ -152,4 +159,4 @@ module AnnotateRb
|
|
152
159
|
end
|
153
160
|
end
|
154
161
|
end
|
155
|
-
end
|
162
|
+
end
|
@@ -3,25 +3,157 @@
|
|
3
3
|
module AnnotateRb
|
4
4
|
module ModelAnnotator
|
5
5
|
class PatternGetter
|
6
|
+
module FilePatterns
|
7
|
+
# Controller files
|
8
|
+
CONTROLLER_DIR = File.join("app", "controllers")
|
9
|
+
|
10
|
+
# Active admin registry files
|
11
|
+
ACTIVEADMIN_DIR = File.join("app", "admin")
|
12
|
+
|
13
|
+
# Helper files
|
14
|
+
HELPER_DIR = File.join("app", "helpers")
|
15
|
+
|
16
|
+
# File.join for windows reverse bar compat?
|
17
|
+
# I dont use windows, can`t test
|
18
|
+
UNIT_TEST_DIR = File.join("test", "unit")
|
19
|
+
MODEL_TEST_DIR = File.join("test", "models") # since rails 4.0
|
20
|
+
SPEC_MODEL_DIR = File.join("spec", "models")
|
21
|
+
|
22
|
+
FIXTURE_TEST_DIR = File.join("test", "fixtures")
|
23
|
+
FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
|
24
|
+
|
25
|
+
# Other test files
|
26
|
+
CONTROLLER_TEST_DIR = File.join("test", "controllers")
|
27
|
+
CONTROLLER_SPEC_DIR = File.join("spec", "controllers")
|
28
|
+
REQUEST_SPEC_DIR = File.join("spec", "requests")
|
29
|
+
ROUTING_SPEC_DIR = File.join("spec", "routing")
|
30
|
+
|
31
|
+
# Object Daddy http://github.com/flogic/object_daddy/tree/master
|
32
|
+
EXEMPLARS_TEST_DIR = File.join("test", "exemplars")
|
33
|
+
EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars")
|
34
|
+
|
35
|
+
# Machinist http://github.com/notahat/machinist
|
36
|
+
BLUEPRINTS_TEST_DIR = File.join("test", "blueprints")
|
37
|
+
BLUEPRINTS_SPEC_DIR = File.join("spec", "blueprints")
|
38
|
+
|
39
|
+
# Factory Bot https://github.com/thoughtbot/factory_bot
|
40
|
+
FACTORY_BOT_TEST_DIR = File.join("test", "factories")
|
41
|
+
FACTORY_BOT_SPEC_DIR = File.join("spec", "factories")
|
42
|
+
|
43
|
+
# Fabrication https://github.com/paulelliott/fabrication.git
|
44
|
+
FABRICATORS_TEST_DIR = File.join("test", "fabricators")
|
45
|
+
FABRICATORS_SPEC_DIR = File.join("spec", "fabricators")
|
46
|
+
|
47
|
+
# Serializers https://github.com/rails-api/active_model_serializers
|
48
|
+
SERIALIZERS_DIR = File.join("app", "serializers")
|
49
|
+
SERIALIZERS_TEST_DIR = File.join("test", "serializers")
|
50
|
+
SERIALIZERS_SPEC_DIR = File.join("spec", "serializers")
|
51
|
+
end
|
52
|
+
|
6
53
|
class << self
|
7
54
|
def call(options, pattern_types = [])
|
8
|
-
|
55
|
+
new(options, pattern_types).get
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(options, pattern_types = [])
|
60
|
+
@options = options
|
61
|
+
@pattern_types = pattern_types
|
62
|
+
end
|
9
63
|
|
10
|
-
|
11
|
-
|
12
|
-
patterns = FilePatterns.generate(root_directory, pattern_type, options)
|
64
|
+
def get
|
65
|
+
current_patterns = []
|
13
66
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
67
|
+
@options[:root_dir].each do |root_directory|
|
68
|
+
Array(@pattern_types).each do |pattern_type|
|
69
|
+
patterns = generate(root_directory, pattern_type)
|
70
|
+
|
71
|
+
current_patterns += if pattern_type.to_sym == :additional_file_patterns
|
72
|
+
patterns
|
73
|
+
else
|
74
|
+
patterns.map { |p| p.sub(/^\/*/, "") }
|
19
75
|
end
|
20
76
|
end
|
77
|
+
end
|
78
|
+
|
79
|
+
current_patterns
|
80
|
+
end
|
21
81
|
|
22
|
-
|
82
|
+
private
|
83
|
+
|
84
|
+
def generate(root_directory, pattern_type)
|
85
|
+
case pattern_type
|
86
|
+
when "test" then test_files(root_directory)
|
87
|
+
when "fixture" then fixture_files(root_directory)
|
88
|
+
when "scaffold" then scaffold_files(root_directory)
|
89
|
+
when "factory" then factory_files(root_directory)
|
90
|
+
when "serializer" then serialize_files(root_directory)
|
91
|
+
when "additional_file_patterns"
|
92
|
+
[@options[:additional_file_patterns] || []].flatten
|
93
|
+
when "controller"
|
94
|
+
[File.join(root_directory, FilePatterns::CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
|
95
|
+
when "admin"
|
96
|
+
[
|
97
|
+
File.join(root_directory, FilePatterns::ACTIVEADMIN_DIR, "%MODEL_NAME%.rb"),
|
98
|
+
File.join(root_directory, FilePatterns::ACTIVEADMIN_DIR, "%PLURALIZED_MODEL_NAME%.rb")
|
99
|
+
]
|
100
|
+
when "helper"
|
101
|
+
[File.join(root_directory, FilePatterns::HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")]
|
102
|
+
else
|
103
|
+
[]
|
23
104
|
end
|
24
105
|
end
|
106
|
+
|
107
|
+
def test_files(root_directory)
|
108
|
+
[
|
109
|
+
File.join(root_directory, FilePatterns::UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
110
|
+
File.join(root_directory, FilePatterns::MODEL_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
111
|
+
File.join(root_directory, FilePatterns::SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb")
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
def fixture_files(root_directory)
|
116
|
+
[
|
117
|
+
File.join(root_directory, FilePatterns::FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"),
|
118
|
+
File.join(root_directory, FilePatterns::FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"),
|
119
|
+
File.join(root_directory, FilePatterns::FIXTURE_TEST_DIR, "%PLURALIZED_MODEL_NAME%.yml"),
|
120
|
+
File.join(root_directory, FilePatterns::FIXTURE_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.yml")
|
121
|
+
]
|
122
|
+
end
|
123
|
+
|
124
|
+
def scaffold_files(root_directory)
|
125
|
+
[
|
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
|
+
File.join(root_directory, FilePatterns::ROUTING_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_routing_spec.rb")
|
130
|
+
]
|
131
|
+
end
|
132
|
+
|
133
|
+
def factory_files(root_directory)
|
134
|
+
[
|
135
|
+
File.join(root_directory, FilePatterns::EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"),
|
136
|
+
File.join(root_directory, FilePatterns::EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
|
137
|
+
File.join(root_directory, FilePatterns::BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
|
138
|
+
File.join(root_directory, FilePatterns::BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
|
139
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
140
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
141
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
|
142
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
|
143
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_TEST_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
144
|
+
File.join(root_directory, FilePatterns::FACTORY_BOT_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
145
|
+
File.join(root_directory, FilePatterns::FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
|
146
|
+
File.join(root_directory, FilePatterns::FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
|
147
|
+
]
|
148
|
+
end
|
149
|
+
|
150
|
+
def serialize_files(root_directory)
|
151
|
+
[
|
152
|
+
File.join(root_directory, FilePatterns::SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb"),
|
153
|
+
File.join(root_directory, FilePatterns::SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_test.rb"),
|
154
|
+
File.join(root_directory, FilePatterns::SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
|
155
|
+
]
|
156
|
+
end
|
25
157
|
end
|
26
158
|
end
|
27
159
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ProjectAnnotationRemover
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def remove_annotations
|
11
|
+
project_model_files = model_files
|
12
|
+
|
13
|
+
removal_instructions = project_model_files.map do |path, filename|
|
14
|
+
file = File.join(path, filename)
|
15
|
+
|
16
|
+
if AnnotationDecider.new(file, @options).annotate?
|
17
|
+
_instructions = build_instructions_for_file(file)
|
18
|
+
end
|
19
|
+
end.flatten.compact
|
20
|
+
|
21
|
+
deannotated = removal_instructions.map do |instruction|
|
22
|
+
if SingleFileAnnotationRemover.call_with_instructions(instruction)
|
23
|
+
instruction.file
|
24
|
+
end
|
25
|
+
rescue => e
|
26
|
+
warn "Unable to process #{File.join(instruction.file)}: #{e.message}"
|
27
|
+
warn "\t" + e.backtrace.join("\n\t") if @options[:trace]
|
28
|
+
end.flatten.compact
|
29
|
+
|
30
|
+
if deannotated.empty?
|
31
|
+
puts "Model files unchanged."
|
32
|
+
else
|
33
|
+
puts "Removed annotations (#{deannotated.length}) from: #{deannotated.join(", ")}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_instructions_for_file(file)
|
40
|
+
klass = ModelClassGetter.call(file, @options)
|
41
|
+
|
42
|
+
instructions = []
|
43
|
+
|
44
|
+
klass.reset_column_information
|
45
|
+
model_name = klass.name.underscore
|
46
|
+
table_name = klass.table_name
|
47
|
+
|
48
|
+
model_instruction = SingleFileRemoveAnnotationInstruction.new(file, @options)
|
49
|
+
instructions << model_instruction
|
50
|
+
|
51
|
+
related_files = RelatedFilesListBuilder.new(file, model_name, table_name, @options).build
|
52
|
+
related_file_instructions = related_files.map do |f, _position_key|
|
53
|
+
_instruction = SingleFileRemoveAnnotationInstruction.new(f, @options)
|
54
|
+
end
|
55
|
+
instructions.concat(related_file_instructions)
|
56
|
+
|
57
|
+
instructions
|
58
|
+
end
|
59
|
+
|
60
|
+
def model_files
|
61
|
+
@model_files ||= ModelFilesGetter.call(@options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ProjectAnnotator
|
6
|
+
def initialize(options)
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def annotate
|
11
|
+
project_model_files = model_files
|
12
|
+
|
13
|
+
annotation_instructions = project_model_files.map do |path, filename|
|
14
|
+
file = File.join(path, filename)
|
15
|
+
|
16
|
+
if AnnotationDecider.new(file, @options).annotate?
|
17
|
+
_instructions = build_instructions_for_file(file)
|
18
|
+
end
|
19
|
+
end.flatten.compact
|
20
|
+
|
21
|
+
annotated = annotation_instructions.map do |instruction|
|
22
|
+
if SingleFileAnnotator.call_with_instructions(instruction)
|
23
|
+
instruction.file
|
24
|
+
end
|
25
|
+
end.compact
|
26
|
+
|
27
|
+
if annotated.empty?
|
28
|
+
puts "Model files unchanged."
|
29
|
+
else
|
30
|
+
puts "Annotated (#{annotated.length}): #{annotated.join(", ")}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_instructions_for_file(file)
|
37
|
+
klass = ModelClassGetter.call(file, @options)
|
38
|
+
|
39
|
+
instructions = []
|
40
|
+
|
41
|
+
klass.reset_column_information
|
42
|
+
annotation = AnnotationBuilder.new(klass, @options).build
|
43
|
+
model_name = klass.name.underscore
|
44
|
+
table_name = klass.table_name
|
45
|
+
|
46
|
+
model_instruction = SingleFileAnnotatorInstruction.new(file, annotation, :position_in_class, @options)
|
47
|
+
instructions << model_instruction
|
48
|
+
|
49
|
+
related_files = RelatedFilesListBuilder.new(file, model_name, table_name, @options).build
|
50
|
+
related_file_instructions = related_files.map do |f, position_key|
|
51
|
+
_instruction = SingleFileAnnotatorInstruction.new(f, annotation, position_key, @options)
|
52
|
+
end
|
53
|
+
instructions.concat(related_file_instructions)
|
54
|
+
|
55
|
+
instructions
|
56
|
+
end
|
57
|
+
|
58
|
+
def model_files
|
59
|
+
@model_files ||= ModelFilesGetter.call(@options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -5,7 +5,7 @@ module AnnotateRb
|
|
5
5
|
# Given a model file and options, this class will return a list of related files (e.g. fixture, controllers, etc)
|
6
6
|
# to also annotate
|
7
7
|
class RelatedFilesListBuilder
|
8
|
-
RELATED_TYPES = %w
|
8
|
+
RELATED_TYPES = %w[test fixture factory serializer scaffold controller helper].freeze
|
9
9
|
|
10
10
|
def initialize(file, model_name, table_name, options)
|
11
11
|
@file = file
|
@@ -35,17 +35,15 @@ module AnnotateRb
|
|
35
35
|
def related_files_for_pattern(pattern_type)
|
36
36
|
patterns = PatternGetter.call(@options, pattern_type)
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
_related_files
|
38
|
+
patterns
|
39
|
+
.map { |f| FileNameResolver.call(f, @model_name, @table_name) }
|
40
|
+
.map { |f| Dir.glob(f) }
|
41
|
+
.flatten
|
44
42
|
end
|
45
43
|
|
46
44
|
def add_related_test_files
|
47
45
|
position_key = :position_in_test
|
48
|
-
pattern_type =
|
46
|
+
pattern_type = "test"
|
49
47
|
|
50
48
|
related_files = related_files_for_pattern(pattern_type)
|
51
49
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -55,7 +53,7 @@ module AnnotateRb
|
|
55
53
|
|
56
54
|
def add_related_fixture_files
|
57
55
|
position_key = :position_in_fixture
|
58
|
-
pattern_type =
|
56
|
+
pattern_type = "fixture"
|
59
57
|
|
60
58
|
related_files = related_files_for_pattern(pattern_type)
|
61
59
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -65,7 +63,7 @@ module AnnotateRb
|
|
65
63
|
|
66
64
|
def add_related_factory_files
|
67
65
|
position_key = :position_in_factory
|
68
|
-
pattern_type =
|
66
|
+
pattern_type = "factory"
|
69
67
|
|
70
68
|
related_files = related_files_for_pattern(pattern_type)
|
71
69
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -75,7 +73,7 @@ module AnnotateRb
|
|
75
73
|
|
76
74
|
def add_related_serializer_files
|
77
75
|
position_key = :position_in_serializer
|
78
|
-
pattern_type =
|
76
|
+
pattern_type = "serializer"
|
79
77
|
|
80
78
|
related_files = related_files_for_pattern(pattern_type)
|
81
79
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -85,7 +83,7 @@ module AnnotateRb
|
|
85
83
|
|
86
84
|
def add_related_scaffold_files
|
87
85
|
position_key = :position_in_scaffold # Key does not exist
|
88
|
-
pattern_type =
|
86
|
+
pattern_type = "scaffold"
|
89
87
|
|
90
88
|
related_files = related_files_for_pattern(pattern_type)
|
91
89
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -95,7 +93,7 @@ module AnnotateRb
|
|
95
93
|
|
96
94
|
def add_related_controller_files
|
97
95
|
position_key = :position_in_controller # Key does not exist
|
98
|
-
pattern_type =
|
96
|
+
pattern_type = "controller"
|
99
97
|
|
100
98
|
related_files = related_files_for_pattern(pattern_type)
|
101
99
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -105,7 +103,7 @@ module AnnotateRb
|
|
105
103
|
|
106
104
|
def add_related_helper_files
|
107
105
|
position_key = :position_in_helper # Key does not exist
|
108
|
-
pattern_type =
|
106
|
+
pattern_type = "helper"
|
109
107
|
|
110
108
|
related_files = related_files_for_pattern(pattern_type)
|
111
109
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -115,7 +113,7 @@ module AnnotateRb
|
|
115
113
|
|
116
114
|
def add_related_admin_files
|
117
115
|
position_key = :position_in_admin # Key does not exist
|
118
|
-
pattern_type =
|
116
|
+
pattern_type = "admin"
|
119
117
|
|
120
118
|
related_files = related_files_for_pattern(pattern_type)
|
121
119
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -124,8 +122,8 @@ module AnnotateRb
|
|
124
122
|
end
|
125
123
|
|
126
124
|
def add_additional_file_patterns
|
127
|
-
position_key = :position_in_additional_file_patterns
|
128
|
-
pattern_type =
|
125
|
+
position_key = :position_in_additional_file_patterns
|
126
|
+
pattern_type = "additional_file_patterns"
|
129
127
|
|
130
128
|
related_files = related_files_for_pattern(pattern_type)
|
131
129
|
files_with_position_key = related_files.map { |f| [f, position_key] }
|
@@ -134,4 +132,4 @@ module AnnotateRb
|
|
134
132
|
end
|
135
133
|
end
|
136
134
|
end
|
137
|
-
end
|
135
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class SingleFileAnnotationRemover
|
6
|
+
class << self
|
7
|
+
def call_with_instructions(instruction)
|
8
|
+
call(instruction.file, instruction.options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(file_name, options = Options.from({}))
|
12
|
+
return false unless File.exist?(file_name)
|
13
|
+
old_content = File.read(file_name)
|
14
|
+
|
15
|
+
file_components = FileComponents.new(old_content, "", options)
|
16
|
+
|
17
|
+
return false if file_components.has_skip_string?
|
18
|
+
# TODO: Uncomment below after tests are fixed
|
19
|
+
# return false if !file_components.has_annotations?
|
20
|
+
|
21
|
+
wrapper_open = if options[:wrapper_open]
|
22
|
+
"# #{options[:wrapper_open]}\n"
|
23
|
+
else
|
24
|
+
""
|
25
|
+
end
|
26
|
+
|
27
|
+
generated_pattern = AnnotationPatternGenerator.call(options)
|
28
|
+
updated_file_content = old_content.sub!(/(#{wrapper_open})?#{generated_pattern}/, "")
|
29
|
+
|
30
|
+
File.open(file_name, "wb") { |f| f.puts updated_file_content }
|
31
|
+
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class SingleFileAnnotator
|
6
|
+
class << self
|
7
|
+
def call_with_instructions(instruction)
|
8
|
+
call(instruction.file, instruction.annotation, instruction.position, instruction.options)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Add a schema block to a file. If the file already contains
|
12
|
+
# a schema info block (a comment starting with "== Schema Information"),
|
13
|
+
# check if it matches the block that is already there. If so, leave it be.
|
14
|
+
# If not, remove the old info block and write a new one.
|
15
|
+
#
|
16
|
+
# == Returns:
|
17
|
+
# true or false depending on whether the file was modified.
|
18
|
+
#
|
19
|
+
# === Options (opts)
|
20
|
+
# :force<Symbol>:: whether to update the file even if it doesn't seem to need it.
|
21
|
+
# :position_in_*<Symbol>:: where to place the annotated section in fixture or model file,
|
22
|
+
# :before, :top, :after or :bottom. Default is :before.
|
23
|
+
#
|
24
|
+
def call(file_name, annotation, annotation_position, options = {})
|
25
|
+
return false unless File.exist?(file_name)
|
26
|
+
old_content = File.read(file_name)
|
27
|
+
|
28
|
+
file_components = FileComponents.new(old_content, annotation, options)
|
29
|
+
builder = FileBuilder.new(file_components, annotation, annotation_position, options)
|
30
|
+
|
31
|
+
return false if file_components.has_skip_string?
|
32
|
+
return false if !file_components.annotations_changed? && !options[:force]
|
33
|
+
|
34
|
+
abort "AnnotateRb error. #{file_name} needs to be updated, but annotaterb was run with `--frozen`." if options[:frozen]
|
35
|
+
|
36
|
+
updated_file_content = if !file_components.has_annotations? || options[:force]
|
37
|
+
builder.generate_content_with_new_annotations
|
38
|
+
else
|
39
|
+
builder.update_existing_annotations
|
40
|
+
end
|
41
|
+
|
42
|
+
File.open(file_name, "wb") { |f| f.puts updated_file_content }
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module AnnotateRb
|
4
4
|
module ModelAnnotator
|
5
|
-
# A plain old Ruby object (PORO) that contains all necessary information for
|
6
|
-
class
|
5
|
+
# A plain old Ruby object (PORO) that contains all necessary information for SingleFileAnnotator
|
6
|
+
class SingleFileAnnotatorInstruction
|
7
7
|
def initialize(file, annotation, position, options = {})
|
8
8
|
@file = file # Path to file
|
9
9
|
@annotation = annotation # Annotation string
|