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.
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
@@ -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
- Dir["*.rb"].map { |f| [dir, f] }
24
- else
25
- Dir["**/*.rb"].reject { |f| f["concerns/"] }.map { |f| [dir, f] }
26
- end
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
- $stderr.puts "No models found in directory '#{options[:model_dir].join("', '")}'."
34
- $stderr.puts "Either specify models on the command line, or use the --model-dir option."
35
- $stderr.puts "Call 'annotaterb --help' for more info."
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
- $stderr.puts "The specified file could not be found in directory '#{options[:model_dir].join("', '")}'."
55
- $stderr.puts "Call 'annotaterb --help' for more info."
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 ||= begin
17
- cols = raw_columns
18
- cols += translated_columns
19
-
20
- ignore_columns = @options[:ignore_columns]
21
- if ignore_columns
22
- cols = cols.reject do |col|
23
- col.name.match(/#{ignore_columns}/)
24
- end
25
- end
26
-
27
- cols = cols.sort_by(&:name) if @options[:sort]
28
- cols = classified_sort(cols) if @options[:classified_sort]
29
-
30
- cols
31
- end
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
- cols = columns
79
-
80
- if with_comments?
81
- max_size = cols.map do |column|
82
- column.name.size + (column.comment ? Helper.width(column.comment) : 0)
83
- end.max || 0
84
- max_size += 2
85
- else
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
- max_size
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?('id')
125
+ if c.name.eql?("id")
119
126
  id = c
120
- elsif c.name.eql?('created_at') || c.name.eql?('updated_at')
127
+ elsif c.name.eql?("created_at") || c.name.eql?("updated_at")
121
128
  timestamps << c
122
- elsif c.name[-3, 3].eql?('_id')
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
- .gsub('::Translation', '').gsub('::', '_')
141
- .downcase,
142
- '_id'
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
- current_patterns = []
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
- options[:root_dir].each do |root_directory|
11
- Array(pattern_types).each do |pattern_type|
12
- patterns = FilePatterns.generate(root_directory, pattern_type, options)
64
+ def get
65
+ current_patterns = []
13
66
 
14
- current_patterns += if pattern_type.to_sym == :additional_file_patterns
15
- patterns
16
- else
17
- patterns.map { |p| p.sub(/^[\/]*/, '') }
18
- end
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
- current_patterns
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(test fixture factory serializer scaffold controller helper).freeze
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
- _related_files = patterns
39
- .map { |f| FileNameResolver.call(f, @model_name, @table_name) }
40
- .map { |f| Dir.glob(f) }
41
- .flatten
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 = 'test'
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 = 'fixture'
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 = 'factory'
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 = 'serializer'
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 = 'scaffold'
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 = 'controller'
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 = 'helper'
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 = 'admin'
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 # Key does not exist
128
- pattern_type = 'additional_file_patterns'
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 FileAnnotator
6
- class FileAnnotatorInstruction
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