annotate 3.1.1 → 3.2.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/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
|