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 +4 -4
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +27 -7
- data/annotate.gemspec +0 -1
- data/bin/annotate +6 -190
- data/lib/annotate.rb +4 -3
- data/lib/annotate/annotate_models.rb +28 -8
- data/lib/annotate/annotate_routes.rb +150 -148
- data/lib/annotate/version.rb +1 -1
- data/lib/generators/annotate/templates/auto_annotate_models.rake +43 -41
- data/lib/tasks/annotate_models.rake +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e4ee3c38fb2ebf3d88712e8836f00570e891cd1a43a6c2bc32c95dc35b7a0d2
|
4
|
+
data.tar.gz: 1082be239480425543d84491e8c03d54ad99b362cc142b93224517499d4417fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4896d07fc9b6d6b95d5916e566cc0d9a304cd16c1592ac0a0546bb273d533c7dfb275c55b2833586e677027e7f34f6a4f38281053e6e454553be527f4e23055c
|
7
|
+
data.tar.gz: c72e8ba788014600e40ba24fe7385b9c6c10c08d293ee98bd71e0d91cc235c1a14242293ae963c9265c8e318fa09a104e60547a24c7697218b06be68f320fa63
|
data/CHANGELOG.rdoc
CHANGED
@@ -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
|
|
data/README.rdoc
CHANGED
@@ -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 --
|
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 (
|
210
|
-
--ignore-routes REGEX don't annotate routes that match a given REGEX (
|
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 (
|
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 (
|
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%/*.rb</code>
|
229
|
+
- <code>/app/lib/forms/%PLURALIZED_MODEL_NAME%/**/*.rb</code>
|
230
|
+
- <code>/app/lib/forms/%TABLE_NAME%/*.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
|
|
data/annotate.gemspec
CHANGED
@@ -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
|
|
data/bin/annotate
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
202
|
-
ENV['ignore_unknown_models'] = 'true'
|
203
|
-
end
|
22
|
+
options_result = Annotate::Parser.parse(ARGV)
|
204
23
|
|
205
|
-
|
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?
|
data/lib/annotate.rb
CHANGED
@@ -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['
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
29
|
-
return
|
28
|
+
def do_annotations(options = {})
|
29
|
+
return unless routes_exists?
|
30
|
+
existing_text = File.read(routes_file)
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
if rewrite_contents_with_header(existing_text, header(options), options)
|
33
|
+
puts "#{routes_file} annotated."
|
34
|
+
end
|
35
|
+
end
|
33
36
|
|
34
|
-
|
35
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
159
|
+
if existing_text == new_text
|
160
|
+
puts "#{routes_file} unchanged."
|
161
|
+
false
|
107
162
|
else
|
108
|
-
|
163
|
+
File.open(routes_file, 'wb') { |f| f.puts(new_text) }
|
164
|
+
true
|
109
165
|
end
|
110
166
|
end
|
111
167
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
141
|
-
|
183
|
+
new_content = magic_comments_map + content + header
|
184
|
+
end
|
142
185
|
|
143
|
-
|
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
|
-
|
159
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
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
|
-
|
194
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
217
|
+
new_content << row
|
217
218
|
end
|
218
219
|
end
|
220
|
+
|
221
|
+
[magic_comments, new_content]
|
219
222
|
end
|
220
223
|
|
221
|
-
|
222
|
-
|
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
|
-
|
225
|
-
|
230
|
+
sprintf("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
|
231
|
+
end.join(' | ')
|
232
|
+
end
|
226
233
|
|
227
|
-
|
228
|
-
|
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
|
-
|
231
|
-
|
237
|
+
# ... unless we have evidence it was at the beginning ...
|
238
|
+
return real_content, :before if header_found_at == 1
|
232
239
|
|
233
|
-
|
234
|
-
|
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
|
-
|
238
|
-
|
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
|
-
|
245
|
-
|
246
|
-
|
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
|
data/lib/annotate/version.rb
CHANGED
@@ -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
|
-
'
|
11
|
-
'
|
12
|
-
'
|
13
|
-
'
|
14
|
-
'
|
15
|
-
'
|
16
|
-
'
|
17
|
-
'
|
18
|
-
'
|
19
|
-
'
|
20
|
-
'
|
21
|
-
'
|
22
|
-
'
|
23
|
-
'
|
24
|
-
'
|
25
|
-
'
|
26
|
-
'
|
27
|
-
'
|
28
|
-
'
|
29
|
-
'
|
30
|
-
'
|
31
|
-
'
|
32
|
-
'
|
33
|
-
'
|
34
|
-
'
|
35
|
-
'
|
36
|
-
'
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'
|
40
|
-
'
|
41
|
-
'
|
42
|
-
'
|
43
|
-
'
|
44
|
-
'
|
45
|
-
'
|
46
|
-
'
|
47
|
-
'
|
48
|
-
'
|
49
|
-
'
|
50
|
-
'
|
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:
|
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-
|
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
|
-
|
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
|