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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e6c2484a81d38c69c86e48305ae0a1b8724e5b1
4
- data.tar.gz: 7463f0ee24a0023b105dc5e48fc9eec49559de0e
3
+ metadata.gz: 365398d9352685a831b09fe60f460131a0fbe2ab
4
+ data.tar.gz: ba3fce8c6c97125af42c90310adac5272c6ef78c
5
5
  SHA512:
6
- metadata.gz: d4dd08320d2fa1b85c21afdeb1fd5daa4ec6cd39877d70a0681b04ce7453f6fd204da258b0a9d20fe22d4eb4649d44c086383a20db3fe4c6b183ac35a8e1171c
7
- data.tar.gz: 25101a0b978d74579bd47e2dba28a3b89fc738fe19966c50a78aaa43543748c5cd523ff7c7be3b708caa80925092a553a28f4dc6b55b6e91547d9ec5fdbb810f
6
+ metadata.gz: 2f219cec844284bd213ca826a12553b862a9ec6dcfb2ccc271a2821576989dba630e5ad86951ab2fba2d6df02b77c5468b6f1a9b60ff14cf71b23c90779e9a78
7
+ data.tar.gz: 9fdc058f6de547f0e3fa13f0b7ddaa931b4be5ad9ba4e041fb95002b6d9bd46631d0f3df5c1428e71774b089f7899d1e3332b5af00f0db8d1fe56dc249044bc3
@@ -1,3 +1,6 @@
1
+ == 2.7.2
2
+ See https://github.com/ctran/annotate_models/releases/tag/v2.7.2
3
+
1
4
  == 2.7.1
2
5
  See https://github.com/ctran/annotate_models/releases/tag/v2.7.1
3
6
 
@@ -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.png" />}[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', github: 'ctran/annotate_models'
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 git://github.com/ctran/annotate_models.git annotate_models
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 comas
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
@@ -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 = "annotate"
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(">= 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 = ["AUTHORS.rdoc", "CHANGELOG.rdoc", "LICENSE.txt", "README.rdoc", "TODO.rdoc", "annotate.gemspec", "bin/annotate", "lib/annotate.rb", "lib/annotate/active_record_patch.rb", "lib/annotate/annotate_models.rb", "lib/annotate/annotate_routes.rb", "lib/annotate/tasks.rb", "lib/annotate/version.rb", "lib/generators/annotate/USAGE", "lib/generators/annotate/install_generator.rb", "lib/generators/annotate/templates/auto_annotate_models.rake", "lib/tasks/annotate_models.rake", "lib/tasks/annotate_routes.rake", "lib/tasks/migrate.rake"]
18
- s.homepage = "http://github.com/ctran/annotate_models"
19
- s.licenses = ["Ruby"]
20
- s.require_paths = ["lib"]
21
- s.rubyforge_project = "annotate"
22
- s.rubygems_version = "2.1.11"
23
- s.summary = "Annotates Rails Models, routes, fixtures, and others based on the database schema."
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 then
26
- s.specification_version = 4
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
@@ -8,11 +8,11 @@ require 'rubygems'
8
8
  begin
9
9
  require 'bundler'
10
10
  Bundler.setup
11
- rescue Exception
11
+ rescue StandardError
12
12
  end
13
13
 
14
14
  here = File.expand_path(File.dirname __FILE__)
15
- $:<< "#{here}/../lib"
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 (has_set_position[key])
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 |p|
94
- ENV['active_admin'] = p
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 comas") do |dir|
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 comas") do |dir|
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 comas (i.e., `integer,boolean,text`)") do |values|
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({is_rake: ENV['is_rake'] && !ENV['is_rake'].empty?})
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?
@@ -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 Exception
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, :ignore_unknown_models
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, :wrapper, :routes,
36
- :hide_limit_column_types, :ignore_routes, :active_admin
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
- [POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS].flatten.each do |key|
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
- end
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
- [POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS, OTHER_OPTIONS].flatten.each do |key|
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 { |rake| load rake }
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].each { |path| require path } if options[:require].count > 0
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 Exception => e
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 = "== Schema Info"
8
- COMPAT_PREFIX_MD = "## Schema Info"
9
- PREFIX = "== Schema Information"
10
- PREFIX_MD = "## Schema Information"
11
- END_MARK = "== Schema Information End"
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("test", "unit")
18
- MODEL_TEST_DIR = File.join("test", "models") # since rails 4.0
19
- SPEC_MODEL_DIR = File.join("spec", "models")
20
- FIXTURE_TEST_DIR = File.join("test", "fixtures")
21
- FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
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("test", "controllers")
25
- CONTROLLER_SPEC_DIR = File.join("spec", "controllers")
26
- REQUEST_SPEC_DIR = File.join("spec", "requests")
27
- ROUTING_SPEC_DIR = File.join("spec", "routing")
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("test", "exemplars")
31
- EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars")
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("test", "blueprints")
35
- BLUEPRINTS_SPEC_DIR = File.join("spec", "blueprints")
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("test", "factories")
39
- FACTORY_GIRL_SPEC_DIR = File.join("spec", "factories")
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("test", "fabricators")
43
- FABRICATORS_SPEC_DIR = File.join("spec", "fabricators")
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("app", "serializers")
47
- SERIALIZERS_TEST_DIR = File.join("test", "serializers")
48
- SERIALIZERS_SPEC_DIR = File.join("spec", "serializers")
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("app", "controllers")
53
+ CONTROLLER_DIR = File.join('app', "controllers")
52
54
 
