annotate 2.7.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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