annotate 2.5.0 → 2.6.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,150 @@
1
- here = File.dirname __FILE__
2
- require "#{here}/annotate/version"
1
+ $:.unshift(File.dirname(__FILE__))
2
+ require 'annotate/version'
3
+ require 'annotate/annotate_models'
4
+ require 'annotate/annotate_routes'
5
+
6
+ begin
7
+ # ActiveSupport 3.x...
8
+ require 'active_support/hash_with_indifferent_access'
9
+ rescue Exception => e
10
+ # ActiveSupport 2.x...
11
+ require 'active_support/core_ext/hash/indifferent_access'
12
+ end
3
13
 
4
14
  module Annotate
15
+ ##
16
+ # The set of available options to customize the behavior of Annotate.
17
+ #
18
+ POSITION_OPTIONS=[
19
+ :position_in_routes, :position_in_class, :position_in_test,
20
+ :position_in_fixture, :position_in_factory, :position,
21
+ ]
22
+ FLAG_OPTIONS=[
23
+ :show_indexes, :simple_indexes, :include_version, :exclude_tests,
24
+ :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
25
+ :format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace,
26
+ ]
27
+ OTHER_OPTIONS=[
28
+ :model_dir,
29
+ ]
30
+ PATH_OPTIONS=[
31
+ :require,
32
+ ]
33
+
34
+
35
+ ##
36
+ # Set default values that can be overridden via environment variables.
37
+ #
38
+ def self.set_defaults(options = {})
39
+ return if(@has_set_defaults)
40
+ @has_set_defaults = true
41
+ options = HashWithIndifferentAccess.new(options)
42
+ [POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS].flatten.each do |key|
43
+ if(options.has_key?(key))
44
+ default_value = if(options[key].is_a?(Array))
45
+ options[key].join(",")
46
+ else
47
+ options[key]
48
+ end
49
+ end
50
+ default_value = ENV[key.to_s] if(!ENV[key.to_s].blank?)
51
+ ENV[key.to_s] = default_value.to_s
52
+ end
53
+ end
54
+
55
+ TRUE_RE = /^(true|t|yes|y|1)$/i
56
+ def self.setup_options(options = {})
57
+ POSITION_OPTIONS.each do |key|
58
+ options[key] = fallback(ENV[key.to_s], ENV['position'], 'before')
59
+ end
60
+ FLAG_OPTIONS.each do |key|
61
+ options[key] = true?(ENV[key.to_s])
62
+ end
63
+ OTHER_OPTIONS.each do |key|
64
+ options[key] = (!ENV[key.to_s].blank?) ? ENV[key.to_s] : nil
65
+ end
66
+ PATH_OPTIONS.each do |key|
67
+ options[key] = (!ENV[key.to_s].blank?) ? ENV[key.to_s].split(',') : []
68
+ end
69
+
70
+ if(!options[:model_dir])
71
+ options[:model_dir] = 'app/models'
72
+ end
73
+
74
+ return options
75
+ end
76
+
77
+ def self.skip_on_migration?
78
+ ENV['skip_on_db_migrate'] =~ TRUE_RE
79
+ end
80
+
81
+ def self.loaded_tasks=(val); @loaded_tasks = val; end
82
+ def self.loaded_tasks; return @loaded_tasks; end
83
+
5
84
  def self.load_tasks
6
- if File.exists?('Rakefile')
7
- require 'rake'
8
- load 'Rakefile'
9
- # Rails 3 wants to load our .rake files for us.
10
- # TODO: selectively do this require on Rails 2.x?
11
- Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake }
12
- return true
85
+ return if(self.loaded_tasks)
86
+ self.loaded_tasks = true
87
+
88
+ Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake }
89
+ end
90
+
91
+ def self.load_requires(options)
92
+ options[:require].each { |path| require path } if options[:require].count > 0
93
+ end
94
+
95
+ def self.eager_load(options)
96
+ self.load_requires(options)
97
+ require "annotate/active_record_patch"
98
+
99
+ if(defined?(Rails))
100
+ if(Rails.version.split('.').first.to_i < 3)
101
+ Rails.configuration.eager_load_paths.each do |load_path|
102
+ matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
103
+ Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
104
+ require_dependency file.sub(matcher, '\1')
105
+ end
106
+ end
107
+ else
108
+ klass = Rails::Application.send(:subclasses).first
109
+ klass.eager_load!
110
+ end
13
111
  else