53
55
  # Active admin registry files
54
- ACTIVEADMIN_DIR = File.join("app", "admin")
56
+ ACTIVEADMIN_DIR = File.join('app', "admin")
55
57
 
56
58
  # Helper files
57
- HELPER_DIR = File.join("app", "helpers")
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.is_a?(Array) ? @root_dir : [@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
- File.join(root_directory, UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"),
89
- File.join(root_directory, MODEL_TEST_DIR, "%MODEL_NAME%_test.rb"),
90
- File.join(root_directory, SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb")
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
- File.join(root_directory, FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"),
97
- File.join(root_directory, FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"),
98
- File.join(root_directory, FIXTURE_TEST_DIR, "%PLURALIZED_MODEL_NAME%.yml"),
99
- File.join(root_directory, FIXTURE_SPEC_DIR, "%PLURALIZED_MODEL_NAME%.yml")
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
- File.join(root_directory, CONTROLLER_TEST_DIR, "%PLURALIZED_MODEL_NAME%_controller_test.rb"),
106
- File.join(root_directory, CONTROLLER_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_controller_spec.rb"),
107
- File.join(root_directory, REQUEST_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_spec.rb"),
108
- File.join(root_directory, ROUTING_SPEC_DIR, "%PLURALIZED_MODEL_NAME%_routing_spec.rb")
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
- File.join(root_directory, EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"),
115
- File.join(root_directory, EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
116
- File.join(root_directory, BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
117
- File.join(root_directory, BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
118
- File.join(root_directory, FACTORY_GIRL_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
119
- File.join(root_directory, FACTORY_GIRL_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
120
- File.join(root_directory, FACTORY_GIRL_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
121
- File.join(root_directory, FACTORY_GIRL_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
122
- File.join(root_directory, FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
123
- File.join(root_directory, FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb")
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
- File.join(root_directory, SERIALIZERS_DIR, "%MODEL_NAME%_serializer.rb"),
130
- File.join(root_directory, SERIALIZERS_TEST_DIR, "%MODEL_NAME%_serializer_spec.rb"),
131
- File.join(root_directory, SERIALIZERS_SPEC_DIR, "%MODEL_NAME%_serializer_spec.rb")
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
- when 'test' then test_files(root_directory)
138
- when 'fixture' then fixture_files(root_directory)
139
- when 'scaffold' then scaffold_files(root_directory)
140
- when 'factory' then factory_files(root_directory)
141
- when 'serializer' then serialize_files(root_directory)
142
- when 'controller'
143
- [File.join(root_directory, CONTROLLER_DIR, "%PLURALIZED_MODEL_NAME%_controller.rb")]
144
- when 'admin'
145
- [File.join(root_directory, ACTIVEADMIN_DIR, "%MODEL_NAME%.rb")]
146
- when 'helper'
147
- [File.join(root_directory, HELPER_DIR, "%PLURALIZED_MODEL_NAME%_helper.rb")]
148
- else
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, Fixnum, Bignum then value.to_s
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<< "#\n"
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? || NO_DEFAULT_COL_TYPES.include?(col_type)
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 = klass.connection.indexes(klass.table_name)
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>", "*#{col.name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
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 - col.name.length
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`", col.name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n"
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", col.name, col_type, attrs.join(", ")).rstrip + "\n"
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
- index_info = "#\n# ### Indexes\n#\n"
293
- else
294
- index_info = "#\n# Indexes\n#\n"
295
- end
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 = klass.connection.indexes(klass.table_name)
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
- index_info << sprintf("# * `%s`%s:\n# * **`%s`**\n", index.name, index.unique ? " (_unique_)" : "", index.columns.join("`**\n# * **`"))
304
- else
305
- index_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{index.columns.join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n"
306
- end
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 get_foreign_key_info(klass, options={})
324
- if options[:format_markdown]
325
- fk_info = "#\n# ### Foreign Keys\n#\n"
326
- else
327
- fk_info = "#\n# Foreign Keys\n#\n"
328
- end
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
- max_size = foreign_keys.collect{|fk| fk.name.size}.max + 1
337
- foreign_keys.sort_by(&:name).each do |fk|
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
- if options[:format_markdown]
344
- fk_info << sprintf("# * `%s`%s:\n# * **`%s`**\n", fk.name, constraints_info.blank? ? '' : " (_#{constraints_info}_)", ref_info)
345
- else
346
- fk_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", fk.name, "(#{ref_info})", constraints_info).rstrip + "\n"
347
- end
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"), check if it
355
- # matches the block that is already there. If so, leave it be. If not, remove the old
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
- new_content = magic_comments.join + (old_content.rstrip + "\n\n" + wrapped_info_block)
404
- else
405
- new_content = magic_comments.join + wrapped_info_block + "\n" + old_content
406
- end
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
- unless options[exclusion_key]
484
- self.get_patterns(key).
485
- map { |f| resolve_filename(f, model_name, table_name) }.
486
- each { |f|
487
- if annotate_one_file(f, info, position_key, options_with_position(options, position_key))
488
- annotated << f
489
- end
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 Exception => e
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
- if !options[:is_rake]
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
- begin
565
- ActiveSupport::Inflector.constantize(ActiveSupport::Inflector.camelize(model_path))
566
- rescue
567
- # Revert to the old way but it is not really robust
568
- ObjectSpace.each_object(::Class).
569
- select do |c|
570
- Class === c && # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a?
571
- c.ancestors.respond_to?(:include?) && # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82
572
- c.ancestors.include?(ActiveRecord::Base)
573
- end.
574
- detect { |c| ActiveSupport::Inflector.underscore(c.to_s) == model_path }
575
- end
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
- if klass && klass < ActiveRecord::Base && !klass.abstract_class? && klass.table_exists?
613
- annotated.concat(annotate(klass, file, header, options))
614
- end
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 Exception => e
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 Exception => e
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
- gsub('%MODEL_NAME%', model_name).
662
- gsub('%PLURALIZED_MODEL_NAME%', model_name.pluralize).
663
- gsub('%TABLE_NAME%', table_name || model_name.pluralize)
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
- return ([id] << rest_cols << timestamps << associations).flatten.compact
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, $VERBOSE = $VERBOSE, nil
742
+ old_verbose = $VERBOSE
743
+ $VERBOSE = nil
691
744
  yield
692
745
  ensure
693
746
  $VERBOSE = old_verbose