annotate 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/annotate.gemspec +6 -3
- data/lib/annotate/annotate_models/file_patterns.rb +127 -0
- data/lib/annotate/annotate_models.rb +71 -160
- data/lib/annotate/annotate_routes/header_generator.rb +113 -0
- data/lib/annotate/annotate_routes.rb +2 -77
- data/lib/annotate/version.rb +1 -1
- data/lib/tasks/annotate_models_migrate.rake +14 -1
- data/lib/tasks/annotate_routes.rake +7 -1
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a49c914d3c2486e109b4a499b71fe905c8534e21b1d44cee15056a3066468e2e
|
4
|
+
data.tar.gz: 383445b9f5c13d02da7190a009ed974b5f88b41fe88f156814e743b4f7ec99d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70b926aba8e1ba91ccf506cfdabb94016efaaf788beaf6bdc0691fb6ad30edf57b794842f93f9860e1f82fa38c2934530e6fc0940f88ce4b47a909da8456ddd0
|
7
|
+
data.tar.gz: bf94c7d38b3a11ddc658947a7c1f2164854070a5707f56c148bcbdd5495b88c270ee0f0e587b07c0c421724b40059f110c808a8f3af90e68a86c5e249dfb1fa1
|
data/README.md
CHANGED
@@ -104,8 +104,8 @@ Into environment gems from Github checkout:
|
|
104
104
|
|
105
105
|
git clone https://github.com/ctran/annotate_models.git annotate_models
|
106
106
|
cd annotate_models
|
107
|
-
rake
|
108
|
-
gem install
|
107
|
+
rake gem
|
108
|
+
gem install dist/annotate-*.gem
|
109
109
|
|
110
110
|
## Usage
|
111
111
|
|
data/annotate.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.executables = ['annotate']
|
16
16
|
s.extra_rdoc_files = ['README.md', 'CHANGELOG.md']
|
17
17
|
s.files = `git ls-files -z LICENSE.txt *.md *.gemspec bin lib`.split("\x0")
|
18
|
-
s.homepage = '
|
18
|
+
s.homepage = 'https://github.com/ctran/annotate_models'
|
19
19
|
s.licenses = ['Ruby']
|
20
20
|
s.require_paths = ['lib']
|
21
21
|
s.rubygems_version = '2.1.11'
|
@@ -23,7 +23,10 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
s.specification_version = 4 if s.respond_to? :specification_version
|
25
25
|
s.add_runtime_dependency(%q<rake>, '>= 10.4', '< 14.0')
|
26
|
-
s.add_runtime_dependency(%q<activerecord>, ['>= 3.2', '<
|
26
|
+
s.add_runtime_dependency(%q<activerecord>, ['>= 3.2', '< 8.0'])
|
27
27
|
|
28
|
-
s.metadata = {
|
28
|
+
s.metadata = {
|
29
|
+
"bug_tracker_uri" => "https://github.com/ctran/annotate_models/issues/",
|
30
|
+
"source_code_uri" => "https://github.com/ctran/annotate_models.git"
|
31
|
+
}
|
29
32
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module AnnotateModels
|
2
|
+
# This module provides module method to get file paths.
|
3
|
+
module FilePatterns
|
4
|
+
# Controller files
|
5
|
+
CONTROLLER_DIR = File.join('app', 'controllers')
|
6
|
+
|
7
|
+
# Active admin registry files
|
8
|
+
ACTIVEADMIN_DIR = File.join('app', 'admin')
|
9
|
+
|
10
|
+
# Helper files
|
11
|
+
HELPER_DIR = File.join('app', 'helpers')
|
12
|
+
|
13
|
+
# File.join for windows reverse bar compat?
|
14
|
+
# I dont use windows, can`t test
|
15
|
+
UNIT_TEST_DIR = File.join('test', 'unit')
|
16
|
+
MODEL_TEST_DIR = File.join('test', 'models') # since rails 4.0
|
17
|
+
SPEC_MODEL_DIR = File.join('spec', 'models')
|
18
|
+
|
19
|
+
FIXTURE_TEST_DIR = File.join('test', 'fixtures')
|
20
|
+
FIXTURE_SPEC_DIR = File.join('spec', 'fixtures')
|
21
|
+
|
22
|
+
# Other test files
|
23
|
+
CONTROLLER_TEST_DIR = File.join('test', 'controllers')
|
24
|
+
CONTROLLER_SPEC_DIR = File.join('spec', 'controllers')
|
25
|
+
REQUEST_SPEC_DIR = File.join('spec', 'requests')
|
26
|
+
ROUTING_SPEC_DIR = File.join('spec', 'routing')
|
27
|
+
|
28
|
+
# Object Daddy http://github.com/flogic/object_daddy/tree/master
|
29
|
+
EXEMPLARS_TEST_DIR = File.join('test', 'exemplars')
|
30
|
+
EXEMPLARS_SPEC_DIR = File.join('spec', 'exemplars')
|
31
|
+
|
32
|
+
# Machinist http://github.com/notahat/machinist
|
33
|
+
BLUEPRINTS_TEST_DIR = File.join('test', 'blueprints')
|
34
|
+
BLUEPRINTS_SPEC_DIR = File.join('spec', 'blueprints')
|
35
|
+
|
36
|
+
# Factory Bot https://github.com/thoughtbot/factory_bot
|
37
|
+
FACTORY_BOT_TEST_DIR = File.join('test', 'factories')
|
38
|
+
FACTORY_BOT_SPEC_DIR = File.join('spec', 'factories')
|
39
|
+
|
40
|
+
# Fabrication https://github.com/paulelliott/fabrication.git
|
41
|
+
FABRICATORS_TEST_DIR = File.join('test', 'fabricators')
|
42
|
+
FABRICATORS_SPEC_DIR = File.join('spec', 'fabricators')
|
43
|
+
|
44
|
+
# Serializers https://github.com/rails-api/active_model_serializers
|
45
|
+
SERIALIZERS_DIR = File.join('app', 'serializers')
|
46
|
+
SERIALIZERS_TEST_DIR = File.join('test', 'serializers')
|
47
|
+
SERIALIZERS_SPEC_DIR = File.join('spec', 'serializers')
|
48
|
+
|
49
|
+
class << self
|
50
|
+
def generate(root_directory, pattern_type, options)
|
51
|
+
case pattern_type
|
52
|
+
when 'test' then test_files(root_directory)
|
53
|
+
when 'fixture' then fixture_files(root_directory)
|
54
|
+
when 'scaffold' then scaffold_files(root_directory)
|
55
|
+
when 'factory' then factory_files(root_directory)
|
56
|
+
when 'serializer' then serialize_files(root_directory)
|
57
|
+
when 'additional_file_patterns'
|
58
|
+
[options[:additional_file_patterns] || []].flatten
|
59
|
+
when 'controller'
|
60
|
+
[File.join(root_directory, CONTROLLER_DIR, '%PLURALIZED_MODEL_NAME%_controller.rb')]
|
61
|
+
when 'admin'
|
62
|
+
[
|
63
|
+
File.join(root_directory, ACTIVEADMIN_DIR, '%MODEL_NAME%.rb'),
|
64
|
+
File.join(root_directory, ACTIVEADMIN_DIR, '%PLURALIZED_MODEL_NAME%.rb')
|
65
|
+
]
|
66
|
+
when 'helper'
|
67
|
+
[File.join(root_directory, HELPER_DIR, '%PLURALIZED_MODEL_NAME%_helper.rb')]
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def test_files(root_directory)
|
76
|
+
[
|
77
|
+
File.join(root_directory, UNIT_TEST_DIR, '%MODEL_NAME%_test.rb'),
|
78
|
+
File.join(root_directory, MODEL_TEST_DIR, '%MODEL_NAME%_test.rb'),
|
79
|
+
File.join(root_directory, SPEC_MODEL_DIR, '%MODEL_NAME%_spec.rb')
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
83
|
+
def fixture_files(root_directory)
|
84
|
+
[
|
85
|
+
File.join(root_directory, FIXTURE_TEST_DIR, '%TABLE_NAME%.yml'),
|
86
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, '%TABLE_NAME%.yml'),
|
87
|
+
File.join(root_directory, FIXTURE_TEST_DIR, '%PLURALIZED_MODEL_NAME%.yml'),
|
88
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, '%PLURALIZED_MODEL_NAME%.yml')
|
89
|
+
]
|
90
|
+
end
|
91
|
+
|
92
|
+
def scaffold_files(root_directory)
|
93
|
+
[
|
94
|
+
File.join(root_directory, CONTROLLER_TEST_DIR, '%PLURALIZED_MODEL_NAME%_controller_test.rb'),
|
95
|
+
File.join(root_directory, CONTROLLER_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_controller_spec.rb'),
|
96
|
+
File.join(root_directory, REQUEST_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_spec.rb'),
|
97
|
+
File.join(root_directory, ROUTING_SPEC_DIR, '%PLURALIZED_MODEL_NAME%_routing_spec.rb')
|
98
|
+
]
|
99
|
+
end
|
100
|
+
|
101
|
+
def factory_files(root_directory)
|
102
|
+
[
|
103
|
+
File.join(root_directory, EXEMPLARS_TEST_DIR, '%MODEL_NAME%_exemplar.rb'),
|
104
|
+
File.join(root_directory, EXEMPLARS_SPEC_DIR, '%MODEL_NAME%_exemplar.rb'),
|
105
|
+
File.join(root_directory, BLUEPRINTS_TEST_DIR, '%MODEL_NAME%_blueprint.rb'),
|
106
|
+
File.join(root_directory, BLUEPRINTS_SPEC_DIR, '%MODEL_NAME%_blueprint.rb'),
|
107
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%MODEL_NAME%_factory.rb'), # (old style)
|
108
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%MODEL_NAME%_factory.rb'), # (old style)
|
109
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%TABLE_NAME%.rb'), # (new style)
|
110
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%TABLE_NAME%.rb'), # (new style)
|
111
|
+
File.join(root_directory, FACTORY_BOT_TEST_DIR, '%PLURALIZED_MODEL_NAME%.rb'), # (new style)
|
112
|
+
File.join(root_directory, FACTORY_BOT_SPEC_DIR, '%PLURALIZED_MODEL_NAME%.rb'), # (new style)
|
113
|
+
File.join(root_directory, FABRICATORS_TEST_DIR, '%MODEL_NAME%_fabricator.rb'),
|
114
|
+
File.join(root_directory, FABRICATORS_SPEC_DIR, '%MODEL_NAME%_fabricator.rb')
|
115
|
+
]
|
116
|
+
end
|
117
|
+
|
118
|
+
def serialize_files(root_directory)
|
119
|
+
[
|
120
|
+
File.join(root_directory, SERIALIZERS_DIR, '%MODEL_NAME%_serializer.rb'),
|
121
|
+
File.join(root_directory, SERIALIZERS_TEST_DIR, '%MODEL_NAME%_serializer_test.rb'),
|
122
|
+
File.join(root_directory, SERIALIZERS_SPEC_DIR, '%MODEL_NAME%_serializer_spec.rb')
|
123
|
+
]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'bigdecimal'
|
4
4
|
|
5
5
|
require 'annotate/constants'
|
6
|
+
require_relative 'annotate_models/file_patterns'
|
6
7
|
|
7
8
|
module AnnotateModels
|
8
9
|
# Annotate Models plugin use this header
|
@@ -16,50 +17,6 @@ module AnnotateModels
|
|
16
17
|
|
17
18
|
MATCHED_TYPES = %w(test fixture factory serializer scaffold controller helper).freeze
|
18
19
|
|
19
|
-
# File.join for windows reverse bar compat?
|
20
|
-
# I dont use windows, can`t test
|
21
|
-
UNIT_TEST_DIR = File.join('test', "unit")
|
22
|
-
MODEL_TEST_DIR = File.join('test', "models") # since rails 4.0
|
23
|
-
SPEC_MODEL_DIR = File.join('spec', "models")
|
24
|
-
FIXTURE_TEST_DIR = File.join('test', "fixtures")
|
25
|
-
FIXTURE_SPEC_DIR = File.join('spec', "fixtures")
|
26
|
-
|
27
|
-
# Other test files
|
28
|
-
CONTROLLER_TEST_DIR = File.join('test', "controllers")
|
29
|
-
CONTROLLER_SPEC_DIR = File.join('spec', "controllers")
|
30
|
-
REQUEST_SPEC_DIR = File.join('spec', "requests")
|
31
|
-
ROUTING_SPEC_DIR = File.join('spec', "routing")
|
32
|
-
|
33
|
-
# Object Daddy http://github.com/flogic/object_daddy/tree/master
|
34
|
-
EXEMPLARS_TEST_DIR = File.join('test', "exemplars")
|
35
|
-
EXEMPLARS_SPEC_DIR = File.join('spec', "exemplars")
|
36
|
-
|
37
|
-
# Machinist http://github.com/notahat/machinist
|
38
|
-
BLUEPRINTS_TEST_DIR = File.join('test', "blueprints")
|
39
|
-
BLUEPRINTS_SPEC_DIR = File.join('spec', "blueprints")
|
40
|
-
|
41
|
-
# Factory Bot https://github.com/thoughtbot/factory_bot
|
42
|
-
FACTORY_BOT_TEST_DIR = File.join('test', "factories")
|
43
|
-
FACTORY_BOT_SPEC_DIR = File.join('spec', "factories")
|
44
|
-
|
45
|
-
# Fabrication https://github.com/paulelliott/fabrication.git
|
46
|
-
FABRICATORS_TEST_DIR = File.join('test', "fabricators")
|
47
|
-
FABRICATORS_SPEC_DIR = File.join('spec', "fabricators")
|
48
|
-
|
49
|
-
# Serializers https://github.com/rails-api/active_model_serializers
|
50
|
-
SERIALIZERS_DIR = File.join('app', "serializers")
|
51
|
-
SERIALIZERS_TEST_DIR = File.join('test', "serializers")
|
52
|
-
SERIALIZERS_SPEC_DIR = File.join('spec', "serializers")
|
53
|
-
|
54
|
-
# Controller files
|
55
|
-
CONTROLLER_DIR = File.join('app', "controllers")
|
56
|
-
|
57
|
-
# Active admin registry files
|
58
|
-
ACTIVEADMIN_DIR = File.join('app', "admin")
|
59
|
-
|
60
|
-
# Helper files
|
61
|
-
HELPER_DIR = File.join('app', "helpers")
|
62
|
-
|
63
20
|
# Don't show limit (#) on these column types
|
64
21
|
# Example: show "integer" instead of "integer(4)"
|
65
22
|
NO_LIMIT_COL_TYPES = %w(integer bigint boolean).freeze
|
@@ -110,82 +67,24 @@ module AnnotateModels
|
|
110
67
|
|
111
68
|
attr_writer :root_dir
|
112
69
|
|
113
|
-
def
|
114
|
-
[
|
115
|
-
|
116
|
-
File.join(root_directory, MODEL_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
117
|
-
File.join(root_directory, SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb")
|
118
|
-
]
|
119
|
-
end
|
120
|
-
|
121
|
-
def fixture_files(root_directory)
|
122
|
-
[
|
123
|
-
File.join(root_directory, FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"),
|
124
|
-
File.join(root_directory, FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"),
|
125
|
-
File.join(root_directory, FIXTURE_TEST_DIR, "%PLURALIZED_MODEL_NAME%.yml"),
|
126
|
-
File.join(root_directory, FIXTURE_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.yml")
|
127
|
-
]
|
128
|
-
end
|
129
|
-
|
130
|
-
def scaffold_files(root_directory)
|
131
|
-
[
|
132
|
-
File.join(root_directory, CONTROLLER_TEST_DIR, "%PLURALIZED_MODEL_NAME%_controller_test.rb"),
|
133
|
-
File.join(root_directory, CONTROLLER_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_controller_spec.rb"),
|
134
|
-
File.join(root_directory, REQUEST_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_spec.rb"),
|
135
|
-
File.join(root_directory, ROUTING_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_routing_spec.rb")
|
136
|
-
]
|
137
|
-
end
|
138
|
-
|
139
|
-
def factory_files(root_directory)
|
140
|
-
[
|
141
|
-
File.join(root_directory, EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"),
|
142
|
-
File.join(root_directory, EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
|
143
|
-
File.join(root_directory, BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
|
144
|
-
File.join(root_directory, BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
|
145
|
-
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
146
|
-
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
147
|
-
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
|
148
|
-
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
|
149
|
-
File.join(root_directory, FACTORY_BOT_TEST_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
150
|
-
File.join(root_directory, FACTORY_BOT_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.rb"), # (new style)
|
151
|
-
File.join(root_directory, FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
|
152
|
-
File.join(root_directory, FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
|
153
|
-
]
|
154
|
-
end
|
155
|
-
|
156
|
-
def serialize_files(root_directory)
|
157
|
-
[
|
158
|
-
File.join(root_directory, SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb"),
|
159
|
-
File.join(root_directory, SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_test.rb"),
|
160
|
-
File.join(root_directory, SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
|
161
|
-
]
|
162
|
-
end
|
70
|
+
def skip_subdirectory_model_load
|
71
|
+
# This option is set in options[:skip_subdirectory_model_load]
|
72
|
+
# and stops the get_loaded_model method from loading a model from a subdir
|
163
73
|
|
164
|
-
|
165
|
-
|
166
|
-
when 'test' then test_files(root_directory)
|
167
|
-
when 'fixture' then fixture_files(root_directory)
|
168
|
-
when 'scaffold' then scaffold_files(root_directory)
|
169
|
-
when 'factory' then factory_files(root_directory)
|
170
|
-
when 'serializer' then serialize_files(root_directory)
|
171
|
-
when 'additional_file_patterns'
|
172
|
-
[options[:additional_file_patterns] || []].flatten
|
173
|
-
when 'controller'
|
174
|
-
[File.join(root_directory, CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
|
175
|
-
when 'admin'
|
176
|
-
[File.join(root_directory, ACTIVEADMIN_DIR, "%MODEL_NAME%.rb")]
|
177
|
-
when 'helper'
|
178
|
-
[File.join(root_directory, HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")]
|
74
|
+
if @skip_subdirectory_model_load.blank?
|
75
|
+
false
|
179
76
|
else
|
180
|
-
|
77
|
+
@skip_subdirectory_model_load
|
181
78
|
end
|
182
79
|
end
|
183
80
|
|
81
|
+
attr_writer :skip_subdirectory_model_load
|
82
|
+
|
184
83
|
def get_patterns(options, pattern_types = [])
|
185
84
|
current_patterns = []
|
186
85
|
root_dir.each do |root_directory|
|
187
86
|
Array(pattern_types).each do |pattern_type|
|
188
|
-
patterns =
|
87
|
+
patterns = FilePatterns.generate(root_directory, pattern_type, options)
|
189
88
|
|
190
89
|
current_patterns += if pattern_type.to_sym == :additional_file_patterns
|
191
90
|
patterns
|
@@ -249,52 +148,13 @@ module AnnotateModels
|
|
249
148
|
cols = columns(klass, options)
|
250
149
|
cols.each do |col|
|
251
150
|
col_type = get_col_type(col)
|
252
|
-
attrs =
|
253
|
-
attrs << "default(#{schema_default(klass, col)})" unless col.default.nil? || hide_default?(col_type, options)
|
254
|
-
attrs << 'unsigned' if col.respond_to?(:unsigned?) && col.unsigned?
|
255
|
-
attrs << 'not null' unless col.null
|
256
|
-
attrs << 'primary key' if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect(&:to_sym).include?(col.name.to_sym) : col.name.to_sym == klass.primary_key.to_sym)
|
257
|
-
|
258
|
-
if col_type == 'decimal'
|
259
|
-
col_type << "(#{col.precision}, #{col.scale})"
|
260
|
-
elsif !%w[spatial geometry geography].include?(col_type)
|
261
|
-
if col.limit && !options[:format_yard]
|
262
|
-
if col.limit.is_a? Array
|
263
|
-
attrs << "(#{col.limit.join(', ')})"
|
264
|
-
else
|
265
|
-
col_type << "(#{col.limit})" unless hide_limit?(col_type, options)
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
# Check out if we got an array column
|
271
|
-
attrs << 'is an Array' if col.respond_to?(:array) && col.array
|
272
|
-
|
273
|
-
# Check out if we got a geometric column
|
274
|
-
# and print the type and SRID
|
275
|
-
if col.respond_to?(:geometry_type)
|
276
|
-
attrs << "#{col.geometry_type}, #{col.srid}"
|
277
|
-
elsif col.respond_to?(:geometric_type) && col.geometric_type.present?
|
278
|
-
attrs << "#{col.geometric_type.to_s.downcase}, #{col.srid}"
|
279
|
-
end
|
280
|
-
|
281
|
-
# Check if the column has indices and print "indexed" if true
|
282
|
-
# If the index includes another column, print it too.
|
283
|
-
if options[:simple_indexes] && klass.table_exists?# Check out if this column is indexed
|
284
|
-
indices = retrieve_indexes_from_table(klass)
|
285
|
-
if indices = indices.select { |ind| ind.columns.include? col.name }
|
286
|
-
indices.sort_by(&:name).each do |ind|
|
287
|
-
next if ind.columns.is_a?(String)
|
288
|
-
ind = ind.columns.reject! { |i| i == col.name }
|
289
|
-
attrs << (ind.empty? ? "indexed" : "indexed => [#{ind.join(", ")}]")
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
151
|
+
attrs = get_attributes(col, col_type, klass, options)
|
293
152
|
col_name = if with_comments?(klass, options) && col.comment
|
294
|
-
"#{col.name}(#{col.comment})"
|
153
|
+
"#{col.name}(#{col.comment.gsub(/\n/, "\\n")})"
|
295
154
|
else
|
296
155
|
col.name
|
297
156
|
end
|
157
|
+
|
298
158
|
if options[:format_rdoc]
|
299
159
|
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
|
300
160
|
elsif options[:format_yard]
|
@@ -739,14 +599,17 @@ module AnnotateModels
|
|
739
599
|
|
740
600
|
# Retrieve loaded model class
|
741
601
|
def get_loaded_model(model_path, file)
|
742
|
-
|
743
|
-
|
602
|
+
unless skip_subdirectory_model_load
|
603
|
+
loaded_model_class = get_loaded_model_by_path(model_path)
|
604
|
+
return loaded_model_class if loaded_model_class
|
605
|
+
end
|
744
606
|
|
745
607
|
# We cannot get loaded model when `model_path` is loaded by Rails
|
746
608
|
# auto_load/eager_load paths. Try all possible model paths one by one.
|
747
609
|
absolute_file = File.expand_path(file)
|
748
610
|
model_paths =
|
749
|
-
$LOAD_PATH.
|
611
|
+
$LOAD_PATH.map(&:to_s)
|
612
|
+
.select { |path| absolute_file.include?(path) }
|
750
613
|
.map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(/^\//, '') }
|
751
614
|
model_paths
|
752
615
|
.map { |path| get_loaded_model_by_path(path) }
|
@@ -769,6 +632,7 @@ module AnnotateModels
|
|
769
632
|
def parse_options(options = {})
|
770
633
|
self.model_dir = split_model_dir(options[:model_dir]) if options[:model_dir]
|
771
634
|
self.root_dir = options[:root_dir] if options[:root_dir]
|
635
|
+
self.skip_subdirectory_model_load = options[:skip_subdirectory_model_load].present?
|
772
636
|
end
|
773
637
|
|
774
638
|
def split_model_dir(option_value)
|
@@ -809,7 +673,7 @@ module AnnotateModels
|
|
809
673
|
begin
|
810
674
|
return false if /#{SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '')
|
811
675
|
klass = get_model_class(file)
|
812
|
-
do_annotate = klass &&
|
676
|
+
do_annotate = klass.is_a?(Class) &&
|
813
677
|
klass < ActiveRecord::Base &&
|
814
678
|
(!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name)) &&
|
815
679
|
!klass.abstract_class? &&
|
@@ -982,9 +846,7 @@ module AnnotateModels
|
|
982
846
|
# Construct the foreign column name in the translations table
|
983
847
|
# eg. Model: Car, foreign column name: car_id
|
984
848
|
foreign_column_name = [
|
985
|
-
klass.
|
986
|
-
.gsub('::Translation', '').gsub('::', '_')
|
987
|
-
.downcase,
|
849
|
+
klass.table_name.to_s.singularize,
|
988
850
|
'_id'
|
989
851
|
].join.to_sym
|
990
852
|
|
@@ -996,6 +858,55 @@ module AnnotateModels
|
|
996
858
|
foreign_column_name
|
997
859
|
]
|
998
860
|
end
|
861
|
+
|
862
|
+
##
|
863
|
+
# Get the list of attributes that should be included in the annotation for
|
864
|
+
# a given column.
|
865
|
+
def get_attributes(column, column_type, klass, options)
|
866
|
+
attrs = []
|
867
|
+
attrs << "default(#{schema_default(klass, column)})" unless column.default.nil? || hide_default?(column_type, options)
|
868
|
+
attrs << 'unsigned' if column.respond_to?(:unsigned?) && column.unsigned?
|
869
|
+
attrs << 'not null' unless column.null
|
870
|
+
attrs << 'primary key' if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect(&:to_sym).include?(column.name.to_sym) : column.name.to_sym == klass.primary_key.to_sym)
|
871
|
+
|
872
|
+
if column_type == 'decimal'
|
873
|
+
column_type << "(#{column.precision}, #{column.scale})"
|
874
|
+
elsif !%w[spatial geometry geography].include?(column_type)
|
875
|
+
if column.limit && !options[:format_yard]
|
876
|
+
if column.limit.is_a? Array
|
877
|
+
attrs << "(#{column.limit.join(', ')})"
|
878
|
+
else
|
879
|
+
column_type << "(#{column.limit})" unless hide_limit?(column_type, options)
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
# Check out if we got an array column
|
885
|
+
attrs << 'is an Array' if column.respond_to?(:array) && column.array
|
886
|
+
|
887
|
+
# Check out if we got a geometric column
|
888
|
+
# and print the type and SRID
|
889
|
+
if column.respond_to?(:geometry_type)
|
890
|
+
attrs << [column.geometry_type, column.try(:srid)].compact.join(', ')
|
891
|
+
elsif column.respond_to?(:geometric_type) && column.geometric_type.present?
|
892
|
+
attrs << [column.geometric_type.to_s.downcase, column.try(:srid)].compact.join(', ')
|
893
|
+
end
|
894
|
+
|
895
|
+
# Check if the column has indices and print "indexed" if true
|
896
|
+
# If the index includes another column, print it too.
|
897
|
+
if options[:simple_indexes] && klass.table_exists?# Check out if this column is indexed
|
898
|
+
indices = retrieve_indexes_from_table(klass)
|
899
|
+
if indices = indices.select { |ind| ind.columns.include? column.name }
|
900
|
+
indices.sort_by(&:name).each do |ind|
|
901
|
+
next if ind.columns.is_a?(String)
|
902
|
+
ind = ind.columns.reject! { |i| i == column.name }
|
903
|
+
attrs << (ind.empty? ? "indexed" : "indexed => [#{ind.join(", ")}]")
|
904
|
+
end
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
attrs
|
909
|
+
end
|
999
910
|
end
|
1000
911
|
|
1001
912
|
class BadModelFileError < LoadError
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative './helpers'
|
2
|
+
|
3
|
+
module AnnotateRoutes
|
4
|
+
class HeaderGenerator
|
5
|
+
PREFIX = '== Route Map'.freeze
|
6
|
+
PREFIX_MD = '## Route Map'.freeze
|
7
|
+
HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action'].freeze
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def generate(options = {})
|
11
|
+
new(options, routes_map(options)).generate
|
12
|
+
end
|
13
|
+
|
14
|
+
private :new
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def routes_map(options)
|
19
|
+
result = `rake routes`.chomp("\n").split(/\n/, -1)
|
20
|
+
|
21
|
+
# In old versions of Rake, the first line of output was the cwd. Not so
|
22
|
+
# much in newer ones. We ditch that line if it exists, and if not, we
|
23
|
+
# keep the line around.
|
24
|
+
result.shift if result.first =~ %r{^\(in \/}
|
25
|
+
|
26
|
+
ignore_routes = options[:ignore_routes]
|
27
|
+
regexp_for_ignoring_routes = ignore_routes ? /#{ignore_routes}/ : nil
|
28
|
+
|
29
|
+
# Skip routes which match given regex
|
30
|
+
# Note: it matches the complete line (route_name, path, controller/action)
|
31
|
+
if regexp_for_ignoring_routes
|
32
|
+
result.reject { |line| line =~ regexp_for_ignoring_routes }
|
33
|
+
else
|
34
|
+
result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(options, routes_map)
|
40
|
+
@options = options
|
41
|
+
@routes_map = routes_map
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate
|
45
|
+
magic_comments_map, contents_without_magic_comments = Helpers.extract_magic_comments_from_array(routes_map)
|
46
|
+
|
47
|
+
out = []
|
48
|
+
|
49
|
+
magic_comments_map.each do |magic_comment|
|
50
|
+
out << magic_comment
|
51
|
+
end
|
52
|
+
out << '' if magic_comments_map.any?
|
53
|
+
|
54
|
+
out << comment(options[:wrapper_open]) if options[:wrapper_open]
|
55
|
+
|
56
|
+
out << comment(markdown? ? PREFIX_MD : PREFIX) + timestamp_if_required
|
57
|
+
out << comment
|
58
|
+
return out if contents_without_magic_comments.size.zero?
|
59
|
+
|
60
|
+
maxs = [HEADER_ROW.map(&:size)] + contents_without_magic_comments[1..-1].map { |line| line.split.map(&:size) }
|
61
|
+
|
62
|
+
if markdown?
|
63
|
+
max = maxs.map(&:max).compact.max
|
64
|
+
|
65
|
+
out << comment(content(HEADER_ROW, maxs))
|
66
|
+
out << comment(content(['-' * max, '-' * max, '-' * max, '-' * max], maxs))
|
67
|
+
else
|
68
|
+
out << comment(content(contents_without_magic_comments[0], maxs))
|
69
|
+
end
|
70
|
+
|
71
|
+
out += contents_without_magic_comments[1..-1].map { |line| comment(content(markdown? ? line.split(' ') : line, maxs)) }
|
72
|
+
out << comment(options[:wrapper_close]) if options[:wrapper_close]
|
73
|
+
|
74
|
+
out
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
attr_reader :options, :routes_map
|
80
|
+
|
81
|
+
def comment(row = '')
|
82
|
+
if row == ''
|
83
|
+
'#'
|
84
|
+
else
|
85
|
+
"# #{row}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def content(line, maxs)
|
90
|
+
return line.rstrip unless markdown?
|
91
|
+
|
92
|
+
line.each_with_index.map { |elem, index| format_line_element(elem, maxs, index) }.join(' | ')
|
93
|
+
end
|
94
|
+
|
95
|
+
def format_line_element(elem, maxs, index)
|
96
|
+
min_length = maxs.map { |arr| arr[index] }.max || 0
|
97
|
+
format("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
|
98
|
+
end
|
99
|
+
|
100
|
+
def markdown?
|
101
|
+
options[:format_markdown]
|
102
|
+
end
|
103
|
+
|
104
|
+
def timestamp_if_required(time = Time.now)
|
105
|
+
if options[:timestamp]
|
106
|
+
time_formatted = time.strftime('%Y-%m-%d %H:%M')
|
107
|
+
" (Updated #{time_formatted})"
|
108
|
+
else
|
109
|
+
''
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# rubocop:disable Metrics/ModuleLength
|
2
|
-
|
3
1
|
# == Annotate Routes
|
4
2
|
#
|
5
3
|
# Based on:
|
@@ -21,18 +19,15 @@
|
|
21
19
|
#
|
22
20
|
|
23
21
|
require_relative './annotate_routes/helpers'
|
22
|
+
require_relative './annotate_routes/header_generator'
|
24
23
|
|
25
24
|
module AnnotateRoutes
|
26
|
-
PREFIX = '== Route Map'.freeze
|
27
|
-
PREFIX_MD = '## Route Map'.freeze
|
28
|
-
HEADER_ROW = ['Prefix', 'Verb', 'URI Pattern', 'Controller#Action'].freeze
|
29
|
-
|
30
25
|
class << self
|
31
26
|
def do_annotations(options = {})
|
32
27
|
if routes_file_exist?
|
33
28
|
existing_text = File.read(routes_file)
|
34
29
|
content, header_position = Helpers.strip_annotations(existing_text)
|
35
|
-
new_content = annotate_routes(
|
30
|
+
new_content = annotate_routes(HeaderGenerator.generate(options), content, header_position, options)
|
36
31
|
new_text = new_content.join("\n")
|
37
32
|
|
38
33
|
if rewrite_contents(existing_text, new_text)
|
@@ -71,49 +66,6 @@ module AnnotateRoutes
|
|
71
66
|
@routes_rb ||= File.join('config', 'routes.rb')
|
72
67
|
end
|
73
68
|
|
74
|
-
def header(options = {})
|
75
|
-
routes_map = app_routes_map(options)
|
76
|
-
|
77
|
-
magic_comments_map, routes_map = Helpers.extract_magic_comments_from_array(routes_map)
|
78
|
-
|
79
|
-
out = []
|
80
|
-
|
81
|
-
magic_comments_map.each do |magic_comment|
|
82
|
-
out << magic_comment
|
83
|
-
end
|
84
|
-
out << '' if magic_comments_map.any?
|
85
|
-
|
86
|
-
out << comment(options[:wrapper_open]) if options[:wrapper_open]
|
87
|
-
|
88
|
-
out << comment(options[:format_markdown] ? PREFIX_MD : PREFIX) + (options[:timestamp] ? " (Updated #{Time.now.strftime('%Y-%m-%d %H:%M')})" : '')
|
89
|
-
out << comment
|
90
|
-
return out if routes_map.size.zero?
|
91
|
-
|
92
|
-
maxs = [HEADER_ROW.map(&:size)] + routes_map[1..-1].map { |line| line.split.map(&:size) }
|
93
|
-
|
94
|
-
if options[:format_markdown]
|
95
|
-
max = maxs.map(&:max).compact.max
|
96
|
-
|
97
|
-
out << comment(content(HEADER_ROW, maxs, options))
|
98
|
-
out << comment(content(['-' * max, '-' * max, '-' * max, '-' * max], maxs, options))
|
99
|
-
else
|
100
|
-
out << comment(content(routes_map[0], maxs, options))
|
101
|
-
end
|
102
|
-
|
103
|
-
out += routes_map[1..-1].map { |line| comment(content(options[:format_markdown] ? line.split(' ') : line, maxs, options)) }
|
104
|
-
out << comment(options[:wrapper_close]) if options[:wrapper_close]
|
105
|
-
|
106
|
-
out
|
107
|
-
end
|
108
|
-
|
109
|
-
def comment(row = '')
|
110
|
-
if row == ''
|
111
|
-
'#'
|
112
|
-
else
|
113
|
-
"# #{row}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
69
|
def strip_on_removal(content, header_position)
|
118
70
|
if header_position == :before
|
119
71
|
content.shift while content.first == ''
|
@@ -162,32 +114,5 @@ module AnnotateRoutes
|
|
162
114
|
|
163
115
|
new_content
|
164
116
|
end
|
165
|
-
|
166
|
-
def app_routes_map(options)
|
167
|
-
routes_map = `rake routes`.chomp("\n").split(/\n/, -1)
|
168
|
-
|
169
|
-
# In old versions of Rake, the first line of output was the cwd. Not so
|
170
|
-
# much in newer ones. We ditch that line if it exists, and if not, we
|
171
|
-
# keep the line around.
|
172
|
-
routes_map.shift if routes_map.first =~ /^\(in \//
|
173
|
-
|
174
|
-
# Skip routes which match given regex
|
175
|
-
# Note: it matches the complete line (route_name, path, controller/action)
|
176
|
-
if options[:ignore_routes]
|
177
|
-
routes_map.reject! { |line| line =~ /#{options[:ignore_routes]}/ }
|
178
|
-
end
|
179
|
-
|
180
|
-
routes_map
|
181
|
-
end
|
182
|
-
|
183
|
-
def content(line, maxs, options = {})
|
184
|
-
return line.rstrip unless options[:format_markdown]
|
185
|
-
|
186
|
-
line.each_with_index.map do |elem, index|
|
187
|
-
min_length = maxs.map { |arr| arr[index] }.max || 0
|
188
|
-
|
189
|
-
sprintf("%-#{min_length}.#{min_length}s", elem.tr('|', '-'))
|
190
|
-
end.join(' | ')
|
191
|
-
end
|
192
117
|
end
|
193
118
|
end
|
data/lib/annotate/version.rb
CHANGED
@@ -4,7 +4,20 @@
|
|
4
4
|
# Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets
|
5
5
|
# run after doing db:migrate.
|
6
6
|
|
7
|
-
%w(db:migrate db:migrate:up db:migrate:down db:migrate:reset db:migrate:redo db:rollback)
|
7
|
+
migration_tasks = %w(db:migrate db:migrate:up db:migrate:down db:migrate:reset db:migrate:redo db:rollback)
|
8
|
+
if defined?(Rails::Application) && Rails.version.split('.').first.to_i >= 6
|
9
|
+
require 'active_record'
|
10
|
+
|
11
|
+
databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
|
12
|
+
|
13
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
|
14
|
+
migration_tasks.concat(%w(db:migrate db:migrate:up db:migrate:down).map { |task| "#{task}:#{spec_name}" })
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
migration_tasks.each do |task|
|
19
|
+
next unless Rake::Task.task_defined?(task)
|
20
|
+
|
8
21
|
Rake::Task[task].enhance do
|
9
22
|
Rake::Task[Rake.application.top_level_tasks.last].enhance do
|
10
23
|
annotation_options_task = if Rake::Task.task_defined?('app:set_annotation_options')
|
@@ -1,6 +1,12 @@
|
|
1
|
+
annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
unless ENV['is_cli']
|
4
|
+
task :set_annotation_options
|
5
|
+
task annotate_routes: :set_annotation_options
|
6
|
+
end
|
7
|
+
|
1
8
|
desc "Adds the route map to routes.rb"
|
2
9
|
task :annotate_routes => :environment do
|
3
|
-
annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
4
10
|
require "#{annotate_lib}/annotate/annotate_routes"
|
5
11
|
|
6
12
|
options={}
|
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: 3.
|
4
|
+
version: 3.2.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:
|
15
|
+
date: 2022-02-10 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rake
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '3.2'
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
46
|
+
version: '8.0'
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
version: '3.2'
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '
|
56
|
+
version: '8.0'
|
57
57
|
description: Annotates Rails/ActiveRecord Models, routes, fixtures, and others based
|
58
58
|
on the database schema.
|
59
59
|
email:
|
@@ -79,7 +79,9 @@ files:
|
|
79
79
|
- lib/annotate.rb
|
80
80
|
- lib/annotate/active_record_patch.rb
|
81
81
|
- lib/annotate/annotate_models.rb
|
82
|
+
- lib/annotate/annotate_models/file_patterns.rb
|
82
83
|
- lib/annotate/annotate_routes.rb
|
84
|
+
- lib/annotate/annotate_routes/header_generator.rb
|
83
85
|
- lib/annotate/annotate_routes/helpers.rb
|
84
86
|
- lib/annotate/constants.rb
|
85
87
|
- lib/annotate/helpers.rb
|
@@ -93,11 +95,12 @@ files:
|
|
93
95
|
- lib/tasks/annotate_models_migrate.rake
|
94
96
|
- lib/tasks/annotate_routes.rake
|
95
97
|
- potato.md
|
96
|
-
homepage:
|
98
|
+
homepage: https://github.com/ctran/annotate_models
|
97
99
|
licenses:
|
98
100
|
- Ruby
|
99
101
|
metadata:
|
100
|
-
|
102
|
+
bug_tracker_uri: https://github.com/ctran/annotate_models/issues/
|
103
|
+
source_code_uri: https://github.com/ctran/annotate_models.git
|
101
104
|
post_install_message:
|
102
105
|
rdoc_options: []
|
103
106
|
require_paths:
|
@@ -113,8 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
116
|
- !ruby/object:Gem::Version
|
114
117
|
version: '0'
|
115
118
|
requirements: []
|
116
|
-
|
117
|
-
rubygems_version: 2.7.7
|
119
|
+
rubygems_version: 3.3.7
|
118
120
|
signing_key:
|
119
121
|
specification_version: 4
|
120
122
|
summary: Annotates Rails Models, routes, fixtures, and others based on the database
|