netsign-annotate 2.4.4

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