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.
- data/History.txt +51 -0
- data/README.rdoc +145 -0
- data/VERSION.yml +5 -0
- data/bin/annotate +74 -0
- data/lib/annotate.rb +23 -0
- data/lib/annotate/annotate_models.rb +356 -0
- data/lib/annotate/annotate_routes.rb +41 -0
- data/lib/tasks/annotate_models.rake +22 -0
- data/lib/tasks/annotate_routes.rake +5 -0
- data/lib/tasks/migrate.rake +50 -0
- data/spec/annotate/annotate_models_spec.rb +230 -0
- data/spec/annotate/annotate_routes_spec.rb +47 -0
- data/spec/annotate_spec.rb +9 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +4 -0
- metadata +89 -0
data/History.txt
ADDED
@@ -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]
|
data/README.rdoc
ADDED
@@ -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.
|
data/VERSION.yml
ADDED
data/bin/annotate
ADDED
@@ -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
|
data/lib/annotate.rb
ADDED
@@ -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,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
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
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
|