14
- return false
112
+ FileList["#{options[:model_dir]}/**/*.rb"].each do |fname|
113
+ require File.expand_path(fname)
114
+ end
15
115
  end
16
116
  end
117
+
118
+ def self.bootstrap_rake
119
+ begin
120
+ require 'rake/dsl_definition'
121
+ rescue Exception => e
122
+ # We might just be on an old version of Rake...
123
+ end
124
+ require 'rake'
125
+
126
+ if File.exists?('./Rakefile')
127
+ load './Rakefile'
128
+ end
129
+ Rake::Task[:environment].invoke rescue nil
130
+ if(!defined?(Rails))
131
+ # Not in a Rails project, so time to load up the parts of
132
+ # ActiveSupport we need.
133
+ require 'active_support'
134
+ require 'active_support/core_ext/class/subclasses'
135
+ require 'active_support/core_ext/string/inflections'
136
+ end
137
+ self.load_tasks
138
+ Rake::Task[:set_annotation_options].invoke
139
+ end
140
+
141
+ def self.fallback(*args)
142
+ return args.detect { |arg| !arg.blank? }
143
+ end
144
+
145
+ def self.true?(val)
146
+ return false if(val.blank?)
147
+ return false unless(val =~ TRUE_RE)
148
+ return true
149
+ end
17
150
  end
@@ -6,4 +6,4 @@ module ::ActiveRecord
6
6
  # ignore this, so unknown/unloaded macros won't cause parsing to fail
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -9,11 +9,10 @@ module AnnotateModels
9
9
 
10
10
  # File.join for windows reverse bar compat?
11
11
  # I dont use windows, can`t test
12
- UNIT_TEST_DIR = File.join("test", "unit" )
12
+ UNIT_TEST_DIR = File.join("test", "unit")
13
13
  SPEC_MODEL_DIR = File.join("spec", "models")
14
14
  FIXTURE_TEST_DIR = File.join("test", "fixtures")
15
15
  FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
16
- FIXTURE_DIRS = ["test/fixtures","spec/fixtures"]
17
16
 
18
17
  # Object Daddy http://github.com/flogic/object_daddy/tree/master
19
18
  EXEMPLARS_TEST_DIR = File.join("test", "exemplars")
@@ -31,6 +30,29 @@ module AnnotateModels
31
30
  FABRICATORS_TEST_DIR = File.join("test", "fabricators")
32
31
  FABRICATORS_SPEC_DIR = File.join("spec", "fabricators")
33
32
 
33
+ TEST_PATTERNS = [
34
+ [UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"],
35
+ [SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"],
36
+ ]
37
+
38
+ FIXTURE_PATTERNS = [
39
+ File.join(FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"),
40
+ File.join(FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"),
41
+ ]
42
+
43
+ FACTORY_PATTERNS = [
44
+ File.join(EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"),
45
+ File.join(EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"),
46
+ File.join(BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"),
47
+ File.join(BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"),
48
+ File.join(FACTORY_GIRL_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
49
+ File.join(FACTORY_GIRL_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style)
50
+ File.join(FACTORY_GIRL_TEST_DIR, "%TABLE_NAME%.rb"), # (new style)
51
+ File.join(FACTORY_GIRL_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style)
52
+ File.join(FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"),
53
+ File.join(FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb"),
54
+ ]
55
+
34
56
  # Don't show limit (#) on these column types
35
57
  # Example: show "integer" instead of "integer(4)"
36
58
  NO_LIMIT_COL_TYPES = ["integer", "boolean"]
@@ -39,7 +61,7 @@ module AnnotateModels
39
61
  def model_dir
40
62
  @model_dir || "app/models"
41
63
  end
42
-
64
+
43
65
  def model_dir=(dir)
44
66
  @model_dir = dir
45
67
  end
@@ -65,15 +87,24 @@ module AnnotateModels
65
87
  def get_schema_info(klass, header, options = {})
66
88
  info = "# #{header}\n"
67
89
  info<< "#\n"
68
- info<< "# Table name: #{klass.table_name}\n"
90
+ if(options[:format_markdown])
91
+ info<< "# Table name: `#{klass.table_name}`\n"
92
+ info<< "#\n"
93
+ info<< "# ### Columns\n"
94
+ else
95
+ info<< "# Table name: #{klass.table_name}\n"
96
+ end
69
97
  info<< "#\n"
70
98
 
71
99
  max_size = klass.column_names.map{|name| name.size}.max || 0
72
100
  max_size += options[:format_rdoc] ? 5 : 1
101
+ md_names_overhead = 6
102
+ md_type_allowance = 18
103
+ bare_type_allowance = 16
73
104
 
74
105
  if(options[:format_markdown])
75
- info<< sprintf( "# %-#{max_size + 4}.#{max_size + 4}s | %-18.18s | %s\n", 'Field', 'Type', 'Attributes' )
76
- info<< "# #{ '-' * ( max_size + 4 ) } | #{'-' * 18} | #{ '-' * 25 }\n"
106
+ 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' )
107
+ info<< "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n"
77
108
  end
78
109
 
79
110
  cols = klass.columns
@@ -82,7 +113,7 @@ module AnnotateModels
82
113
  attrs = []
83
114
  attrs << "default(#{quote(col.default)})" unless col.default.nil?
84
115
  attrs << "not null" unless col.null
85
- attrs << "primary key" if klass.primary_key && col.name.to_sym == klass.primary_key.to_sym
116
+ 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)
86
117
 
87
118
  col_type = (col.type || col.sql_type).to_s
88
119
  if col_type == "decimal"
@@ -92,7 +123,7 @@ module AnnotateModels
92
123
  col_type << "(#{col.limit})" unless NO_LIMIT_COL_TYPES.include?(col_type)
93
124
  end
94
125
  end
95
-
126
+
96
127
  # Check out if we got a geometric column
97
128
  # and print the type and SRID
98
129
  if col.respond_to?(:geometry_type)
@@ -114,14 +145,16 @@ module AnnotateModels
114
145
  if options[:format_rdoc]
115
146
  info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col.name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
116
147
  elsif options[:format_markdown]
117
- info << sprintf("# **%-#{max_size}.#{max_size}s** | `%-16.16s` | `%s`", col.name, col_type, attrs.join(", ").rstrip) + "\n"
148
+ name_remainder = max_size - col.name.length
149
+ type_remainder = (md_type_allowance - 2) - col_type.length
150
+ info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col.name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n"
118
151
  else
119
- info << sprintf("# %-#{max_size}.#{max_size}s:%-16.16s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n"
152
+ info << sprintf("# %-#{max_size}.#{max_size}s:%-#{bare_type_allowance}.#{bare_type_allowance}s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n"
120
153
  end
121
154
  end
122
155
 
123
156
  if options[:show_indexes] && klass.table_exists?
124
- info << get_index_info(klass)
157
+ info << get_index_info(klass, options)
125
158
  end
126
159
 
127
160
  if options[:format_rdoc]
@@ -133,15 +166,23 @@ module AnnotateModels
133
166
  end
134
167
  end
135
168
 
136
- def get_index_info(klass)
137
- index_info = "#\n# Indexes\n#\n"
169
+ def get_index_info(klass, options={})
170
+ if(options[:format_markdown])
171
+ index_info = "#\n# ### Indexes\n#\n"
172
+ else
173
+ index_info = "#\n# Indexes\n#\n"
174
+ end
138
175
 
139
176
  indexes = klass.connection.indexes(klass.table_name)
140
177
  return "" if indexes.empty?
141
178
 
142
179
  max_size = indexes.collect{|index| index.name.size}.max + 1
143
180
  indexes.sort_by{|index| index.name}.each do |index|
144
- index_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{index.columns.join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n"
181
+ if(options[:format_markdown])
182
+ index_info << sprintf("# * `%s`%s:\n# * **`%s`**\n", index.name, index.unique ? " (_unique_)" : "", index.columns.join("`**\n# * **`"))
183
+ else
184
+ index_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{index.columns.join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n"
185
+ end
145
186
  end
146
187
  return index_info
147
188
  end
@@ -153,14 +194,11 @@ module AnnotateModels
153
194
  # Returns true or false depending on whether the file was modified.
154
195
  #
155
196
  # === Options (opts)
156
- # :position<Symbol>:: where to place the annotated section in fixture or model file,
157
- # :before or :after. Default is :before.
158
- # :position_in_class<Symbol>:: where to place the annotated section in model file
159
- # :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
160
- # :position_in_others<Symbol>:: where to place the annotated section in the rest of
161
- # supported files
197
+ # :force<Symbol>:: whether to update the file even if it doesn't seem to need it.
198
+ # :position_in_*<Symbol>:: where to place the annotated section in fixture or model file,
199
+ # :before or :after. Default is :before.
162
200
  #
163
- def annotate_one_file(file_name, info_block, options={})
201
+ def annotate_one_file(file_name, info_block, position, options={})
164
202
  if File.exist?(file_name)
165
203
  old_content = File.read(file_name)
166
204
  return false if(old_content =~ /# -\*- SkipSchemaAnnotations.*\n/)
@@ -178,9 +216,9 @@ module AnnotateModels
178
216
  encoding_header = old_content.match(encoding).to_s
179
217
 
180
218
  if old_columns == new_columns && !options[:force]
181
- false
219
+ return false
182
220
  else
183
-
221
+
184
222
  # todo: figure out if we need to extract any logic from this merge chunk
185
223
  # <<<<<<< HEAD
186
224
  # # Replace the old schema info with the new schema info
@@ -197,22 +235,30 @@ module AnnotateModels
197
235
  # Strip the old schema info, and insert new schema info.
198
236
  old_content.sub!(encoding, '')
199
237
  old_content.sub!(PATTERN, '')
200
-
201
- new_content = (options[:position] || 'before').to_s == 'after' ?
238
+
239
+ new_content = options[position].to_s == 'after' ?
202
240
  (encoding_header + (old_content.rstrip + "\n\n" + info_block)) :
203
241
  (encoding_header + info_block + old_content)
204
242
 
205
243
  File.open(file_name, "wb") { |f| f.puts new_content }
206
- true
244
+ return true
207
245
  end
246
+ else
247
+ return false
208
248
  end
209
249
  end
210
-
250
+
211
251
  def remove_annotation_of_file(file_name)
212
252
  if File.exist?(file_name)
213
253
  content = File.read(file_name)
254
+
214
255
  content.sub!(PATTERN, '')
256
+
215
257
  File.open(file_name, "wb") { |f| f.puts content }
258
+
259
+ return true
260
+ else
261
+ return false
216
262
  end
217
263
  end
218
264
 
@@ -222,48 +268,55 @@ module AnnotateModels
222
268
  # of the model and fixture source files.
223
269
  # Returns true or false depending on whether the source
224
270
  # files were modified.
271
+ #
272
+ # === Options (opts)
273
+ # :position_in_class<Symbol>:: where to place the annotated section in model file
274
+ # :position_in_test<Symbol>:: where to place the annotated section in test/spec file(s)
275
+ # :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
276
+ # :position_in_factory<Symbol>:: where to place the annotated section in factory file
277
+ # :exclude_tests<Symbol>:: whether to skip modification of test/spec files
278
+ # :exclude_fixtures<Symbol>:: whether to skip modification of fixture files
279
+ # :exclude_factories<Symbol>:: whether to skip modification of factory files
280
+ #
225
281
  def annotate(klass, file, header, options={})
226
- info = get_schema_info(klass, header, options)
227
- annotated = false
228
- model_name = klass.name.underscore
229
- model_file_name = File.join(model_dir, file)
282
+ begin
283
+ info = get_schema_info(klass, header, options)
284
+ did_annotate = false
285
+ model_name = klass.name.underscore
286
+ table_name = klass.table_name
287
+ model_file_name = File.join(model_dir, file)
288
+
289
+ if annotate_one_file(model_file_name, info, :position_in_class, options_with_position(options, :position_in_class))
290
+ did_annotate = true
291
+ end
230
292
 
231
- if annotate_one_file(model_file_name, info, options_with_position(options, :position_in_class))
232
- annotated = true
233
- end
293
+ unless options[:exclude_tests]
294
+ did_annotate = TEST_PATTERNS.
295
+ map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)] }.
296
+ map { |pat| find_test_file(*pat) }.
297
+ map { |file| annotate_one_file(file, info, :position_in_test, options_with_position(options, :position_in_test)) }.
298
+ detect { |result| result } || did_annotate
299
+ end
234
300
 
235
- unless options[:exclude_tests]
236
- [
237
- find_test_file(UNIT_TEST_DIR, "#{model_name}_test.rb"), # test
238
- find_test_file(SPEC_MODEL_DIR, "#{model_name}_spec.rb"), # spec
239
- ].each do |file|
240
- # todo: add an option "position_in_test" -- or maybe just ask if anyone ever wants different positions for model vs. test vs. fixture
241
- if annotate_one_file(file, info, options_with_position(options, :position_in_fixture))
242
- annotated = true
243
- end
301
+ unless options[:exclude_fixtures]
302
+ did_annotate = FIXTURE_PATTERNS.
303
+ map { |file| resolve_filename(file, model_name, table_name) }.
304
+ map { |file| annotate_one_file(file, info, :position_in_fixture, options_with_position(options, :position_in_fixture)) }.
305
+ detect { |result| result } || did_annotate
244
306
  end
245
- end
246
307
 
247
- unless options[:exclude_fixtures]
248
- [
249
- File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
250
- File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
251
- File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
252
- File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
253
- File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
254
- File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
255
- File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
256
- File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
257
- File.join(FABRICATORS_TEST_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
258
- File.join(FABRICATORS_SPEC_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
259
- ].each do |file|
260
- if annotate_one_file(file, info, options_with_position(options, :position_in_fixture))
261
- annotated = true
262
- end
308
+ unless options[:exclude_factories]
309
+ did_annotate = FACTORY_PATTERNS.
310
+ map { |file| resolve_filename(file, model_name, table_name) }.
311
+ map { |file| annotate_one_file(file, info, :position_in_factory, options_with_position(options, :position_in_factory)) }.
312
+ detect { |result| result } || did_annotate
263
313
  end
264
- end
265
314
 
266
- annotated
315
+ return did_annotate
316
+ rescue Exception => e
317
+ puts "Unable to annotate #{file}: #{e.message}"
318
+ puts "\t" + e.backtrace.join("\n\t") if options[:trace]
319
+ end
267
320
  end
268
321
 
269
322
  # position = :position_in_fixture or :position_in_class
@@ -297,19 +350,18 @@ module AnnotateModels
297
350
  puts "No models found in directory '#{model_dir}'."
298
351
  puts "Either specify models on the command line, or use the --model-dir option."
299
352
  puts "Call 'annotate --help' for more info."
300
- exit 1;
353
+ exit 1
301
354
  end
302
355
  end
303
356
  models
304
357
  end
305
-
358
+
306
359
  # Retrieve the classes belonging to the model names we're asked to process
307
360
  # Check for namespaced models in subdirectories as well as models
308
361
  # in subdirectories without namespacing.
309
362
  def get_model_class(file)
310
363
  # this is for non-rails projects, which don't get Rails auto-require magic
311
- require File.expand_path("#{model_dir}/#{file}")
312
-
364
+ require File.expand_path("#{model_dir}/#{file}") unless Module.const_defined?(:Rails)
313
365
  model_path = file.gsub(/\.rb$/, '')
314
366
  get_loaded_model(model_path) || get_loaded_model(model_path.split('/').last)
315
367
  end
@@ -320,7 +372,7 @@ module AnnotateModels
320
372
  select do |c|
321
373
  Class === c and # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a?
322
374
  c.ancestors.respond_to?(:include?) and # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82
323
- c.ancestors.include?(ActiveRecord::Base)
375
+ c.ancestors.include?(ActiveRecord::Base)
324
376
  end.
325
377
  detect { |c| ActiveSupport::Inflector.underscore(c) == model_path }
326
378
  end
@@ -330,21 +382,15 @@ module AnnotateModels
330
382
  # if its a subclass of ActiveRecord::Base,
331
383
  # then pass it to the associated block
332
384
  def do_annotations(options={})
333
- if options[:require]
334
- options[:require].each do |path|
335
- require path
336
- end
337
- end
338
-
339
385
  header = options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
340
386
 
341
387
  if options[:include_version]
342
388
  version = ActiveRecord::Migrator.current_version rescue 0
343
389
  if version > 0
344
390
  header << "\n# Schema version: #{version}"
345
- end
391
+ end
346
392
  end
347
-
393
+
348
394
  self.model_dir = options[:model_dir] if options[:model_dir]
349
395
 
350
396
  annotated = []
@@ -373,46 +419,54 @@ module AnnotateModels
373
419
  end
374
420
 
375
421
  def remove_annotations(options={})
422
+
376
423
  self.model_dir = options[:model_dir] if options[:model_dir]
377
424
  deannotated = []
425
+ deannotated_klass = false
378
426
  get_model_files(options).each do |file|
379
427
  begin
380
428
  klass = get_model_class(file)
381
429
  if klass < ActiveRecord::Base && !klass.abstract_class?
382
- deannotated << klass
383
-
384
430
  model_name = klass.name.underscore
431
+ table_name = klass.table_name
385
432
  model_file_name = File.join(model_dir, file)
386
- remove_annotation_of_file(model_file_name)
387
-
388
- [
389
- File.join(UNIT_TEST_DIR, "#{model_name}_test.rb"),
390
- File.join(SPEC_MODEL_DIR, "#{model_name}_spec.rb"),
391
- File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
392
- File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
393
- File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
394
- File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
395
- File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
396
- File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
397
- File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
398
- File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
399
- File.join(FABRICATORS_TEST_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
400
- File.join(FABRICATORS_SPEC_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
401
- ].each do |file|
402
- remove_annotation_of_file(file) if File.exist?(file)
403
- end
404
-
433
+ deannotated_klass = true if(remove_annotation_of_file(model_file_name))
434
+
435
+ TEST_PATTERNS.
436
+ map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)]}.
437
+ map { |pat| find_test_file(*pat) }.each do |file|
438
+ if(File.exist?(file))
439
+ remove_annotation_of_file(file)
440
+ deannotated_klass = true
441
+ end
442
+ end
443
+
444
+ (FIXTURE_PATTERNS + FACTORY_PATTERNS).
445
+ map { |file| resolve_filename(file, model_name, table_name) }.
446
+ each do |file|
447
+ if File.exist?(file)
448
+ remove_annotation_of_file(file)
449
+ deannotated_klass = true
450
+ end
451
+ end
405
452
  end
453
+ deannotated << klass if(deannotated_klass)
406
454
  rescue Exception => e
407
455
  puts "Unable to deannotate #{file}: #{e.message}"
408
- puts "\t" + e.backtrace.join("\n\t") if options[:trace]
456
+ puts "\t" + e.backtrace.join("\n\t") if options[:trace]
409
457
  end
410
458
  end
411
- puts "Removed annotation from: #{deannotated.join(', ')}"
459
+ puts "Removed annotations from: #{deannotated.join(', ')}"
412
460
  end
413
461
 
414
462
  def find_test_file(dir, file_name)
415
463
  Dir.glob(File.join(dir, "**", file_name)).first || File.join(dir, file_name)
416
464
  end
465
+
466
+ def resolve_filename(filename_template, model_name, table_name)
467
+ return filename_template.
468
+ gsub('%MODEL_NAME%', model_name).
469
+ gsub('%TABLE_NAME%', table_name || model_name.pluralize)
470
+ end
417
471
  end
418
472
  end