annotate 2.7.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19c80b25d2326ba60d78120276156ea6223fd07024dd9b9c771d4fa405f68204
4
- data.tar.gz: 6e8409e098cdecbc97053480e8948f04e4cba6c758b8035255d5e027ed46097d
3
+ metadata.gz: 0e4ee3c38fb2ebf3d88712e8836f00570e891cd1a43a6c2bc32c95dc35b7a0d2
4
+ data.tar.gz: 1082be239480425543d84491e8c03d54ad99b362cc142b93224517499d4417fa
5
5
  SHA512:
6
- metadata.gz: 0b8dcb130221c519f1639d8fbea17f0047e915ad6fc7cb3a95cdb9f20b6d25088b04f8cd181519f8ef4ce39e62986d9edee7cabd2824673a4c41878e27d6c24d
7
- data.tar.gz: f0b1f5b74e818782c6ecda0aafe926a055734f5aaaf9ef82592a3dfcfe96d4589b82f6253b4cc72595e6aeef0fa8e07c177c6a0ef70f8511ceeea81ef167b122
6
+ metadata.gz: 4896d07fc9b6d6b95d5916e566cc0d9a304cd16c1592ac0a0546bb273d533c7dfb275c55b2833586e677027e7f34f6a4f38281053e6e454553be527f4e23055c
7
+ data.tar.gz: c72e8ba788014600e40ba24fe7385b9c6c10c08d293ee98bd71e0d91cc235c1a14242293ae963c9265c8e318fa09a104e60547a24c7697218b06be68f320fa63
@@ -1,3 +1,13 @@
1
+ == 3.0.0
2
+ * Added `--models` CLI option fixing issue #563 (#647)
3
+ * Added `--additional_file_patterns` option for additional file patterns (#633) #636) #637)
4
+ * Refactored CLI parser (#646)
5
+ * Fixed BigDecimal.new deprecation warning (#634)
6
+ * Fixed annotations for columns with long data types (#622)
7
+ * Made methods private in AnnotateRoutes (#598)
8
+
9
+ See https://github.com/ctran/annotate_models/releases/tag/v3.0.0
10
+
1
11
  == 2.7.5
2
12
  See https://github.com/ctran/annotate_models/releases/tag/v2.7.5
3
13
 
@@ -6,7 +6,6 @@
6
6
  {<img src="https://coveralls.io/repos/ctran/annotate_models/badge.svg?branch=develop" />}[https://coveralls.io/r/ctran/annotate_models?branch=develop]
7
7
  {<img src="https://codeclimate.com/github/ctran/annotate_models/badges/gpa.svg" />}[https://codeclimate.com/github/ctran/annotate_models]
8
8
  {<img src="http://inch-ci.org/github/ctran/annotate_models.svg?branch=develop" alt="Inline docs" />}[http://inch-ci.org/github/ctran/annotate_models]
9
- {<img src="https://gemnasium.com/ctran/annotate_models.png" />}[https://gemnasium.com/ctran/annotate_models]
10
9
 
11
10
  Add a comment summarizing the current schema to the top or bottom of each of
12
11
  your...
@@ -90,11 +89,11 @@ To annotate all your models, tests, fixtures, and factories:
90
89
 
91
90
  To annotate just your models, tests, and factories:
92
91
 
93
- annotate --exclude fixtures
92
+ annotate --models --exclude fixtures
94
93
 
95
94
  To annotate just your models:
96
95
 
97
- annotate --exclude tests,fixtures,factories,serializers
96
+ annotate --models
98
97
 
99
98
  To annotate routes.rb:
100
99
 
@@ -164,6 +163,7 @@ you can do so with a simple environment variable, instead of editing the
164
163
  == Options
165
164
 
166
165
  Usage: annotate [options] [model_file]*
166
+ --additional_file_patterns Additional file paths or globs to annotate, separated by commas (e.g. `/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb`)
167
167
  -d, --delete Remove annotations from all model files or the routes.rb file
168
168
  -p [before|top|after|bottom], Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)
169
169
  --position
@@ -184,6 +184,7 @@ you can do so with a simple environment variable, instead of editing the
184
184
  --wo, --wrapper-open STR Annotation wrapper opening.
185
185
  --wc, --wrapper-close STR Annotation wrapper closing
186
186
  -r, --routes Annotate routes.rb with the output of 'rake routes'
187
+ --models Annotate ActiveRecord models
187
188
  -a, --active-admin Annotate active_admin models
188
189
  -v, --version Show the current version of this gem
189
190
  -m, --show-migration Include the migration version number in the annotation
@@ -206,16 +207,35 @@ you can do so with a simple environment variable, instead of editing the
206
207
  --frozen Do not allow to change annotations. Exits non-zero if there are going to be changes to files.
207
208
  --timestamp Include timestamp in (routes) annotation
208
209
  --trace If unable to annotate a file, print the full stack trace, not just the exception message.
209
- -I, --ignore-columns REGEX don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`
210
- --ignore-routes REGEX don't annotate routes that match a given REGEX (i.e., `annotate -I '(mobile|resque|pghero)'`
210
+ -I, --ignore-columns REGEX don't annotate columns that match a given REGEX (e.g. `annotate -I '^(id|updated_at|created_at)'`)
211
+ --ignore-routes REGEX don't annotate routes that match a given REGEX (e.g. `annotate -I '(mobile|resque|pghero)'`)_
211
212
  --hide-limit-column-types VALUES
212
- don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)
213
+ don't show limit for given column types, separated by commas (e.g. `integer,boolean,text`)
213
214
  --hide-default-column-types VALUES
214
- don't show default for given column types, separated by commas (i.e., `json,jsonb,hstore`)
215
+ don't show default for given column types, separated by commas (e.g. `json,jsonb,hstore`)
215
216
  --ignore-unknown-models don't display warnings for bad model files
216
217
  --with-comment include database comments in model annotations
217
218
 
219
+ === Option: +additional_file_patterns+
218
220
 
221
+ CLI: +--additional_file_patterns+<br>
222
+ Ruby: +:additional_file_patterns+
223
+
224
+ Provide additional paths for the gem to annotate. These paths can include globs.
225
+ It is recommended to use absolute paths. Here are some examples:
226
+
227
+
228
+ - <code>/app/lib/decorates/%MODEL_NAME%/&ast;.rb</code>
229
+ - <code>/app/lib/forms/%PLURALIZED_MODEL_NAME%/&ast;&ast;/&ast;.rb</code>
230
+ - <code>/app/lib/forms/%TABLE_NAME%/&ast;.rb</code>
231
+
232
+ The appropriate model will be inferred using the <code>%*%</code> syntax, annotating any matching files.
233
+ It works with existing filename resolutions (options for which can be found in the +resolve_filename+ method of
234
+ +annotate_models.rb+).
235
+
236
+ When using in a Rails config, you can use the following:
237
+
238
+ <code>File.join(Rails.application.root, 'app/lib/forms/%PLURALIZED_MODEL_NAME%/**/*.rb')</code>
219
239
 
220
240
  == Sorting
221
241
 
@@ -38,7 +38,6 @@ Gem::Specification.new do |s|
38
38
  s.homepage = 'http://github.com/ctran/annotate_models'
39
39
  s.licenses = ['Ruby']
40
40
  s.require_paths = ['lib']
41
- s.rubyforge_project = 'annotate'
42
41
  s.rubygems_version = '2.1.11'
43
42
  s.summary = 'Annotates Rails Models, routes, fixtures, and others based on the database schema.'
44
43
 
@@ -14,203 +14,19 @@ end
14
14
  here = File.expand_path(File.dirname __FILE__)
15
15
  $LOAD_PATH << "#{here}/../lib"
16
16
 
17
- require 'optparse'
18
17
  require 'annotate'
19
- Annotate.bootstrap_rake
20
-
21
- has_set_position = {}
22
- target_action = :do_annotations
23
- positions = %w(before top after bottom)
24
-
25
- OptionParser.new do |opts|
26
- opts.banner = 'Usage: annotate [options] [model_file]*'
27
-
28
- opts.on('-d', '--delete', 'Remove annotations from all model files or the routes.rb file') do
29
- target_action = :remove_annotations
30
- end
31
-
32
- opts.on('-p', '--position [before|top|after|bottom]', positions,
33
- 'Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)') do |p|
34
- ENV['position'] = p
35
- %w(position_in_class position_in_factory position_in_fixture position_in_test position_in_routes position_in_serializer).each do |key|
36
- ENV[key] = p unless has_set_position[key]
37
- end
38
- end
39
-
40
- opts.on('--pc', '--position-in-class [before|top|after|bottom]', positions,
41
- 'Place the annotations at the top (before) or the bottom (after) of the model file') do |p|
42
- ENV['position_in_class'] = p
43
- has_set_position['position_in_class'] = true
44
- end
45
-
46
- opts.on('--pf', '--position-in-factory [before|top|after|bottom]', positions,
47
- 'Place the annotations at the top (before) or the bottom (after) of any factory files') do |p|
48
- ENV['position_in_factory'] = p
49
- has_set_position['position_in_factory'] = true
50
- end
51
-
52
- opts.on('--px', '--position-in-fixture [before|top|after|bottom]', positions,
53
- 'Place the annotations at the top (before) or the bottom (after) of any fixture files') do |p|
54
- ENV['position_in_fixture'] = p
55
- has_set_position['position_in_fixture'] = true
56
- end
57
-
58
- opts.on('--pt', '--position-in-test [before|top|after|bottom]', positions,
59
- 'Place the annotations at the top (before) or the bottom (after) of any test files') do |p|
60
- ENV['position_in_test'] = p
61
- has_set_position['position_in_test'] = true
62
- end
63
-
64
- opts.on('--pr', '--position-in-routes [before|top|after|bottom]', positions,
65
- 'Place the annotations at the top (before) or the bottom (after) of the routes.rb file') do |p|
66
- ENV['position_in_routes'] = p
67
- has_set_position['position_in_routes'] = true
68
- end
69
-
70
- opts.on('--ps', '--position-in-serializer [before|top|after|bottom]', positions,
71
- 'Place the annotations at the top (before) or the bottom (after) of the serializer files') do |p|
72
- ENV['position_in_serializer'] = p
73
- has_set_position['position_in_serializer'] = true
74
- end
75
-
76
- opts.on('--w', '--wrapper STR', 'Wrap annotation with the text passed as parameter.',
77
- 'If --w option is used, the same text will be used as opening and closing') do |p|
78
- ENV['wrapper'] = p
79
- end
80
-
81
- opts.on('--wo', '--wrapper-open STR', 'Annotation wrapper opening.') do |p|
82
- ENV['wrapper_open'] = p
83
- end
84
-
85
- opts.on('--wc', '--wrapper-close STR', 'Annotation wrapper closing') do |p|
86
- ENV['wrapper_close'] = p
87
- end
88
-
89
- opts.on('-r', '--routes', "Annotate routes.rb with the output of 'rake routes'") do
90
- ENV['routes'] = 'true'
91
- end
92
-
93
- opts.on('-a', '--active-admin', 'Annotate active_admin models') do
94
- ENV['active_admin'] = 'true'
95
- end
96
-
97
- opts.on('-v', '--version', 'Show the current version of this gem') do
98
- puts "annotate v#{Annotate.version}"; exit
99
- end
100
-
101
- opts.on('-m', '--show-migration', 'Include the migration version number in the annotation') do
102
- ENV['include_version'] = 'yes'
103
- end
104
-
105
- opts.on('-k', '--show-foreign-keys',
106
- "List the table's foreign key constraints in the annotation") do
107
- ENV['show_foreign_keys'] = 'yes'
108
- end
18
+ require 'annotate/parser'
109
19
 
110
- opts.on('--ck',
111
- '--complete-foreign-keys', 'Complete foreign key names in the annotation') do
112
- ENV['show_foreign_keys'] = 'yes'
113
- ENV['show_complete_foreign_keys'] = 'yes'
114
- end
115
-
116
- opts.on('-i', '--show-indexes',
117
- "List the table's database indexes in the annotation") do
118
- ENV['show_indexes'] = 'yes'
119
- end
120
-
121
- opts.on('-s', '--simple-indexes',
122
- "Concat the column's related indexes in the annotation") do
123
- ENV['simple_indexes'] = 'yes'
124
- end
125
-
126
- opts.on('--model-dir dir',
127
- "Annotate model files stored in dir rather than app/models, separate multiple dirs with commas") do |dir|
128
- ENV['model_dir'] = dir
129
- end
130
-
131
- opts.on('--root-dir dir',
132
- "Annotate files stored within root dir projects, separate multiple dirs with commas") do |dir|
133
- ENV['root_dir'] = dir
134
- end
135
-
136
- opts.on('--ignore-model-subdirects',
137
- "Ignore subdirectories of the models directory") do |dir|
138
- ENV['ignore_model_sub_dir'] = 'yes'
139
- end
140
-
141
- opts.on('--sort',
142
- "Sort columns alphabetically, rather than in creation order") do |dir|
143
- ENV['sort'] = 'yes'
144
- end
145
-
146
- opts.on('--classified-sort',
147
- "Sort columns alphabetically, but first goes id, then the rest columns, then the timestamp columns and then the association columns") do |dir|
148
- ENV['classified_sort'] = 'yes'
149
- end
150
-
151
- opts.on('-R', '--require path',
152
- "Additional file to require before loading models, may be used multiple times") do |path|
153
- if !ENV['require'].blank?
154
- ENV['require'] = ENV['require'] + ",#{path}"
155
- else
156
- ENV['require'] = path
157
- end
158
- end
159
-
160
- opts.on('-e', '--exclude [tests,fixtures,factories,serializers]', Array, "Do not annotate fixtures, test files, factories, and/or serializers") do |exclusions|
161
- exclusions ||= %w(tests fixtures factories)
162
- exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = 'yes' }
163
- end
164
-
165
- opts.on('-f', '--format [bare|rdoc|markdown]', %w(bare rdoc markdown), 'Render Schema Infomation as plain/RDoc/Markdown') do |fmt|
166
- ENV["format_#{fmt}"] = 'yes'
167
- end
168
-
169
- opts.on('--force', 'Force new annotations even if there are no changes.') do |force|
170
- ENV['force'] = 'yes'
171
- end
172
-
173
- opts.on('--frozen', 'Do not allow to change annotations. Exits non-zero if there are going to be changes to files.') do
174
- ENV['frozen'] = 'yes'
175
- end
176
-
177
- opts.on('--timestamp', 'Include timestamp in (routes) annotation') do
178
- ENV['timestamp'] = 'true'
179
- end
180
-
181
- opts.on('--trace', 'If unable to annotate a file, print the full stack trace, not just the exception message.') do |value|
182
- ENV['trace'] = 'yes'
183
- end
184
-
185
- opts.on('-I', '--ignore-columns REGEX', "don't annotate columns that match a given REGEX (i.e., `annotate -I '^(id|updated_at|created_at)'`") do |regex|
186
- ENV['ignore_columns'] = regex
187
- end
188
-
189
- opts.on('--ignore-routes REGEX', "don't annotate routes that match a given REGEX (i.e., `annotate -I '(mobile|resque|pghero)'`") do |regex|
190
- ENV['ignore_routes'] = regex
191
- end
192
-
193
- opts.on('--hide-limit-column-types VALUES', "don't show limit for given column types, separated by commas (i.e., `integer,boolean,text`)") do |values|
194
- ENV['hide_limit_column_types'] = "#{values}"
195
- end
196
-
197
- opts.on('--hide-default-column-types VALUES', "don't show default for given column types, separated by commas (i.e., `json,jsonb,hstore`)") do |values|
198
- ENV['hide_default_column_types'] = "#{values}"
199
- end
20
+ Annotate.bootstrap_rake
200
21
 
201
- opts.on('--ignore-unknown-models', "don't display warnings for bad model files") do |values|
202
- ENV['ignore_unknown_models'] = 'true'
203
- end
22
+ options_result = Annotate::Parser.parse(ARGV)
204
23
 
205
- opts.on('--with-comment', "include database comments in model annotations") do |values|
206
- ENV['with_comment'] = 'true'
207
- end
208
- end.parse!
24
+ exit if options_result[:exit]
209
25
 
210
26
  options = Annotate.setup_options(
211
27
  is_rake: ENV['is_rake'] && !ENV['is_rake'].empty?
212
28
  )
213
29
  Annotate.eager_load(options) if Annotate.include_models?
214
30
 
215
- AnnotateModels.send(target_action, options) if Annotate.include_models?
216
- AnnotateRoutes.send(target_action, options) if Annotate.include_routes?
31
+ AnnotateModels.send(options_result[:target_action], options) if Annotate.include_models?
32
+ AnnotateRoutes.send(options_result[:target_action], options) if Annotate.include_routes?
@@ -36,8 +36,8 @@ module Annotate
36
36
  :exclude_sti_subclasses, :ignore_unknown_models, :with_comment
37
37
  ].freeze
38
38
  OTHER_OPTIONS = [
39
- :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
40
- :wrapper, :routes, :hide_limit_column_types, :hide_default_column_types,
39
+ :additional_file_patterns, :ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
40
+ :wrapper, :routes, :models, :hide_limit_column_types, :hide_default_column_types,
41
41
  :ignore_routes, :active_admin
42
42
  ].freeze
43
43
  PATH_OPTIONS = [
@@ -88,6 +88,7 @@ module Annotate
88
88
  options[key] = !ENV[key.to_s].blank? ? ENV[key.to_s].split(',') : []
89
89
  end
90
90
 
91
+ options[:additional_file_patterns] ||= []
91
92
  options[:model_dir] = ['app/models'] if options[:model_dir].empty?
92
93
 
93
94
  options[:wrapper_open] ||= options[:wrapper]
@@ -114,7 +115,7 @@ module Annotate
114
115
  end
115
116
 
116
117
  def self.include_models?
117
- ENV['routes'] !~ TRUE_RE
118
+ ENV['models'] =~ TRUE_RE
118
119
  end
119
120
 
120
121
  def self.loaded_tasks=(val)
@@ -159,13 +159,15 @@ module AnnotateModels
159
159
  ]
160
160
  end
161
161
 
162
- def files_by_pattern(root_directory, pattern_type)
162
+ def files_by_pattern(root_directory, pattern_type, options)
163
163
  case pattern_type
164
164
  when 'test' then test_files(root_directory)
165
165
  when 'fixture' then fixture_files(root_directory)
166
166
  when 'scaffold' then scaffold_files(root_directory)
167
167
  when 'factory' then factory_files(root_directory)
168
168
  when 'serializer' then serialize_files(root_directory)
169
+ when 'additional_file_patterns'
170
+ [options[:additional_file_patterns] || []].flatten
169
171
  when 'controller'
170
172
  [File.join(root_directory, CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
171
173
  when 'admin'
@@ -177,14 +179,20 @@ module AnnotateModels
177
179
  end
178
180
  end
179
181
 
180
- def get_patterns(pattern_types = [])
182
+ def get_patterns(options, pattern_types = [])
181
183
  current_patterns = []
182
184
  root_dir.each do |root_directory|
183
185
  Array(pattern_types).each do |pattern_type|
184
- current_patterns += files_by_pattern(root_directory, pattern_type)
186
+ patterns = files_by_pattern(root_directory, pattern_type, options)
187
+
188
+ current_patterns += if pattern_type.to_sym == :additional_file_patterns
189
+ patterns
190
+ else
191
+ patterns.map { |p| p.sub(/^[\/]*/, '') }
192
+ end
185
193
  end
186
194
  end
187
- current_patterns.map { |p| p.sub(/^[\/]*/, '') }
195
+ current_patterns
188
196
  end
189
197
 
190
198
  # Simple quoting for the default column value
@@ -581,8 +589,9 @@ module AnnotateModels
581
589
  end
582
590
 
583
591
  def matched_types(options)
584
- types = MATCHED_TYPES
592
+ types = MATCHED_TYPES.dup
585
593
  types << 'admin' if options[:active_admin] =~ TRUE_RE && !types.include?('admin')
594
+ types << 'additional_file_patterns' if options[:additional_file_patterns].present?
586
595
 
587
596
  types
588
597
  end
@@ -634,8 +643,11 @@ module AnnotateModels
634
643
  end
635
644
 
636
645
  next if options[exclusion_key]
637
- get_patterns(key)
646
+
647
+ get_patterns(options, key)
638
648
  .map { |f| resolve_filename(f, model_name, table_name) }
649
+ .map { |f| expand_glob_into_files(f) }
650
+ .flatten
639
651
  .each do |f|
640
652
  if annotate_one_file(f, info, position_key, options_with_position(options, position_key))
641
653
  annotated << f
@@ -793,6 +805,10 @@ module AnnotateModels
793
805
  end
794
806
  end
795
807
 
808
+ def expand_glob_into_files(glob)
809
+ Dir.glob(glob)
810
+ end
811
+
796
812
  def annotate_model_file(annotated, file, header, options)
797
813
  begin
798
814
  return false if /#{SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '')
@@ -830,7 +846,7 @@ module AnnotateModels
830
846
  model_file_name = file
831
847
  deannotated_klass = true if remove_annotation_of_file(model_file_name, options)
832
848
 
833
- get_patterns(matched_types(options))
849
+ get_patterns(options, matched_types(options))
834
850
  .map { |f| resolve_filename(f, model_name, table_name) }
835
851
  .each do |f|
836
852
  if File.exist?(f)
@@ -910,7 +926,11 @@ module AnnotateModels
910
926
  def mb_chars_ljust(string, length)
911
927
  string = string.to_s
912
928
  padding = length - width(string)
913
- string + (' ' * padding)
929
+ if padding > 0
930
+ string + (' ' * padding)
931
+ else
932
+ string[0..length-1]
933
+ end
914
934
  end
915
935
  end
916
936
 
@@ -10,7 +10,7 @@
10
10
  # Yes, it's simple but I'm thick and often need a reminder of what my routes
11
11
  # mean.
12
12
  #
13
- # Running this task will replace any exising route comment generated by the
13
+ # Running this task will replace any existing route comment generated by the
14
14
  # task. Best to back up your routes file before running:
15
15
  #
16
16
  # Author:
@@ -25,14 +25,53 @@ module AnnotateRoutes
25
25
  HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action']
26
26
 
27
27
  class << self
28
- def content(line, maxs, options = {})
29
- return line.rstrip unless options[:format_markdown]
28
+ def do_annotations(options = {})
29
+ return unless routes_exists?
30
+ existing_text = File.read(routes_file)
30
31
 
31
- line.each_with_index.map do |elem, index|
32
- min_length = maxs.map { |arr| arr[index] }.max || 0
32
+ if rewrite_contents_with_header(existing_text, header(options), options)
33
+ puts "#{routes_file} annotated."
34
+ end
35
+ end
33
36
 
34
- sprintf("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
35
- end.join(' | ')
37
+ def remove_annotations(_options={})
38
+ return unless routes_exists?
39
+ existing_text = File.read(routes_file)
40
+ content, where_header_found = strip_annotations(existing_text)
41
+ new_content = strip_on_removal(content, where_header_found)
42
+ if rewrite_contents(existing_text, new_content)
43
+ puts "Removed annotations from #{routes_file}."
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def routes_exists?
50
+ routes_exists = File.exists?(routes_file)
51
+ puts "Can't find routes.rb" unless routes_exists
52
+
53
+ routes_exists
54
+ end
55
+
56
+ def routes_file
57
+ @routes_rb ||= File.join('config', 'routes.rb')
58
+ end
59
+
60
+ def rewrite_contents_with_header(existing_text, header, options = {})
61
+ content, where_header_found = strip_annotations(existing_text)
62
+ new_content = annotate_routes(header, content, where_header_found, options)
63
+
64
+ # Make sure we end on a trailing newline.
65
+ new_content << '' unless new_content.last == ''
66
+ new_text = new_content.join("\n")
67
+
68
+ if existing_text == new_text
69
+ puts "#{routes_file} unchanged."
70
+ false
71
+ else
72
+ File.open(routes_file, 'wb') { |f| f.puts(new_text) }
73
+ true
74
+ end
36
75
  end
37
76
 
38
77
  def header(options = {})
@@ -70,180 +109,143 @@ module AnnotateRoutes
70
109
  out
71
110
  end
72
111
 
73
- def do_annotations(options = {})
74
- return unless routes_exists?
75
- existing_text = File.read(routes_file)
76
-
77
- if rewrite_contents_with_header(existing_text, header(options), options)
78
- puts "#{routes_file} annotated."
112
+ # TODO: write the method doc using ruby rdoc formats
113
+ # where_header_found => This will either be :before, :after, or
114
+ # a number. If the number is > 0, the
115
+ # annotation was found somewhere in the
116
+ # middle of the file. If the number is
117
+ # zero, no annotation was found.
118
+ def strip_annotations(content)
119
+ real_content = []
120
+ mode = :content
121
+ header_found_at = 0
122
+
123
+ content.split(/\n/, -1).each_with_index do |line, line_number|
124
+ if mode == :header && line !~ /\s*#/
125
+ mode = :content
126
+ real_content << line unless line.blank?
127
+ elsif mode == :content
128
+ if line =~ /^\s*#\s*== Route.*$/
129
+ header_found_at = line_number + 1 # index start's at 0
130
+ mode = :header
131
+ else
132
+ real_content << line
133
+ end
134
+ end
79
135
  end
136
+
137
+ where_header_found(real_content, header_found_at)
80
138
  end
81
139
 
82
- def remove_annotations(_options={})
83
- return unless routes_exists?
84
- existing_text = File.read(routes_file)
85
- content, where_header_found = strip_annotations(existing_text)
86
- new_content = strip_on_removal(content, where_header_found)
87
- if rewrite_contents(existing_text, new_content)
88
- puts "Removed annotations from #{routes_file}."
140
+ def strip_on_removal(content, where_header_found)
141
+ if where_header_found == :before
142
+ content.shift while content.first == ''
143
+ elsif where_header_found == :after
144
+ content.pop while content.last == ''
89
145
  end
90
- end
91
- end
92
146
 
93
- def self.magic_comment_matcher
94
- Regexp.new(/(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/)
95
- end
147
+ # TODO: If the user buried it in the middle, we should probably see about
148
+ # TODO: preserving a single line of space between the content above and
149
+ # TODO: below...
150
+ content
151
+ end
96
152
 
97
- # @param [Array<String>] content
98
- # @return [Array<String>] all found magic comments
99
- # @return [Array<String>] content without magic comments
100
- def self.extract_magic_comments_from_array(content_array)
101
- magic_comments = []
102
- new_content = []
153
+ # @param [String, Array<String>]
154
+ def rewrite_contents(existing_text, new_content)
155
+ # Make sure we end on a trailing newline.
156
+ new_content << '' unless new_content.last == ''
157
+ new_text = new_content.join("\n")
103
158
 
104
- content_array.map do |row|
105
- if row =~ magic_comment_matcher
106
- magic_comments << row.strip
159
+ if existing_text == new_text
160
+ puts "#{routes_file} unchanged."
161
+ false
107
162
  else
108
- new_content << row
163
+ File.open(routes_file, 'wb') { |f| f.puts(new_text) }
164
+ true
109
165
  end
110
166
  end
111
167
 
112
- [magic_comments, new_content]
113
- end
114
-
115
- def self.app_routes_map(options)
116
- routes_map = `rake routes`.chomp("\n").split(/\n/, -1)
117
-
118
- # In old versions of Rake, the first line of output was the cwd. Not so
119
- # much in newer ones. We ditch that line if it exists, and if not, we
120
- # keep the line around.
121
- routes_map.shift if routes_map.first =~ /^\(in \//
122
-
123
- # Skip routes which match given regex
124
- # Note: it matches the complete line (route_name, path, controller/action)
125
- if options[:ignore_routes]
126
- routes_map.reject! { |line| line =~ /#{options[:ignore_routes]}/ }
127
- end
128
-
129
- routes_map
130
- end
131
-
132
- def self.routes_file
133
- @routes_rb ||= File.join('config', 'routes.rb')
134
- end
168
+ def annotate_routes(header, content, where_header_found, options = {})
169
+ magic_comments_map, content = extract_magic_comments_from_array(content)
170
+ if %w(before top).include?(options[:position_in_routes])
171
+ header = header << '' if content.first != ''
172
+ magic_comments_map << '' if magic_comments_map.any?
173
+ new_content = magic_comments_map + header + content
174
+ else
175
+ # Ensure we have adequate trailing newlines at the end of the file to
176
+ # ensure a blank line separating the content from the annotation.
177
+ content << '' unless content.last == ''
135
178
 
136
- def self.routes_exists?
137
- routes_exists = File.exists?(routes_file)
138
- puts "Can't find routes.rb" unless routes_exists
179
+ # We're moving something from the top of the file to the bottom, so ditch
180
+ # the spacer we put in the first time around.
181
+ content.shift if where_header_found == :before && content.first == ''
139
182
 
140
- routes_exists
141
- end
183
+ new_content = magic_comments_map + content + header
184
+ end
142
185
 
143
- # @param [String, Array<String>]
144
- def self.rewrite_contents(existing_text, new_content)
145
- # Make sure we end on a trailing newline.
146
- new_content << '' unless new_content.last == ''
147
- new_text = new_content.join("\n")
148
-
149
- if existing_text == new_text
150
- puts "#{routes_file} unchanged."
151
- false
152
- else
153
- File.open(routes_file, 'wb') { |f| f.puts(new_text) }
154
- true
186
+ new_content
155
187
  end
156
- end
157
188
 
158
- def self.rewrite_contents_with_header(existing_text, header, options = {})
159
- content, where_header_found = strip_annotations(existing_text)
160
- new_content = annotate_routes(header, content, where_header_found, options)
189
+ def app_routes_map(options)
190
+ routes_map = `rake routes`.chomp("\n").split(/\n/, -1)
161
191
 
162
- # Make sure we end on a trailing newline.
163
- new_content << '' unless new_content.last == ''
164
- new_text = new_content.join("\n")
192
+ # In old versions of Rake, the first line of output was the cwd. Not so
193
+ # much in newer ones. We ditch that line if it exists, and if not, we
194
+ # keep the line around.
195
+ routes_map.shift if routes_map.first =~ /^\(in \//
165
196
 
166
- if existing_text == new_text
167
- puts "#{routes_file} unchanged."
168
- false
169
- else
170
- File.open(routes_file, 'wb') { |f| f.puts(new_text) }
171
- true
172
- end
173
- end
197
+ # Skip routes which match given regex
198
+ # Note: it matches the complete line (route_name, path, controller/action)
199
+ if options[:ignore_routes]
200
+ routes_map.reject! { |line| line =~ /#{options[:ignore_routes]}/ }
201
+ end
174
202
 
175
- def self.annotate_routes(header, content, where_header_found, options = {})
176
- magic_comments_map, content = extract_magic_comments_from_array(content)
177
- if %w(before top).include?(options[:position_in_routes])
178
- header = header << '' if content.first != ''
179
- magic_comments_map << '' if magic_comments_map.any?
180
- new_content = magic_comments_map + header + content
181
- else
182
- # Ensure we have adequate trailing newlines at the end of the file to
183
- # ensure a blank line separating the content from the annotation.
184
- content << '' unless content.last == ''
185
-
186
- # We're moving something from the top of the file to the bottom, so ditch
187
- # the spacer we put in the first time around.
188
- content.shift if where_header_found == :before && content.first == ''
189
-
190
- new_content = magic_comments_map + content + header
203
+ routes_map
191
204
  end
192
205
 
193
- new_content
194
- end
206
+ # @param [Array<String>] content
207
+ # @return [Array<String>] all found magic comments
208
+ # @return [Array<String>] content without magic comments
209
+ def extract_magic_comments_from_array(content_array)
210
+ magic_comments = []
211
+ new_content = []
195
212
 
196
- # TODO: write the method doc using ruby rdoc formats
197
- # where_header_found => This will either be :before, :after, or
198
- # a number. If the number is > 0, the
199
- # annotation was found somewhere in the
200
- # middle of the file. If the number is
201
- # zero, no annotation was found.
202
- def self.strip_annotations(content)
203
- real_content = []
204
- mode = :content
205
- header_found_at = 0
206
-
207
- content.split(/\n/, -1).each_with_index do |line, line_number|
208
- if mode == :header && line !~ /\s*#/
209
- mode = :content
210
- real_content << line unless line.blank?
211
- elsif mode == :content
212
- if line =~ /^\s*#\s*== Route.*$/
213
- header_found_at = line_number + 1 # index start's at 0
214
- mode = :header
213
+ content_array.map do |row|
214
+ if row =~ magic_comment_matcher
215
+ magic_comments << row.strip
215
216
  else
216
- real_content << line
217
+ new_content << row
217
218
  end
218
219
  end
220
+
221
+ [magic_comments, new_content]
219
222
  end
220
223
 
221
- where_header_found(real_content, header_found_at)
222
- end
224
+ def content(line, maxs, options = {})
225
+ return line.rstrip unless options[:format_markdown]
226
+
227
+ line.each_with_index.map do |elem, index|
228
+ min_length = maxs.map { |arr| arr[index] }.max || 0
223
229
 
224
- def self.where_header_found(real_content, header_found_at)
225
- # By default assume the annotation was found in the middle of the file
230
+ sprintf("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
231
+ end.join(' | ')
232
+ end
226
233
 
227
- # ... unless we have evidence it was at the beginning ...
228
- return real_content, :before if header_found_at == 1
234
+ def where_header_found(real_content, header_found_at)
235
+ # By default assume the annotation was found in the middle of the file
229
236
 
230
- # ... or that it was at the end.
231
- return real_content, :after if header_found_at >= real_content.count
237
+ # ... unless we have evidence it was at the beginning ...
238
+ return real_content, :before if header_found_at == 1
232
239
 
233
- # and the default
234
- return real_content, header_found_at
235
- end
240
+ # ... or that it was at the end.
241
+ return real_content, :after if header_found_at >= real_content.count
236
242
 
237
- def self.strip_on_removal(content, where_header_found)
238
- if where_header_found == :before
239
- content.shift while content.first == ''
240
- elsif where_header_found == :after
241
- content.pop while content.last == ''
243
+ # and the default
244
+ return real_content, header_found_at
242
245
  end
243
246
 
244
- # TODO: If the user buried it in the middle, we should probably see about
245
- # TODO: preserving a single line of space between the content above and
246
- # TODO: below...
247
- content
247
+ def magic_comment_matcher
248
+ Regexp.new(/(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/)
249
+ end
248
250
  end
249
251
  end
@@ -1,5 +1,5 @@
1
1
  module Annotate
2
2
  def self.version
3
- '2.7.5'
3
+ '3.0.0'
4
4
  end
5
5
  end
@@ -7,47 +7,49 @@ if Rails.env.development?
7
7
  # You can override any of these by setting an environment variable of the
8
8
  # same name.
9
9
  Annotate.set_defaults(
10
- 'routes' => 'false',
11
- 'position_in_routes' => 'before',
12
- 'position_in_class' => 'before',
13
- 'position_in_test' => 'before',
14
- 'position_in_fixture' => 'before',
15
- 'position_in_factory' => 'before',
16
- 'position_in_serializer' => 'before',
17
- 'show_foreign_keys' => 'true',
18
- 'show_complete_foreign_keys' => 'false',
19
- 'show_indexes' => 'true',
20
- 'simple_indexes' => 'false',
21
- 'model_dir' => 'app/models',
22
- 'root_dir' => '',
23
- 'include_version' => 'false',
24
- 'require' => '',
25
- 'exclude_tests' => 'false',
26
- 'exclude_fixtures' => 'false',
27
- 'exclude_factories' => 'false',
28
- 'exclude_serializers' => 'false',
29
- 'exclude_scaffolds' => 'true',
30
- 'exclude_controllers' => 'true',
31
- 'exclude_helpers' => 'true',
32
- 'exclude_sti_subclasses' => 'false',
33
- 'ignore_model_sub_dir' => 'false',
34
- 'ignore_columns' => nil,
35
- 'ignore_routes' => nil,
36
- 'ignore_unknown_models' => 'false',
37
- 'hide_limit_column_types' => '<%= AnnotateModels::NO_LIMIT_COL_TYPES.join(",") %>',
38
- 'hide_default_column_types' => '<%= AnnotateModels::NO_DEFAULT_COL_TYPES.join(",") %>',
39
- 'skip_on_db_migrate' => 'false',
40
- 'format_bare' => 'true',
41
- 'format_rdoc' => 'false',
42
- 'format_markdown' => 'false',
43
- 'sort' => 'false',
44
- 'force' => 'false',
45
- 'frozen' => 'false',
46
- 'classified_sort' => 'true',
47
- 'trace' => 'false',
48
- 'wrapper_open' => nil,
49
- 'wrapper_close' => nil,
50
- 'with_comment' => 'true'
10
+ 'additional_file_patterns' => [],
11
+ 'routes' => 'false',
12
+ 'models' => 'false',
13
+ 'position_in_routes' => 'before',
14
+ 'position_in_class' => 'before',
15
+ 'position_in_test' => 'before',
16
+ 'position_in_fixture' => 'before',
17
+ 'position_in_factory' => 'before',
18
+ 'position_in_serializer' => 'before',
19
+ 'show_foreign_keys' => 'true',
20
+ 'show_complete_foreign_keys' => 'false',
21
+ 'show_indexes' => 'true',
22
+ 'simple_indexes' => 'false',
23
+ 'model_dir' => 'app/models',
24
+ 'root_dir' => '',
25
+ 'include_version' => 'false',
26
+ 'require' => '',
27
+ 'exclude_tests' => 'false',
28
+ 'exclude_fixtures' => 'false',
29
+ 'exclude_factories' => 'false',
30
+ 'exclude_serializers' => 'false',
31
+ 'exclude_scaffolds' => 'true',
32
+ 'exclude_controllers' => 'true',
33
+ 'exclude_helpers' => 'true',
34
+ 'exclude_sti_subclasses' => 'false',
35
+ 'ignore_model_sub_dir' => 'false',
36
+ 'ignore_columns' => nil,
37
+ 'ignore_routes' => nil,
38
+ 'ignore_unknown_models' => 'false',
39
+ 'hide_limit_column_types' => '<%= AnnotateModels::NO_LIMIT_COL_TYPES.join(",") %>',
40
+ 'hide_default_column_types' => '<%= AnnotateModels::NO_DEFAULT_COL_TYPES.join(",") %>',
41
+ 'skip_on_db_migrate' => 'false',
42
+ 'format_bare' => 'true',
43
+ 'format_rdoc' => 'false',
44
+ 'format_markdown' => 'false',
45
+ 'sort' => 'false',
46
+ 'force' => 'false',
47
+ 'frozen' => 'false',
48
+ 'classified_sort' => 'true',
49
+ 'trace' => 'false',
50
+ 'wrapper_open' => nil,
51
+ 'wrapper_close' => nil,
52
+ 'with_comment' => 'true'
51
53
  )
52
54
  end
53
55
 
@@ -12,6 +12,7 @@ task annotate_models: :environment do
12
12
 
13
13
  options = {is_rake: true}
14
14
  ENV['position'] = options[:position] = Annotate.fallback(ENV['position'], 'before')
15
+ options[:additional_file_patterns] = ENV['additional_file_patterns'] ? ENV['additional_file_patterns'].split(',') : []
15
16
  options[:position_in_class] = Annotate.fallback(ENV['position_in_class'], ENV['position'])
16
17
  options[:position_in_fixture] = Annotate.fallback(ENV['position_in_fixture'], ENV['position'])
17
18
  options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position'])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: annotate
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.5
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Chaffee
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2019-04-27 00:00:00.000000000 Z
15
+ date: 2019-09-27 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rake
@@ -108,7 +108,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
- rubygems_version: 3.0.3
111
+ rubyforge_project:
112
+ rubygems_version: 2.7.7
112
113
  signing_key:
113
114
  specification_version: 4
114
115
  summary: Annotates Rails Models, routes, fixtures, and others based on the database