miyucy-annotate 2.4.3

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.
@@ -0,0 +1,51 @@
1
+ == 2.4.2 2009-11-21
2
+
3
+ * Annotates (spec|test)/factories/<model>_factory.rb files
4
+
5
+ == 2.4.1 2009-11-20
6
+
7
+ * Annotates thoughtbot's factory_girl factories (test/factories/<model>_factory.rb)
8
+ * Move default annotation position back to top
9
+
10
+ == 2.4.0 2009-12-13
11
+
12
+ * Incorporated lots of patches from the Github community, including support for Blueprints fixtures
13
+ * Several bug fixes
14
+
15
+ == 2.1 2009-10-18
16
+
17
+ * New options
18
+ * -R to require additional files before loading the models
19
+ * -i to show database indexes in annotations
20
+ * -e to exclude annotating tests or fixtures
21
+ * -m to include the migration version number in the annotation
22
+ * --model-dir to annotate model files stored a different place than app/models
23
+ * Ignore unknown macros ('acts_as_whatever')
24
+
25
+ == 2.0 2009-02-03
26
+
27
+ * Add annotate_models plugin fork additions
28
+ * Annotates Rspec and Test Unit models
29
+ * Annotates Object Daddy exemplars
30
+ * Annotates geometrical columns
31
+ * Add AnnotateRoutes rake task
32
+ * Up gem structure to newgem defaults
33
+
34
+ == 1.0.4 2008-09-04
35
+
36
+ * Only update modified models since last run, thanks to sant0sk1
37
+
38
+ == 1.0.3 2008-05-02
39
+
40
+ * Add misc changes from Dustin Sallings and Henrik N
41
+ * Remove trailing whitespace
42
+ * More intuitive info messages
43
+ * Update README file with update-to-date example
44
+
45
+ == 1.0.2 2008-03-22
46
+
47
+ * Add contributions from Michael Bumann (http://github.com/bumi)
48
+ * added an option "position" to choose to put the annotation,
49
+ * spec/fixtures now also get annotated
50
+ * added a task to remove the annotations
51
+ * these options can be specified from command line as -d and -p [before|after]
@@ -0,0 +1,145 @@
1
+ == Annotate (aka AnnotateModels)
2
+
3
+ Add a comment summarizing the current schema to the top or bottom of each of your...
4
+
5
+ * ActiveRecord models
6
+ * Fixture files
7
+ * Tests and Specs
8
+ * Object Daddy exemplars
9
+ * Machinist blueprints
10
+ * Thoughtbot's factory_girl factories, i.e. the (spec|test)/factories/<model>_factory.rb files
11
+
12
+ The schema comment looks like this:
13
+
14
+ # == Schema Info
15
+ #
16
+ # Table name: line_items
17
+ #
18
+ # id :integer(11) not null, primary key
19
+ # quantity :integer(11) not null
20
+ # product_id :integer(11) not null
21
+ # unit_price :float
22
+ # order_id :integer(11)
23
+ #
24
+
25
+ class LineItem < ActiveRecord::Base
26
+ belongs_to :product
27
+ . . .
28
+
29
+ It also annotates geometrical columns, geom type and srid, when using SpatialAdapter or PostgisAdapter:
30
+
31
+ # == Schema Info
32
+ #
33
+ # Table name: trips
34
+ #
35
+ # local :geometry point, 4326
36
+ # path :geometry line_string, 4326
37
+
38
+ Also, if you pass the -r option, it'll annotate routes.rb with the output of "rake routes".
39
+
40
+ == INSTALL
41
+
42
+ From rubyforge:
43
+
44
+ sudo gem install annotate
45
+
46
+ From github:
47
+
48
+ git clone git://github.com/ctran/annotate_models.git annotate
49
+ cd annotate
50
+ gem build annotate.gemspec
51
+ sudo gem install annotate-<version>.gem
52
+
53
+ == USAGE
54
+
55
+ To annotate all your models, tests, fixtures, etc.:
56
+
57
+ cd /path/to/app
58
+ annotate
59
+
60
+ To annotate your models and tests:
61
+
62
+ annotate --exclude fixtures
63
+
64
+ To annotate just your models:
65
+
66
+ annotate --exclude tests,fixtures
67
+
68
+ To annotate routes.rb:
69
+
70
+ annotate -r
71
+
72
+ To automatically annotate after running 'rake db:migrate':
73
+
74
+ [needs more clarity] unpack the gem into vendor/plugins, or maybe vendor/gems, or maybe just require tasks/migrate.rake.
75
+
76
+ If you install annotate_models as a plugin, it will automatically
77
+ adjust your <tt>rake db:migrate</tt> tasks so that they update the
78
+ annotations in your model files for you once the migration is
79
+ completed.
80
+
81
+ Warning: ImageMagick installs a tool called `annotate` too (if you're using MacPorts it's in `/opt/local/bin/annotate`. So if you see Usage: annotate imagein.jpg imageout.jpg then put `/usr/bin` ahead on the path and you'll get ours instead.
82
+
83
+
84
+ == OPTIONS
85
+
86
+ Usage: annotate [options] [model_file]*
87
+ -d, --delete Remove annotations from all model files
88
+ -p, --position [before|after] Place the annotations at the top (before) or the bottom (after) of the model file
89
+ -r, --routes Annotate routes.rb with the output of 'rake routes'
90
+ -v, --version Show the current version of this gem
91
+ -m, --show-migration Include the migration version number in the annotation
92
+ -i, --show-indexes List the table's database indexes in the annotation
93
+ -s, --simple-indexes Concat the column's related indexes in the annotation
94
+ --model-dir dir Annotate model files stored in dir rather than app/models
95
+ -R, --require path Additional files to require before loading models
96
+ -e [tests,fixtures,factories] Do not annotate fixtures, test files, and/or factories
97
+ --exclude
98
+
99
+
100
+ == WARNING
101
+
102
+ Note that this code will blow away the initial/final comment
103
+ block in your models if it looks like it was previously added
104
+ by annotate models, so you don't want to add additional text
105
+ to an automatically created comment block.
106
+
107
+ * * Back up your model files before using... * *
108
+
109
+ == LINKS
110
+
111
+ * Factory Girl => http://github.com/thoughtbot/factory_girl
112
+ * Object Daddy => http://github.com/flogic/object_daddy
113
+ * SpatialAdapter => http://github.com/pdeffendol/spatial_adapter
114
+ * PostgisAdapter => http://github.com/nofxx/postgis_adapter
115
+
116
+ == LICENSE:
117
+
118
+ Released under the same license as Ruby. No Support. No Warranty.
119
+
120
+ == AUTHOR:
121
+
122
+ Original code by: Dave Thomas -- Pragmatic Programmers, LLC
123
+ Overhauled by: Alex Chaffee
124
+ Gemmed by: Cuong Tran
125
+ Maintained by: Alex Chaffee and Cuong Tran
126
+ Homepage: http://github.com/ctran/annotate_models
127
+
128
+ Modifications by:
129
+
130
+ - Alex Chaffee - http://github.com/alexch - alex@pivotallabs.com
131
+ - Cuong Tran - http://github.com/ctran - ctran@pragmaquest.com
132
+ - Jack Danger - http://github.com/JackDanger
133
+ - Michael Bumann - http://github.com/bumi
134
+ - Henrik Nyh - http://github.com/henrik
135
+ - Marcos Piccinini - http://github.com/nofxx
136
+ - Neal Clark - http://github.com/nclark
137
+ - Jacqui Maher - http://github.com/jacqui
138
+ - Nick Plante - http://github.com/zapnap - http://blog.zerosum.org
139
+ - Pedro Visintin - http://github.com/peterpunk - http://www.pedrovisintin.com
140
+ - Bob Potter - http://github.com/bpot
141
+ - Gavin Montague - http://github.com/govan/
142
+ - Alexander Semyonov - http://github.com/rotuka/
143
+ - Nathan Brazil - http://github.com/bitaxis/
144
+
145
+ and many others that I may have missed to add.
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 2
3
+ :minor: 4
4
+ :patch: 3
5
+ :build:
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'annotate'
5
+
6
+ task = :annotate_models
7
+
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: annotate [options] [model_file]*"
10
+
11
+ opts.on('-d', '--delete',
12
+ "Remove annotations from all model files") do
13
+ task = :remove_annotation
14
+ end
15
+
16
+ opts.on('-p', '--position [before|after]', ['before', 'after'],
17
+ "Place the annotations at the top (before) or the bottom (after) of the model file") do |p|
18
+ ENV['position'] = p
19
+ end
20
+
21
+ opts.on('-r', '--routes',
22
+ "Annotate routes.rb with the output of 'rake routes'") do
23
+ task = :annotate_routes
24
+ end
25
+
26
+ opts.on('-v', '--version',
27
+ "Show the current version of this gem") do
28
+ puts "annotate v#{Annotate.version}"; exit
29
+ end
30
+
31
+ opts.on('-m', '--show-migration',
32
+ "Include the migration version number in the annotation") do
33
+ ENV['include_version'] = "yes"
34
+ end
35
+
36
+ opts.on('-i', '--show-indexes',
37
+ "List the table's database indexes in the annotation") do
38
+ ENV['show_indexes'] = "yes"
39
+ end
40
+
41
+ opts.on('-s', '--simple-indexes',
42
+ "Concat the column's related indexes in the annotation") do
43
+ ENV['simple_indexes'] = "yes"
44
+ end
45
+
46
+ opts.on('--model-dir dir',
47
+ "Annotate model files stored in dir rather than app/models") do |dir|
48
+ ENV['model_dir'] = dir
49
+ end
50
+
51
+ opts.on('-R', '--require path',
52
+ "Additional files to require before loading models") do |path|
53
+ if ENV['require']
54
+ ENV['require'] = ENV['require'] + ",#{path}"
55
+ else
56
+ ENV['require'] = path
57
+ end
58
+ end
59
+
60
+ opts.on('-e', '--exclude [tests,fixtures]', Array, "Do not annotate fixtures, test files, or both") do |exclusions|
61
+ exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = "yes" }
62
+ end
63
+
64
+ opts.on('-f', '--format [bare|rdoc]', ['bare', 'rdoc'], 'rdoc: render Schema Infomation as RDoc') do |fmt|
65
+ ENV['format_#{fmt}'] = 'yes'
66
+ end
67
+
68
+ end.parse!
69
+
70
+ if Annotate.load_tasks
71
+ Rake::Task[task].invoke
72
+ else
73
+ STDERR.puts "Can't find Rakefile. Are we in a Rails folder?"
74
+ end
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ module Annotate
4
+ def self.version
5
+ version_file = File.dirname(__FILE__) + "/../VERSION.yml"
6
+ if File.exist?(version_file)
7
+ config = YAML.load(File.read(version_file))
8
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
9
+ else
10
+ version = "0.0.0"
11
+ end
12
+ end
13
+
14
+ def self.load_tasks
15
+ if File.exists?('Rakefile')
16
+ load 'Rakefile'
17
+ Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake }
18
+ return true
19
+ else
20
+ return false
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,356 @@
1
+ module AnnotateModels
2
+ # Annotate Models plugin use this header
3
+ COMPAT_PREFIX = "== Schema Info"
4
+ PREFIX = "== Schema Information"
5
+ END_MARK = "== Schema Information End"
6
+ PATTERN = /^\n?# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n/
7
+
8
+ # File.join for windows reverse bar compat?
9
+ # I dont use windows, can`t test
10
+ UNIT_TEST_DIR = File.join("test", "unit" )
11
+ SPEC_MODEL_DIR = File.join("spec", "models")
12
+ FIXTURE_TEST_DIR = File.join("test", "fixtures")
13
+ FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
14
+ # Object Daddy http://github.com/flogic/object_daddy/tree/master
15
+ EXEMPLARS_TEST_DIR = File.join("test", "exemplars")
16
+ EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars")
17
+ # Machinist http://github.com/notahat/machinist
18
+ BLUEPRINTS_TEST_DIR = File.join("test", "blueprints")
19
+ BLUEPRINTS_SPEC_DIR = File.join("spec", "blueprints")
20
+ # Factory Girl http://github.com/thoughtbot/factory_girl
21
+ FACTORY_GIRL_TEST_DIR = File.join("test", "factories")
22
+ FACTORY_GIRL_SPEC_DIR = File.join("spec", "factories")
23
+
24
+ # Don't show limit (#) on these column types
25
+ # Example: show "integer" instead of "integer(4)"
26
+ NO_LIMIT_COL_TYPES = ["integer", "boolean"]
27
+
28
+ class << self
29
+ def model_dir
30
+ @model_dir || "app/models"
31
+ end
32
+
33
+ def model_dir=(dir)
34
+ @model_dir = dir
35
+ end
36
+
37
+ # Simple quoting for the default column value
38
+ def quote(value)
39
+ case value
40
+ when NilClass then "NULL"
41
+ when TrueClass then "TRUE"
42
+ when FalseClass then "FALSE"
43
+ when Float, Fixnum, Bignum then value.to_s
44
+ # BigDecimals need to be output in a non-normalized form and quoted.
45
+ when BigDecimal then value.to_s('F')
46
+ else
47
+ value.inspect
48
+ end
49
+ end
50
+
51
+ # Use the column information in an ActiveRecord class
52
+ # to create a comment block containing a line for
53
+ # each column. The line contains the column name,
54
+ # the type (and length), and any optional attributes
55
+ def get_schema_info(klass, header, options = {})
56
+ info = "# #{header}\n"
57
+ info<< "#\n"
58
+ info<< "# Table name: #{klass.table_name}\n"
59
+ info<< "#\n"
60
+
61
+ max_size = klass.column_names.map{|name| name.size}.max + (ENV['format_rdoc'] ? 5 : 1)
62
+ klass.columns.each do |col|
63
+ attrs = []
64
+ attrs << "default(#{quote(col.default)})" unless col.default.nil?
65
+ attrs << "not null" unless col.null
66
+ attrs << "primary key" if col.name.to_sym == klass.primary_key.to_sym
67
+
68
+ col_type = col.type.to_s
69
+ if col_type == "decimal"
70
+ col_type << "(#{col.precision}, #{col.scale})"
71
+ else
72
+ if (col.limit)
73
+ col_type << "(#{col.limit})" unless NO_LIMIT_COL_TYPES.include?(col_type)
74
+ end
75
+ end
76
+
77
+ # Check out if we got a geometric column
78
+ # and print the type and SRID
79
+ if col.respond_to?(:geometry_type)
80
+ attrs << "#{col.geometry_type}, #{col.srid}"
81
+ end
82
+
83
+ # Check if the column has indices and print "indexed" if true
84
+ # If the indice include another colum, print it too.
85
+ if options[:simple_indexes] # Check out if this column is indexed
86
+ indices = klass.connection.indexes(klass.table_name)
87
+ if indices = indices.select { |ind| ind.columns.include? col.name }
88
+ indices.each do |ind|
89
+ ind = ind.columns.reject! { |i| i == col.name }
90
+ attrs << (ind.length == 0 ? "indexed" : "indexed => [#{ind.join(", ")}]")
91
+ end
92
+ end
93
+ end
94
+
95
+ if ENV['format_rdoc']
96
+ info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col.name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
97
+ else
98
+ info << sprintf("# %-#{max_size}.#{max_size}s:%-15.15s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n"
99
+ end
100
+ end
101
+
102
+ if options[:show_indexes]
103
+ info << get_index_info(klass)
104
+ end
105
+
106
+ if ENV['format_rdoc']
107
+ info << "#--\n"
108
+ info << "# #{END_MARK}\n"
109
+ info << "#++\n\n"
110
+ else
111
+ info << "#\n\n"
112
+ end
113
+ end
114
+
115
+ def get_index_info(klass)
116
+ index_info = "#\n# Indexes\n#\n"
117
+
118
+ indexes = klass.connection.indexes(klass.table_name)
119
+ return "" if indexes.empty?
120
+
121
+ max_size = indexes.collect{|index| index.name.size}.max + 1
122
+ indexes.each do |index|
123
+ index_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{index.columns.join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n"
124
+ end
125
+ return index_info
126
+ end
127
+
128
+ # Add a schema block to a file. If the file already contains
129
+ # a schema info block (a comment starting with "== Schema Information"), check if it
130
+ # matches the block that is already there. If so, leave it be. If not, remove the old
131
+ # info block and write a new one.
132
+ # Returns true or false depending on whether the file was modified.
133
+ #
134
+ # === Options (opts)
135
+ # :position<Symbol>:: where to place the annotated section in fixture or model file,
136
+ # "before" or "after". Default is "before".
137
+ # :position_in_class<Symbol>:: where to place the annotated section in model file
138
+ # :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
139
+ # :position_in_others<Symbol>:: where to place the annotated section in the rest of
140
+ # supported files
141
+ #
142
+ def annotate_one_file(file_name, info_block, options={})
143
+ if File.exist?(file_name)
144
+ old_content = File.read(file_name)
145
+
146
+ # Ignore the Schema version line because it changes with each migration
147
+ header = Regexp.new(/(^# Table name:.*?\n(#.*\n)*\n)/)
148
+ old_header = old_content.match(header).to_s
149
+ new_header = info_block.match(header).to_s
150
+
151
+ if old_header == new_header
152
+ false
153
+ else
154
+ # Remove old schema info
155
+ old_content.sub!(PATTERN, '')
156
+
157
+ # Write it back
158
+ new_content = options[:position].to_s == 'after' ? (old_content + "\n" + info_block) : (info_block + old_content)
159
+
160
+ File.open(file_name, "wb") { |f| f.puts new_content }
161
+ true
162
+ end
163
+ end
164
+ end
165
+
166
+ def remove_annotation_of_file(file_name)
167
+ if File.exist?(file_name)
168
+ content = File.read(file_name)
169
+
170
+ content.sub!(PATTERN, '')
171
+
172
+ File.open(file_name, "wb") { |f| f.puts content }
173
+ end
174
+ end
175
+
176
+ # Given the name of an ActiveRecord class, create a schema
177
+ # info block (basically a comment containing information
178
+ # on the columns and their types) and put it at the front
179
+ # of the model and fixture source files.
180
+ # Returns true or false depending on whether the source
181
+ # files were modified.
182
+ def annotate(klass, file, header,options={})
183
+ info = get_schema_info(klass, header, options)
184
+ annotated = false
185
+ model_name = klass.name.underscore
186
+ model_file_name = File.join(model_dir, file)
187
+
188
+ if annotate_one_file(model_file_name, info, options_with_position(options, :position_in_class))
189
+ annotated = true
190
+ end
191
+
192
+ unless ENV['exclude_tests']
193
+ [
194
+ File.join(UNIT_TEST_DIR, "#{model_name}_test.rb"), # test
195
+ File.join(SPEC_MODEL_DIR, "#{model_name}_spec.rb"), # spec
196
+ ].each do |file|
197
+ # todo: add an option "position_in_test" -- or maybe just ask if anyone ever wants different positions for model vs. test vs. fixture
198
+ annotate_one_file(file, info, options_with_position(options, :position_in_fixture)) if File.exist?(file)
199
+ end
200
+ end
201
+
202
+ unless ENV['exclude_fixtures']
203
+ [
204
+ File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
205
+ File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
206
+ File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
207
+ File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
208
+ File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
209
+ File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
210
+ File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
211
+ File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
212
+ ].each do |file|
213
+ annotate_one_file(file, info, options_with_position(options, :position_in_fixture)) if File.exist?(file)
214
+ end
215
+ end
216
+
217
+ annotated
218
+ end
219
+
220
+ # position = :position_in_fixture or :position_in_class
221
+ def options_with_position(options, position_in)
222
+ options.merge(:position=>(options[position_in] || options[:position]))
223
+ end
224
+
225
+ # Return a list of the model files to annotate. If we have
226
+ # command line arguments, they're assumed to be either
227
+ # the underscore or CamelCase versions of model names.
228
+ # Otherwise we take all the model files in the
229
+ # model_dir directory.
230
+ def get_model_files
231
+ models = ARGV.dup
232
+ models.shift
233
+ models.reject!{|m| m.match(/^(.*)=/)}
234
+ if models.empty?
235
+ begin
236
+ Dir.chdir(model_dir) do
237
+ models = Dir["**/*.rb"]
238
+ end
239
+ rescue SystemCallError
240
+ puts "No models found in directory '#{model_dir}'."
241
+ puts "Either specify models on the command line, or use the --model-dir option."
242
+ puts "Call 'annotate --help' for more info."
243
+ exit 1;
244
+ end
245
+ end
246
+ models
247
+ end
248
+
249
+ # Retrieve the classes belonging to the model names we're asked to process
250
+ # Check for namespaced models in subdirectories as well as models
251
+ # in subdirectories without namespacing.
252
+ def get_model_class(file)
253
+ require File.expand_path("#{model_dir}/#{file}") # this is for non-rails projects, which don't get Rails auto-require magic
254
+ model = file.gsub(/\.rb$/, '').camelize
255
+ parts = model.split('::')
256
+ begin
257
+ parts.inject(Object) {|klass, part| klass.const_get(part) }
258
+ rescue LoadError, NameError
259
+ Object.const_get(parts.last)
260
+ end
261
+ end
262
+
263
+ # We're passed a name of things that might be
264
+ # ActiveRecord models. If we can find the class, and
265
+ # if its a subclass of ActiveRecord::Base,
266
+ # then pass it to the associated block
267
+ def do_annotations(options={})
268
+ if options[:require]
269
+ options[:require].each do |path|
270
+ require path
271
+ end
272
+ end
273
+
274
+ header = PREFIX.dup
275
+
276
+ if options[:include_version]
277
+ version = ActiveRecord::Migrator.current_version rescue 0
278
+ if version > 0
279
+ header << "\n# Schema version: #{version}"
280
+ end
281
+ end
282
+
283
+ if options[:model_dir]
284
+ self.model_dir = options[:model_dir]
285
+ end
286
+
287
+ annotated = []
288
+ get_model_files.each do |file|
289
+ begin
290
+ klass = get_model_class(file)
291
+ if klass < ActiveRecord::Base && !klass.abstract_class?
292
+ if annotate(klass, file, header, options)
293
+ annotated << klass
294
+ end
295
+ end
296
+ rescue Exception => e
297
+ puts "Unable to annotate #{file}: #{e.message} (#{e.backtrace.first})"
298
+ end
299
+ end
300
+ if annotated.empty?
301
+ puts "Nothing annotated."
302
+ else
303
+ puts "Annotated (#{annotated.length}): #{annotated.join(', ')}"
304
+ end
305
+ end
306
+
307
+ def remove_annotations(options={})
308
+ if options[:model_dir]
309
+ puts "removing"
310
+ self.model_dir = options[:model_dir]
311
+ end
312
+ deannotated = []
313
+ get_model_files.each do |file|
314
+ begin
315
+ klass = get_model_class(file)
316
+ if klass < ActiveRecord::Base && !klass.abstract_class?
317
+ deannotated << klass
318
+
319
+ model_name = klass.name.underscore
320
+ model_file_name = File.join(model_dir, file)
321
+ remove_annotation_of_file(model_file_name)
322
+
323
+ [
324
+ File.join(UNIT_TEST_DIR, "#{model_name}_test.rb"),
325
+ File.join(SPEC_MODEL_DIR, "#{model_name}_spec.rb"),
326
+ File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
327
+ File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
328
+ File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
329
+ File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
330
+ File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
331
+ File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
332
+ File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
333
+ File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
334
+ ].each do |file|
335
+ remove_annotation_of_file(file) if File.exist?(file)
336
+ end
337
+
338
+ end
339
+ rescue Exception => e
340
+ puts "Unable to annotate #{file}: #{e.message}"
341
+ end
342
+ end
343
+ puts "Removed annotation from: #{deannotated.join(', ')}"
344
+ end
345
+ end
346
+ end
347
+
348
+ # monkey patches
349
+
350
+ module ::ActiveRecord
351
+ class Base
352
+ def self.method_missing(name, *args)
353
+ # ignore this, so unknown/unloaded macros won't cause parsing to fail
354
+ end
355
+ end
356
+ end
@@ -0,0 +1,41 @@
1
+ # == Annotate Routes
2
+ #
3
+ # Based on:
4
+ #
5
+ #
6
+ #
7
+ # Prepends the output of "rake routes" to the top of your routes.rb file.
8
+ # Yes, it's simple but I'm thick and often need a reminder of what my routes mean.
9
+ #
10
+ # Running this task will replace any exising route comment generated by the task.
11
+ # Best to back up your routes file before running:
12
+ #
13
+ # Author:
14
+ # Gavin Montague
15
+ # gavin@leftbrained.co.uk
16
+ #
17
+ # Released under the same license as Ruby. No Support. No Warranty.module AnnotateRoutes
18
+ #
19
+ module AnnotateRoutes
20
+ PREFIX = "#== Route Map"
21
+
22
+ def self.do_annotate
23
+ routes_rb = File.join("config", "routes.rb")
24
+ header = PREFIX + "\n# Generated on #{Time.now.strftime("%d %b %Y %H:%M")}\n#"
25
+ if File.exists? routes_rb
26
+ routes_map = `rake routes`
27
+ routes_map = routes_map.split("\n")
28
+ routes_map.shift # remove the first line of rake routes which is just a file path
29
+ routes_map = routes_map.inject(header){|sum, line| sum<<"\n# "<<line}
30
+ content = File.read(routes_rb)
31
+ content, old = content.split(/^#== Route .*?\n/)
32
+ File.open(routes_rb, "wb") do |f|
33
+ f.puts content.sub!(/\n?\z/, "\n") + routes_map
34
+ end
35
+ puts "Route file annotated."
36
+ else
37
+ puts "Can`t find routes.rb"
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,22 @@
1
+ desc "Add schema information (as comments) to model and fixture files"
2
+ task :annotate_models => :environment do
3
+ require 'annotate/annotate_models'
4
+ options={}
5
+ options[:position_in_class] = ENV['position_in_class'] || ENV['position'] || :before
6
+ options[:position_in_factory] = ENV['position_in_factory'] || ENV['position'] || :before
7
+ options[:position_in_fixture] = ENV['position_in_fixture'] || ENV['position'] || :before
8
+ options[:show_indexes] = ENV['show_indexes']
9
+ options[:simple_indexes] = ENV['simple_indexes']
10
+ options[:model_dir] = ENV['model_dir']
11
+ options[:include_version] = ENV['include_version']
12
+ options[:require] = ENV['require'] ? ENV['require'].split(', ') : []
13
+ AnnotateModels.do_annotations(options)
14
+ end
15
+
16
+ desc "Remove schema information from model and fixture files"
17
+ task :remove_annotation => :environment do
18
+ require 'annotate/annotate_models'
19
+ options={}
20
+ options[:model_dir] = ENV['model_dir']
21
+ AnnotateModels.remove_annotations(options)
22
+ end
@@ -0,0 +1,5 @@
1
+ desc "Prepends the route map to the top of routes.rb"
2
+ task :annotate_routes => :environment do
3
+ require 'annotate/annotate_routes'
4
+ AnnotateRoutes.do_annotate
5
+ end
@@ -0,0 +1,50 @@
1
+ # These tasks are added to the project if you install annotate as a Rails plugin.
2
+ # (They are not used to build annotate itself.)
3
+
4
+ # Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets
5
+ # run after doing db:migrate.
6
+ # Unfortunately it relies on ENV for options; it'd be nice to be able to set options
7
+ # in a per-project config file so this task can read them.
8
+
9
+ def run_annotate_models?
10
+ update_on_migrate = true
11
+ (defined? ANNOTATE_MODELS_PREFS::UPDATE_ON_MIGRATE) &&
12
+ (!ANNOTATE_MODELS_PREFS::UPDATE_ON_MIGRATE.nil?) ?
13
+ ANNOTATE_MODELS_PREFS::UPDATE_ON_MIGRATE : true
14
+ end
15
+
16
+
17
+ namespace :db do
18
+ task :migrate do
19
+ if run_annotate_models?
20
+ Annotate::Migration.update_annotations
21
+ end
22
+ end
23
+
24
+ task :update => [:migrate] do
25
+ Annotate::Migration.update_annotations
26
+ end
27
+
28
+ namespace :migrate do
29
+ [:up, :down, :reset, :redo].each do |t|
30
+ task t do
31
+ if run_annotate_models?
32
+ Annotate::Migration.update_annotations
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module Annotate
40
+ class Migration
41
+ @@working = false
42
+
43
+ def self.update_annotations
44
+ unless @@working
45
+ @@working = true
46
+ Rake::Task['annotate_models'].invoke
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,230 @@
1
+ #encoding: utf-8
2
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
3
+ require 'annotate/annotate_models'
4
+ require 'active_support'
5
+ require 'fakefs/spec_helpers'
6
+ require 'tmpdir'
7
+
8
+ describe AnnotateModels do
9
+ include FakeFS::SpecHelpers
10
+
11
+ def mock_class(table_name, primary_key, columns)
12
+ options = {
13
+ :connection => mock("Conn", :indexes => []),
14
+ :table_name => table_name,
15
+ :primary_key => primary_key.to_s,
16
+ :column_names => columns.map { |col| col.name.to_s },
17
+ :columns => columns
18
+ }
19
+
20
+ mock("An ActiveRecord class", options)
21
+ end
22
+
23
+ def mock_column(name, type, options={})
24
+ default_options = {
25
+ :limit => nil,
26
+ :null => false,
27
+ :default => nil
28
+ }
29
+
30
+ stubs = default_options.dup
31
+ stubs.merge!(options)
32
+ stubs.merge!(:name => name, :type => type)
33
+
34
+ mock("Column", stubs)
35
+ end
36
+
37
+ it { AnnotateModels.quote(nil).should eql("NULL") }
38
+ it { AnnotateModels.quote(true).should eql("TRUE") }
39
+ it { AnnotateModels.quote(false).should eql("FALSE") }
40
+ it { AnnotateModels.quote(25).should eql("25") }
41
+ it { AnnotateModels.quote(25.6).should eql("25.6") }
42
+ it { AnnotateModels.quote(1e-20).should eql("1.0e-20") }
43
+
44
+ it "should get schema info" do
45
+ klass = mock_class(:users, :id, [
46
+ mock_column(:id, :integer),
47
+ mock_column(:name, :string, :limit => 50)
48
+ ])
49
+
50
+ AnnotateModels.get_schema_info(klass, "Schema Info").should eql(<<-EOS)
51
+ # Schema Info
52
+ #
53
+ # Table name: users
54
+ #
55
+ # id :integer not null, primary key
56
+ # name :string(50) not null
57
+ #
58
+
59
+ EOS
60
+ end
61
+
62
+ it "should get schema info as RDoc" do
63
+ klass = mock_class(:users, :id, [
64
+ mock_column(:id, :integer),
65
+ mock_column(:name, :string, :limit => 50)
66
+ ])
67
+ ENV.stub!(:[]).with('format_rdoc').and_return(true)
68
+ AnnotateModels.get_schema_info(klass, AnnotateModels::PREFIX).should eql(<<-EOS)
69
+ # #{AnnotateModels::PREFIX}
70
+ #
71
+ # Table name: users
72
+ #
73
+ # *id*:: <tt>integer, not null, primary key</tt>
74
+ # *name*:: <tt>string(50), not null</tt>
75
+ #--
76
+ # #{AnnotateModels::END_MARK}
77
+ #++
78
+
79
+ EOS
80
+ end
81
+
82
+ describe "#get_model_class" do
83
+
84
+ def create(file, body="hi")
85
+ path = @dir + '/' + file
86
+ File.open(path, "w") do |f|
87
+ f.puts(body)
88
+ end
89
+ path
90
+ end
91
+
92
+ before :all do
93
+ @dir = File.join Dir.tmpdir, "annotate_models"
94
+ FileUtils.mkdir_p(@dir)
95
+ AnnotateModels.model_dir = @dir
96
+
97
+ create('foo.rb', <<-EOS)
98
+ class Foo < ActiveRecord::Base
99
+ end
100
+ EOS
101
+ create('foo_with_macro.rb', <<-EOS)
102
+ class FooWithMacro < ActiveRecord::Base
103
+ acts_as_awesome :yah
104
+ end
105
+ EOS
106
+ create('foo_with_utf8.rb', <<-EOS)
107
+ #encoding: utf-8
108
+ class FooWithUtf8 < ActiveRecord::Base
109
+ UTF8STRINGS = %w[résumé façon âge]
110
+ end
111
+ EOS
112
+ end
113
+
114
+ it "should work" do
115
+ klass = AnnotateModels.get_model_class("foo.rb")
116
+ klass.name.should == "Foo"
117
+ end
118
+
119
+ it "should not care about unknown macros" do
120
+ klass = AnnotateModels.get_model_class("foo_with_macro.rb")
121
+ klass.name.should == "FooWithMacro"
122
+ end
123
+
124
+ it "should not complain of invalid multibyte char (USASCII)" do
125
+ klass = AnnotateModels.get_model_class("foo_with_utf8.rb")
126
+ klass.name.should == "FooWithUtf8"
127
+ end
128
+ end
129
+
130
+ describe "#remove_annotation_of_file" do
131
+ def create(file, body="hi")
132
+ File.open(file, "w") do |f|
133
+ f.puts(body)
134
+ end
135
+ end
136
+
137
+ def content(file)
138
+ File.read(file)
139
+ end
140
+
141
+ it "should remove before annotate" do
142
+ create("before.rb", <<-EOS)
143
+ # == Schema Information
144
+ #
145
+ # Table name: foo
146
+ #
147
+ # id :integer not null, primary key
148
+ # created_at :datetime
149
+ # updated_at :datetime
150
+ #
151
+
152
+ class Foo < ActiveRecord::Base
153
+ end
154
+ EOS
155
+
156
+ AnnotateModels.remove_annotation_of_file("before.rb")
157
+
158
+ content("before.rb").should == <<-EOS
159
+ class Foo < ActiveRecord::Base
160
+ end
161
+ EOS
162
+ end
163
+
164
+ it "should remove after annotate" do
165
+ create("after.rb", <<-EOS)
166
+ class Foo < ActiveRecord::Base
167
+ end
168
+
169
+ # == Schema Information
170
+ #
171
+ # Table name: foo
172
+ #
173
+ # id :integer not null, primary key
174
+ # created_at :datetime
175
+ # updated_at :datetime
176
+ #
177
+
178
+ EOS
179
+
180
+ AnnotateModels.remove_annotation_of_file("after.rb")
181
+
182
+ content("after.rb").should == <<-EOS
183
+ class Foo < ActiveRecord::Base
184
+ end
185
+ EOS
186
+ end
187
+ end
188
+
189
+ describe "annotating a file" do
190
+ before do
191
+ @file_name = "user.rb"
192
+ @file_content = <<-EOS
193
+ class User < ActiveRecord::Base
194
+ end
195
+ EOS
196
+ File.open(@file_name, "wb") { |f| f.write @file_content }
197
+ @klass = mock_class(:users, :id, [
198
+ mock_column(:id, :integer),
199
+ mock_column(:name, :string, :limit => 50)
200
+ ])
201
+ @schema_info = AnnotateModels.get_schema_info(@klass, "== Schema Info")
202
+ end
203
+
204
+ it "should annotate the file before the model if position == 'before'" do
205
+ AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => "before")
206
+ File.read(@file_name).should == "#{@schema_info}#{@file_content}"
207
+ end
208
+
209
+ it "should annotate before if given :position => :before" do
210
+ AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :before)
211
+ File.read(@file_name).should == "#{@schema_info}#{@file_content}"
212
+ end
213
+
214
+ it "should annotate before if given :position => :after" do
215
+ AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :after)
216
+ File.read(@file_name).should == "#{@file_content}\n#{@schema_info}"
217
+ end
218
+
219
+ it "should update annotate position" do
220
+ AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :before)
221
+
222
+ another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]),
223
+ "== Schema Info")
224
+
225
+ AnnotateModels.annotate_one_file(@file_name, another_schema_info, :position => :after)
226
+
227
+ File.read(@file_name).should == "#{@file_content}\n#{another_schema_info}"
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'annotate/annotate_routes'
3
+
4
+ describe AnnotateRoutes do
5
+
6
+ def mock_file(stubs={})
7
+ @mock_file ||= mock(File, stubs)
8
+ end
9
+
10
+ describe "Annotate Job" do
11
+
12
+ before(:each) do
13
+ File.should_receive(:join).with("config", "routes.rb").and_return("config/routes.rb")
14
+ end
15
+
16
+ it "should check if routes.rb exists" do
17
+ File.should_receive(:exists?).with("config/routes.rb").and_return(false)
18
+ AnnotateRoutes.should_receive(:puts).with("Can`t find routes.rb")
19
+ AnnotateRoutes.do_annotate
20
+ end
21
+
22
+ describe "When Annotating" do
23
+
24
+ before(:each) do
25
+ File.should_receive(:exists?).with("config/routes.rb").and_return(true)
26
+ AnnotateRoutes.should_receive(:`).with("rake routes").and_return("bad line\ngood line")
27
+ File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
28
+ AnnotateRoutes.should_receive(:puts).with("Route file annotated.")
29
+ end
30
+
31
+ it "should annotate and add a newline!" do
32
+ File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo")
33
+ @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n#== Route Map\n# Generated on .*\n#\n# good line/)
34
+ AnnotateRoutes.do_annotate
35
+ end
36
+
37
+ it "should not add a newline if there are empty lines" do
38
+ File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n")
39
+ @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n#== Route Map\n# Generated on .*\n#\n# good line/)
40
+ AnnotateRoutes.do_annotate
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Annotate do
4
+
5
+ it "should have a version" do
6
+ Annotate.version.should be_instance_of(String)
7
+ end
8
+
9
+ end
@@ -0,0 +1,2 @@
1
+ --format=specdoc
2
+ --colour
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+ require 'annotate'
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: miyucy-annotate
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 4
9
+ - 3
10
+ version: 2.4.3
11
+ platform: ruby
12
+ authors:
13
+ - Cuong Tran
14
+ - Alex Chaffee
15
+ - Marcos Piccinini
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-10-15 00:00:00 +09:00
21
+ default_executable: annotate
22
+ dependencies: []
23
+
24
+ description: Annotates Rails Models, routes, fixtures, and others based on the database schema.
25
+ email:
26
+ - alex@stinky.com
27
+ - ctran@pragmaquest.com
28
+ - x@nofxx.com
29
+ executables:
30
+ - annotate
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - README.rdoc
35
+ files:
36
+ - History.txt
37
+ - README.rdoc
38
+ - VERSION.yml
39
+ - bin/annotate
40
+ - lib/annotate.rb
41
+ - lib/annotate/annotate_models.rb
42
+ - lib/annotate/annotate_routes.rb
43
+ - lib/tasks/annotate_models.rake
44
+ - lib/tasks/annotate_routes.rake
45
+ - lib/tasks/migrate.rake
46
+ - spec/annotate/annotate_models_spec.rb
47
+ - spec/annotate/annotate_routes_spec.rb
48
+ - spec/annotate_spec.rb
49
+ - spec/spec.opts
50
+ - spec/spec_helper.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/miyucy/annotate
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: annotate
81
+ rubygems_version: 1.3.7
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Annotates Rails Models, routes, fixtures, and others based on the database schema.
85
+ test_files:
86
+ - spec/annotate_spec.rb
87
+ - spec/spec_helper.rb
88
+ - spec/annotate/annotate_models_spec.rb
89
+ - spec/annotate/annotate_routes_spec.rb