Commit 6e41ec0a by Jon Frisby

Merge remote-tracking branch 'miyucy/restart'

WARNING: EVIL MERGE. I'm fixing a number of problems with this branch and ommitting one or two things. Conflicts: .gitignore History.txt README.rdoc Rakefile VERSION.yml annotate.gemspec lib/annotate/annotate_models.rb lib/tasks/annotate_models.rake lib/tasks/annotate_routes.rake lib/tasks/migrate.rake spec/annotate/annotate_models_spec.rb spec/spec_helper.rb
parents cc7f3b15 280a9e56
...@@ -3,6 +3,7 @@ source :rubygems ...@@ -3,6 +3,7 @@ source :rubygems
group :development do group :development do
gem 'jeweler' gem 'jeweler'
gem 'rspec' gem 'rspec'
gem 'fakefs', :require => false
end end
gem 'active_support' gem 'activesupport', :require => nil
...@@ -5,6 +5,7 @@ GEM ...@@ -5,6 +5,7 @@ GEM
activesupport (= 3.0.0) activesupport (= 3.0.0)
activesupport (3.0.0) activesupport (3.0.0)
diff-lcs (1.1.3) diff-lcs (1.1.3)
fakefs (0.4.0)
git (1.2.5) git (1.2.5)
jeweler (1.6.4) jeweler (1.6.4)
bundler (~> 1.0) bundler (~> 1.0)
...@@ -25,5 +26,6 @@ PLATFORMS ...@@ -25,5 +26,6 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
active_support active_support
fakefs
jeweler jeweler
rspec rspec
...@@ -24,6 +24,20 @@ ...@@ -24,6 +24,20 @@
* Rename "annotate" bin to "annotate_models" to avoid conflicting with * Rename "annotate" bin to "annotate_models" to avoid conflicting with
ImageMagick. ImageMagick.
== 2.4.2 2009-11-21
* Annotates (spec|test)/factories/<model>_factory.rb files
== 2.4.1 2009-11-20
* Annotates thoughtbot's factory_girl factories (test/factories/<model>_factory.rb)
* Move default annotation position back to top
== 2.4.0 2009-12-13
* Incorporated lots of patches from the Github community, including support for Blueprints fixtures
* Several bug fixes
== 2.1 2009-10-18 == 2.1 2009-10-18
* New options * New options
......
...@@ -8,6 +8,7 @@ Add a comment summarizing the current schema to the top or bottom of each of you ...@@ -8,6 +8,7 @@ Add a comment summarizing the current schema to the top or bottom of each of you
* Object Daddy exemplars * Object Daddy exemplars
* Machinist blueprints * Machinist blueprints
* Fabrication fabricators * Fabrication fabricators
* Thoughtbot's factory_girl factories, i.e. the (spec|test)/factories/<model>_factory.rb files
The schema comment looks like this: The schema comment looks like this:
...@@ -96,7 +97,8 @@ you can use to tailor the output. ...@@ -96,7 +97,8 @@ you can use to tailor the output.
-s, --simple-indexes Concat the column's related indexes in the annotation -s, --simple-indexes Concat the column's related indexes in the annotation
--model-dir dir Annotate model files stored in dir rather than app/models --model-dir dir Annotate model files stored in dir rather than app/models
-R, --require path Additional files to require before loading models -R, --require path Additional files to require before loading models
-e, --exclude [tests,fixtures] Do not annotate fixtures, test files, or both -e [tests,fixtures,factories] Do not annotate fixtures, test files, and/or factories
--exclude
== WARNING == WARNING
...@@ -110,7 +112,7 @@ to an automatically created comment block. ...@@ -110,7 +112,7 @@ to an automatically created comment block.
== LINKS == LINKS
* Factory Girl => http://github.com/thoughtbot/factory_girl (NOT IMPLEMENTED) * Factory Girl => http://github.com/thoughtbot/factory_girl
* Object Daddy => http://github.com/flogic/object_daddy * Object Daddy => http://github.com/flogic/object_daddy
* Machinist => http://github.com/notahat/machinist * Machinist => http://github.com/notahat/machinist
* Fabrication => http://github.com/paulelliott/fabrication * Fabrication => http://github.com/paulelliott/fabrication
...@@ -144,6 +146,7 @@ Modifications by: ...@@ -144,6 +146,7 @@ Modifications by:
- Bob Potter - http://github.com/bpot - Bob Potter - http://github.com/bpot
- Gavin Montague - http://github.com/govan/ - Gavin Montague - http://github.com/govan/
- Alexander Semyonov - http://github.com/rotuka/ - Alexander Semyonov - http://github.com/rotuka/
- Nathan Brazil - http://github.com/bitaxis/
- Ian Duggan http://github.com/ijcd/ - Ian Duggan http://github.com/ijcd/
- Jon Frisby http://github.com/mrjoy/ - Jon Frisby http://github.com/mrjoy/
......
...@@ -32,12 +32,6 @@ RSpec::Core::RakeTask.new(:spec) do |t| ...@@ -32,12 +32,6 @@ RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = ['spec/*_spec.rb', 'spec/**/*_spec.rb'] t.pattern = ['spec/*_spec.rb', 'spec/**/*_spec.rb']
end end
# FIXME not working yet
RSpec::Core::RakeTask.new(:rcov) do |t|
t.pattern = 'spec/**/*_spec.rb'
t.rcov = true
end
# FIXME warns "already initialized constant Task" # FIXME warns "already initialized constant Task"
# FIXME throws "uninitialized constant RDoc::VISIBILITIES" # FIXME throws "uninitialized constant RDoc::VISIBILITIES"
# require 'rdoc/task' # require 'rdoc/task'
......
--- ---
:major: 2 :major: 2
:minor: 4 :minor: 4
:patch: 1 :patch: 2
:build: 'beta1'
\ No newline at end of file
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "annotate" s.name = "annotate"
s.version = "2.4.1.beta1" s.version = "2.4.2"
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad"] s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad"]
s.date = "2012-03-01" s.date = "2012-03-01"
s.description = "When run, inserts table descriptions from db.schema into a comment block of relevant source code." s.description = "When run, inserts table descriptions from db.schema into a comment block of relevant source code."
s.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net"] s.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net"]
s.executables = ["annotate_models"]
s.extra_rdoc_files = [ s.extra_rdoc_files = [
"README.rdoc" "README.rdoc"
] ]
...@@ -24,6 +25,7 @@ Gem::Specification.new do |s| ...@@ -24,6 +25,7 @@ Gem::Specification.new do |s|
"Rakefile", "Rakefile",
"VERSION.yml", "VERSION.yml",
"annotate.gemspec", "annotate.gemspec",
"bin/annotate_models",
"lib/annotate.rb", "lib/annotate.rb",
"lib/annotate/active_record_patch.rb", "lib/annotate/active_record_patch.rb",
"lib/annotate/annotate_models.rb", "lib/annotate/annotate_models.rb",
......
...@@ -10,48 +10,48 @@ task = :annotate_models ...@@ -10,48 +10,48 @@ task = :annotate_models
OptionParser.new do |opts| OptionParser.new do |opts|
opts.banner = "Usage: annotate_models [options] [model_file]*" opts.banner = "Usage: annotate_models [options] [model_file]*"
opts.on('-d', '--delete', opts.on('-d', '--delete',
"Remove annotations from all model files") do "Remove annotations from all model files") do
task = :remove_annotation task = :remove_annotation
end end
opts.on('-p', '--position [before|after]', ['before', 'after'], opts.on('-p', '--position [before|after]', ['before', 'after'],
"Place the annotations at the top (before) or the bottom (after) of the model file") do |p| "Place the annotations at the top (before) or the bottom (after) of the model file") do |p|
ENV['position'] = p ENV['position'] = p
end end
opts.on('-r', '--routes', opts.on('-r', '--routes',
"Annotate routes.rb with the output of 'rake routes'") do "Annotate routes.rb with the output of 'rake routes'") do
task = :annotate_routes task = :annotate_routes
end end
opts.on('-v', '--version', opts.on('-v', '--version',
"Show the current version of this gem") do "Show the current version of this gem") do
puts "annotate v#{Annotate.version}"; exit puts "annotate v#{Annotate.version}"; exit
end end
opts.on('-m', '--show-migration', opts.on('-m', '--show-migration',
"Include the migration version number in the annotation") do "Include the migration version number in the annotation") do
ENV['include_version'] = "yes" ENV['include_version'] = "yes"
end end
opts.on('-i', '--show-indexes', opts.on('-i', '--show-indexes',
"List the table's database indexes in the annotation") do "List the table's database indexes in the annotation") do
ENV['show_indexes'] = "yes" ENV['show_indexes'] = "yes"
end end
opts.on('-s', '--simple-indexes', opts.on('-s', '--simple-indexes',
"Concat the column's related indexes in the annotation") do "Concat the column's related indexes in the annotation") do
ENV['simple_indexes'] = "yes" ENV['simple_indexes'] = "yes"
end end
opts.on('--model-dir dir', opts.on('--model-dir dir',
"Annotate model files stored in dir rather than app/models") do |dir| "Annotate model files stored in dir rather than app/models") do |dir|
ENV['model_dir'] = dir ENV['model_dir'] = dir
end end
opts.on('-R', '--require path', opts.on('-R', '--require path',
"Additional files to require before loading models") do |path| "Additional files to require before loading models") do |path|
if ENV['require'] if ENV['require']
ENV['require'] = ENV['require'] + ",#{path}" ENV['require'] = ENV['require'] + ",#{path}"
else else
...@@ -63,6 +63,10 @@ OptionParser.new do |opts| ...@@ -63,6 +63,10 @@ OptionParser.new do |opts|
exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = "yes" } exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = "yes" }
end end
opts.on('-f', '--format [bare|rdoc]', ['bare', 'rdoc'], 'rdoc: render Schema Infomation as RDoc') do |fmt|
ENV['format_#{fmt}'] = 'yes'
end
end.parse! end.parse!
if Annotate.load_tasks if Annotate.load_tasks
......
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
require 'yaml' require 'yaml'
......
module AnnotateModels module AnnotateModels
class << self # Annotate Models plugin use this header
# Annotate Models plugin use this header COMPAT_PREFIX = "== Schema Info"
COMPAT_PREFIX = "== Schema Info" PREFIX = "== Schema Information"
PREFIX = "== Schema Information" END_MARK = "== Schema Information End"
PATTERN = /\n?# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n*/
FIXTURE_DIRS = ["test/fixtures","spec/fixtures"] # File.join for windows reverse bar compat?
# File.join for windows reverse bar compat? # I dont use windows, can`t test
# I dont use windows, can`t test UNIT_TEST_DIR = File.join("test", "unit" )
UNIT_TEST_DIR = File.join("test", "unit" ) SPEC_MODEL_DIR = File.join("spec", "models")
SPEC_MODEL_DIR = File.join("spec", "models") FIXTURE_TEST_DIR = File.join("test", "fixtures")
# Object Daddy http://github.com/flogic/object_daddy FIXTURE_SPEC_DIR = File.join("spec", "fixtures")
EXEMPLARS_TEST_DIR = File.join("test", "exemplars") # Object Daddy http://github.com/flogic/object_daddy/tree/master
EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars") EXEMPLARS_TEST_DIR = File.join("test", "exemplars")
# Machinist http://github.com/notahat/machinist EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars")
BLUEPRINTS_DIR = File.join("test", "blueprints") # Machinist http://github.com/notahat/machinist
# FactoryGirl http://github.com/thoughtbot/factory_girl BLUEPRINTS_TEST_DIR = File.join("test", "blueprints")
FACTORIES_TEST_DIR = File.join("test", "factories") BLUEPRINTS_SPEC_DIR = File.join("spec", "blueprints")
FACTORIES_SPEC_DIR = File.join("spec", "factories") # Factory Girl http://github.com/thoughtbot/factory_girl
# Fabrication https://github.com/paulelliott/fabrication.git FACTORY_GIRL_TEST_DIR = File.join("test", "factories")
FABRICATORS_TEST_DIR = File.join("test", "fabricators") FACTORY_GIRL_SPEC_DIR = File.join("spec", "factories")
FABRICATORS_SPEC_DIR = File.join("spec", "fabricators") # Fabrication https://github.com/paulelliott/fabrication.git
FABRICATORS_TEST_DIR = File.join("test", "fabricators")
FABRICATORS_SPEC_DIR = File.join("spec", "fabricators")
# Don't show limit (#) on these column types
# Example: show "integer" instead of "integer(4)"
NO_LIMIT_COL_TYPES = ["integer", "boolean"]
class << self
def model_dir def model_dir
@model_dir || "app/models" @model_dir || "app/models"
end end
...@@ -33,14 +39,14 @@ module AnnotateModels ...@@ -33,14 +39,14 @@ module AnnotateModels
# Simple quoting for the default column value # Simple quoting for the default column value
def quote(value) def quote(value)
case value case value
when NilClass then "NULL" when NilClass then "NULL"
when TrueClass then "TRUE" when TrueClass then "TRUE"
when FalseClass then "FALSE" when FalseClass then "FALSE"
when Float, Fixnum, Bignum then value.to_s when Float, Fixnum, Bignum then value.to_s
# BigDecimals need to be output in a non-normalized form and quoted. # BigDecimals need to be output in a non-normalized form and quoted.
when BigDecimal then value.to_s('F') when BigDecimal then value.to_s('F')
else else
value.inspect value.inspect
end end
end end
...@@ -49,22 +55,26 @@ module AnnotateModels ...@@ -49,22 +55,26 @@ module AnnotateModels
# each column. The line contains the column name, # each column. The line contains the column name,
# the type (and length), and any optional attributes # the type (and length), and any optional attributes
def get_schema_info(klass, header, options = {}) def get_schema_info(klass, header, options = {})
info = "# #{header}\n#\n" info = "# #{header}\n"
info << "# Table name: #{klass.table_name}\n#\n" info<< "#\n"
info<< "# Table name: #{klass.table_name}\n"
info<< "#\n"
max_size = klass.column_names.collect{|name| name.size}.max || 0 max_size = klass.column_names.map{|name| name.size}.max || 0
max_size += 1 max_size += ENV['format_rdoc'] ? 5 : 1
klass.columns.sort_by(&:name).each do |col| klass.columns.sort_by(&:name).each do |col|
attrs = [] attrs = []
attrs << "default(#{quote(col.default)})" unless col.default.nil? attrs << "default(#{quote(col.default)})" unless col.default.nil?
attrs << "not null" unless col.null attrs << "not null" unless col.null
attrs << "primary key" if col.name == klass.primary_key attrs << "primary key" if col.name.to_sym == klass.primary_key.to_sym
col_type = (col.type || col.sql_type).to_s col_type = (col.type || col.sql_type).to_s
if col_type == "decimal" if col_type == "decimal"
col_type << "(#{col.precision}, #{col.scale})" col_type << "(#{col.precision}, #{col.scale})"
else else
col_type << "(#{col.limit})" if col.limit if (col.limit)
col_type << "(#{col.limit})" unless NO_LIMIT_COL_TYPES.include?(col_type)
end
end end
# Check out if we got a geometric column # Check out if we got a geometric column
...@@ -85,14 +95,24 @@ module AnnotateModels ...@@ -85,14 +95,24 @@ module AnnotateModels
end end
end end
info << sprintf("# %-#{max_size}.#{max_size}s:%-15.15s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n" if ENV['format_rdoc']
info << sprintf("# %-#{max_size}.#{max_size}s<tt>%s</tt>", "*#{col.name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n"
else
info << sprintf("# %-#{max_size}.#{max_size}s:%-15.15s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n"
end
end end
if options[:show_indexes] && klass.table_exists? if options[:show_indexes] && klass.table_exists?
info << get_index_info(klass) info << get_index_info(klass)
end end
info << "#\n\n" if ENV['format_rdoc']
info << "#--\n"
info << "# #{END_MARK}\n"
info << "#++\n\n"
else
info << "#\n\n"
end
end end
def get_index_info(klass) def get_index_info(klass)
...@@ -136,21 +156,18 @@ module AnnotateModels ...@@ -136,21 +156,18 @@ module AnnotateModels
old_columns = old_header && old_header.scan(column_pattern).sort old_columns = old_header && old_header.scan(column_pattern).sort
new_columns = new_header && new_header.scan(column_pattern).sort new_columns = new_header && new_header.scan(column_pattern).sort
encoding = Regexp.new(/(^# encoding:.*\n)|(^# coding:.*\n)|(^# -\*- coding:.*\n)/) encoding = Regexp.new(/(^#\s*encoding:.*\n)|(^# coding:.*\n)|(^# -\*- coding:.*\n)/)
encoding_header = old_content.match(encoding).to_s encoding_header = old_content.match(encoding).to_s
if old_columns == new_columns if old_columns == new_columns
false false
else else
# Replace the old schema info with the new schema info # Strip the old schema info, and insert new schema info.
new_content = old_content.sub(/^# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n*/, info_block) old_content.sub!(encoding, '')
# But, if there *was* no old schema info, we simply need to insert it old_content.sub!(PATTERN, '')
if new_content == old_content new_content = (options[:position] || 'before').to_s == 'after' ?
old_content.sub!(encoding, '') (encoding_header + (old_content.rstrip + "\n\n" + info_block)) :
new_content = (options[:position] || 'before').to_s == 'after' ? (encoding_header + info_block + old_content)
(encoding_header + (old_content.rstrip + "\n\n" + info_block)) :
(encoding_header + info_block + old_content)
end
File.open(file_name, "wb") { |f| f.puts new_content } File.open(file_name, "wb") { |f| f.puts new_content }
true true
...@@ -162,7 +179,7 @@ module AnnotateModels ...@@ -162,7 +179,7 @@ module AnnotateModels
if File.exist?(file_name) if File.exist?(file_name)
content = File.read(file_name) content = File.read(file_name)
content.sub!(/^# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n*/, '') content.sub!(PATTERN, '')
File.open(file_name, "wb") { |f| f.puts content } File.open(file_name, "wb") { |f| f.puts content }
end end
...@@ -183,7 +200,7 @@ module AnnotateModels ...@@ -183,7 +200,7 @@ module AnnotateModels
if annotate_one_file(model_file_name, info, options_with_position(options, :position_in_class)) if annotate_one_file(model_file_name, info, options_with_position(options, :position_in_class))
annotated = true annotated = true
end end
unless options[:exclude_tests] unless options[:exclude_tests]
[ [
find_test_file(UNIT_TEST_DIR, "#{model_name}_test.rb"), # test find_test_file(UNIT_TEST_DIR, "#{model_name}_test.rb"), # test
...@@ -198,32 +215,26 @@ module AnnotateModels ...@@ -198,32 +215,26 @@ module AnnotateModels
unless options[:exclude_fixtures] unless options[:exclude_fixtures]
[ [
File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
File.join(BLUEPRINTS_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
File.join(FACTORIES_TEST_DIR, "#{model_name.pluralize}.rb"), # FactoryGirl Factories File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
File.join(FACTORIES_SPEC_DIR, "#{model_name.pluralize}.rb"), # FactoryGirl Factories File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
File.join(FABRICATORS_TEST_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
File.join(FABRICATORS_SPEC_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
].each do |file| File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
File.join(FABRICATORS_TEST_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
File.join(FABRICATORS_SPEC_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
].each do |file|
if annotate_one_file(file, info, options_with_position(options, :position_in_fixture)) if annotate_one_file(file, info, options_with_position(options, :position_in_fixture))
annotated = true annotated = true
end end
end end
FIXTURE_DIRS.each do |dir|
fixture_file_name = File.join(dir,klass.table_name + ".yml")
if File.exist?(fixture_file_name)
if annotate_one_file(fixture_file_name, info, options_with_position(options, :position_in_fixture))
annotated = true
end
end
end
end end
annotated annotated
end end
# position = :position_in_fixture or :position_in_class # position = :position_in_fixture or :position_in_class
def options_with_position(options, position_in) def options_with_position(options, position_in)
options.merge(:position=>(options[position_in] || options[:position])) options.merge(:position=>(options[position_in] || options[:position]))
...@@ -253,7 +264,9 @@ module AnnotateModels ...@@ -253,7 +264,9 @@ module AnnotateModels
models models
end end
# Retrieve model class from the given file. # Retrieve the classes belonging to the model names we're asked to process
# Check for namespaced models in subdirectories as well as models
# in subdirectories without namespacing.
def get_model_class(file) def get_model_class(file)
# this is for non-rails projects, which don't get Rails auto-require magic # this is for non-rails projects, which don't get Rails auto-require magic
require File.expand_path("#{model_dir}/#{file}") unless Module.const_defined?(:Rails) require File.expand_path("#{model_dir}/#{file}") unless Module.const_defined?(:Rails)
...@@ -303,10 +316,7 @@ module AnnotateModels ...@@ -303,10 +316,7 @@ module AnnotateModels
end end
end end
rescue Exception => e rescue Exception => e
puts "Unable to annotate #{file}: #{e.inspect}" puts "Unable to annotate #{file}: #{e.message} (#{e.backtrace.first})"
puts ""
# todo: check if all backtrace lines are in "gems" -- if so, it's an annotate bug, so print the whole stack trace.
# puts e.backtrace.join("\n\t")
end end
end end
if annotated.empty? if annotated.empty?
...@@ -328,19 +338,27 @@ module AnnotateModels ...@@ -328,19 +338,27 @@ module AnnotateModels
if klass < ActiveRecord::Base && !klass.abstract_class? if klass < ActiveRecord::Base && !klass.abstract_class?
deannotated << klass deannotated << klass
model_name = klass.name.underscore
model_file_name = File.join(model_dir, file) model_file_name = File.join(model_dir, file)
remove_annotation_of_file(model_file_name) remove_annotation_of_file(model_file_name)
FIXTURE_DIRS.each do |dir| [
fixture_file_name = File.join(dir,klass.table_name + ".yml") File.join(UNIT_TEST_DIR, "#{model_name}_test.rb"),
remove_annotation_of_file(fixture_file_name) if File.exist?(fixture_file_name) File.join(SPEC_MODEL_DIR, "#{model_name}_spec.rb"),
end File.join(FIXTURE_TEST_DIR, "#{klass.table_name}.yml"), # fixture
File.join(FIXTURE_SPEC_DIR, "#{klass.table_name}.yml"), # fixture
[ find_test_file(UNIT_TEST_DIR, "#{klass.name.underscore}_test.rb"), File.join(EXEMPLARS_TEST_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
find_test_file(SPEC_MODEL_DIR,"#{klass.name.underscore}_spec.rb")].each do |file| File.join(EXEMPLARS_SPEC_DIR, "#{model_name}_exemplar.rb"), # Object Daddy
File.join(BLUEPRINTS_TEST_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
File.join(BLUEPRINTS_SPEC_DIR, "#{model_name}_blueprint.rb"), # Machinist Blueprints
File.join(FACTORY_GIRL_TEST_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
File.join(FACTORY_GIRL_SPEC_DIR, "#{model_name}_factory.rb"), # Factory Girl Factories
File.join(FABRICATORS_TEST_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
File.join(FABRICATORS_SPEC_DIR, "#{model_name}_fabricator.rb"), # Fabrication Fabricators
].each do |file|
remove_annotation_of_file(file) if File.exist?(file) remove_annotation_of_file(file) if File.exist?(file)
end end
end end
rescue Exception => e rescue Exception => e
puts "Unable to annotate #{file}: #{e.message}" puts "Unable to annotate #{file}: #{e.message}"
......
...@@ -8,6 +8,7 @@ task :annotate_models => :environment do ...@@ -8,6 +8,7 @@ task :annotate_models => :environment do
options={} options={}
options[:position_in_class] = ENV['position_in_class'] || ENV['position'] || 'before' options[:position_in_class] = ENV['position_in_class'] || ENV['position'] || 'before'
options[:position_in_fixture] = ENV['position_in_fixture'] || ENV['position'] || 'before' options[:position_in_fixture] = ENV['position_in_fixture'] || ENV['position'] || 'before'
options[:position_in_factory] = ENV['position_in_factory'] || ENV['position'] || 'before'
options[:show_indexes] = ENV['show_indexes'] =~ true_re options[:show_indexes] = ENV['show_indexes'] =~ true_re
options[:simple_indexes] = ENV['simple_indexes'] =~ true_re options[:simple_indexes] = ENV['simple_indexes'] =~ true_re
options[:model_dir] = ENV['model_dir'] options[:model_dir] = ENV['model_dir']
......
desc "Prepends the route map to the top of routes.rb" desc "Prepends the route map to the top of routes.rb"
task :annotate_routes do task :annotate_routes => :environment do
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'annotate', 'annotate_routes')) require File.expand_path(File.join(File.dirname(__FILE__), '..', 'annotate', 'annotate_routes'))
AnnotateRoutes.do_annotate AnnotateRoutes.do_annotate
end end
#encoding: utf-8
require File.dirname(__FILE__) + '/../spec_helper.rb' require File.dirname(__FILE__) + '/../spec_helper.rb'
require 'annotate/annotate_models' require 'annotate/annotate_models'
require 'annotate/active_record_patch' require 'annotate/active_record_patch'
require 'rubygems'
require 'active_support'
describe AnnotateModels do describe AnnotateModels do
def mock_class(table_name, primary_key, columns)
options = {
:connection => mock("Conn", :indexes => []),
:table_name => table_name,
:primary_key => primary_key.to_s,
:column_names => columns.map { |col| col.name.to_s },
:columns => columns
}
def mock_klass(stubs={}) mock("An ActiveRecord class", options)
@mock_file ||= mock("Klass", stubs)
end end
def mock_column(stubs={}) def mock_column(name, type, options={})
@mock_column ||= mock("Column", stubs) default_options = {
:limit => nil,
:null => false,
:default => nil
}
stubs = default_options.dup
stubs.merge!(options)
stubs.merge!(:name => name, :type => type)
mock("Column", stubs)
end end
it { AnnotateModels.quote(nil).should eql("NULL") } it { AnnotateModels.quote(nil).should eql("NULL") }
...@@ -22,43 +38,54 @@ describe AnnotateModels do ...@@ -22,43 +38,54 @@ describe AnnotateModels do
it { AnnotateModels.quote(1e-20).should eql("1.0e-20") } it { AnnotateModels.quote(1e-20).should eql("1.0e-20") }
it "should get schema info" do it "should get schema info" do
klass = mock_class(:users, :id, [
mock_column(:id, :integer),
mock_column(:name, :string, :limit => 50)
])
AnnotateModels.get_schema_info(mock_klass( AnnotateModels.get_schema_info(klass, "Schema Info").should eql(<<-EOS)
:connection => mock("Conn", :indexes => []),
:table_name => "users",
:primary_key => "id",
:column_names => ["id","login"],
:columns => [
mock_column(:type => "integer", :default => nil, :null => false, :name => "id", :limit => nil),
mock_column(:type => "string", :default => nil, :null => false, :name => "name", :limit => 50)
]), "Schema Info").should eql(<<-EOS)
# Schema Info # Schema Info
# #
# Table name: users # Table name: users
# #
# id :integer not null, primary key # id :integer not null, primary key
# id :integer not null, primary key # name :string(50) not null
# #
EOS EOS
end
it "should get schema info as RDoc" do
klass = mock_class(:users, :id, [
mock_column(:id, :integer),
mock_column(:name, :string, :limit => 50)
])
ENV.stub!(:[]).with('format_rdoc').and_return(true)
AnnotateModels.get_schema_info(klass, AnnotateModels::PREFIX).should eql(<<-EOS)
# #{AnnotateModels::PREFIX}
#
# Table name: users
#
# *id*:: <tt>integer, not null, primary key</tt>
# *name*:: <tt>string(50), not null</tt>
#--
# #{AnnotateModels::END_MARK}
#++
EOS
end end
describe "#get_model_class" do describe "#get_model_class" do
require "tmpdir" require "tmpdir"
module ::ActiveRecord
class Base
end
end
def create(file, body="hi") def create(file, body="hi")
file_path = File.join(AnnotateModels.model_dir, file) file_path = File.join(AnnotateModels.model_dir, file)
FileUtils.mkdir_p(File.dirname(file_path)) FileUtils.mkdir_p(File.dirname(file_path))
File.open(file_path, "w") do |f| File.open(file_path, "wb") do |f|
f.puts(body) f.puts(body)
end end
file_path
end end
def check_class_name(file, class_name) def check_class_name(file, class_name)
...@@ -80,15 +107,6 @@ EOS ...@@ -80,15 +107,6 @@ EOS
check_class_name 'foo.rb', 'Foo' check_class_name 'foo.rb', 'Foo'
end end
it "should not care about unknown macros" do
create 'foo_with_macro.rb', <<-EOS
class FooWithMacro < ActiveRecord::Base
acts_as_awesome :yah
end
EOS
check_class_name 'foo_with_macro.rb', 'FooWithMacro'
end
it "should find models with non standard capitalization" do it "should find models with non standard capitalization" do
create 'foo_with_capitals.rb', <<-EOS create 'foo_with_capitals.rb', <<-EOS
class FooWithCAPITALS < ActiveRecord::Base class FooWithCAPITALS < ActiveRecord::Base
...@@ -107,6 +125,25 @@ EOS ...@@ -107,6 +125,25 @@ EOS
check_class_name 'bar/foo_inside_bar.rb', 'Bar::FooInsideBar' check_class_name 'bar/foo_inside_bar.rb', 'Bar::FooInsideBar'
end end
it "should not care about unknown macros" do
create 'foo_with_macro.rb', <<-EOS
class FooWithMacro < ActiveRecord::Base
acts_as_awesome :yah
end
EOS
check_class_name 'foo_with_macro.rb', 'FooWithMacro'
end
it "should not complain of invalid multibyte char (USASCII)" do
create 'foo_with_utf8.rb', <<-EOS
#encoding: utf-8
class FooWithUtf8 < ActiveRecord::Base
UTF8STRINGS = %w[résumé façon âge]
end
EOS
check_class_name 'foo_with_utf8.rb', 'FooWithUtf8'
end
it "should find models inside modules with non standard capitalization" do it "should find models inside modules with non standard capitalization" do
create 'bar/foo_inside_capitals_bar.rb', <<-EOS create 'bar/foo_inside_capitals_bar.rb', <<-EOS
module BAR module BAR
...@@ -132,61 +169,114 @@ EOS ...@@ -132,61 +169,114 @@ EOS
EOS EOS
check_class_name 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', 'NonNamespacedFooWithCapitalsInsideBar' check_class_name 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', 'NonNamespacedFooWithCapitalsInsideBar'
end end
end
it "should not get confused by existing annotations on a model when the schema changes" do describe "#remove_annotation_of_file" do
create 'foo.rb', <<-EOS require "tmpdir"
class Foo < ActiveRecord::Base
end
# == Schema Information
#
# Table name: users
#
# id :integer(4) not null, primary key
# name :string
#
# Indexes
#
# index_users_on_name (name) UNIQUE
#
EOS def create(file, body="hi")
path = File.join(@dir, file)
File.open(path, "w") do |f|
f.puts(body)
end
return path
end
def content(path)
File.read(path)
end
before :each do
@dir = Dir.mktmpdir 'annotate_models'
end
info_block = <<-EOS it "should remove before annotate" do
path = create "before.rb", <<-EOS
# == Schema Information # == Schema Information
# #
# Table name: users # Table name: foo
#
# id :integer(4) not null, primary key
# name :string
# new :string
#
# Indexes
# #
# index_users_on_name (name) UNIQUE # id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
# #
EOS class Foo < ActiveRecord::Base
fname = File.join(AnnotateModels.model_dir, 'foo.rb') end
EOS
AnnotateModels.annotate_one_file(fname, info_block).should be_true AnnotateModels.remove_annotation_of_file(path)
content(path).should == <<-EOS
class Foo < ActiveRecord::Base
end
EOS
end
File.read(fname).should == <<-EOS it "should remove after annotate" do
path = create "after.rb", <<-EOS
class Foo < ActiveRecord::Base class Foo < ActiveRecord::Base
end end
# == Schema Information # == Schema Information
# #
# Table name: users # Table name: foo
#
# id :integer(4) not null, primary key
# name :string
# new :string
#
# Indexes
# #
# index_users_on_name (name) UNIQUE # id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
# #
EOS EOS
AnnotateModels.remove_annotation_of_file(path)
content(path).should == <<-EOS
class Foo < ActiveRecord::Base
end
EOS
end
end
describe "annotating a file" do
before do
@file_name = File.join(Dir.mktmpdir('annotate_models'), "user.rb")
@file_content = <<-EOS
class User < ActiveRecord::Base
end
EOS
File.open(@file_name, "wb") { |f| f.write @file_content }
@klass = mock_class(:users, :id, [
mock_column(:id, :integer),
mock_column(:name, :string, :limit => 50)
])
@schema_info = AnnotateModels.get_schema_info(@klass, "== Schema Info")
end
it "should annotate the file before the model if position == 'before'" do
AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => "before")
File.read(@file_name).should == "#{@schema_info}#{@file_content}"
end
it "should annotate before if given :position => :before" do
AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :before)
File.read(@file_name).should == "#{@schema_info}#{@file_content}"
end
it "should annotate before if given :position => :after" do
AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :after)
File.read(@file_name).should == "#{@file_content}\n#{@schema_info}"
end
it "should update annotate position" do
AnnotateModels.annotate_one_file(@file_name, @schema_info, :position => :before)
another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]),
"== Schema Info")
AnnotateModels.annotate_one_file(@file_name, another_schema_info, :position => :after)
File.read(@file_name).should == "#{@file_content}\n#{another_schema_info}"
end end
end end
end end
--format=specdoc
--colour --colour
\ No newline at end of file
...@@ -7,5 +7,6 @@ rescue LoadError ...@@ -7,5 +7,6 @@ rescue LoadError
end end
$:.unshift(File.dirname(__FILE__) + '/../lib') $:.unshift(File.dirname(__FILE__) + '/../lib')
require 'bigdecimal' require 'active_support'
require 'active_support/core_ext/string/inflections'
require 'annotate' require 'annotate'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment