Skip to content

Commit 1de5bfb

Browse files
committed
Merge branch 'release/v2.6.9'
2 parents 52ffefc + 75a1836 commit 1de5bfb

File tree

12 files changed

+135
-41
lines changed

12 files changed

+135
-41
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
language: ruby
22
rvm:
33
- 1.9.3
4-
4+
- 2.0
5+
- 2.1
6+
- 2.2
57
before_install:
68
- rvm @global do gem install bundler

CHANGELOG.rdoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
== 2.6.9
2+
* Support foreigh key (#241)
3+
* Check if model has skip tag in annotate_model_file (#167)
4+
* Fix issue where serializer-related flags weren't being honored (#246)
5+
* Prefer SQL column type over normalized AR type (#231)
6+
17
== 2.6.8
28
* Nothing annotated unless options[:model_dir] is specified, #234
39

README.rdoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ you can do so with a simple environment variable, instead of editing the
175175
-v, --version Show the current version of this gem
176176
-m, --show-migration Include the migration version number in the annotation
177177
-i, --show-indexes List the table's database indexes in the annotation
178+
-k, --show-foreign-keys List the table's foreign key constraints in the annotation
178179
-s, --simple-indexes Concat the column's related indexes in the annotation
179180
--model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with comas
180181
--ignore-model-subdirects Ignore subdirectories of the models directory

bin/annotate

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ OptionParser.new do |opts|
3333
end
3434

3535
opts.on('-p', '--position [before|top|after|bottom]', ['before', 'top', 'after', 'bottom'],
36-
"Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/routes file(s)") do |p|
36+
"Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/route/serializer file(s)") do |p|
3737
ENV['position'] = p
3838
[
3939
'position_in_class','position_in_factory','position_in_fixture','position_in_test', 'position_in_routes', 'position_in_serializer'
@@ -109,6 +109,11 @@ OptionParser.new do |opts|
109109
ENV['include_version'] = "yes"
110110
end
111111

112+
opts.on('-k', '--show-foreign-keys',
113+
"List the table's foreign key constraints in the annotation") do
114+
ENV['show_foreign_keys'] = "yes"
115+
end
116+
112117
opts.on('-i', '--show-indexes',
113118
"List the table's database indexes in the annotation") do
114119
ENV['show_indexes'] = "yes"

lib/annotate.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ module Annotate
2020
POSITION_OPTIONS=[
2121
:position_in_routes, :position_in_class, :position_in_test,
2222
:position_in_fixture, :position_in_factory, :position,
23-
:position_in_serializer,
23+
:position_in_serializer
2424
]
2525
FLAG_OPTIONS=[
2626
:show_indexes, :simple_indexes, :include_version, :exclude_tests,
2727
:exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
2828
:format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace,
29-
:timestamp, :exclude_serializers, :classified_sort
29+
:timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys,
3030
]
3131
OTHER_OPTIONS=[
3232
:ignore_columns

lib/annotate/annotate_models.rb

100755100644
Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module AnnotateModels
77
PREFIX = "== Schema Information"
88
PREFIX_MD = "## Schema Information"
99
END_MARK = "== Schema Information End"
10-
PATTERN = /^\n?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?\n(#.*\n)*\n*/
10+
PATTERN = /^\r?\n?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?\r?\n(#.*\r?\n)*(\r?\n)*/
1111

1212
# File.join for windows reverse bar compat?
1313
# I dont use windows, can`t test
@@ -140,7 +140,7 @@ def get_schema_info(klass, header, options = {})
140140
attrs << "not null" unless col.null
141141
attrs << "primary key" if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect{|c|c.to_sym}.include?(col.name.to_sym) : col.name.to_sym == klass.primary_key.to_sym)
142142

143-
col_type = (col.type || col.sql_type).to_s
143+
col_type = (col.sql_type || col.type).to_s
144144
if col_type == "decimal"
145145
col_type << "(#{col.precision}, #{col.scale})"
146146
elsif col_type != "spatial"
@@ -193,6 +193,10 @@ def get_schema_info(klass, header, options = {})
193193
info << get_index_info(klass, options)
194194
end
195195

196+
if options[:show_foreign_keys] && klass.table_exists?
197+
info << get_foreign_key_info(klass, options)
198+
end
199+
196200
if options[:format_rdoc]
197201
info << "#--\n"
198202
info << "# #{END_MARK}\n"
@@ -223,6 +227,28 @@ def get_index_info(klass, options={})
223227
return index_info
224228
end
225229

230+
def get_foreign_key_info(klass, options={})
231+
if(options[:format_markdown])
232+
fk_info = "#\n# ### Foreign Keys\n#\n"
233+
else
234+
fk_info = "#\n# Foreign Keys\n#\n"
235+
end
236+
237+
foreign_keys = klass.connection.respond_to?(:foreign_keys) ? klass.connection.foreign_keys(klass.table_name) : []
238+
return "" if foreign_keys.empty?
239+
240+
max_size = foreign_keys.collect{|fk| fk.name.size}.max + 1
241+
foreign_keys.sort_by{|fk| fk.name}.each do |fk|
242+
ref_info = "#{fk.column} => #{fk.to_table}.#{fk.primary_key}"
243+
if(options[:format_markdown])
244+
fk_info << sprintf("# * `%s`:\n# * **`%s`**\n", fk.name, ref_info)
245+
else
246+
fk_info << sprintf("# %-#{max_size}.#{max_size}s %s", fk.name, "(#{ref_info})").rstrip + "\n"
247+
end
248+
end
249+
return fk_info
250+
end
251+
226252
# Add a schema block to a file. If the file already contains
227253
# a schema info block (a comment starting with "== Schema Information"), check if it
228254
# matches the block that is already there. If so, leave it be. If not, remove the old
@@ -309,9 +335,11 @@ def remove_annotation_of_file(file_name)
309335
# :position_in_test<Symbol>:: where to place the annotated section in test/spec file(s)
310336
# :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
311337
# :position_in_factory<Symbol>:: where to place the annotated section in factory file
338+
# :position_in_serializer<Symbol>:: where to place the annotated section in serializer file
312339
# :exclude_tests<Symbol>:: whether to skip modification of test/spec files
313340
# :exclude_fixtures<Symbol>:: whether to skip modification of fixture files
314341
# :exclude_factories<Symbol>:: whether to skip modification of factory files
342+
# :exclude_serializers<Symbol>:: whether to skip modification of serializer files
315343
#
316344
def annotate(klass, file, header, options={})
317345
begin
@@ -350,9 +378,9 @@ def options_with_position(options, position_in)
350378
options.merge(:position=>(options[position_in] || options[:position]))
351379
end
352380

353-
# Return a list of the model files to annotate.
381+
# Return a list of the model files to annotate.
354382
# If we have command line arguments, they're assumed to the path
355-
# of model files from root dir. Otherwise we take all the model files
383+
# of model files from root dir. Otherwise we take all the model files
356384
# in the model_dir directory.
357385
def get_model_files(options)
358386
models = []
@@ -364,7 +392,7 @@ def get_model_files(options)
364392
begin
365393
model_dir.each do |dir|
366394
Dir.chdir(dir) do
367-
lst =
395+
lst =
368396
if options[:ignore_model_sub_dir]
369397
Dir["*.rb"].map{ |f| [dir, f] }
370398
else
@@ -451,6 +479,7 @@ def do_annotations(options={})
451479

452480
def annotate_model_file(annotated, file, header, options)
453481
begin
482+
return false if (/# -\*- SkipSchemaAnnotations.*/ =~ (File.exist?(file) ? File.read(file) : '') )
454483
klass = get_model_class(file)
455484
if klass && klass < ActiveRecord::Base && !klass.abstract_class? && klass.table_exists?
456485
if annotate(klass, file, header, options)
@@ -477,7 +506,7 @@ def remove_annotations(options={})
477506
model_file_name = file
478507
deannotated_klass = true if(remove_annotation_of_file(model_file_name))
479508

480-
(TEST_PATTERNS + FIXTURE_PATTERNS + FACTORY_PATTERNS).
509+
(TEST_PATTERNS + FIXTURE_PATTERNS + FACTORY_PATTERNS + SERIALIZER_PATTERNS).
481510
map { |file| resolve_filename(file, model_name, table_name) }.
482511
each do |file|
483512
if File.exist?(file)

lib/annotate/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Annotate
22
def self.version
3-
'2.6.8'
3+
'2.6.9'
44
end
55
end

lib/generators/annotate/templates/auto_annotate_models.rake

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,30 @@ if Rails.env.development?
66
# You can override any of these by setting an environment variable of the
77
# same name.
88
Annotate.set_defaults({
9-
'position_in_routes' => "before",
10-
'position_in_class' => "before",
11-
'position_in_test' => "before",
12-
'position_in_fixture' => "before",
13-
'position_in_factory' => "before",
14-
'show_indexes' => "true",
15-
'simple_indexes' => "false",
16-
'model_dir' => "app/models",
17-
'include_version' => "false",
18-
'require' => "",
19-
'exclude_tests' => "false",
20-
'exclude_fixtures' => "false",
21-
'exclude_factories' => "false",
22-
'ignore_model_sub_dir' => "false",
23-
'skip_on_db_migrate' => "false",
24-
'format_bare' => "true",
25-
'format_rdoc' => "false",
26-
'format_markdown' => "false",
27-
'sort' => "false",
28-
'force' => "false",
29-
'trace' => "false",
9+
'position_in_routes' => "before",
10+
'position_in_class' => "before",
11+
'position_in_test' => "before",
12+
'position_in_fixture' => "before",
13+
'position_in_factory' => "before",
14+
'position_in_serializer' => "before",
15+
'show_foreign_keys' => "true",
16+
'show_indexes' => "true",
17+
'simple_indexes' => "false",
18+
'model_dir' => "app/models",
19+
'include_version' => "false",
20+
'require' => "",
21+
'exclude_tests' => "false",
22+
'exclude_fixtures' => "false",
23+
'exclude_factories' => "false",
24+
'exclude_serializers' => "false",
25+
'ignore_model_sub_dir' => "false",
26+
'skip_on_db_migrate' => "false",
27+
'format_bare' => "true",
28+
'format_rdoc' => "false",
29+
'format_markdown' => "false",
30+
'sort' => "false",
31+
'force' => "false",
32+
'trace' => "false",
3033
})
3134
end
3235

lib/tasks/annotate_models.rake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ task :annotate_models => :environment do
1616
options[:position_in_fixture] = Annotate.fallback(ENV['position_in_fixture'], ENV['position'])
1717
options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position'])
1818
options[:position_in_test] = Annotate.fallback(ENV['position_in_test'], ENV['position'])
19+
options[:position_in_serializer] = Annotate.fallback(ENV['position_in_serializer'], ENV['position'])
1920
options[:show_indexes] = Annotate.true?(ENV['show_indexes'])
2021
options[:simple_indexes] = Annotate.true?(ENV['simple_indexes'])
2122
options[:model_dir] = ENV['model_dir'] ? ENV['model_dir'].split(',') : []
@@ -24,6 +25,7 @@ task :annotate_models => :environment do
2425
options[:exclude_tests] = Annotate.true?(ENV['exclude_tests'])
2526
options[:exclude_factories] = Annotate.true?(ENV['exclude_factories'])
2627
options[:exclude_fixtures] = Annotate.true?(ENV['exclude_fixtures'])
28+
options[:exclude_serializers] = Annotate.true?(ENV['exclude_serializers'])
2729
options[:ignore_model_sub_dir] = Annotate.true?(ENV['ignore_model_sub_dir'])
2830
options[:format_bare] = Annotate.true?(ENV['format_bare'])
2931
options[:format_rdoc] = Annotate.true?(ENV['format_rdoc'])

spec/annotate/annotate_models_spec.rb

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,32 @@
44
require 'annotate/active_record_patch'
55

66
describe AnnotateModels do
7-
def mock_class(table_name, primary_key, columns)
7+
def mock_foreign_key(name, from_column, to_table, to_column = 'id')
8+
double("ForeignKeyDefinition",
9+
:name => name,
10+
:column => from_column,
11+
:to_table => to_table,
12+
:primary_key => to_column,
13+
)
14+
end
15+
16+
def mock_connection(indexes = [], foreign_keys = [])
17+
double("Conn",
18+
:indexes => indexes,
19+
:foreign_keys => foreign_keys,
20+
)
21+
end
22+
23+
def mock_class(table_name, primary_key, columns, foreign_keys = [])
824
options = {
9-
:connection => double("Conn", :indexes => []),
10-
:table_name => table_name,
11-
:primary_key => primary_key,
12-
:column_names => columns.map { |col| col.name.to_s },
13-
:columns => columns,
14-
:column_defaults => Hash[columns.map { |col|
15-
[col.name, col.default]
25+
:connection => mock_connection([], foreign_keys),
26+
:table_exists? => true,
27+
:table_name => table_name,
28+
:primary_key => primary_key,
29+
:column_names => columns.map { |col| col.name.to_s },
30+
:columns => columns,
31+
:column_defaults => Hash[columns.map { |col|
32+
[col.name, col.default]
1633
}]
1734
}
1835

@@ -28,7 +45,7 @@ def mock_column(name, type, options={})
2845

2946
stubs = default_options.dup
3047
stubs.merge!(options)
31-
stubs.merge!(:name => name, :type => type)
48+
stubs.merge!(:name => name, :sql_type => type, :type => type)
3249

3350
double("Column", stubs)
3451
end
@@ -127,6 +144,33 @@ def mock_column(name, type, options={})
127144
EOS
128145
end
129146

147+
it "should get foreign key info" do
148+
klass = mock_class(:users, :id, [
149+
mock_column(:id, :integer),
150+
mock_column(:foreign_thing_id, :integer),
151+
],
152+
[
153+
mock_foreign_key(
154+
'fk_rails_02e851e3b7',
155+
'foreign_thing_id',
156+
'foreign_things'
157+
)
158+
])
159+
expect(AnnotateModels.get_schema_info(klass, "Schema Info", :show_foreign_keys => true)).to eql(<<-EOS)
160+
# Schema Info
161+
#
162+
# Table name: users
163+
#
164+
# id :integer not null, primary key
165+
# foreign_thing_id :integer not null
166+
#
167+
# Foreign Keys
168+
#
169+
# fk_rails_02e851e3b7 (foreign_thing_id => foreign_things.id)
170+
#
171+
EOS
172+
end
173+
130174
it "should get schema info as RDoc" do
131175
klass = mock_class(:users, :id, [
132176
mock_column(:id, :integer),

spec/integration/rails_4.1.1/lib/tasks/auto_annotate_models.rake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ if Rails.env.development?
1111
'position_in_test' => "before",
1212
'position_in_fixture' => "before",
1313
'position_in_factory' => "before",
14+
'show_foreign_keys' => "true",
1415
'show_indexes' => "true",
1516
'simple_indexes' => "false",
1617
'model_dir' => "app/models",

spec/integration/rails_4.2.0/lib/tasks/auto_annotate_models.rake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ if Rails.env.development?
1111
'position_in_test' => "before",
1212
'position_in_fixture' => "before",
1313
'position_in_factory' => "before",
14+
'show_foreign_keys' => "true",
1415
'show_indexes' => "true",
1516
'simple_indexes' => "false",
1617
'model_dir' => "app/models",

0 commit comments

Comments
 (0)