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