annotaterb 4.1.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/README.md +6 -0
  4. data/VERSION +1 -1
  5. data/exe/annotaterb +7 -7
  6. data/lib/annotate_rb/active_record_patch.rb +2 -0
  7. data/lib/annotate_rb/commands/annotate_models.rb +0 -1
  8. data/lib/annotate_rb/commands/annotate_routes.rb +0 -1
  9. data/lib/annotate_rb/commands/print_help.rb +0 -1
  10. data/lib/annotate_rb/commands/print_version.rb +0 -1
  11. data/lib/annotate_rb/commands.rb +4 -4
  12. data/lib/annotate_rb/config_finder.rb +1 -1
  13. data/lib/annotate_rb/config_loader.rb +2 -2
  14. data/lib/annotate_rb/core.rb +3 -3
  15. data/lib/annotate_rb/helper.rb +16 -0
  16. data/lib/annotate_rb/model_annotator/{annotation_generator.rb → annotation_builder.rb} +18 -14
  17. data/lib/annotate_rb/model_annotator/annotation_decider.rb +10 -12
  18. data/lib/annotate_rb/model_annotator/annotation_diff.rb +1 -1
  19. data/lib/annotate_rb/model_annotator/annotation_diff_generator.rb +9 -9
  20. data/lib/annotate_rb/model_annotator/annotation_pattern_generator.rb +3 -3
  21. data/lib/annotate_rb/model_annotator/annotator.rb +12 -53
  22. data/lib/annotate_rb/model_annotator/column_annotation/annotation_builder.rb +135 -0
  23. data/lib/annotate_rb/model_annotator/column_annotation/attributes_builder.rb +104 -0
  24. data/lib/annotate_rb/model_annotator/column_annotation/column_wrapper.rb +103 -0
  25. data/lib/annotate_rb/model_annotator/column_annotation/type_builder.rb +54 -0
  26. data/lib/annotate_rb/model_annotator/column_annotation.rb +12 -0
  27. data/lib/annotate_rb/model_annotator/file_builder.rb +58 -0
  28. data/lib/annotate_rb/model_annotator/file_components.rb +78 -0
  29. data/lib/annotate_rb/model_annotator/file_name_resolver.rb +3 -3
  30. data/lib/annotate_rb/model_annotator/foreign_key_annotation/annotation_builder.rb +57 -0
  31. data/lib/annotate_rb/model_annotator/foreign_key_annotation.rb +9 -0
  32. data/lib/annotate_rb/model_annotator/index_annotation/annotation_builder.rb +113 -0
  33. data/lib/annotate_rb/model_annotator/index_annotation.rb +9 -0
  34. data/lib/annotate_rb/model_annotator/magic_comment_parser.rb +32 -0
  35. data/lib/annotate_rb/model_annotator/model_class_getter.rb +6 -6
  36. data/lib/annotate_rb/model_annotator/model_files_getter.rb +12 -10
  37. data/lib/annotate_rb/model_annotator/model_wrapper.rb +44 -37
  38. data/lib/annotate_rb/model_annotator/pattern_getter.rb +142 -10
  39. data/lib/annotate_rb/model_annotator/project_annotation_remover.rb +65 -0
  40. data/lib/annotate_rb/model_annotator/project_annotator.rb +63 -0
  41. data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +16 -18
  42. data/lib/annotate_rb/model_annotator/single_file_annotation_remover.rb +37 -0
  43. data/lib/annotate_rb/model_annotator/single_file_annotator.rb +49 -0
  44. data/lib/annotate_rb/model_annotator/{file_annotator_instruction.rb → single_file_annotator_instruction.rb} +2 -2
  45. data/lib/annotate_rb/model_annotator/single_file_remove_annotation_instruction.rb +15 -0
  46. data/lib/annotate_rb/model_annotator.rb +25 -26
  47. data/lib/annotate_rb/options.rb +20 -25
  48. data/lib/annotate_rb/parser.rb +150 -142
  49. data/lib/annotate_rb/rake_bootstrapper.rb +8 -8
  50. data/lib/annotate_rb/route_annotator/annotation_processor.rb +7 -8
  51. data/lib/annotate_rb/route_annotator/annotator.rb +2 -2
  52. data/lib/annotate_rb/route_annotator/base_processor.rb +3 -3
  53. data/lib/annotate_rb/route_annotator/header_generator.rb +15 -15
  54. data/lib/annotate_rb/route_annotator/helper.rb +9 -9
  55. data/lib/annotate_rb/route_annotator/removal_processor.rb +4 -4
  56. data/lib/annotate_rb/route_annotator.rb +6 -6
  57. data/lib/annotate_rb/runner.rb +0 -4
  58. data/lib/annotate_rb/tasks/annotate_models_migrate.rake +5 -5
  59. data/lib/annotate_rb.rb +19 -19
  60. data/lib/generators/annotate_rb/install/install_generator.rb +3 -2
  61. data/lib/generators/annotate_rb/install/templates/annotate_rb.rake +3 -2
  62. metadata +22 -16
  63. data/lib/annotate_rb/model_annotator/column_annotation_builder.rb +0 -92
  64. data/lib/annotate_rb/model_annotator/column_attributes_builder.rb +0 -102
  65. data/lib/annotate_rb/model_annotator/column_type_builder.rb +0 -51
  66. data/lib/annotate_rb/model_annotator/column_wrapper.rb +0 -84
  67. data/lib/annotate_rb/model_annotator/constants.rb +0 -22
  68. data/lib/annotate_rb/model_annotator/file_annotation_remover.rb +0 -25
  69. data/lib/annotate_rb/model_annotator/file_annotator.rb +0 -77
  70. data/lib/annotate_rb/model_annotator/file_patterns.rb +0 -129
  71. data/lib/annotate_rb/model_annotator/foreign_key_annotation_builder.rb +0 -55
  72. data/lib/annotate_rb/model_annotator/helper.rb +0 -107
  73. data/lib/annotate_rb/model_annotator/index_annotation_builder.rb +0 -74
  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
- 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