annotate 2.7.1 → 2.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +3 -0
- data/README.rdoc +5 -4
- data/annotate.gemspec +37 -28
- data/bin/annotate +16 -12
- data/lib/annotate.rb +22 -14
- data/lib/annotate/annotate_models.rb +229 -176
- data/lib/annotate/annotate_routes.rb +46 -18
- data/lib/annotate/version.rb +1 -1
- data/lib/generators/annotate/templates/auto_annotate_models.rake +40 -35
- data/lib/tasks/annotate_models.rake +6 -3
- data/lib/tasks/{migrate.rake → annotate_models_migrate.rake} +0 -0
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 365398d9352685a831b09fe60f460131a0fbe2ab
|
4
|
+
data.tar.gz: ba3fce8c6c97125af42c90310adac5272c6ef78c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f219cec844284bd213ca826a12553b862a9ec6dcfb2ccc271a2821576989dba630e5ad86951ab2fba2d6df02b77c5468b6f1a9b60ff14cf71b23c90779e9a78
|
7
|
+
data.tar.gz: 9fdc058f6de547f0e3fa13f0b7ddaa931b4be5ad9ba4e041fb95002b6d9bd46631d0f3df5c1428e71774b089f7899d1e3332b5af00f0db8d1fe56dc249044bc3
|
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
{<img src="https://badge.fury.io/rb/annotate.svg" alt="Gem Version" />}[http://badge.fury.io/rb/annotate]
|
4
4
|
{<img src="https://img.shields.io/gem/dt/annotate.svg?style=flat" />}[https://rubygems.org/gems/annotate]
|
5
|
-
{<img src="https://travis-ci.org/ctran/annotate_models.
|
5
|
+
{<img src="https://travis-ci.org/ctran/annotate_models.svg?branch=develop" />}[https://travis-ci.org/ctran/annotate_models]
|
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
|
+
{<img src="http://inch-ci.org/github/ctran/annotate_models.svg?branch=develop" alt="Inline docs" />}[http://inch-ci.org/github/ctran/annotate_models]
|
8
9
|
{<img src="https://gemnasium.com/ctran/annotate_models.png" />}[https://gemnasium.com/ctran/annotate_models]
|
9
10
|
|
10
11
|
Add a comment summarizing the current schema to the top or bottom of each of
|
@@ -58,7 +59,7 @@ Into Gemfile from rubygems.org:
|
|
58
59
|
|
59
60
|
Into Gemfile from Github:
|
60
61
|
|
61
|
-
gem 'annotate',
|
62
|
+
gem 'annotate', git: 'https://github.com/ctran/annotate_models.git'
|
62
63
|
|
63
64
|
Into environment gems from rubygems.org:
|
64
65
|
|
@@ -66,7 +67,7 @@ Into environment gems from rubygems.org:
|
|
66
67
|
|
67
68
|
Into environment gems from Github checkout:
|
68
69
|
|
69
|
-
git clone
|
70
|
+
git clone https://github.com/ctran/annotate_models.git annotate_models
|
70
71
|
cd annotate_models
|
71
72
|
rake build
|
72
73
|
gem install pkg/annotate-*.gem
|
@@ -184,7 +185,7 @@ you can do so with a simple environment variable, instead of editing the
|
|
184
185
|
-i, --show-indexes List the table's database indexes in the annotation
|
185
186
|
-k, --show-foreign-keys List the table's foreign key constraints in the annotation
|
186
187
|
-s, --simple-indexes Concat the column's related indexes in the annotation
|
187
|
-
--model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with
|
188
|
+
--model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with commas
|
188
189
|
--ignore-model-subdirects Ignore subdirectories of the models directory
|
189
190
|
--sort Sort columns alphabetically, rather than in creation order
|
190
191
|
-R, --require path Additional file to require before loading models, may be used multiple times
|
data/annotate.gemspec
CHANGED
@@ -4,36 +4,45 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'annotate/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
7
|
+
s.name = 'annotate'
|
8
8
|
s.version = Annotate.version
|
9
9
|
|
10
10
|
s.required_ruby_version = '>= 1.9.3'
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
12
|
-
s.authors = [
|
13
|
-
s.description =
|
14
|
-
s.email = [
|
15
|
-
s.executables = [
|
16
|
-
s.extra_rdoc_files = [
|
17
|
-
s.files = [
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ['Alex Chaffee', 'Cuong Tran', 'Marcos Piccinini', 'Turadg Aleahmad', 'Jon Frisby']
|
13
|
+
s.description = 'Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.'
|
14
|
+
s.email = ['alex@stinky.com', 'cuong.tran@gmail.com', 'x@nofxx.com', 'turadg@aleahmad.net', 'jon@cloudability.com']
|
15
|
+
s.executables = ['annotate']
|
16
|
+
s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc', 'TODO.rdoc']
|
17
|
+
s.files = [
|
18
|
+
'AUTHORS.rdoc',
|
19
|
+
'CHANGELOG.rdoc',
|
20
|
+
'LICENSE.txt',
|
21
|
+
'README.rdoc',
|
22
|
+
'TODO.rdoc',
|
23
|
+
'annotate.gemspec',
|
24
|
+
'bin/annotate',
|
25
|
+
'lib/annotate.rb',
|
26
|
+
'lib/annotate/active_record_patch.rb',
|
27
|
+
'lib/annotate/annotate_models.rb',
|
28
|
+
'lib/annotate/annotate_routes.rb',
|
29
|
+
'lib/annotate/tasks.rb',
|
30
|
+
'lib/annotate/version.rb',
|
31
|
+
'lib/generators/annotate/USAGE',
|
32
|
+
'lib/generators/annotate/install_generator.rb',
|
33
|
+
'lib/generators/annotate/templates/auto_annotate_models.rake',
|
34
|
+
'lib/tasks/annotate_models.rake',
|
35
|
+
'lib/tasks/annotate_routes.rake',
|
36
|
+
'lib/tasks/annotate_models_migrate.rake'
|
37
|
+
]
|
38
|
+
s.homepage = 'http://github.com/ctran/annotate_models'
|
39
|
+
s.licenses = ['Ruby']
|
40
|
+
s.require_paths = ['lib']
|
41
|
+
s.rubyforge_project = 'annotate'
|
42
|
+
s.rubygems_version = '2.1.11'
|
43
|
+
s.summary = 'Annotates Rails Models, routes, fixtures, and others based on the database schema.'
|
24
44
|
|
25
|
-
if s.respond_to? :specification_version
|
26
|
-
|
27
|
-
|
28
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
29
|
-
s.add_runtime_dependency(%q<rake>, [">= 10.4", "< 12.0"])
|
30
|
-
s.add_runtime_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
|
31
|
-
else
|
32
|
-
s.add_dependency(%q<rake>, [">= 10.4", "< 12.0"])
|
33
|
-
s.add_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
|
34
|
-
end
|
35
|
-
else
|
36
|
-
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
37
|
-
s.add_dependency(%q<activerecord>, [">= 3.2", "< 6.0"])
|
38
|
-
end
|
45
|
+
s.specification_version = 4 if s.respond_to? :specification_version
|
46
|
+
s.add_runtime_dependency(%q<rake>, ['>= 10.4', '< 13.0'])
|
47
|
+
s.add_runtime_dependency(%q<activerecord>, ['>= 3.2', '< 6.0'])
|
39
48
|
end
|
data/bin/annotate
CHANGED
@@ -8,11 +8,11 @@ require 'rubygems'
|
|
8
8
|
begin
|
9
9
|
require 'bundler'
|
10
10
|
Bundler.setup
|
11
|
-
rescue
|
11
|
+
rescue StandardError
|
12
12
|
end
|
13
13
|
|
14
14
|
here = File.expand_path(File.dirname __FILE__)
|
15
|
-
|
15
|
+
$LOAD_PATH << "#{here}/../lib"
|
16
16
|
|
17
17
|
require 'optparse'
|
18
18
|
require 'annotate'
|
@@ -33,7 +33,7 @@ OptionParser.new do |opts|
|
|
33
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
34
|
ENV['position'] = p
|
35
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
|
36
|
+
ENV[key] = p unless has_set_position[key]
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -90,12 +90,11 @@ OptionParser.new do |opts|
|
|
90
90
|
ENV['routes'] = 'true'
|
91
91
|
end
|
92
92
|
|
93
|
-
opts.on('-aa', '--active-admin', 'Annotate active_admin models') do
|
94
|
-
ENV['active_admin'] =
|
93
|
+
opts.on('-aa', '--active-admin', 'Annotate active_admin models') do
|
94
|
+
ENV['active_admin'] = 'true'
|
95
95
|
end
|
96
96
|
|
97
|
-
opts.on('-v', '--version',
|
98
|
-
'Show the current version of this gem') do
|
97
|
+
opts.on('-v', '--version', 'Show the current version of this gem') do
|
99
98
|
puts "annotate v#{Annotate.version}"; exit
|
100
99
|
end
|
101
100
|
|
@@ -119,12 +118,12 @@ OptionParser.new do |opts|
|
|
119
118
|
end
|
120
119
|
|
121
120
|
opts.on('--model-dir dir',
|
122
|
-
"Annotate model files stored in dir rather than app/models, separate multiple dirs with
|
121
|
+
"Annotate model files stored in dir rather than app/models, separate multiple dirs with commas") do |dir|
|
123
122
|
ENV['model_dir'] = dir
|
124
123
|
end
|
125
124
|
|
126
125
|
opts.on('--root-dir dir',
|
127
|
-
"Annotate files stored within root dir projects, separate multiple dirs with
|
126
|
+
"Annotate files stored within root dir projects, separate multiple dirs with commas") do |dir|
|
128
127
|
ENV['root_dir'] = dir
|
129
128
|
end
|
130
129
|
|
@@ -181,17 +180,22 @@ OptionParser.new do |opts|
|
|
181
180
|
ENV['ignore_routes'] = regex
|
182
181
|
end
|
183
182
|
|
184
|
-
opts.on('--hide-limit-column-types VALUES', "don't show limit for given column types, separated by
|
183
|
+
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|
|
185
184
|
ENV['hide_limit_column_types'] = "#{values}"
|
186
185
|
end
|
187
186
|
|
187
|
+
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|
|
188
|
+
ENV['hide_default_column_types'] = "#{values}"
|
189
|
+
end
|
190
|
+
|
188
191
|
opts.on('--ignore-unknown-models', "don't display warnings for bad model files") do |values|
|
189
192
|
ENV['ignore_unknown_models'] = 'true'
|
190
193
|
end
|
191
|
-
|
192
194
|
end.parse!
|
193
195
|
|
194
|
-
options = Annotate.setup_options(
|
196
|
+
options = Annotate.setup_options(
|
197
|
+
is_rake: ENV['is_rake'] && !ENV['is_rake'].empty?
|
198
|
+
)
|
195
199
|
Annotate.eager_load(options)
|
196
200
|
|
197
201
|
AnnotateModels.send(target_action, options) if Annotate.include_models?
|
data/lib/annotate.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# rubocop:disable Metrics/ModuleLength
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
4
|
require 'annotate/version'
|
3
5
|
require 'annotate/annotate_models'
|
@@ -7,7 +9,7 @@ begin
|
|
7
9
|
# ActiveSupport 3.x...
|
8
10
|
require 'active_support/hash_with_indifferent_access'
|
9
11
|
require 'active_support/core_ext/object/blank'
|
10
|
-
rescue
|
12
|
+
rescue StandardError
|
11
13
|
# ActiveSupport 2.x...
|
12
14
|
require 'active_support/core_ext/hash/indifferent_access'
|
13
15
|
require 'active_support/core_ext/blank'
|
@@ -29,16 +31,22 @@ module Annotate
|
|
29
31
|
:exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
|
30
32
|
:format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace,
|
31
33
|
:timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys,
|
32
|
-
:exclude_scaffolds, :exclude_controllers, :exclude_helpers,
|
34
|
+
:exclude_scaffolds, :exclude_controllers, :exclude_helpers,
|
35
|
+
:exclude_sti_subclasses, :ignore_unknown_models
|
33
36
|
].freeze
|
34
37
|
OTHER_OPTIONS = [
|
35
|
-
:ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
|
36
|
-
:
|
38
|
+
:ignore_columns, :skip_on_db_migrate, :wrapper_open, :wrapper_close,
|
39
|
+
:wrapper, :routes, :hide_limit_column_types, :hide_default_column_types,
|
40
|
+
:ignore_routes, :active_admin
|
37
41
|
].freeze
|
38
42
|
PATH_OPTIONS = [
|
39
43
|
:require, :model_dir, :root_dir
|
40
44
|
].freeze
|
41
45
|
|
46
|
+
def self.all_options
|
47
|
+
[POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS]
|
48
|
+
end
|
49
|
+
|
42
50
|
##
|
43
51
|
# Set default values that can be overridden via environment variables.
|
44
52
|
#
|
@@ -48,13 +56,13 @@ module Annotate
|
|
48
56
|
|
49
57
|
options = HashWithIndifferentAccess.new(options)
|
50
58
|
|
51
|
-
|
59
|
+
all_options.flatten.each do |key|
|
52
60
|
if options.key?(key)
|
53
61
|
default_value = if options[key].is_a?(Array)
|
54
62
|
options[key].join(',')
|
55
63
|
else
|
56
64
|
options[key]
|
57
|
-
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
default_value = ENV[key.to_s] unless ENV[key.to_s].blank?
|
@@ -80,7 +88,6 @@ module Annotate
|
|
80
88
|
end
|
81
89
|
|
82
90
|
options[:model_dir] = ['app/models'] if options[:model_dir].empty?
|
83
|
-
options[:root_dir] = [''] if options[:root_dir].empty?
|
84
91
|
|
85
92
|
options[:wrapper_open] ||= options[:wrapper]
|
86
93
|
options[:wrapper_close] ||= options[:wrapper]
|
@@ -94,9 +101,7 @@ module Annotate
|
|
94
101
|
end
|
95
102
|
|
96
103
|
def self.reset_options
|
97
|
-
|
98
|
-
ENV[key.to_s] = nil
|
99
|
-
end
|
104
|
+
all_options.flatten.each { |key| ENV[key.to_s] = nil }
|
100
105
|
end
|
101
106
|
|
102
107
|
def self.skip_on_migration?
|
@@ -123,18 +128,21 @@ module Annotate
|
|
123
128
|
return if loaded_tasks
|
124
129
|
self.loaded_tasks = true
|
125
130
|
|
126
|
-
Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each
|
131
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each do |rake|
|
132
|
+
load rake
|
133
|
+
end
|
127
134
|
end
|
128
135
|
|
129
136
|
def self.load_requires(options)
|
130
|
-
options[:require].
|
137
|
+
options[:require].count > 0 &&
|
138
|
+
options[:require].each { |path| require path }
|
131
139
|
end
|
132
140
|
|
133
141
|
def self.eager_load(options)
|
134
142
|
load_requires(options)
|
135
143
|
require 'annotate/active_record_patch'
|
136
144
|
|
137
|
-
if defined?(Rails)
|
145
|
+
if defined?(Rails::Application)
|
138
146
|
if Rails.version.split('.').first.to_i < 3
|
139
147
|
Rails.configuration.eager_load_paths.each do |load_path|
|
140
148
|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
|
@@ -158,7 +166,7 @@ module Annotate
|
|
158
166
|
def self.bootstrap_rake
|
159
167
|
begin
|
160
168
|
require 'rake/dsl_definition'
|
161
|
-
rescue
|
169
|
+
rescue StandardError => e
|
162
170
|
# We might just be on an old version of Rake...
|
163
171
|
puts e.message
|
164
172
|
exit e.status_code
|
@@ -1,67 +1,69 @@
|
|
1
|
+
# rubocop:disable Metrics/ModuleLength
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
|
3
5
|
module AnnotateModels
|
4
6
|
TRUE_RE = /^(true|t|yes|y|1)$/i
|
5
7
|
|
6
8
|
# Annotate Models plugin use this header
|
7
|
-
COMPAT_PREFIX =
|
8
|
-
COMPAT_PREFIX_MD =
|
9
|
-
PREFIX =
|
10
|
-
PREFIX_MD =
|
11
|
-
END_MARK =
|
9
|
+
COMPAT_PREFIX = '== Schema Info'.freeze
|
10
|
+
COMPAT_PREFIX_MD = '## Schema Info'.freeze
|
11
|
+
PREFIX = '== Schema Information'.freeze
|
12
|
+
PREFIX_MD = '## Schema Information'.freeze
|
13
|
+
END_MARK = '== Schema Information End'.freeze
|
12
14
|
|
13
|
-
MATCHED_TYPES = %w(test fixture factory serializer scaffold controller helper)
|
15
|
+
MATCHED_TYPES = %w(test fixture factory serializer scaffold controller helper).freeze
|
14
16
|
|
15
17
|
# File.join for windows reverse bar compat?
|
16
18
|
# I dont use windows, can`t test
|
17
|
-
UNIT_TEST_DIR = File.join(
|
18
|
-
MODEL_TEST_DIR = File.join(
|
19
|
-
SPEC_MODEL_DIR = File.join(
|
20
|
-
FIXTURE_TEST_DIR = File.join(
|
21
|
-
FIXTURE_SPEC_DIR = File.join(
|
19
|
+
UNIT_TEST_DIR = File.join('test', "unit")
|
20
|
+
MODEL_TEST_DIR = File.join('test', "models") # since rails 4.0
|
21
|
+
SPEC_MODEL_DIR = File.join('spec', "models")
|
22
|
+
FIXTURE_TEST_DIR = File.join('test', "fixtures")
|
23
|
+
FIXTURE_SPEC_DIR = File.join('spec', "fixtures")
|
22
24
|
|
23
25
|
# Other test files
|
24
|
-
CONTROLLER_TEST_DIR = File.join(
|
25
|
-
CONTROLLER_SPEC_DIR = File.join(
|
26
|
-
REQUEST_SPEC_DIR = File.join(
|
27
|
-
ROUTING_SPEC_DIR = File.join(
|
26
|
+
CONTROLLER_TEST_DIR = File.join('test', "controllers")
|
27
|
+
CONTROLLER_SPEC_DIR = File.join('spec', "controllers")
|
28
|
+
REQUEST_SPEC_DIR = File.join('spec', "requests")
|
29
|
+
ROUTING_SPEC_DIR = File.join('spec', "routing")
|
28
30
|
|
29
31
|
# Object Daddy http://github.com/flogic/object_daddy/tree/master
|
30
|
-
EXEMPLARS_TEST_DIR = File.join(
|
31
|
-
EXEMPLARS_SPEC_DIR = File.join(
|
32
|
+
EXEMPLARS_TEST_DIR = File.join('test', "exemplars")
|
33
|
+
EXEMPLARS_SPEC_DIR = File.join('spec', "exemplars")
|
32
34
|
|
33
35
|
# Machinist http://github.com/notahat/machinist
|
34
|
-
BLUEPRINTS_TEST_DIR = File.join(
|
35
|
-
BLUEPRINTS_SPEC_DIR = File.join(
|
36
|
+
BLUEPRINTS_TEST_DIR = File.join('test', "blueprints")
|
37
|
+
BLUEPRINTS_SPEC_DIR = File.join('spec', "blueprints")
|
36
38
|
|
37
39
|
# Factory Girl http://github.com/thoughtbot/factory_girl
|
38
|
-
FACTORY_GIRL_TEST_DIR = File.join(
|
39
|
-
FACTORY_GIRL_SPEC_DIR = File.join(
|
40
|
+
FACTORY_GIRL_TEST_DIR = File.join('test', "factories")
|
41
|
+
FACTORY_GIRL_SPEC_DIR = File.join('spec', "factories")
|
40
42
|
|
41
43
|
# Fabrication https://github.com/paulelliott/fabrication.git
|
42
|
-
FABRICATORS_TEST_DIR = File.join(
|
43
|
-
FABRICATORS_SPEC_DIR = File.join(
|
44
|
+
FABRICATORS_TEST_DIR = File.join('test', "fabricators")
|
45
|
+
FABRICATORS_SPEC_DIR = File.join('spec', "fabricators")
|
44
46
|
|
45
47
|
# Serializers https://github.com/rails-api/active_model_serializers
|
46
|
-
SERIALIZERS_DIR = File.join(
|
47
|
-
SERIALIZERS_TEST_DIR = File.join(
|
48
|
-
SERIALIZERS_SPEC_DIR = File.join(
|
48
|
+
SERIALIZERS_DIR = File.join('app', "serializers")
|
49
|
+
SERIALIZERS_TEST_DIR = File.join('test', "serializers")
|
50
|
+
SERIALIZERS_SPEC_DIR = File.join('spec', "serializers")
|
49
51
|
|
50
52
|
# Controller files
|
51
|
-
CONTROLLER_DIR = File.join(
|
53
|
+
CONTROLLER_DIR = File.join('app', "controllers")
|
52
54
|
|
53
55
|
# Active admin registry files
|
54
|
-
ACTIVEADMIN_DIR = File.join(
|
56
|
+
ACTIVEADMIN_DIR = File.join('app', "admin")
|
55
57
|
|
56
58
|
# Helper files
|
57
|
-
HELPER_DIR = File.join(
|
59
|
+
HELPER_DIR = File.join('app', "helpers")
|
58
60
|
|
59
61
|
# Don't show limit (#) on these column types
|
60
62
|
# Example: show "integer" instead of "integer(4)"
|
61
|
-
NO_LIMIT_COL_TYPES = %w(integer boolean)
|
63
|
+
NO_LIMIT_COL_TYPES = %w(integer boolean).freeze
|
62
64
|
|
63
65
|
# Don't show default value for these column types
|
64
|
-
NO_DEFAULT_COL_TYPES = %w(json jsonb)
|
66
|
+
NO_DEFAULT_COL_TYPES = %w(json jsonb hstore).freeze
|
65
67
|
|
66
68
|
class << self
|
67
69
|
def annotate_pattern(options = {})
|
@@ -78,86 +80,92 @@ module AnnotateModels
|
|
78
80
|
attr_writer :model_dir
|
79
81
|
|
80
82
|
def root_dir
|
81
|
-
@root_dir.
|
83
|
+
if @root_dir.blank?
|
84
|
+
['']
|
85
|
+
elsif @root_dir.is_a?(String)
|
86
|
+
@root_dir.split(',')
|
87
|
+
else
|
88
|
+
@root_dir
|
89
|
+
end
|
82
90
|
end
|
83
91
|
|
84
92
|
attr_writer :root_dir
|
85
93
|
|
86
94
|
def test_files(root_directory)
|
87
95
|
[
|
88
|
-
|
89
|
-
|
90
|
-
|
96
|
+
File.join(root_directory, UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
97
|
+
File.join(root_directory, MODEL_TEST_DIR, "%MODEL_NAME%_test.rb"),
|
98
|
+
File.join(root_directory, SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb")
|
91
99
|
]
|
92
100
|
end
|
93
101
|
|
94
102
|
def fixture_files(root_directory)
|
95
103
|
[
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
104
|
+
File.join(root_directory, FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"),
|
105
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"),
|
106
|
+
File.join(root_directory, FIXTURE_TEST_DIR, "%PLURALIZED_MODEL_NAME%.yml"),
|
107
|
+
File.join(root_directory, FIXTURE_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.yml")
|
100
108
|
]
|
101
109
|
end
|
102
110
|
|
103
111
|
def scaffold_files(root_directory)
|
104
112
|
[
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
113
|
+
File.join(root_directory, CONTROLLER_TEST_DIR, "%PLURALIZED_MODEL_NAME%_controller_test.rb"),
|
114
|
+
File.join(root_directory, CONTROLLER_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_controller_spec.rb"),
|
115
|
+
File.join(root_directory, REQUEST_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_spec.rb"),
|
116
|
+
File.join(root_directory, ROUTING_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_routing_spec.rb")
|
109
117
|
]
|
110
118
|
end
|
111
119
|
|
112
120
|
def factory_files(root_directory)
|
113
121
|
[
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
122
|
+
File.join(root_directory, EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"),
|
123
|
+
File.join(root_directory, EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
|
124
|
+
File.join(root_directory, BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
|
125
|
+
File.join(root_directory, BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
|
126
|
+
File.join(root_directory, FACTORY_GIRL_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
127
|
+
File.join(root_directory, FACTORY_GIRL_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
|
128
|
+
File.join(root_directory, FACTORY_GIRL_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
|
129
|
+
File.join(root_directory, FACTORY_GIRL_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
|
130
|
+
File.join(root_directory, FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
|
131
|
+
File.join(root_directory, FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
|
124
132
|
]
|
125
133
|
end
|
126
134
|
|
127
135
|
def serialize_files(root_directory)
|
128
136
|
[
|
129
|
-
|
130
|
-
|
131
|
-
|
137
|
+
File.join(root_directory, SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb"),
|
138
|
+
File.join(root_directory, SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_spec.rb"),
|
139
|
+
File.join(root_directory, SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
|
132
140
|
]
|
133
141
|
end
|
134
142
|
|
135
143
|
def files_by_pattern(root_directory, pattern_type)
|
136
144
|
case pattern_type
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
145
|
+
when 'test' then test_files(root_directory)
|
146
|
+
when 'fixture' then fixture_files(root_directory)
|
147
|
+
when 'scaffold' then scaffold_files(root_directory)
|
148
|
+
when 'factory' then factory_files(root_directory)
|
149
|
+
when 'serializer' then serialize_files(root_directory)
|
150
|
+
when 'controller'
|
151
|
+
[File.join(root_directory, CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
|
152
|
+
when 'admin'
|
153
|
+
[File.join(root_directory, ACTIVEADMIN_DIR, "%MODEL_NAME%.rb")]
|
154
|
+
when 'helper'
|
155
|
+
[File.join(root_directory, HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")]
|
156
|
+
else
|
157
|
+
[]
|
150
158
|
end
|
151
159
|
end
|
152
160
|
|
153
|
-
def get_patterns(pattern_types=[])
|
161
|
+
def get_patterns(pattern_types = [])
|
154
162
|
current_patterns = []
|
155
163
|
root_dir.each do |root_directory|
|
156
164
|
Array(pattern_types).each do |pattern_type|
|
157
165
|
current_patterns += files_by_pattern(root_directory, pattern_type)
|
158
166
|
end
|
159
167
|
end
|
160
|
-
current_patterns.map{ |p| p.sub(/^[\/]*/, '') }
|
168
|
+
current_patterns.map { |p| p.sub(/^[\/]*/, '') }
|
161
169
|
end
|
162
170
|
|
163
171
|
# Simple quoting for the default column value
|
@@ -166,10 +174,10 @@ module AnnotateModels
|
|
166
174
|
when NilClass then 'NULL'
|
167
175
|
when TrueClass then 'TRUE'
|
168
176
|
when FalseClass then 'FALSE'
|
169
|
-
when Float,
|
177
|
+
when Float, Integer then value.to_s
|
170
178
|
# BigDecimals need to be output in a non-normalized form and quoted.
|
171
179
|
when BigDecimal then value.to_s('F')
|
172
|
-
when Array then value.map {|v| quote(v)}
|
180
|
+
when Array then value.map { |v| quote(v) }
|
173
181
|
else
|
174
182
|
value.inspect
|
175
183
|
end
|
@@ -179,31 +187,38 @@ module AnnotateModels
|
|
179
187
|
quote(klass.column_defaults[column.name])
|
180
188
|
end
|
181
189
|
|
190
|
+
def retrieve_indexes_from_table(klass)
|
191
|
+
table_name = klass.table_name
|
192
|
+
return [] unless table_name
|
193
|
+
|
194
|
+
indexes = klass.connection.indexes(table_name)
|
195
|
+
return indexes if indexes.any? || !klass.table_name_prefix
|
196
|
+
|
197
|
+
# Try to search the table without prefix
|
198
|
+
table_name.to_s.slice!(klass.table_name_prefix)
|
199
|
+
klass.connection.indexes(table_name)
|
200
|
+
end
|
201
|
+
|
182
202
|
# Use the column information in an ActiveRecord class
|
183
203
|
# to create a comment block containing a line for
|
184
204
|
# each column. The line contains the column name,
|
185
205
|
# the type (and length), and any optional attributes
|
186
206
|
def get_schema_info(klass, header, options = {})
|
187
207
|
info = "# #{header}\n"
|
188
|
-
info<<
|
189
|
-
if options[:format_markdown]
|
190
|
-
info<< "# Table name: `#{klass.table_name}`\n"
|
191
|
-
info<< "#\n"
|
192
|
-
info<< "# ### Columns\n"
|
193
|
-
else
|
194
|
-
info<< "# Table name: #{klass.table_name}\n"
|
195
|
-
end
|
196
|
-
info<< "#\n"
|
208
|
+
info << get_schema_header_text(klass, options)
|
197
209
|
|
198
210
|
max_size = klass.column_names.map(&:size).max || 0
|
211
|
+
with_comment = options[:with_comment] && klass.columns.first.respond_to?(:comment)
|
212
|
+
max_size = klass.columns.map{|col| col.name.size + col.comment.size }.max || 0 if with_comment
|
213
|
+
max_size += 2 if with_comment
|
199
214
|
max_size += options[:format_rdoc] ? 5 : 1
|
200
215
|
md_names_overhead = 6
|
201
216
|
md_type_allowance = 18
|
202
217
|
bare_type_allowance = 16
|
203
218
|
|
204
219
|
if options[:format_markdown]
|
205
|
-
info<< sprintf( "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' )
|
206
|
-
info<< "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n"
|
220
|
+
info << sprintf( "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' )
|
221
|
+
info << "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n"
|
207
222
|
end
|
208
223
|
|
209
224
|
cols = if ignore_columns = options[:ignore_columns]
|
@@ -218,9 +233,9 @@ module AnnotateModels
|
|
218
233
|
cols = classified_sort(cols) if options[:classified_sort]
|
219
234
|
cols.each do |col|
|
220
235
|
col_type = (col.type || col.sql_type).to_s
|
221
|
-
|
222
236
|
attrs = []
|
223
|
-
attrs << "default(#{schema_default(klass, col)})" unless col.default.nil? ||
|
237
|
+
attrs << "default(#{schema_default(klass, col)})" unless col.default.nil? || hide_default?(col_type, options)
|
238
|
+
attrs << 'unsigned' if col.respond_to?(:unsigned?) && col.unsigned?
|
224
239
|
attrs << 'not null' unless col.null
|
225
240
|
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)
|
226
241
|
|
@@ -250,23 +265,28 @@ module AnnotateModels
|
|
250
265
|
# Check if the column has indices and print "indexed" if true
|
251
266
|
# If the index includes another column, print it too.
|
252
267
|
if options[:simple_indexes] && klass.table_exists?# Check out if this column is indexed
|
253
|
-
indices =
|
268
|
+
indices = retrieve_indexes_from_table(klass)
|
254
269
|
if indices = indices.select { |ind| ind.columns.include? col.name }
|
255
270
|
indices.sort_by(&:name).each do |ind|
|
271
|
+
next if ind.columns.is_a?(String)
|
256
272
|
ind = ind.columns.reject! { |i| i == col.name }
|
257
273
|
attrs << (ind.empty? ? "indexed" : "indexed => [#{ind.join(", ")}]")
|
258
274
|
end
|
259
275
|
end
|
260
276
|
end
|
261
|
-
|
277
|
+
col_name = if with_comment
|
278
|
+
"#{col.name}(#{col.comment})"
|
279
|
+
else
|
280
|
+
col.name
|
281
|
+
end
|
262
282
|
if options[:format_rdoc]
|
263
|
-
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{
|
283
|
+
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col_name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
|
264
284
|
elsif options[:format_markdown]
|
265
|
-
name_remainder = max_size -
|
285
|
+
name_remainder = max_size - col_name.length
|
266
286
|
type_remainder = (md_type_allowance - 2) - col_type.length
|
267
|
-
info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`",
|
287
|
+
info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col_name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n"
|
268
288
|
else
|
269
|
-
info << sprintf("# %-#{max_size}.#{max_size}s:%-#{bare_type_allowance}.#{bare_type_allowance}s %s",
|
289
|
+
info << sprintf("# %-#{max_size}.#{max_size}s:%-#{bare_type_allowance}.#{bare_type_allowance}s %s", col_name, col_type, attrs.join(", ")).rstrip + "\n"
|
270
290
|
end
|
271
291
|
end
|
272
292
|
|
@@ -278,6 +298,23 @@ module AnnotateModels
|
|
278
298
|
info << get_foreign_key_info(klass, options)
|
279
299
|
end
|
280
300
|
|
301
|
+
info << get_schema_footer_text(klass, options)
|
302
|
+
end
|
303
|
+
|
304
|
+
def get_schema_header_text(klass, options = {})
|
305
|
+
info = "#\n"
|
306
|
+
if options[:format_markdown]
|
307
|
+
info << "# Table name: `#{klass.table_name}`\n"
|
308
|
+
info << "#\n"
|
309
|
+
info << "# ### Columns\n"
|
310
|
+
else
|
311
|
+
info << "# Table name: #{klass.table_name}\n"
|
312
|
+
end
|
313
|
+
info << "#\n"
|
314
|
+
end
|
315
|
+
|
316
|
+
def get_schema_footer_text(_klass, options = {})
|
317
|
+
info = ''
|
281
318
|
if options[:format_rdoc]
|
282
319
|
info << "#--\n"
|
283
320
|
info << "# #{END_MARK}\n"
|
@@ -287,23 +324,23 @@ module AnnotateModels
|
|
287
324
|
end
|
288
325
|
end
|
289
326
|
|
290
|
-
def get_index_info(klass, options={})
|
291
|
-
if options[:format_markdown]
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
327
|
+
def get_index_info(klass, options = {})
|
328
|
+
index_info = if options[:format_markdown]
|
329
|
+
"#\n# ### Indexes\n#\n"
|
330
|
+
else
|
331
|
+
"#\n# Indexes\n#\n"
|
332
|
+
end
|
296
333
|
|
297
|
-
indexes =
|
334
|
+
indexes = retrieve_indexes_from_table(klass)
|
298
335
|
return '' if indexes.empty?
|
299
336
|
|
300
337
|
max_size = indexes.collect{|index| index.name.size}.max + 1
|
301
338
|
indexes.sort_by(&:name).each do |index|
|
302
|
-
if options[:format_markdown]
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
339
|
+
index_info << if options[:format_markdown]
|
340
|
+
sprintf("# * `%s`%s:\n# * **`%s`**\n", index.name, index.unique ? " (_unique_)" : "", Array(index.columns).join("`**\n# * **`"))
|
341
|
+
else
|
342
|
+
sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{Array(index.columns).join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n"
|
343
|
+
end
|
307
344
|
end
|
308
345
|
|
309
346
|
index_info
|
@@ -320,12 +357,23 @@ module AnnotateModels
|
|
320
357
|
excludes.include?(col_type)
|
321
358
|
end
|
322
359
|
|
323
|
-
def
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
360
|
+
def hide_default?(col_type, options)
|
361
|
+
excludes =
|
362
|
+
if options[:hide_default_column_types].blank?
|
363
|
+
NO_DEFAULT_COL_TYPES
|
364
|
+
else
|
365
|
+
options[:hide_default_column_types].split(',')
|
366
|
+
end
|
367
|
+
|
368
|
+
excludes.include?(col_type)
|
369
|
+
end
|
370
|
+
|
371
|
+
def get_foreign_key_info(klass, options = {})
|
372
|
+
fk_info = if options[:format_markdown]
|
373
|
+
"#\n# ### Foreign Keys\n#\n"
|
374
|
+
else
|
375
|
+
"#\n# Foreign Keys\n#\n"
|
376
|
+
end
|
329
377
|
|
330
378
|
return '' unless klass.connection.respond_to?(:supports_foreign_keys?) &&
|
331
379
|
klass.connection.supports_foreign_keys? && klass.connection.respond_to?(:foreign_keys)
|
@@ -333,27 +381,30 @@ module AnnotateModels
|
|
333
381
|
foreign_keys = klass.connection.foreign_keys(klass.table_name)
|
334
382
|
return '' if foreign_keys.empty?
|
335
383
|
|
336
|
-
|
337
|
-
|
384
|
+
format_name = ->(fk) { options[:show_complete_foreign_keys] ? fk.name : fk.name.gsub(/(?<=^fk_rails_)[0-9a-f]{10}$/, '...') }
|
385
|
+
|
386
|
+
max_size = foreign_keys.map(&format_name).map(&:size).max + 1
|
387
|
+
foreign_keys.sort_by {|fk| [format_name.call(fk), fk.column]}.each do |fk|
|
338
388
|
ref_info = "#{fk.column} => #{fk.to_table}.#{fk.primary_key}"
|
339
389
|
constraints_info = ''
|
340
390
|
constraints_info += "ON DELETE => #{fk.on_delete} " if fk.on_delete
|
341
391
|
constraints_info += "ON UPDATE => #{fk.on_update} " if fk.on_update
|
342
392
|
constraints_info.strip!
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
393
|
+
|
394
|
+
fk_info << if options[:format_markdown]
|
395
|
+
sprintf("# * `%s`%s:\n# * **`%s`**\n", format_name.call(fk), constraints_info.blank? ? '' : " (_#{constraints_info}_)", ref_info)
|
396
|
+
else
|
397
|
+
sprintf("# %-#{max_size}.#{max_size}s %s %s", format_name.call(fk), "(#{ref_info})", constraints_info).rstrip + "\n"
|
398
|
+
end
|
348
399
|
end
|
349
400
|
|
350
401
|
fk_info
|
351
402
|
end
|
352
403
|
|
353
404
|
# Add a schema block to a file. If the file already contains
|
354
|
-
# a schema info block (a comment starting with "== Schema Information"),
|
355
|
-
# matches the block that is already there. If so, leave it be.
|
356
|
-
# info block and write a new one.
|
405
|
+
# a schema info block (a comment starting with "== Schema Information"),
|
406
|
+
# check if it matches the block that is already there. If so, leave it be.
|
407
|
+
# If not, remove the old info block and write a new one.
|
357
408
|
#
|
358
409
|
# == Returns:
|
359
410
|
# true or false depending on whether the file was modified.
|
@@ -363,7 +414,7 @@ module AnnotateModels
|
|
363
414
|
# :position_in_*<Symbol>:: where to place the annotated section in fixture or model file,
|
364
415
|
# :before, :top, :after or :bottom. Default is :before.
|
365
416
|
#
|
366
|
-
def annotate_one_file(file_name, info_block, position, options={})
|
417
|
+
def annotate_one_file(file_name, info_block, position, options = {})
|
367
418
|
if File.exist?(file_name)
|
368
419
|
old_content = File.read(file_name)
|
369
420
|
return false if old_content =~ /# -\*- SkipSchemaAnnotations.*\n/
|
@@ -377,8 +428,8 @@ module AnnotateModels
|
|
377
428
|
old_columns = old_header && old_header.scan(column_pattern).sort
|
378
429
|
new_columns = new_header && new_header.scan(column_pattern).sort
|
379
430
|
|
380
|
-
magic_comment_matcher= Regexp.new(/(^#\s*encoding:.*\n)|(^# coding:.*\n)|(^# -\*- coding:.*\n)|(^# -\*- encoding\s?:.*\n)|(^#\s*frozen_string_literal:.+\n)|(^# -\*- frozen_string_literal\s*:.+-\*-\n)/)
|
381
|
-
magic_comments= old_content.scan(magic_comment_matcher).flatten.compact
|
431
|
+
magic_comment_matcher = Regexp.new(/(^#\s*encoding:.*\n)|(^# coding:.*\n)|(^# -\*- coding:.*\n)|(^# -\*- encoding\s?:.*\n)|(^#\s*frozen_string_literal:.+\n)|(^# -\*- frozen_string_literal\s*:.+-\*-\n)/)
|
432
|
+
magic_comments = old_content.scan(magic_comment_matcher).flatten.compact
|
382
433
|
|
383
434
|
if old_columns == new_columns && !options[:force]
|
384
435
|
return false
|
@@ -399,11 +450,11 @@ module AnnotateModels
|
|
399
450
|
old_content.sub!(magic_comment_matcher, '')
|
400
451
|
old_content.sub!(annotate_pattern(options), '')
|
401
452
|
|
402
|
-
if %w(after bottom).include?(options[position].to_s)
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
453
|
+
new_content = if %w(after bottom).include?(options[position].to_s)
|
454
|
+
magic_comments.join + (old_content.rstrip + "\n\n" + wrapped_info_block)
|
455
|
+
else
|
456
|
+
magic_comments.join + wrapped_info_block + "\n" + old_content
|
457
|
+
end
|
407
458
|
end
|
408
459
|
|
409
460
|
File.open(file_name, 'wb') { |f| f.puts new_content }
|
@@ -414,10 +465,10 @@ module AnnotateModels
|
|
414
465
|
end
|
415
466
|
end
|
416
467
|
|
417
|
-
def remove_annotation_of_file(file_name, options={})
|
468
|
+
def remove_annotation_of_file(file_name, options = {})
|
418
469
|
if File.exist?(file_name)
|
419
470
|
content = File.read(file_name)
|
420
|
-
wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" :
|
471
|
+
wrapper_open = options[:wrapper_open] ? "# #{options[:wrapper_open]}\n" : ''
|
421
472
|
content.sub!(/(#{wrapper_open})?#{annotate_pattern(options)}/, '')
|
422
473
|
|
423
474
|
File.open(file_name, 'wb') { |f| f.puts content }
|
@@ -453,11 +504,12 @@ module AnnotateModels
|
|
453
504
|
# :exclude_scaffolds<Symbol>:: whether to skip modification of scaffold files
|
454
505
|
# :exclude_controllers<Symbol>:: whether to skip modification of controller files
|
455
506
|
# :exclude_helpers<Symbol>:: whether to skip modification of helper files
|
507
|
+
# :exclude_sti_subclasses<Symbol>:: whether to skip modification of files for STI subclasses
|
456
508
|
#
|
457
509
|
# == Returns:
|
458
510
|
# an array of file names that were annotated.
|
459
511
|
#
|
460
|
-
def annotate(klass, file, header, options={})
|
512
|
+
def annotate(klass, file, header, options = {})
|
461
513
|
begin
|
462
514
|
klass.reset_column_information
|
463
515
|
info = get_schema_info(klass, header, options)
|
@@ -480,17 +532,16 @@ module AnnotateModels
|
|
480
532
|
position_key = 'position_in_class'.to_sym
|
481
533
|
end
|
482
534
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
end
|
535
|
+
next if options[exclusion_key]
|
536
|
+
get_patterns(key)
|
537
|
+
.map { |f| resolve_filename(f, model_name, table_name) }
|
538
|
+
.each do |f|
|
539
|
+
if annotate_one_file(f, info, position_key, options_with_position(options, position_key))
|
540
|
+
annotated << f
|
541
|
+
end
|
542
|
+
end
|
492
543
|
end
|
493
|
-
rescue
|
544
|
+
rescue StandardError => e
|
494
545
|
puts "Unable to annotate #{file}: #{e.message}"
|
495
546
|
puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
496
547
|
end
|
@@ -509,8 +560,8 @@ module AnnotateModels
|
|
509
560
|
# in the model_dir directory.
|
510
561
|
def get_model_files(options)
|
511
562
|
models = []
|
512
|
-
|
513
|
-
models = ARGV.dup.reject{|m| m.match(/^(.*)=/)}
|
563
|
+
unless options[:is_rake]
|
564
|
+
models = ARGV.dup.reject { |m| m.match(/^(.*)=/) }
|
514
565
|
end
|
515
566
|
|
516
567
|
if models.empty?
|
@@ -561,21 +612,18 @@ module AnnotateModels
|
|
561
612
|
|
562
613
|
# Retrieve loaded model class by path to the file where it's supposed to be defined.
|
563
614
|
def get_loaded_model(model_path)
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
end
|
577
|
-
|
578
|
-
def parse_options(options={})
|
615
|
+
ActiveSupport::Inflector.constantize(ActiveSupport::Inflector.camelize(model_path))
|
616
|
+
rescue
|
617
|
+
# Revert to the old way but it is not really robust
|
618
|
+
ObjectSpace.each_object(::Class)
|
619
|
+
.select do |c|
|
620
|
+
Class === c && # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a?
|
621
|
+
c.ancestors.respond_to?(:include?) && # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82
|
622
|
+
c.ancestors.include?(ActiveRecord::Base)
|
623
|
+
end.detect { |c| ActiveSupport::Inflector.underscore(c.to_s) == model_path }
|
624
|
+
end
|
625
|
+
|
626
|
+
def parse_options(options = {})
|
579
627
|
self.model_dir = options[:model_dir] if options[:model_dir]
|
580
628
|
self.root_dir = options[:root_dir] if options[:root_dir]
|
581
629
|
end
|
@@ -584,7 +632,7 @@ module AnnotateModels
|
|
584
632
|
# ActiveRecord models. If we can find the class, and
|
585
633
|
# if its a subclass of ActiveRecord::Base,
|
586
634
|
# then pass it to the associated block
|
587
|
-
def do_annotations(options={})
|
635
|
+
def do_annotations(options = {})
|
588
636
|
parse_options(options)
|
589
637
|
|
590
638
|
header = options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
|
@@ -609,21 +657,25 @@ module AnnotateModels
|
|
609
657
|
begin
|
610
658
|
return false if /# -\*- SkipSchemaAnnotations.*/ =~ (File.exist?(file) ? File.read(file) : '')
|
611
659
|
klass = get_model_class(file)
|
612
|
-
|
613
|
-
|
614
|
-
|
660
|
+
do_annotate = klass &&
|
661
|
+
klass < ActiveRecord::Base &&
|
662
|
+
(!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name)) &&
|
663
|
+
!klass.abstract_class? &&
|
664
|
+
klass.table_exists?
|
665
|
+
|
666
|
+
annotated.concat(annotate(klass, file, header, options)) if do_annotate
|
615
667
|
rescue BadModelFileError => e
|
616
668
|
unless options[:ignore_unknown_models]
|
617
669
|
puts "Unable to annotate #{file}: #{e.message}"
|
618
670
|
puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
619
671
|
end
|
620
|
-
rescue
|
672
|
+
rescue StandardError => e
|
621
673
|
puts "Unable to annotate #{file}: #{e.message}"
|
622
674
|
puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
623
675
|
end
|
624
676
|
end
|
625
677
|
|
626
|
-
def remove_annotations(options={})
|
678
|
+
def remove_annotations(options = {})
|
627
679
|
parse_options(options)
|
628
680
|
|
629
681
|
deannotated = []
|
@@ -638,9 +690,9 @@ module AnnotateModels
|
|
638
690
|
model_file_name = file
|
639
691
|
deannotated_klass = true if remove_annotation_of_file(model_file_name, options)
|
640
692
|
|
641
|
-
get_patterns(matched_types(options))
|
642
|
-
map { |f| resolve_filename(f, model_name, table_name) }
|
643
|
-
each do |f|
|
693
|
+
get_patterns(matched_types(options))
|
694
|
+
.map { |f| resolve_filename(f, model_name, table_name) }
|
695
|
+
.each do |f|
|
644
696
|
if File.exist?(f)
|
645
697
|
remove_annotation_of_file(f, options)
|
646
698
|
deannotated_klass = true
|
@@ -648,7 +700,7 @@ module AnnotateModels
|
|
648
700
|
end
|
649
701
|
end
|
650
702
|
deannotated << klass if deannotated_klass
|
651
|
-
rescue
|
703
|
+
rescue StandardError => e
|
652
704
|
puts "Unable to deannotate #{File.join(file)}: #{e.message}"
|
653
705
|
puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
654
706
|
end
|
@@ -657,10 +709,10 @@ module AnnotateModels
|
|
657
709
|
end
|
658
710
|
|
659
711
|
def resolve_filename(filename_template, model_name, table_name)
|
660
|
-
filename_template
|
661
|
-
|
662
|
-
|
663
|
-
|
712
|
+
filename_template
|
713
|
+
.gsub('%MODEL_NAME%', model_name)
|
714
|
+
.gsub('%PLURALIZED_MODEL_NAME%', model_name.pluralize)
|
715
|
+
.gsub('%TABLE_NAME%', table_name || model_name.pluralize)
|
664
716
|
end
|
665
717
|
|
666
718
|
def classified_sort(cols)
|
@@ -674,20 +726,21 @@ module AnnotateModels
|
|
674
726
|
id = c
|
675
727
|
elsif c.name.eql?('created_at') || c.name.eql?('updated_at')
|
676
728
|
timestamps << c
|
677
|
-
elsif c.name[-3,3].eql?('_id')
|
729
|
+
elsif c.name[-3, 3].eql?('_id')
|
678
730
|
associations << c
|
679
731
|
else
|
680
732
|
rest_cols << c
|
681
733
|
end
|
682
734
|
end
|
683
|
-
[rest_cols, timestamps, associations].each {|a| a.sort_by!(&:name) }
|
735
|
+
[rest_cols, timestamps, associations].each { |a| a.sort_by!(&:name) }
|
684
736
|
|
685
|
-
|
737
|
+
([id] << rest_cols << timestamps << associations).flatten.compact
|
686
738
|
end
|
687
739
|
|
688
740
|
# Ignore warnings for the duration of the block ()
|
689
741
|
def silence_warnings
|
690
|
-
old_verbose
|
742
|
+
old_verbose = $VERBOSE
|
743
|
+
$VERBOSE = nil
|
691
744
|
yield
|
692
745
|
ensure
|
693
746
|
$VERBOSE = old_verbose
|