├── .yardopts ├── spec ├── integration │ ├── rails_3.2.2 │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── Rakefile │ │ ├── script │ │ │ └── rails │ │ ├── config │ │ │ ├── boot.rb │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── test.rb │ │ │ │ └── development.rb │ │ │ ├── application.rb │ │ │ ├── routes.rb │ │ │ └── initializers │ │ │ │ └── unified_initializer.rb │ │ ├── db │ │ │ ├── schema.rb │ │ │ ├── migrate │ │ │ │ └── 20120816164927_create_tasks.rb │ │ │ └── development.sqlite3 │ │ ├── app │ │ │ └── models │ │ │ │ └── task.rb │ │ ├── test │ │ │ ├── test_helper.rb │ │ │ ├── fixtures │ │ │ │ └── tasks.yml │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ ├── Gemfile │ │ └── Gemfile.lock │ ├── rails_3.2.8 │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── Gemfile │ │ ├── Rakefile │ │ ├── script │ │ │ └── rails │ │ ├── Gemfile.lock │ │ ├── config │ │ │ ├── boot.rb │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── test.rb │ │ │ │ └── development.rb │ │ │ ├── routes.rb │ │ │ ├── initializers │ │ │ │ └── unified_initializer.rb │ │ │ └── application.rb │ │ ├── db │ │ │ ├── schema.rb │ │ │ ├── migrate │ │ │ │ └── 20120816164927_create_tasks.rb │ │ │ └── development.sqlite3 │ │ ├── test │ │ │ ├── test_helper.rb │ │ │ ├── fixtures │ │ │ │ └── tasks.yml │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ └── app │ │ │ └── models │ │ │ └── task.rb │ ├── rails_2.3_with_bundler │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── app │ │ │ └── models │ │ │ │ └── task.rb │ │ ├── .gitignore │ │ ├── config │ │ │ ├── routes.rb │ │ │ ├── database.yml │ │ │ ├── environments │ │ │ │ ├── development.rb │ │ │ │ └── test.rb │ │ │ ├── environment.rb │ │ │ ├── initializers │ │ │ │ └── unified_initializer.rb │ │ │ └── boot.rb │ │ ├── script │ │ │ └── console │ │ ├── db │ │ │ ├── development.sqlite3 │ │ │ ├── migrate │ │ │ │ └── 20120816085200_create_tasks.rb │ │ │ └── schema.rb │ │ ├── test │ │ │ ├── fixtures │ │ │ │ └── tasks.yml │ │ │ ├── test_helper.rb │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ ├── Rakefile │ │ ├── Gemfile.lock │ │ └── Gemfile │ ├── rails_3.2_custom_inflections │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── Gemfile │ │ ├── Rakefile │ │ ├── config │ │ │ ├── boot.rb │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── application.rb │ │ │ ├── environments │ │ │ │ ├── test.rb │ │ │ │ └── development.rb │ │ │ ├── routes.rb │ │ │ └── initializers │ │ │ │ └── unified_initializer.rb │ │ ├── script │ │ │ └── rails │ │ ├── Gemfile.lock │ │ ├── db │ │ │ ├── schema.rb │ │ │ ├── migrate │ │ │ │ └── 20120816164927_create_tasks.rb │ │ │ └── development.sqlite3 │ │ ├── test │ │ │ ├── test_helper.rb │ │ │ ├── fixtures │ │ │ │ └── tasks.yml │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ └── app │ │ │ └── models │ │ │ └── task.rb │ ├── standalone │ │ ├── .rvmrc │ │ ├── db │ │ │ ├── schema.rb │ │ │ └── development.sqlite3 │ │ ├── app │ │ │ └── models │ │ │ │ └── task.rb │ │ ├── config │ │ │ └── init.rb │ │ ├── Gemfile.lock │ │ └── Gemfile │ ├── rails_3.2_with_asset_pipeline │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── Rakefile │ │ ├── script │ │ │ └── rails │ │ ├── config │ │ │ ├── boot.rb │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── test.rb │ │ │ │ └── development.rb │ │ │ ├── routes.rb │ │ │ ├── application.rb │ │ │ └── initializers │ │ │ │ └── unified_initializer.rb │ │ ├── db │ │ │ ├── schema.rb │ │ │ ├── migrate │ │ │ │ └── 20120816164927_create_tasks.rb │ │ │ └── development.sqlite3 │ │ ├── test │ │ │ ├── test_helper.rb │ │ │ ├── fixtures │ │ │ │ └── tasks.yml │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ ├── app │ │ │ └── models │ │ │ │ └── task.rb │ │ ├── Gemfile │ │ └── Gemfile.lock │ ├── rails_3.2_autoloading_factory_girl │ │ ├── log │ │ │ └── .gitkeep │ │ ├── tmp │ │ │ └── .gitkeep │ │ ├── .rvmrc │ │ ├── Rakefile │ │ ├── script │ │ │ └── rails │ │ ├── config │ │ │ ├── boot.rb │ │ │ ├── database.yml │ │ │ ├── application.rb │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── test.rb │ │ │ │ └── development.rb │ │ │ ├── routes.rb │ │ │ └── initializers │ │ │ │ └── unified_initializer.rb │ │ ├── db │ │ │ ├── schema.rb │ │ │ ├── migrate │ │ │ │ └── 20120816164927_create_tasks.rb │ │ │ └── development.sqlite3 │ │ ├── test │ │ │ ├── test_helper.rb │ │ │ ├── factories │ │ │ │ └── tasks.rb │ │ │ └── unit │ │ │ │ └── task_test.rb │ │ ├── app │ │ │ └── models │ │ │ │ └── task.rb │ │ ├── Gemfile │ │ └── Gemfile.lock │ ├── rails_3.2.2.rb │ ├── rails_3.2.8.rb │ ├── standalone.rb │ ├── rails_3.2_with_asset_pipeline.rb │ ├── rails_2.3_with_bundler.rb │ ├── rails_3.2_custom_inflections.rb │ ├── rails_3.2_autoloading_factory_girl.rb │ ├── integration_spec.rb │ └── common_validation.rb ├── fixtures │ ├── rails_32_environment.rb │ ├── rails_32_test_helper.rb │ ├── 20120816164927_create_tasks.rb │ ├── rails32_boot.rb │ ├── rails_32_rakefile │ ├── rails_32_rails │ ├── database.yml │ ├── rails_32_development.rb │ ├── rails32_unified_initializer.rb │ ├── rails_32_test.rb │ ├── rails_32old_application.rb │ ├── rails_328_gemfile │ ├── rails_32_schema.rb │ ├── rvmrc.sh │ └── rails_328_gemfile.lock ├── annotate_spec.rb ├── spec_helper.rb └── annotate │ ├── annotate_routes_spec.rb │ └── annotate_models_spec.rb ├── .rspec ├── .document ├── lib ├── annotate │ ├── version.rb │ ├── active_record_patch.rb │ ├── tasks.rb │ ├── annotate_routes.rb │ └── annotate_models.rb ├── generators │ └── annotate │ │ ├── USAGE │ │ ├── install_generator.rb │ │ └── templates │ │ └── auto_annotate_models.rake ├── tasks │ ├── annotate_routes.rake │ └── annotate_models.rake └── annotate.rb ├── .gitignore ├── TODO.rdoc ├── Gemfile ├── tasks └── migrate.rake ├── annotate.gemspec ├── bin └── annotate ├── Rakefile ├── CHANGELOG.rdoc └── README.rdoc /.yardopts: -------------------------------------------------------------------------------- 1 | --no-private 2 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | --format documentation 3 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/standalone/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/Gemfile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_328_gemfile -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/tmp/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/Rakefile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_32_rakefile -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/script/rails: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_rails -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/Rakefile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_32_rakefile -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/script/rails: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_rails -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/boot.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails32_boot.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/database.yml: -------------------------------------------------------------------------------- 1 | ../../../fixtures/database.yml -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/Gemfile.lock: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_328_gemfile.lock -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/boot.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails32_boot.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/database.yml: -------------------------------------------------------------------------------- 1 | ../../../fixtures/database.yml -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/standalone/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/.rvmrc: -------------------------------------------------------------------------------- 1 | ../../fixtures/rvmrc.sh -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/Gemfile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_328_gemfile -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/Rakefile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_32_rakefile -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/Rakefile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_32_rakefile -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/environment.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_environment.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_test.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_test_helper.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/environment.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_environment.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_test.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_test_helper.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/Rakefile: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_32_rakefile -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/boot.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails32_boot.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/script/rails: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_rails -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/script/rails: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_rails -------------------------------------------------------------------------------- /.document: -------------------------------------------------------------------------------- 1 | spec/**/*.rb 2 | lib/**/*.rb 3 | - 4 | README.rdoc 5 | CHANGELOG.rdoc 6 | TODO.rdoc 7 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/application.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32old_application.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/script/rails: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_rails -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/Gemfile.lock: -------------------------------------------------------------------------------- 1 | ../../fixtures/rails_328_gemfile.lock -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/database.yml: -------------------------------------------------------------------------------- 1 | ../../../fixtures/database.yml -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/boot.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails32_boot.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/database.yml: -------------------------------------------------------------------------------- 1 | ../../../fixtures/database.yml -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/boot.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails32_boot.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/database.yml: -------------------------------------------------------------------------------- 1 | ../../../fixtures/database.yml -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/db/schema.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_schema.rb -------------------------------------------------------------------------------- /lib/annotate/version.rb: -------------------------------------------------------------------------------- 1 | module Annotate 2 | def self.version 3 | '2.6.0.beta1' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_development.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_development.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/environment.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_environment.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_test_helper.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_test_helper.rb -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/.gitignore: -------------------------------------------------------------------------------- 1 | tmp/* 2 | !tmp/.gitkeep 3 | 4 | log/* 5 | !log/.gitkeep 6 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_test_helper.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/application.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32old_application.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_test.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/environment.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_environment.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_test.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/routes.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.routes.draw do 2 | resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/routes.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.routes.draw do 2 | resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/application.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32old_application.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/environment.rb: -------------------------------------------------------------------------------- 1 | ../../../fixtures/rails_32_environment.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_test.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails32_unified_initializer.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/db/migrate/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/20120816164927_create_tasks.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | attr_accessible :content 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails32_unified_initializer.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/db/migrate/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/20120816164927_create_tasks.rb -------------------------------------------------------------------------------- /spec/integration/standalone/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | attr_accessible :content 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_development.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails_32_development.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/routes.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.routes.draw do 2 | resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/db/migrate/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/20120816164927_create_tasks.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/routes.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.routes.draw do 2 | resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/routes.rb: -------------------------------------------------------------------------------- 1 | ActionController::Routing::Routes.draw do |map| 2 | map.resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/routes.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.routes.draw do 2 | resources :tasks 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/app/models/task.rb: -------------------------------------------------------------------------------- 1 | class TASk < ActiveRecord::Base 2 | attr_accessible :content 3 | end 4 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/db/migrate/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/20120816164927_create_tasks.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/rails32_unified_initializer.rb -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/db/migrate/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | ../../../../fixtures/20120816164927_create_tasks.rb -------------------------------------------------------------------------------- /spec/integration/standalone/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/standalone/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_3.2.2/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_3.2.8/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/script/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require File.expand_path('../../config/boot', __FILE__) 3 | require 'commands/console' 4 | -------------------------------------------------------------------------------- /lib/generators/annotate/USAGE: -------------------------------------------------------------------------------- 1 | Add a .rake file that automatically annotates models when you do a db:migrate 2 | in development mode: 3 | 4 | rails generate annotate:install 5 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_2.3_with_bundler/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_3.2_custom_inflections/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_3.2_with_asset_pipeline/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/fixtures/rails_32_environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | TestApp::Application.initialize! 6 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] = "test" 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | end 7 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstacruz/annotate_models/master/spec/integration/rails_3.2_autoloading_factory_girl/db/development.sqlite3 -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/test/fixtures/tasks.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 2 | 3 | one: 4 | content: MyString 5 | 6 | two: 7 | content: MyString 8 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/test/fixtures/tasks.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 2 | 3 | one: 4 | content: MyString 5 | 6 | two: 7 | content: MyString 8 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/test/fixtures/tasks.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 2 | 3 | one: 4 | content: MyString 5 | 6 | two: 7 | content: MyString 8 | -------------------------------------------------------------------------------- /spec/integration/standalone/config/init.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | 3 | ActiveRecord::Base.establish_connection({ 4 | adapter: 'sqlite3', 5 | database: 'db/development.sqlite3', 6 | pool: 1, 7 | timeout: 5000 8 | }) 9 | -------------------------------------------------------------------------------- /spec/annotate_spec.rb: -------------------------------------------------------------------------------- 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 10 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/test/fixtures/tasks.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 2 | 3 | one: 4 | content: MyString 5 | 6 | two: 7 | content: MyString 8 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/test/fixtures/tasks.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 2 | 3 | one: 4 | content: MyString 5 | 6 | two: 7 | content: MyString 8 | -------------------------------------------------------------------------------- /spec/fixtures/20120816164927_create_tasks.rb: -------------------------------------------------------------------------------- 1 | class CreateTasks < ActiveRecord::Migration 2 | def change 3 | create_table :tasks do |t| 4 | t.string :content 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/fixtures/rails32_boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] = "test" 2 | require File.expand_path(File.dirname(__FILE__) + "/../config/environment") 3 | 4 | require 'test_help' 5 | 6 | class ActiveSupport::TestCase 7 | end 8 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/test/factories/tasks.rb: -------------------------------------------------------------------------------- 1 | # Read about factories at https://github.com/thoughtbot/factory_girl 2 | 3 | FactoryGirl.define do 4 | factory :task do 5 | content "MyString" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/test/unit/task_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class TaskTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/annotate/active_record_patch.rb: -------------------------------------------------------------------------------- 1 | # monkey patches 2 | 3 | module ::ActiveRecord 4 | class Base 5 | def self.method_missing(name, *args) 6 | # ignore this, so unknown/unloaded macros won't cause parsing to fail 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/annotate/tasks.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | 4 | # Make tasks visible for Rails also when used as gem. 5 | Dir[File.join(File.dirname(__FILE__), '..', 'tasks', '**/*.rake')].each { |rake| load rake } 6 | Dir[File.join(File.dirname(__FILE__), '..', '..', 'tasks', '**/*.rake')].each { |rake| load rake } 7 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | TestApp::Application.load_tasks 8 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/db/migrate/20120816085200_create_tasks.rb: -------------------------------------------------------------------------------- 1 | class CreateTasks < ActiveRecord::Migration 2 | def self.up 3 | create_table :tasks do |t| 4 | t.string :content 5 | 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :tasks 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 | development: 4 | adapter: sqlite3 5 | database: db/development.sqlite3 6 | pool: 1 7 | timeout: 5000 8 | 9 | test: 10 | adapter: sqlite3 11 | database: db/test.sqlite3 12 | pool: 1 13 | timeout: 5000 14 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | config.cache_classes = false 2 | config.whiny_nils = true 3 | config.action_controller.consider_all_requests_local = true 4 | config.action_controller.perform_caching = false 5 | config.action_view.debug_rjs = true 6 | config.action_mailer.raise_delivery_errors = false 7 | -------------------------------------------------------------------------------- /spec/fixtures/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 1 10 | timeout: 5000 11 | 12 | test: 13 | adapter: sqlite3 14 | database: db/test.sqlite3 15 | pool: 1 16 | timeout: 5000 17 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require(File.join(File.dirname(__FILE__), 'config', 'boot')) 5 | 6 | require 'rake' 7 | require 'rake/testtask' 8 | require 'rake/rdoctask' 9 | 10 | require 'tasks/rails' 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.yardoc/* 3 | /doc/* 4 | /coverage/* 5 | /spec/debug.log 6 | /pkg/* 7 | /dist 8 | /Gemfile.lock 9 | *.gem 10 | /.idea/ 11 | /.rvmrc 12 | .bundle 13 | /.rbx 14 | /spec/integration/*/bin/ 15 | /spec/integration/*/log/* 16 | !/spec/integration/*/log/.gitkeep 17 | /spec/integration/*/tmp/* 18 | !/spec/integration/*/tmp/.gitkeep 19 | /spec/integration/*/db/test.* 20 | .rbenv-version -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | config.cache_classes = true 2 | config.whiny_nils = true 3 | config.action_controller.consider_all_requests_local = true 4 | config.action_controller.perform_caching = false 5 | config.action_controller.allow_forgery_protection = false 6 | config.action_view.cache_template_loading = true 7 | config.action_mailer.delivery_method = :test 8 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_development.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.configure do 2 | config.action_dispatch.best_standards_support = :builtin 3 | config.active_record.auto_explain_threshold_in_seconds = 0.5 4 | config.active_record.mass_assignment_sanitizer = :strict 5 | config.active_support.deprecation = :log 6 | config.cache_classes = false 7 | config.consider_all_requests_local = true 8 | config.whiny_nils = true 9 | end 10 | -------------------------------------------------------------------------------- /spec/fixtures/rails32_unified_initializer.rb: -------------------------------------------------------------------------------- 1 | # secret_token.rb 2 | TestApp::Application.config.secret_token = '4768b21141022d583b141fde0db7e0b31759321b7fce459963914fdd82db248ea0318d9568030dcde70d404d4e86003ce5f51a7a83c8130842e5a97062b68c3c' 3 | 4 | # session_store.rb 5 | TestApp::Application.config.session_store :cookie_store, key: '_session' 6 | 7 | # wrap_parameters.rb 8 | ActiveSupport.on_load(:active_record) { self.include_root_in_json = false } 9 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_test.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.configure do 2 | config.action_dispatch.show_exceptions = false 3 | config.active_record.mass_assignment_sanitizer = :strict 4 | config.active_support.deprecation = :stderr 5 | config.cache_classes = true 6 | config.consider_all_requests_local = true 7 | config.serve_static_assets = true 8 | config.static_cache_control = "public, max-age=3600" 9 | config.whiny_nils = true 10 | end 11 | -------------------------------------------------------------------------------- /lib/generators/annotate/install_generator.rb: -------------------------------------------------------------------------------- 1 | module Annotate 2 | module Generators 3 | class InstallGenerator < Rails::Generators::Base 4 | desc "Copy annotate_models rakefiles for automatic annotation" 5 | source_root File.expand_path('../templates', __FILE__) 6 | 7 | # copy rake tasks 8 | def copy_tasks 9 | template "auto_annotate_models.rake", "lib/tasks/auto_annotate_models.rake" 10 | end 11 | 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32old_application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require "active_record/railtie" 4 | require "rails/test_unit/railtie" 5 | 6 | if defined?(Bundler) 7 | # If you precompile assets before deploying to production, use this line 8 | Bundler.require(*Rails.groups(:assets => %w(development test))) 9 | end 10 | 11 | module TestApp 12 | class Application < Rails::Application 13 | config.assets.enabled = false 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /TODO.rdoc: -------------------------------------------------------------------------------- 1 | == TODO 2 | 3 | - clean up history 4 | - change default position back to "top" for all annotations 5 | - add "top" and "bottom" as synonyms for "before" and "after" 6 | - change 'exclude' to 'only' (double negatives are not unconfusing) 7 | 8 | == TODO (proposed) 9 | 10 | - push two identical gems, named 'annotate' and 'annotate_models' 11 | - supply two binaries, named 'annotate' and 'annotate_models', since there's already a unix tool named 'annotate' 12 | - test EVERYTHING 13 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file 2 | 3 | # Specifies gem version of Rails to use when vendor/rails is not present 4 | RAILS_GEM_VERSION = '2.3.14' unless defined? RAILS_GEM_VERSION 5 | 6 | # Bootstrap the Rails environment, frameworks, and default configuration 7 | require File.join(File.dirname(__FILE__), 'boot') 8 | 9 | Rails::Initializer.run do |config| 10 | config.frameworks -= [ :active_resource, :action_mailer ] 11 | end 12 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.configure do 2 | config.action_dispatch.best_standards_support = :builtin 3 | config.active_record.auto_explain_threshold_in_seconds = 0.5 4 | config.active_record.mass_assignment_sanitizer = :strict 5 | config.active_support.deprecation = :log 6 | config.assets.compress = false 7 | config.assets.debug = true 8 | config.cache_classes = false 9 | config.consider_all_requests_local = true 10 | config.whiny_nils = true 11 | end 12 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require "active_record/railtie" 4 | require "sprockets/railtie" 5 | require "rails/test_unit/railtie" 6 | 7 | if defined?(Bundler) 8 | # If you precompile assets before deploying to production, use this line 9 | Bundler.require(*Rails.groups(:assets => %w(development test))) 10 | end 11 | 12 | module TestApp 13 | class Application < Rails::Application 14 | config.assets.enabled = true 15 | config.assets.version = '1.0' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | # secret_token.rb 2 | TestApp::Application.config.secret_token = '4768b21141022d583b141fde0db7e0b31759321b7fce459963914fdd82db248ea0318d9568030dcde70d404d4e86003ce5f51a7a83c8130842e5a97062b68c3c' 3 | 4 | # session_store.rb 5 | TestApp::Application.config.session_store :cookie_store, key: '_session' 6 | 7 | # wrap_parameters.rb 8 | ActiveSupport.on_load(:action_controller) { wrap_parameters format: [:json] } 9 | ActiveSupport.on_load(:active_record) { self.include_root_in_json = false } 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem 'rake', '>= 0.8.7', :require => false 4 | gem 'activerecord', '>= 2.3.0', :require => false 5 | 6 | group :development do 7 | gem 'mg', :require => false 8 | platforms :mri do 9 | gem 'yard', :require => false 10 | end 11 | end 12 | 13 | group :development, :test do 14 | gem 'rspec', :require => false 15 | platforms :mri do 16 | gem 'pry', :require => false 17 | gem 'pry-coolline', :require => false 18 | end 19 | end 20 | 21 | group :test do 22 | gem 'wrong', '>=0.6.2', :require => false 23 | gem 'files', '>=0.2.1', :require => false 24 | end 25 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require "active_record/railtie" 4 | require "rails/test_unit/railtie" 5 | 6 | if defined?(Bundler) 7 | # If you precompile assets before deploying to production, use this line 8 | Bundler.require(*Rails.groups(:assets => %w(development test))) 9 | end 10 | 11 | module TestApp 12 | class Application < Rails::Application 13 | config.active_record.whitelist_attributes = true 14 | config.active_support.escape_html_entities_in_json = true 15 | config.assets.enabled = false 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | # secret_token.rb 2 | TestApp::Application.config.secret_token = '4768b21141022d583b141fde0db7e0b31759321b7fce459963914fdd82db248ea0318d9568030dcde70d404d4e86003ce5f51a7a83c8130842e5a97062b68c3c' 3 | 4 | # session_store.rb 5 | TestApp::Application.config.session_store :cookie_store, key: '_session' 6 | 7 | # wrap_parameters.rb 8 | ActiveSupport.on_load(:active_record) { self.include_root_in_json = false } 9 | 10 | # inflections.rb 11 | ActiveSupport::Inflector.inflections do |inflect| 12 | inflect.acronym 'TASk' 13 | end 14 | -------------------------------------------------------------------------------- /spec/integration/standalone/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | activemodel (3.2.8) 12 | activesupport (= 3.2.8) 13 | builder (~> 3.0.0) 14 | activerecord (3.2.8) 15 | activemodel (= 3.2.8) 16 | activesupport (= 3.2.8) 17 | arel (~> 3.0.2) 18 | tzinfo (~> 0.3.29) 19 | activesupport (3.2.8) 20 | i18n (~> 0.6) 21 | multi_json (~> 1.0) 22 | arel (3.0.2) 23 | builder (3.0.0) 24 | i18n (0.6.0) 25 | multi_json (1.3.6) 26 | rake (0.9.2.2) 27 | sqlite3 (1.3.6) 28 | tzinfo (0.3.33) 29 | 30 | PLATFORMS 31 | ruby 32 | 33 | DEPENDENCIES 34 | activerecord (= 3.2.8) 35 | annotate! 36 | sqlite3 37 | -------------------------------------------------------------------------------- /lib/tasks/annotate_routes.rake: -------------------------------------------------------------------------------- 1 | desc "Adds the route map to routes.rb" 2 | task :annotate_routes => :environment do 3 | annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) 4 | require "#{annotate_lib}/annotate/annotate_routes" 5 | 6 | options={} 7 | ENV['position'] = options[:position] = Annotate.fallback(ENV['position'], 'before') 8 | options[:position_in_routes] = Annotate.fallback(ENV['position_in_routes'], ENV['position']) 9 | options[:require] = ENV['require'] ? ENV['require'].split(',') : [] 10 | AnnotateRoutes.do_annotations(options) 11 | end 12 | 13 | desc "Removes the route map from routes.rb" 14 | task :remove_routes => :environment do 15 | annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) 16 | require "#{annotate_lib}/annotate/annotate_routes" 17 | 18 | options={} 19 | options[:require] = ENV['require'] ? ENV['require'].split(',') : [] 20 | AnnotateRoutes.remove_annotations(options) 21 | end 22 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (2.3.14) 12 | actionpack (= 2.3.14) 13 | actionpack (2.3.14) 14 | activesupport (= 2.3.14) 15 | rack (~> 1.1.0) 16 | activerecord (2.3.14) 17 | activesupport (= 2.3.14) 18 | activeresource (2.3.14) 19 | activesupport (= 2.3.14) 20 | activesupport (2.3.14) 21 | rack (1.1.3) 22 | rails (2.3.14) 23 | actionmailer (= 2.3.14) 24 | actionpack (= 2.3.14) 25 | activerecord (= 2.3.14) 26 | activeresource (= 2.3.14) 27 | activesupport (= 2.3.14) 28 | rake (>= 0.8.3) 29 | rake (0.8.7) 30 | sqlite3 (1.3.5) 31 | 32 | PLATFORMS 33 | ruby 34 | 35 | DEPENDENCIES 36 | annotate! 37 | bundler 38 | rails (~> 2.3.14) 39 | rake (~> 0.8.7) 40 | sqlite3 41 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/initializers/unified_initializer.rb: -------------------------------------------------------------------------------- 1 | # new_rails_defaults.rb 2 | if defined?(ActiveRecord) 3 | ActiveRecord::Base.include_root_in_json = true 4 | ActiveRecord::Base.store_full_sti_class = true 5 | end 6 | ActionController::Routing.generate_best_match = false 7 | ActiveSupport.use_standard_json_time_format = true 8 | ActiveSupport.escape_html_entities_in_json = false 9 | 10 | # session_store.rb 11 | ActionController::Base.session = { 12 | :key => '_session', 13 | :secret => 'a61ce930be7219beee70d3e3411e0794d90ab22d12e87a1f7f50c98ad7b08771ed92e72e1a7299c8ec4795d45d566a39e0a0a1f7e7095e2eeb31320a0c5d7ee5' 14 | } 15 | 16 | # cookie_verification_secret.rb 17 | ActionController::Base.cookie_verifier_secret = '1b2363a161fbf01041bd9d0b0d9a332e5c7445503c9e89585c8a248698d28054e3918fa77a0206e662629ee9a00d2831949e74801f27ee85ba2116b62b675935'; 18 | 19 | # Hacks for Ruby 1.9.3... 20 | MissingSourceFile::REGEXPS << [/^cannot load such file -- (.+)$/i, 1] 21 | -------------------------------------------------------------------------------- /spec/fixtures/rails_328_gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'rails', '3.2.8' 15 | 16 | gem 'sqlite3' 17 | 18 | group :development do 19 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 20 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 21 | else 22 | gem 'annotate', :path => '../../..' 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/Gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'rails', '3.2.2' 15 | 16 | gem 'sqlite3' 17 | 18 | group :development do 19 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 20 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 21 | else 22 | gem 'annotate', :path => '../../..' 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/integration/standalone/Gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'activerecord', '3.2.8' 15 | 16 | gem 'sqlite3' 17 | 18 | group :development do 19 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 20 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 21 | else 22 | gem 'annotate', :path => '../../..' 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead of editing this file, 2 | # please use the migrations feature of Active Record to incrementally modify your database, and 3 | # then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your database schema. If you need 6 | # to create the application database on another system, you should be using db:schema:load, not running 7 | # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations 8 | # you'll amass, the slower it'll run and the greater likelihood for issues). 9 | # 10 | # It's strongly recommended to check this file into your version control system. 11 | 12 | ActiveRecord::Schema.define(:version => 20120816085200) do 13 | 14 | create_table "tasks", :force => true do |t| 15 | t.string "content" 16 | t.datetime "created_at" 17 | t.datetime "updated_at" 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /tasks/migrate.rake: -------------------------------------------------------------------------------- 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 | [:change, :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 || (ENV['skip_on_db_migrate'] =~ /(true|t|yes|y|1)$/i) 28 | @@working = true 29 | Rake::Task['annotate_models'].invoke 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/fixtures/rails_32_schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20120816164927) do 15 | 16 | create_table "tasks", :force => true do |t| 17 | t.string "content" 18 | t.datetime "created_at", :null => false 19 | t.datetime "updated_at", :null => false 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/Gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'bundler' 15 | gem 'rake', '~>0.8.7', :require => false 16 | gem 'rails', '~>2.3.14' 17 | gem 'sqlite3' 18 | 19 | group :development do 20 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 21 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 22 | else 23 | gem 'annotate', :path => '../../..' 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails322 < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) tasks#index 25 | # POST /tasks(.:format) tasks#create 26 | # new_task GET /tasks/new(.:format) tasks#new 27 | # edit_task GET /tasks/:id/edit(.:format) tasks#edit 28 | # task GET /tasks/:id(.:format) tasks#show 29 | # PUT /tasks/:id(.:format) tasks#update 30 | # DELETE /tasks/:id(.:format) tasks#destroy 31 | # 32 | RUBY 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.8.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails328 < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) tasks#index 25 | # POST /tasks(.:format) tasks#create 26 | # new_task GET /tasks/new(.:format) tasks#new 27 | # edit_task GET /tasks/:id/edit(.:format) tasks#edit 28 | # task GET /tasks/:id(.:format) tasks#show 29 | # PUT /tasks/:id(.:format) tasks#update 30 | # DELETE /tasks/:id(.:format) tasks#destroy 31 | # 32 | RUBY 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/integration/standalone.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Standalone < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.test_commands 21 | return %q{ 22 | bin/annotate --require ./config/init.rb 23 | } 24 | end 25 | 26 | def self.verify_output(output) 27 | output.should =~ /Annotated \(1\): Task/ 28 | end 29 | 30 | def self.verify_files(test_rig) 31 | return Annotate::Validations::Common.verify_files({ 32 | :model => true, 33 | :test => false, 34 | :fixture => false, 35 | :factory => false, 36 | :routes => false 37 | }, test_rig, self.schema_annotation, nil, true) 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails32WithAssetPipeline < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) tasks#index 25 | # POST /tasks(.:format) tasks#create 26 | # new_task GET /tasks/new(.:format) tasks#new 27 | # edit_task GET /tasks/:id/edit(.:format) tasks#edit 28 | # task GET /tasks/:id(.:format) tasks#show 29 | # PUT /tasks/:id(.:format) tasks#update 30 | # DELETE /tasks/:id(.:format) tasks#destroy 31 | # 32 | RUBY 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/Gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'rails', '3.2.2' 15 | 16 | gem 'sqlite3' 17 | 18 | group :development do 19 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 20 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 21 | else 22 | gem 'annotate', :path => '../../..' 23 | end 24 | end 25 | 26 | group :test do 27 | gem 'factory_girl' 28 | gem 'factory_girl_rails' 29 | end 30 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails23WithBundler < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime 15 | # updated_at :datetime 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) {:controller=>"tasks", :action=>"index"} 25 | # POST /tasks(.:format) {:controller=>"tasks", :action=>"create"} 26 | # new_task GET /tasks/new(.:format) {:controller=>"tasks", :action=>"new"} 27 | # edit_task GET /tasks/:id/edit(.:format) {:controller=>"tasks", :action=>"edit"} 28 | # task GET /tasks/:id(.:format) {:controller=>"tasks", :action=>"show"} 29 | # PUT /tasks/:id(.:format) {:controller=>"tasks", :action=>"update"} 30 | # DELETE /tasks/:id(.:format) {:controller=>"tasks", :action=>"destroy"} 31 | # 32 | RUBY 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/Gemfile: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template.Gemfile and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | source 'https://rubygems.org' 13 | 14 | gem 'rails', '3.2.2' 15 | 16 | gem 'sqlite3' 17 | 18 | # Gems used only for assets and not required 19 | # in production environments by default. 20 | group :assets do 21 | gem 'sass-rails', '~> 3.2.3' 22 | gem 'coffee-rails', '~> 3.2.1' 23 | gem 'uglifier', '>= 1.0.3' 24 | end 25 | 26 | group :development do 27 | if(ENV['AUTOMATED_TEST'] && ENV['AUTOMATED_TEST'] != '') 28 | gem 'annotate', :path => ENV['AUTOMATED_TEST'] 29 | else 30 | gem 'annotate', :path => '../../..' 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_custom_inflections.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails32CustomInflection < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) tasks#index 25 | # POST /tasks(.:format) tasks#create 26 | # new_task GET /tasks/new(.:format) tasks#new 27 | # edit_task GET /tasks/:id/edit(.:format) tasks#edit 28 | # task GET /tasks/:id(.:format) tasks#show 29 | # PUT /tasks/:id(.:format) tasks#update 30 | # DELETE /tasks/:id(.:format) tasks#destroy 31 | # 32 | RUBY 33 | end 34 | 35 | def self.verify_output(output) 36 | output.should =~ /Annotated \(1\): TASk/ 37 | output.should =~ /Route file annotated./ 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl.rb: -------------------------------------------------------------------------------- 1 | require 'common_validation' 2 | 3 | module Annotate 4 | module Validations 5 | class Rails32AutoloadingFactoryGirl < Base 6 | def self.schema_annotation 7 | return <<-RUBY 8 | # == Schema Information 9 | # 10 | # Table name: tasks 11 | # 12 | # id :integer not null, primary key 13 | # content :string(255) 14 | # created_at :datetime not null 15 | # updated_at :datetime not null 16 | # 17 | RUBY 18 | end 19 | 20 | def self.route_annotation 21 | return <<-RUBY 22 | # == Route Map (Updated YYYY-MM-DD HH:MM) 23 | # 24 | # tasks GET /tasks(.:format) tasks#index 25 | # POST /tasks(.:format) tasks#create 26 | # new_task GET /tasks/new(.:format) tasks#new 27 | # edit_task GET /tasks/:id/edit(.:format) tasks#edit 28 | # task GET /tasks/:id(.:format) tasks#show 29 | # PUT /tasks/:id(.:format) tasks#update 30 | # DELETE /tasks/:id(.:format) tasks#destroy 31 | # 32 | RUBY 33 | end 34 | 35 | def self.verify_files(test_rig) 36 | return Annotate::Validations::Common.verify_files({ 37 | :model => true, 38 | :test => true, 39 | :fixture => false, 40 | :factory => true, 41 | :routes => true 42 | }, test_rig, self.schema_annotation, self.route_annotation, true) 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/generators/annotate/templates/auto_annotate_models.rake: -------------------------------------------------------------------------------- 1 | # NOTE: only doing this in development as some production environments (Heroku) 2 | # NOTE: are sensitive to local FS writes, and besides -- it's just not proper 3 | # NOTE: to have a dev-mode tool do its thing in production. 4 | if(Rails.env.development?) 5 | task :set_annotation_options do 6 | # You can override any of these by setting an environment variable of the 7 | # same name. 8 | Annotate.set_defaults({ 9 | 'position_in_routes' => "before", 10 | 'position_in_class' => "before", 11 | 'position_in_test' => "before", 12 | 'position_in_fixture' => "before", 13 | 'position_in_factory' => "before", 14 | 'show_indexes' => "true", 15 | 'simple_indexes' => "false", 16 | 'model_dir' => "app/models", 17 | 'include_version' => "false", 18 | 'require' => "", 19 | 'exclude_tests' => "false", 20 | 'exclude_fixtures' => "false", 21 | 'exclude_factories' => "false", 22 | 'ignore_model_sub_dir' => "false", 23 | 'skip_on_db_migrate' => "false", 24 | 'format_bare' => "true", 25 | 'format_rdoc' => "false", 26 | 'format_markdown' => "false", 27 | 'sort' => "false", 28 | 'force' => "false", 29 | 'trace' => "false", 30 | }) 31 | end 32 | 33 | Annotate.load_tasks 34 | end 35 | -------------------------------------------------------------------------------- /spec/fixtures/rvmrc.sh: -------------------------------------------------------------------------------- 1 | # This file is a hybrid file meant for live debugging without going through an 2 | # actual RSpec run, and for being used in an RSpec run. To change it, change 3 | # template..rvmrc and run 'rake templates:rebuild' which will do so for all 4 | # templates in all build scenarios. 5 | # 6 | # ALSO, be sure NOT to commit any changes that happen in app/* or config/* 7 | # when debugging this way as that will defeat the point of the automated tests! 8 | # 9 | # In fact, before running RSpec again after manual testing, you should run 10 | # 'rake integration:clober' to reset modified files to their pristine state, 11 | # and remove cruft that may interfere with the build. 12 | if [ "$(type rvm | head -1)" != "rvm is a function" ]; then 13 | # First, make sure we're not in 'sh' mode (I.E. strict-superset-of-Bourne 14 | # mode), as RVM doesn't like this... 15 | shopt -u -o posix 16 | # Now, load RVM... 17 | source $HOME/.rvm/scripts/rvm 18 | fi 19 | 20 | # Now, switch to our preferred Ruby and gemset... 21 | GEMSET=annotate_test_$(basename $(pwd) | perl -pse 's/\.//g') 22 | rvm use --create ${rvm_ruby_string}@${GEMSET} 23 | 24 | # Early-out when we just want to wipe the gemsets clean... 25 | if [ "$SKIP_BUNDLER" != "1" ]; then 26 | # ... and make sure everything's up-to-date, that it'll use the right Gemfile, 27 | # etc. 28 | if [ $(which bundle) == "" ]; then 29 | gem install bundler 30 | fi 31 | export BUNDLE_GEMFILE=./Gemfile 32 | # The apparently superfluous --gemfile param is to work around some stupidness 33 | # in Bundler. Specifically it gets very confused about BUNDLE_GEMFILE not 34 | # pointing at an absolute path. 35 | # 36 | # The special-case handling of bin being empty is to support debug workflows 37 | # where the gemset will in fact already be set up, but the binstubs get nuked. 38 | mkdir -p bin 39 | if [ $(($(ls bin | wc -l) + 0)) -eq 0 ]; then 40 | bundle install --binstubs=bin --gemfile ./Gemfile 41 | else 42 | bundle check || bundle install --binstubs=bin --gemfile ./Gemfile 43 | fi 44 | fi 45 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | Bundler.setup 4 | 5 | require 'rspec' 6 | require 'wrong/adapters/rspec' 7 | 8 | $:.unshift(File.join(File.dirname(__FILE__), '../lib')) 9 | $:.unshift(File.dirname(__FILE__)) 10 | 11 | require 'active_support' 12 | require 'active_support/core_ext/class/subclasses' 13 | require 'active_support/core_ext/string/inflections' 14 | require 'annotate' 15 | 16 | module Annotate 17 | module Integration 18 | ABSOLUTE_GEM_ROOT=File.expand_path('../../', __FILE__) 19 | 20 | CRUFT_PATTERNS=[ 21 | "%SCENARIO%/bin/*", "%SCENARIO%/log/*", "%SCENARIO%/tmp/*", 22 | "%SCENARIO%/.bundle" 23 | ] 24 | SCENARIO_HOME=File.join(File.dirname(__FILE__), 'integration') 25 | SCENARIOS=Dir.glob("#{SCENARIO_HOME}/*"). 26 | select { |candidate| File.directory?(candidate) }. 27 | map do |test_rig| 28 | base_dir = File.basename(test_rig) 29 | [test_rig, base_dir, base_dir.titlecase] 30 | end 31 | 32 | def self.nuke_cruft(test_rig) 33 | FileList[ 34 | Annotate::Integration::CRUFT_PATTERNS. 35 | map { |pattern| pattern.sub('%SCENARIO%', test_rig) } 36 | ].each do |fname| 37 | FileUtils.rm_rf(fname) 38 | end 39 | end 40 | 41 | def self.nuke_all_cruft 42 | SCENARIOS.each do |test_rig, base_dir, test_name| 43 | nuke_cruft(test_rig) 44 | end 45 | end 46 | 47 | def self.empty_gemset(test_rig) 48 | Dir.chdir(test_rig) do 49 | system(%q{ 50 | ( 51 | export SKIP_BUNDLER=1 52 | source .rvmrc && 53 | rvm --force gemset empty 54 | ) 2>&1 55 | }) 56 | end 57 | end 58 | 59 | def self.reset_dirty_files 60 | system("git checkout HEAD -- #{SCENARIO_HOME}/*/") 61 | end 62 | 63 | def self.clear_untracked_files 64 | system("git clean -dfx #{SCENARIO_HOME}/*/") 65 | end 66 | 67 | def self.is_clean?(test_rig) 68 | return `git status --porcelain #{test_rig}/ | wc -l`.strip.to_i == 0 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /annotate.gemspec: -------------------------------------------------------------------------------- 1 | # This file is auto-generated! 2 | # DO NOT EDIT THIS FILE DIRECTLY! 3 | # Instead, edit the Rakefile and run 'rake gem:gemspec'.# -*- encoding: utf-8 -*- 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "annotate" 7 | s.version = "2.6.0.beta1" 8 | 9 | s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= 10 | s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] 11 | s.date = "2012-10-16" 12 | s.description = "Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema." 13 | s.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] 14 | s.executables = ["annotate"] 15 | s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "TODO.rdoc"] 16 | s.files = ["CHANGELOG.rdoc", "README.rdoc", "TODO.rdoc", "annotate.gemspec", "bin/annotate", "lib/annotate.rb", "lib/annotate/active_record_patch.rb", "lib/annotate/annotate_models.rb", "lib/annotate/annotate_routes.rb", "lib/annotate/tasks.rb", "lib/annotate/version.rb", "lib/generators/annotate/USAGE", "lib/generators/annotate/install_generator.rb", "lib/generators/annotate/templates/auto_annotate_models.rake", "lib/tasks/annotate_models.rake", "lib/tasks/annotate_routes.rake", "tasks/migrate.rake"] 17 | s.homepage = "http://github.com/ctran/annotate_models" 18 | s.licenses = ["Ruby"] 19 | s.require_paths = ["lib"] 20 | s.rubyforge_project = "annotate" 21 | s.rubygems_version = "1.8.24" 22 | s.summary = "Annotates Rails Models, routes, fixtures, and others based on the database schema." 23 | 24 | if s.respond_to? :specification_version then 25 | s.specification_version = 3 26 | 27 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 28 | s.add_runtime_dependency(%q, [">= 0.8.7"]) 29 | s.add_runtime_dependency(%q, [">= 2.3.0"]) 30 | else 31 | s.add_dependency(%q, [">= 0.8.7"]) 32 | s.add_dependency(%q, [">= 2.3.0"]) 33 | end 34 | else 35 | s.add_dependency(%q, [">= 0.8.7"]) 36 | s.add_dependency(%q, [">= 2.3.0"]) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2.2/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.2) 12 | actionpack (= 3.2.2) 13 | mail (~> 2.4.0) 14 | actionpack (3.2.2) 15 | activemodel (= 3.2.2) 16 | activesupport (= 3.2.2) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.1) 20 | rack (~> 1.4.0) 21 | rack-cache (~> 1.1) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.1.2) 24 | activemodel (3.2.2) 25 | activesupport (= 3.2.2) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.2) 28 | activemodel (= 3.2.2) 29 | activesupport (= 3.2.2) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.2) 33 | activemodel (= 3.2.2) 34 | activesupport (= 3.2.2) 35 | activesupport (3.2.2) 36 | i18n (~> 0.6) 37 | multi_json (~> 1.0) 38 | arel (3.0.2) 39 | builder (3.0.0) 40 | erubis (2.7.0) 41 | hike (1.2.1) 42 | i18n (0.6.0) 43 | journey (1.0.4) 44 | json (1.7.4) 45 | mail (2.4.4) 46 | i18n (>= 0.4.0) 47 | mime-types (~> 1.16) 48 | treetop (~> 1.4.8) 49 | mime-types (1.19) 50 | multi_json (1.3.6) 51 | polyglot (0.3.3) 52 | rack (1.4.1) 53 | rack-cache (1.2) 54 | rack (>= 0.4) 55 | rack-ssl (1.3.2) 56 | rack 57 | rack-test (0.6.1) 58 | rack (>= 1.0) 59 | rails (3.2.2) 60 | actionmailer (= 3.2.2) 61 | actionpack (= 3.2.2) 62 | activerecord (= 3.2.2) 63 | activeresource (= 3.2.2) 64 | activesupport (= 3.2.2) 65 | bundler (~> 1.0) 66 | railties (= 3.2.2) 67 | railties (3.2.2) 68 | actionpack (= 3.2.2) 69 | activesupport (= 3.2.2) 70 | rack-ssl (~> 1.3.2) 71 | rake (>= 0.8.7) 72 | rdoc (~> 3.4) 73 | thor (~> 0.14.6) 74 | rake (0.9.2.2) 75 | rdoc (3.12) 76 | json (~> 1.4) 77 | sprockets (2.1.3) 78 | hike (~> 1.2) 79 | rack (~> 1.0) 80 | tilt (~> 1.1, != 1.3.0) 81 | sqlite3 (1.3.6) 82 | thor (0.14.6) 83 | tilt (1.3.3) 84 | treetop (1.4.10) 85 | polyglot 86 | polyglot (>= 0.3.1) 87 | tzinfo (0.3.33) 88 | 89 | PLATFORMS 90 | ruby 91 | 92 | DEPENDENCIES 93 | annotate! 94 | rails (= 3.2.2) 95 | sqlite3 96 | -------------------------------------------------------------------------------- /spec/fixtures/rails_328_gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.8) 12 | actionpack (= 3.2.8) 13 | mail (~> 2.4.4) 14 | actionpack (3.2.8) 15 | activemodel (= 3.2.8) 16 | activesupport (= 3.2.8) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.4) 20 | rack (~> 1.4.0) 21 | rack-cache (~> 1.2) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.1.3) 24 | activemodel (3.2.8) 25 | activesupport (= 3.2.8) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.8) 28 | activemodel (= 3.2.8) 29 | activesupport (= 3.2.8) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.8) 33 | activemodel (= 3.2.8) 34 | activesupport (= 3.2.8) 35 | activesupport (3.2.8) 36 | i18n (~> 0.6) 37 | multi_json (~> 1.0) 38 | arel (3.0.2) 39 | builder (3.0.0) 40 | erubis (2.7.0) 41 | hike (1.2.1) 42 | i18n (0.6.0) 43 | journey (1.0.4) 44 | json (1.7.4) 45 | mail (2.4.4) 46 | i18n (>= 0.4.0) 47 | mime-types (~> 1.16) 48 | treetop (~> 1.4.8) 49 | mime-types (1.19) 50 | multi_json (1.3.6) 51 | polyglot (0.3.3) 52 | rack (1.4.1) 53 | rack-cache (1.2) 54 | rack (>= 0.4) 55 | rack-ssl (1.3.2) 56 | rack 57 | rack-test (0.6.1) 58 | rack (>= 1.0) 59 | rails (3.2.8) 60 | actionmailer (= 3.2.8) 61 | actionpack (= 3.2.8) 62 | activerecord (= 3.2.8) 63 | activeresource (= 3.2.8) 64 | activesupport (= 3.2.8) 65 | bundler (~> 1.0) 66 | railties (= 3.2.8) 67 | railties (3.2.8) 68 | actionpack (= 3.2.8) 69 | activesupport (= 3.2.8) 70 | rack-ssl (~> 1.3.2) 71 | rake (>= 0.8.7) 72 | rdoc (~> 3.4) 73 | thor (>= 0.14.6, < 2.0) 74 | rake (0.9.2.2) 75 | rdoc (3.12) 76 | json (~> 1.4) 77 | sprockets (2.1.3) 78 | hike (~> 1.2) 79 | rack (~> 1.0) 80 | tilt (~> 1.1, != 1.3.0) 81 | sqlite3 (1.3.6) 82 | thor (0.16.0) 83 | tilt (1.3.3) 84 | treetop (1.4.10) 85 | polyglot 86 | polyglot (>= 0.3.1) 87 | tzinfo (0.3.33) 88 | 89 | PLATFORMS 90 | ruby 91 | 92 | DEPENDENCIES 93 | annotate! 94 | rails (= 3.2.8) 95 | sqlite3 96 | -------------------------------------------------------------------------------- /lib/tasks/annotate_models.rake: -------------------------------------------------------------------------------- 1 | annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) 2 | 3 | if(!ENV['is_cli']) 4 | task :set_annotation_options 5 | task :annotate_models => :set_annotation_options 6 | end 7 | 8 | desc "Add schema information (as comments) to model and fixture files" 9 | task :annotate_models => :environment do 10 | require "#{annotate_lib}/annotate/annotate_models" 11 | require "#{annotate_lib}/annotate/active_record_patch" 12 | 13 | options={ :is_rake => true } 14 | ENV['position'] = options[:position] = Annotate.fallback(ENV['position'], 'before') 15 | options[:position_in_class] = Annotate.fallback(ENV['position_in_class'], ENV['position']) 16 | options[:position_in_fixture] = Annotate.fallback(ENV['position_in_fixture'], ENV['position']) 17 | options[:position_in_factory] = Annotate.fallback(ENV['position_in_factory'], ENV['position']) 18 | options[:position_in_test] = Annotate.fallback(ENV['position_in_test'], ENV['position']) 19 | options[:show_indexes] = Annotate.true?(ENV['show_indexes']) 20 | options[:simple_indexes] = Annotate.true?(ENV['simple_indexes']) 21 | options[:model_dir] = ENV['model_dir'] 22 | options[:include_version] = Annotate.true?(ENV['include_version']) 23 | options[:require] = ENV['require'] ? ENV['require'].split(',') : [] 24 | options[:exclude_tests] = Annotate.true?(ENV['exclude_tests']) 25 | options[:exclude_factories] = Annotate.true?(ENV['exclude_factories']) 26 | options[:exclude_fixtures] = Annotate.true?(ENV['exclude_fixtures']) 27 | options[:ignore_model_sub_dir] = Annotate.true?(ENV['ignore_model_sub_dir']) 28 | options[:format_bare] = Annotate.true?(ENV['format_bare']) 29 | options[:format_rdoc] = Annotate.true?(ENV['format_rdoc']) 30 | options[:format_markdown] = Annotate.true?(ENV['format_markdown']) 31 | options[:sort] = Annotate.true?(ENV['sort']) 32 | options[:force] = Annotate.true?(ENV['force']) 33 | options[:trace] = Annotate.true?(ENV['trace']) 34 | AnnotateModels.do_annotations(options) 35 | end 36 | 37 | desc "Remove schema information from model and fixture files" 38 | task :remove_annotation => :environment do 39 | require "#{annotate_lib}/annotate/annotate_models" 40 | require "#{annotate_lib}/annotate/active_record_patch" 41 | 42 | options={ :is_rake => true } 43 | options[:model_dir] = ENV['model_dir'] 44 | options[:require] = ENV['require'] ? ENV['require'].split(',') : [] 45 | options[:trace] = Annotate.true?(ENV['trace']) 46 | AnnotateModels.remove_annotations(options) 47 | end 48 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_autoloading_factory_girl/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.2) 12 | actionpack (= 3.2.2) 13 | mail (~> 2.4.0) 14 | actionpack (3.2.2) 15 | activemodel (= 3.2.2) 16 | activesupport (= 3.2.2) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.1) 20 | rack (~> 1.4.0) 21 | rack-cache (~> 1.1) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.1.2) 24 | activemodel (3.2.2) 25 | activesupport (= 3.2.2) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.2) 28 | activemodel (= 3.2.2) 29 | activesupport (= 3.2.2) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.2) 33 | activemodel (= 3.2.2) 34 | activesupport (= 3.2.2) 35 | activesupport (3.2.2) 36 | i18n (~> 0.6) 37 | multi_json (~> 1.0) 38 | arel (3.0.2) 39 | builder (3.0.0) 40 | erubis (2.7.0) 41 | factory_girl (4.0.0) 42 | activesupport (>= 3.0.0) 43 | factory_girl_rails (4.0.0) 44 | factory_girl (~> 4.0.0) 45 | railties (>= 3.0.0) 46 | hike (1.2.1) 47 | i18n (0.6.0) 48 | journey (1.0.4) 49 | json (1.7.4) 50 | mail (2.4.4) 51 | i18n (>= 0.4.0) 52 | mime-types (~> 1.16) 53 | treetop (~> 1.4.8) 54 | mime-types (1.19) 55 | multi_json (1.3.6) 56 | polyglot (0.3.3) 57 | rack (1.4.1) 58 | rack-cache (1.2) 59 | rack (>= 0.4) 60 | rack-ssl (1.3.2) 61 | rack 62 | rack-test (0.6.1) 63 | rack (>= 1.0) 64 | rails (3.2.2) 65 | actionmailer (= 3.2.2) 66 | actionpack (= 3.2.2) 67 | activerecord (= 3.2.2) 68 | activeresource (= 3.2.2) 69 | activesupport (= 3.2.2) 70 | bundler (~> 1.0) 71 | railties (= 3.2.2) 72 | railties (3.2.2) 73 | actionpack (= 3.2.2) 74 | activesupport (= 3.2.2) 75 | rack-ssl (~> 1.3.2) 76 | rake (>= 0.8.7) 77 | rdoc (~> 3.4) 78 | thor (~> 0.14.6) 79 | rake (0.9.2.2) 80 | rdoc (3.12) 81 | json (~> 1.4) 82 | sprockets (2.1.3) 83 | hike (~> 1.2) 84 | rack (~> 1.0) 85 | tilt (~> 1.1, != 1.3.0) 86 | sqlite3 (1.3.6) 87 | thor (0.14.6) 88 | tilt (1.3.3) 89 | treetop (1.4.10) 90 | polyglot 91 | polyglot (>= 0.3.1) 92 | tzinfo (0.3.33) 93 | 94 | PLATFORMS 95 | ruby 96 | 97 | DEPENDENCIES 98 | annotate! 99 | factory_girl 100 | factory_girl_rails 101 | rails (= 3.2.2) 102 | sqlite3 103 | -------------------------------------------------------------------------------- /spec/integration/integration_spec.rb: -------------------------------------------------------------------------------- 1 | # Smoke test to assure basic functionality works on a variety of Rails versions. 2 | $:.unshift(File.dirname(__FILE__)) 3 | require 'spec_helper' 4 | require 'files' 5 | require 'wrong' 6 | require 'rake' 7 | include Files 8 | include Wrong::D 9 | 10 | BASEDIR=File.expand_path(File.join(File.dirname(__FILE__), '..', '..')) 11 | RVM_BIN = `which rvm`.chomp 12 | USING_RVM = (RVM_BIN != '') 13 | 14 | CURRENT_RUBY = `rvm-prompt i v p 2>/dev/null`.chomp 15 | ENV['rvm_pretty_print_flag'] = '0' 16 | ENV['BUNDLE_GEMFILE'] = './Gemfile' 17 | 18 | describe "annotate inside Rails, using #{CURRENT_RUBY}" do 19 | here = File.expand_path('..', __FILE__) 20 | chosen_scenario = nil 21 | if(!ENV['SCENARIO'].blank?) 22 | chosen_scenario = File.expand_path(ENV['SCENARIO']) 23 | raise "Can't find specified scenario '#{chosen_scenario}'!" unless(File.directory?(chosen_scenario)) 24 | end 25 | Annotate::Integration::SCENARIOS.each do |test_rig, base_dir, test_name| 26 | next if(chosen_scenario && chosen_scenario != test_rig) 27 | it "works under #{test_name}" do 28 | if(!USING_RVM) 29 | pending "Must have RVM installed." 30 | next 31 | end 32 | 33 | # Don't proceed if the working copy is dirty! 34 | Annotate::Integration.is_clean?(test_rig).should == true 35 | 36 | Bundler.with_clean_env do 37 | dir base_dir do 38 | temp_dir = Dir.pwd 39 | File.basename(temp_dir).should == base_dir 40 | 41 | # Delete cruft from hands-on debugging... 42 | Annotate::Integration.nuke_cruft(test_rig) 43 | 44 | # Copy everything to our test directory... 45 | exclusions = ["#{test_rig}/.", "#{test_rig}/.."] 46 | 47 | files = (FileList["#{test_rig}/*", "#{test_rig}/.*"] - exclusions).to_a 48 | # We want to NOT preserve symlinks during this copy... 49 | system("rsync -aL #{files.shelljoin} #{temp_dir.shellescape}") 50 | 51 | # By default, rvm_ruby_string isn't inherited over properly, so let's 52 | # make sure it's there so our .rvmrc will work. 53 | ENV['rvm_ruby_string']=CURRENT_RUBY 54 | 55 | require "#{base_dir}" # Will get "#{base_dir}.rb"... 56 | klass = "Annotate::Validations::#{base_dir.gsub('.', '_').classify}".constantize 57 | 58 | Dir.chdir(temp_dir) do 59 | # bash is required by rvm 60 | # the shopt command forces us out of "strict sh" mode 61 | commands = <<-BASH 62 | export AUTOMATED_TEST="#{BASEDIR}"; 63 | shopt -u -o posix; 64 | source .rvmrc && 65 | (bundle check || bundle install) && 66 | #{klass.test_commands} 67 | BASH 68 | output = `/usr/bin/env bash -c '#{commands}' 2>&1`.chomp 69 | klass.verify_output(output) 70 | klass.verify_files(test_rig) 71 | end 72 | end 73 | end 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/integration/rails_3.2_with_asset_pipeline/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../.. 3 | specs: 4 | annotate (2.5.0) 5 | activerecord 6 | rake 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.2) 12 | actionpack (= 3.2.2) 13 | mail (~> 2.4.0) 14 | actionpack (3.2.2) 15 | activemodel (= 3.2.2) 16 | activesupport (= 3.2.2) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.1) 20 | rack (~> 1.4.0) 21 | rack-cache (~> 1.1) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.1.2) 24 | activemodel (3.2.2) 25 | activesupport (= 3.2.2) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.2) 28 | activemodel (= 3.2.2) 29 | activesupport (= 3.2.2) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.2) 33 | activemodel (= 3.2.2) 34 | activesupport (= 3.2.2) 35 | activesupport (3.2.2) 36 | i18n (~> 0.6) 37 | multi_json (~> 1.0) 38 | arel (3.0.2) 39 | builder (3.0.0) 40 | coffee-rails (3.2.2) 41 | coffee-script (>= 2.2.0) 42 | railties (~> 3.2.0) 43 | coffee-script (2.2.0) 44 | coffee-script-source 45 | execjs 46 | coffee-script-source (1.3.3) 47 | erubis (2.7.0) 48 | execjs (1.4.0) 49 | multi_json (~> 1.0) 50 | hike (1.2.1) 51 | i18n (0.6.0) 52 | journey (1.0.4) 53 | json (1.7.4) 54 | mail (2.4.4) 55 | i18n (>= 0.4.0) 56 | mime-types (~> 1.16) 57 | treetop (~> 1.4.8) 58 | mime-types (1.19) 59 | multi_json (1.3.6) 60 | polyglot (0.3.3) 61 | rack (1.4.1) 62 | rack-cache (1.2) 63 | rack (>= 0.4) 64 | rack-ssl (1.3.2) 65 | rack 66 | rack-test (0.6.1) 67 | rack (>= 1.0) 68 | rails (3.2.2) 69 | actionmailer (= 3.2.2) 70 | actionpack (= 3.2.2) 71 | activerecord (= 3.2.2) 72 | activeresource (= 3.2.2) 73 | activesupport (= 3.2.2) 74 | bundler (~> 1.0) 75 | railties (= 3.2.2) 76 | railties (3.2.2) 77 | actionpack (= 3.2.2) 78 | activesupport (= 3.2.2) 79 | rack-ssl (~> 1.3.2) 80 | rake (>= 0.8.7) 81 | rdoc (~> 3.4) 82 | thor (~> 0.14.6) 83 | rake (0.9.2.2) 84 | rdoc (3.12) 85 | json (~> 1.4) 86 | sass (3.2.1) 87 | sass-rails (3.2.5) 88 | railties (~> 3.2.0) 89 | sass (>= 3.1.10) 90 | tilt (~> 1.3) 91 | sprockets (2.1.3) 92 | hike (~> 1.2) 93 | rack (~> 1.0) 94 | tilt (~> 1.1, != 1.3.0) 95 | sqlite3 (1.3.6) 96 | thor (0.14.6) 97 | tilt (1.3.3) 98 | treetop (1.4.10) 99 | polyglot 100 | polyglot (>= 0.3.1) 101 | tzinfo (0.3.33) 102 | uglifier (1.2.7) 103 | execjs (>= 0.3.0) 104 | multi_json (~> 1.3) 105 | 106 | PLATFORMS 107 | ruby 108 | 109 | DEPENDENCIES 110 | annotate! 111 | coffee-rails (~> 3.2.1) 112 | rails (= 3.2.2) 113 | sass-rails (~> 3.2.3) 114 | sqlite3 115 | uglifier (>= 1.0.3) 116 | -------------------------------------------------------------------------------- /spec/integration/common_validation.rb: -------------------------------------------------------------------------------- 1 | module Annotate 2 | module Validations 3 | module Common 4 | def self.test_commands 5 | return %q{ 6 | bin/annotate && 7 | bin/annotate --routes 8 | } 9 | end 10 | 11 | def self.verify_output(output) 12 | output.should =~ /Annotated \(1\): Task/ 13 | output.should =~ /Route file annotated./ 14 | end 15 | 16 | def self.verify_files(which_files, test_rig, schema_annotation, routes_annotation, place_before=true) 17 | check_task_model(test_rig, schema_annotation, place_before) if(which_files[:model]) 18 | check_task_unittest(test_rig, schema_annotation, place_before) if(which_files[:test]) 19 | check_task_fixture(test_rig, schema_annotation, place_before) if(which_files[:fixture]) 20 | check_task_factory(test_rig, schema_annotation, place_before) if(which_files[:factory]) 21 | check_routes(test_rig, routes_annotation, place_before) if(which_files[:routes]) 22 | end 23 | 24 | def self.check_task_model(test_rig, annotation, place_before=true) 25 | model = apply_annotation(test_rig, "app/models/task.rb", annotation, place_before) 26 | File.read("app/models/task.rb").should == model 27 | end 28 | 29 | def self.check_routes(test_rig, annotation, place_before=true) 30 | routes = apply_annotation(test_rig, "config/routes.rb", annotation, place_before) 31 | File.read("config/routes.rb"). 32 | sub(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/, 'YYYY-MM-DD HH:MM'). 33 | should == routes 34 | end 35 | 36 | def self.check_task_unittest(test_rig, annotation, place_before=true) 37 | unittest = apply_annotation(test_rig, "test/unit/task_test.rb", annotation, place_before) 38 | File.read("test/unit/task_test.rb").should == unittest 39 | end 40 | 41 | def self.check_task_factory(test_rig, annotation, place_before=true) 42 | fixture = apply_annotation(test_rig, "test/factories/tasks.rb", annotation, place_before) 43 | File.read("test/factories/tasks.rb").should == fixture 44 | end 45 | 46 | def self.check_task_fixture(test_rig, annotation, place_before=true) 47 | fixture = apply_annotation(test_rig, "test/fixtures/tasks.yml", annotation, place_before) 48 | File.read("test/fixtures/tasks.yml").should == fixture 49 | end 50 | 51 | protected 52 | 53 | def self.apply_annotation(test_rig, fname, annotation, place_before=true) 54 | corpus = File.read(File.join(test_rig, fname)) 55 | if(place_before) 56 | corpus = annotation + "\n" + corpus 57 | else 58 | corpus = corpus + "\n" + annotation 59 | end 60 | end 61 | end 62 | end 63 | end 64 | 65 | module Annotate 66 | module Validations 67 | class Base 68 | def self.test_commands 69 | return Annotate::Validations::Common.test_commands 70 | end 71 | 72 | def self.verify_output(output) 73 | return Annotate::Validations::Common.verify_output(output) 74 | end 75 | 76 | def self.verify_files(test_rig) 77 | return Annotate::Validations::Common.verify_files({ 78 | :model => true, 79 | :test => true, 80 | :fixture => true, 81 | :factory => false, 82 | :routes => true 83 | }, test_rig, self.schema_annotation, self.route_annotation, true) 84 | end 85 | 86 | def self.foo 87 | require 'pry' 88 | require 'pry-coolline' 89 | binding.pry 90 | end 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /spec/integration/rails_2.3_with_bundler/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Don't change this file! 2 | # Configure your app in config/environment.rb and config/environments/*.rb 3 | 4 | RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) 5 | 6 | module Rails 7 | class << self 8 | def boot! 9 | unless booted? 10 | preinitialize 11 | pick_boot.run 12 | end 13 | end 14 | 15 | def booted? 16 | defined? Rails::Initializer 17 | end 18 | 19 | def pick_boot 20 | (vendor_rails? ? VendorBoot : GemBoot).new 21 | end 22 | 23 | def vendor_rails? 24 | File.exist?("#{RAILS_ROOT}/vendor/rails") 25 | end 26 | 27 | def preinitialize 28 | load(preinitializer_path) if File.exist?(preinitializer_path) 29 | end 30 | 31 | def preinitializer_path 32 | "#{RAILS_ROOT}/config/preinitializer.rb" 33 | end 34 | end 35 | 36 | class Boot 37 | def run 38 | load_initializer 39 | Rails::Initializer.run(:set_load_path) 40 | end 41 | end 42 | 43 | class VendorBoot < Boot 44 | def load_initializer 45 | require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer" 46 | Rails::Initializer.run(:install_gem_spec_stubs) 47 | Rails::GemDependency.add_frozen_gem_path 48 | end 49 | end 50 | 51 | class GemBoot < Boot 52 | def load_initializer 53 | self.class.load_rubygems 54 | load_rails_gem 55 | require 'initializer' 56 | end 57 | 58 | def load_rails_gem 59 | if version = self.class.gem_version 60 | gem 'rails', version 61 | else 62 | gem 'rails' 63 | end 64 | rescue Gem::LoadError => load_error 65 | if load_error.message =~ /Could not find RubyGem rails/ 66 | STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) 67 | exit 1 68 | else 69 | raise 70 | end 71 | end 72 | 73 | class << self 74 | def rubygems_version 75 | Gem::RubyGemsVersion rescue nil 76 | end 77 | 78 | def gem_version 79 | if defined? RAILS_GEM_VERSION 80 | RAILS_GEM_VERSION 81 | elsif ENV.include?('RAILS_GEM_VERSION') 82 | ENV['RAILS_GEM_VERSION'] 83 | else 84 | parse_gem_version(read_environment_rb) 85 | end 86 | end 87 | 88 | def load_rubygems 89 | min_version = '1.3.2' 90 | require 'rubygems' 91 | unless rubygems_version >= min_version 92 | $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.) 93 | exit 1 94 | end 95 | 96 | rescue LoadError 97 | $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org) 98 | exit 1 99 | end 100 | 101 | def parse_gem_version(text) 102 | $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/ 103 | end 104 | 105 | private 106 | def read_environment_rb 107 | File.read("#{RAILS_ROOT}/config/environment.rb") 108 | end 109 | end 110 | end 111 | end 112 | 113 | # All that for this: 114 | class Rails::Boot 115 | def run 116 | load_initializer 117 | 118 | Rails::Initializer.class_eval do 119 | def load_gems 120 | @bundler_loaded ||= Bundler.require :default, Rails.env 121 | end 122 | end 123 | 124 | Rails::Initializer.run(:set_load_path) 125 | end 126 | end 127 | 128 | Rails.boot! 129 | -------------------------------------------------------------------------------- /spec/annotate/annotate_routes_spec.rb: -------------------------------------------------------------------------------- 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 | it "should check if routes.rb exists" do 11 | File.should_receive(:exists?).with("config/routes.rb").and_return(false) 12 | AnnotateRoutes.should_receive(:puts).with("Can`t find routes.rb") 13 | AnnotateRoutes.do_annotations 14 | end 15 | 16 | describe "When Annotating, with older Rake Versions" do 17 | 18 | before(:each) do 19 | File.should_receive(:exists?).with("config/routes.rb").and_return(true) 20 | AnnotateRoutes.should_receive(:`).with("rake routes").and_return("(in /bad/line)\ngood line") 21 | File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) 22 | AnnotateRoutes.should_receive(:puts).with("Route file annotated.") 23 | end 24 | 25 | it "should annotate and add a newline!" do 26 | File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") 27 | @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# good line\n/) 28 | AnnotateRoutes.do_annotations 29 | end 30 | 31 | it "should not add a newline if there are empty lines" do 32 | File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") 33 | @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# good line\n/) 34 | AnnotateRoutes.do_annotations 35 | end 36 | 37 | end 38 | 39 | describe "When Annotating, with newer Rake Versions" do 40 | 41 | before(:each) do 42 | File.should_receive(:exists?).with("config/routes.rb").and_return(true) 43 | AnnotateRoutes.should_receive(:`).with("rake routes").and_return("another good line\ngood line") 44 | File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) 45 | AnnotateRoutes.should_receive(:puts).with("Route file annotated.") 46 | end 47 | 48 | it "should annotate and add a newline!" do 49 | File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") 50 | @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/) 51 | AnnotateRoutes.do_annotations 52 | end 53 | 54 | it "should not add a newline if there are empty lines" do 55 | File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") 56 | @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/) 57 | AnnotateRoutes.do_annotations 58 | end 59 | 60 | end 61 | 62 | describe "When Removing Annotation" do 63 | 64 | before(:each) do 65 | File.should_receive(:exists?).with("config/routes.rb").and_return(true) 66 | File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file) 67 | AnnotateRoutes.should_receive(:puts).with("Removed annotations from routes file.") 68 | end 69 | 70 | it "should remove trailing annotation and trim trailing newlines, but leave leading newlines alone" do 71 | File.should_receive(:read).with("config/routes.rb").and_return("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n# == Route Map (Updated 2012-08-16 00:00)\n#\n# another good line\n# good line\n") 72 | @mock_file.should_receive(:puts).with(/\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n/) 73 | AnnotateRoutes.remove_annotations 74 | end 75 | 76 | it "should remove prepended annotation and trim leading newlines, but leave trailing newlines alone" do 77 | File.should_receive(:read).with("config/routes.rb").and_return("# == Route Map (Updated 2012-08-16 00:00)\n#\n# another good line\n# good line\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n") 78 | @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n/) 79 | AnnotateRoutes.remove_annotations 80 | end 81 | 82 | end 83 | 84 | end 85 | -------------------------------------------------------------------------------- /lib/annotate.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(File.dirname(__FILE__)) 2 | require 'annotate/version' 3 | require 'annotate/annotate_models' 4 | require 'annotate/annotate_routes' 5 | 6 | begin 7 | # ActiveSupport 3.x... 8 | require 'active_support/hash_with_indifferent_access' 9 | rescue Exception => e 10 | # ActiveSupport 2.x... 11 | require 'active_support/core_ext/hash/indifferent_access' 12 | end 13 | 14 | module Annotate 15 | ## 16 | # The set of available options to customize the behavior of Annotate. 17 | # 18 | POSITION_OPTIONS=[ 19 | :position_in_routes, :position_in_class, :position_in_test, 20 | :position_in_fixture, :position_in_factory, :position, 21 | ] 22 | FLAG_OPTIONS=[ 23 | :show_indexes, :simple_indexes, :include_version, :exclude_tests, 24 | :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir, 25 | :format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace, 26 | ] 27 | OTHER_OPTIONS=[ 28 | :model_dir, 29 | ] 30 | PATH_OPTIONS=[ 31 | :require, 32 | ] 33 | 34 | 35 | ## 36 | # Set default values that can be overridden via environment variables. 37 | # 38 | def self.set_defaults(options = {}) 39 | return if(@has_set_defaults) 40 | @has_set_defaults = true 41 | options = HashWithIndifferentAccess.new(options) 42 | [POSITION_OPTIONS, FLAG_OPTIONS, PATH_OPTIONS].flatten.each do |key| 43 | if(options.has_key?(key)) 44 | default_value = if(options[key].is_a?(Array)) 45 | options[key].join(",") 46 | else 47 | options[key] 48 | end 49 | end 50 | default_value = ENV[key.to_s] if(!ENV[key.to_s].blank?) 51 | ENV[key.to_s] = default_value.to_s 52 | end 53 | end 54 | 55 | TRUE_RE = /^(true|t|yes|y|1)$/i 56 | def self.setup_options(options = {}) 57 | POSITION_OPTIONS.each do |key| 58 | options[key] = fallback(ENV[key.to_s], ENV['position'], 'before') 59 | end 60 | FLAG_OPTIONS.each do |key| 61 | options[key] = true?(ENV[key.to_s]) 62 | end 63 | OTHER_OPTIONS.each do |key| 64 | options[key] = (!ENV[key.to_s].blank?) ? ENV[key.to_s] : nil 65 | end 66 | PATH_OPTIONS.each do |key| 67 | options[key] = (!ENV[key.to_s].blank?) ? ENV[key.to_s].split(',') : [] 68 | end 69 | 70 | if(!options[:model_dir]) 71 | options[:model_dir] = 'app/models' 72 | end 73 | 74 | return options 75 | end 76 | 77 | def self.skip_on_migration? 78 | ENV['skip_on_db_migrate'] =~ TRUE_RE 79 | end 80 | 81 | def self.loaded_tasks=(val); @loaded_tasks = val; end 82 | def self.loaded_tasks; return @loaded_tasks; end 83 | 84 | def self.load_tasks 85 | return if(self.loaded_tasks) 86 | self.loaded_tasks = true 87 | 88 | Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake } 89 | end 90 | 91 | def self.load_requires(options) 92 | options[:require].each { |path| require path } if options[:require].count > 0 93 | end 94 | 95 | def self.eager_load(options) 96 | self.load_requires(options) 97 | require "annotate/active_record_patch" 98 | 99 | if(defined?(Rails)) 100 | if(Rails.version.split('.').first.to_i < 3) 101 | Rails.configuration.eager_load_paths.each do |load_path| 102 | matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/ 103 | Dir.glob("#{load_path}/**/*.rb").sort.each do |file| 104 | require_dependency file.sub(matcher, '\1') 105 | end 106 | end 107 | else 108 | klass = Rails::Application.send(:subclasses).first 109 | klass.eager_load! 110 | end 111 | else 112 | FileList["#{options[:model_dir]}/**/*.rb"].each do |fname| 113 | require File.expand_path(fname) 114 | end 115 | end 116 | end 117 | 118 | def self.bootstrap_rake 119 | begin 120 | require 'rake/dsl_definition' 121 | rescue Exception => e 122 | # We might just be on an old version of Rake... 123 | end 124 | require 'rake' 125 | 126 | if File.exists?('./Rakefile') 127 | load './Rakefile' 128 | end 129 | Rake::Task[:environment].invoke rescue nil 130 | if(!defined?(Rails)) 131 | # Not in a Rails project, so time to load up the parts of 132 | # ActiveSupport we need. 133 | require 'active_support' 134 | require 'active_support/core_ext/class/subclasses' 135 | require 'active_support/core_ext/string/inflections' 136 | end 137 | self.load_tasks 138 | Rake::Task[:set_annotation_options].invoke 139 | end 140 | 141 | def self.fallback(*args) 142 | return args.detect { |arg| !arg.blank? } 143 | end 144 | 145 | def self.true?(val) 146 | return false if(val.blank?) 147 | return false unless(val =~ TRUE_RE) 148 | return true 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /lib/annotate/annotate_routes.rb: -------------------------------------------------------------------------------- 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 9 | # mean. 10 | # 11 | # Running this task will replace any exising route comment generated by the 12 | # task. Best to back up your routes file before running: 13 | # 14 | # Author: 15 | # Gavin Montague 16 | # gavin@leftbrained.co.uk 17 | # 18 | # Released under the same license as Ruby. No Support. No Warranty. 19 | # 20 | module AnnotateRoutes 21 | PREFIX = "# == Route Map" 22 | 23 | def self.do_annotations(options={}) 24 | return unless(routes_exists?) 25 | 26 | position_after = options[:position_in_routes] != 'before' 27 | 28 | routes_map = `rake routes`.split(/\n/, -1) 29 | 30 | # In old versions of Rake, the first line of output was the cwd. Not so 31 | # much in newer ones. We ditch that line if it exists, and if not, we 32 | # keep the line around. 33 | routes_map.shift if(routes_map.first =~ /^\(in \//) 34 | 35 | header = [ 36 | "#{PREFIX} (Updated #{Time.now.strftime("%Y-%m-%d %H:%M")})", 37 | "#" 38 | ] + routes_map.map { |line| "# #{line}".rstrip } 39 | 40 | (content, where_header_found) = strip_annotations(File.read(routes_file)) 41 | changed = where_header_found != 0 # This will either be :before, :after, or 42 | # a number. If the number is > 0, the 43 | # annotation was found somewhere in the 44 | # middle of the file. If the number is 45 | # zero, no annotation was found. 46 | 47 | if(position_after) 48 | # Ensure we have adequate trailing newlines at the end of the file to 49 | # ensure a blank line separating the content from the annotation. 50 | content << '' if(content.last != '') 51 | 52 | # We're moving something from the top of the file to the bottom, so ditch 53 | # the spacer we put in the first time around. 54 | if(changed && where_header_found == :before) 55 | content.shift if(content.first == '') 56 | end 57 | else 58 | header = header << '' if(content.first != '' || changed) 59 | end 60 | 61 | content = position_after ? (content + header) : header + content 62 | 63 | write_contents(content) 64 | 65 | puts "Route file annotated." 66 | end 67 | 68 | def self.remove_annotations(options={}) 69 | return unless(routes_exists?) 70 | 71 | (content, where_header_found) = strip_annotations(File.read(routes_file)) 72 | 73 | content = strip_on_removal(content, where_header_found) 74 | 75 | write_contents(content) 76 | 77 | puts "Removed annotations from routes file." 78 | end 79 | 80 | protected 81 | 82 | def self.routes_file 83 | @routes_rb ||= File.join("config", "routes.rb") 84 | end 85 | 86 | def self.routes_exists? 87 | routes_exists = File.exists?(routes_file) 88 | puts "Can`t find routes.rb" if(!routes_exists) 89 | return routes_exists 90 | end 91 | 92 | def self.write_contents(content) 93 | content << '' unless(content.last == '') # Make sure we end on a trailing 94 | # newline. 95 | 96 | File.open(routes_file, "wb") { |f| f.puts(content.join("\n")) } 97 | end 98 | 99 | def self.strip_annotations(content) 100 | real_content = [] 101 | mode = :content 102 | line_number = 0 103 | header_found_at = 0 104 | content.split(/\n/, -1).each do |line| 105 | line_number += 1 106 | begin 107 | if(mode == :header) 108 | if(line !~ /\s*#/) 109 | mode = :content 110 | raise unless (line == '') 111 | end 112 | elsif(mode == :content) 113 | if(line =~ /^\s*#\s*== Route.*$/) 114 | header_found_at = line_number 115 | mode = :header 116 | else 117 | real_content << line 118 | end 119 | end 120 | rescue 121 | retry 122 | end 123 | end 124 | content_lines = real_content.count 125 | 126 | # By default assume the annotation was found in the middle of the file... 127 | where_header_found = header_found_at 128 | # ... unless we have evidence it was at the beginning ... 129 | where_header_found = :before if(header_found_at == 1) 130 | # ... or that it was at the end. 131 | where_header_found = :after if(header_found_at >= content_lines) 132 | 133 | return real_content, where_header_found 134 | end 135 | 136 | def self.strip_on_removal(content, where_header_found) 137 | if(where_header_found == :before) 138 | content.shift while(content.first == '') 139 | elsif(where_header_found == :after) 140 | content.pop while(content.last == '') 141 | end 142 | # TODO: If the user buried it in the middle, we should probably see about 143 | # TODO: preserving a single line of space between the content above and 144 | # TODO: below... 145 | return content 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /bin/annotate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'rubygems' 3 | begin 4 | require 'bundler' 5 | Bundler.setup 6 | rescue Exception => e 7 | end 8 | 9 | here = File.expand_path(File.dirname __FILE__) 10 | $:<< "#{here}/../lib" 11 | 12 | require 'optparse' 13 | require 'annotate' 14 | Annotate.bootstrap_rake 15 | 16 | target = { 17 | :klass => AnnotateModels, 18 | :task => :do_annotations, 19 | } 20 | has_set_position = {} 21 | OptionParser.new do |opts| 22 | opts.banner = "Usage: annotate [options] [model_file]*" 23 | 24 | opts.on('-d', '--delete', 25 | "Remove annotations from all model files or the routes.rb file") do 26 | 27 | target[:task] = :remove_annotations 28 | end 29 | 30 | opts.on('-p', '--position [before|after]', ['before', 'after'], 31 | "Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/routes file(s)") do |p| 32 | ENV['position'] = p 33 | [ 34 | 'position_in_class','position_in_factory','position_in_fixture','position_in_test', 'position_in_routes' 35 | ].each do |key| 36 | ENV[key] = p unless(has_set_position[key]) 37 | end 38 | end 39 | 40 | opts.on('--pc', '--position-in-class [before|after]', ['before', 'after'], 41 | "Place the annotations at the top (before) or the bottom (after) of the model file") do |p| 42 | ENV['position_in_class'] = p 43 | has_set_position['position_in_class'] = true 44 | end 45 | 46 | opts.on('--pf', '--position-in-factory [before|after]', ['before', 'after'], 47 | "Place the annotations at the top (before) or the bottom (after) of any factory files") do |p| 48 | ENV['position_in_factory'] = p 49 | has_set_position['position_in_factory'] = true 50 | end 51 | 52 | opts.on('--px', '--position-in-fixture [before|after]', ['before', 'after'], 53 | "Place the annotations at the top (before) or the bottom (after) of any fixture files") do |p| 54 | ENV['position_in_fixture'] = p 55 | has_set_position['position_in_fixture'] = true 56 | end 57 | 58 | opts.on('--pt', '--position-in-test [before|after]', ['before', 'after'], 59 | "Place the annotations at the top (before) or the bottom (after) of any test files") do |p| 60 | ENV['position_in_test'] = p 61 | has_set_position['position_in_test'] = true 62 | end 63 | 64 | opts.on('--pr', '--position-in-routes [before|after]', ['before', 'after'], 65 | "Place the annotations at the top (before) or the bottom (after) of the routes.rb file") do |p| 66 | ENV['position_in_test'] = p 67 | has_set_position['position_in_routes'] = true 68 | end 69 | 70 | opts.on('-r', '--routes', 71 | "Annotate routes.rb with the output of 'rake routes'") do 72 | target = { 73 | :klass => AnnotateRoutes, 74 | :task => :do_annotations 75 | } 76 | end 77 | 78 | opts.on('-v', '--version', 79 | "Show the current version of this gem") do 80 | puts "annotate v#{Annotate.version}"; exit 81 | end 82 | 83 | opts.on('-m', '--show-migration', 84 | "Include the migration version number in the annotation") do 85 | ENV['include_version'] = "yes" 86 | end 87 | 88 | opts.on('-i', '--show-indexes', 89 | "List the table's database indexes in the annotation") do 90 | ENV['show_indexes'] = "yes" 91 | end 92 | 93 | opts.on('-s', '--simple-indexes', 94 | "Concat the column's related indexes in the annotation") do 95 | ENV['simple_indexes'] = "yes" 96 | end 97 | 98 | opts.on('--model-dir dir', 99 | "Annotate model files stored in dir rather than app/models") do |dir| 100 | ENV['model_dir'] = dir 101 | end 102 | 103 | opts.on('--ignore-model-subdirects', 104 | "Ignore subdirectories of the models directory") do |dir| 105 | ENV['ignore_model_sub_dir'] = "yes" 106 | end 107 | 108 | opts.on('--sort', 109 | "Sort columns alphabetically, rather than in creation order") do |dir| 110 | ENV['sort'] = "yes" 111 | end 112 | 113 | opts.on('-R', '--require path', 114 | "Additional file to require before loading models, may be used multiple times") do |path| 115 | if !ENV['require'].blank? 116 | ENV['require'] = ENV['require'] + ",#{path}" 117 | else 118 | ENV['require'] = path 119 | end 120 | end 121 | 122 | opts.on('-e', '--exclude [tests,fixtures,factories]', ['tests','fixtures','factories'], "Do not annotate fixtures, test files, and/or factories") do |exclusions| 123 | exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = "yes" } 124 | end 125 | 126 | opts.on('-f', '--format [bare|rdoc|markdown]', ['bare', 'rdoc', 'markdown'], 'Render Schema Infomation as plain/RDoc/Markdown') do |fmt| 127 | ENV["format_#{fmt}"] = 'yes' 128 | end 129 | 130 | opts.on('--force', 'Force new annotations even if there are no changes.') do |force| 131 | ENV['force'] = 'yes' 132 | end 133 | 134 | opts.on('--trace', 'If unable to annotate a file, print the full stack trace, not just the exception message.') do |value| 135 | ENV['trace'] = 'yes' 136 | end 137 | end.parse! 138 | 139 | 140 | options=Annotate.setup_options({ :is_rake => !ENV['is_rake'].blank? }) 141 | Annotate.eager_load(options) 142 | target[:klass].send(target[:task], options) 143 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Note : this causes annoying psych warnings under Ruby 1.9.2-p180; to fix, upgrade to 1.9.3 2 | begin 3 | require 'bundler' 4 | Bundler.setup(:default, :development) 5 | rescue Bundler::BundlerError => e 6 | $stderr.puts e.message 7 | $stderr.puts "Run `bundle install` to install missing gems" 8 | exit e.status_code 9 | end 10 | 11 | using_dsl = false 12 | begin 13 | require 'rake/dsl_definition' 14 | using_dsl = true 15 | rescue Exception => e 16 | # We might just be on an old version of Rake... 17 | end 18 | require 'rake' 19 | if(using_dsl) 20 | include Rake::DSL 21 | end 22 | 23 | require "./lib/annotate" 24 | 25 | require "mg" 26 | begin 27 | MG.new("annotate.gemspec") 28 | rescue Exception => e 29 | STDERR.puts("WARNING: Couldn't read gemspec. As such, a number of tasks may be unavailable to you until you run 'rake gem:gemspec' to correct the issue.") 30 | # Gemspec is probably in a broken state, so let's give ourselves a chance to 31 | # build a new one... 32 | end 33 | DEVELOPMENT_GROUPS=[:development, :test] 34 | RUNTIME_GROUPS=Bundler.definition.groups - DEVELOPMENT_GROUPS 35 | namespace :gem do 36 | task :gemspec do 37 | spec = Gem::Specification.new do |gem| 38 | # See http://docs.rubygems.org/read/chapter/20 39 | # for more options. 40 | gem.version = Annotate.version 41 | gem.name = "annotate" 42 | gem.homepage = "http://github.com/ctran/annotate_models" 43 | gem.rubyforge_project = "annotate" 44 | gem.license = "Ruby" 45 | gem.summary = %q{Annotates Rails Models, routes, fixtures, and others based on the database schema.} 46 | gem.description = %q{Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.} 47 | gem.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] 48 | gem.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] 49 | gem.require_paths = ["lib"] 50 | # gem.rdoc_options = ["--charset=UTF-8"] 51 | # gem.required_ruby_version = "> 1.9.2" 52 | 53 | Bundler.load.dependencies_for(*RUNTIME_GROUPS).each do |dep| 54 | runtime_resolved = Bundler.definition.specs_for(RUNTIME_GROUPS).select { |spec| spec.name == dep.name }.first 55 | if(!runtime_resolved.nil?) 56 | gem.add_dependency(dep.name, dep.requirement) 57 | end 58 | end 59 | 60 | gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 61 | gem.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc', 'TODO.rdoc'] 62 | 63 | gem.files = `git ls-files -- .`.split("\n").reject do |fn| 64 | fn =~ /^Gemfile.*/ || 65 | fn =~ /^Rakefile/ || 66 | fn =~ /^\.rvmrc/ || 67 | fn =~ /^\.gitignore/ || 68 | fn =~ /^\.rspec/ || 69 | fn =~ /^\.document/ || 70 | fn =~ /^\.yardopts/ || 71 | fn =~ /^pkg/ || 72 | fn =~ /^spec/ || 73 | fn =~ /^doc/ || 74 | fn =~ /^vendor\/cache/ 75 | end.sort 76 | end 77 | File.open("annotate.gemspec", "wb") do |fh| 78 | fh.write("# This file is auto-generated!\n") 79 | fh.write("# DO NOT EDIT THIS FILE DIRECTLY!\n") 80 | fh.write("# Instead, edit the Rakefile and run 'rake gems:gemspec'.") 81 | fh.write(spec.to_ruby) 82 | end 83 | end 84 | end 85 | 86 | namespace :jeweler do 87 | task :clobber do 88 | FileUtils.rm_f("pkg") 89 | end 90 | end 91 | task :clobber => :'jeweler:clobber' 92 | 93 | require "rspec/core/rake_task" # RSpec 2.0 94 | RSpec::Core::RakeTask.new(:spec) do |t| 95 | t.pattern = ['spec/*_spec.rb', 'spec/**/*_spec.rb'] 96 | t.rspec_opts = ['--backtrace', '--format d'] 97 | end 98 | 99 | # Placeholder for running bin/* in development... 100 | task :environment 101 | 102 | task :integration_environment do 103 | require './spec/spec_helper' 104 | end 105 | 106 | namespace :gemsets do 107 | desc "Completely empty any gemsets used by scenarios, so they'll be perfectly clean on the next run." 108 | task :empty => [:integration_environment] do 109 | Annotate::Integration::SCENARIOS.each do |test_rig, base_dir, test_name| 110 | Annotate::Integration.empty_gemset(test_rig) 111 | end 112 | end 113 | end 114 | task :clobber => :'gemsets:empty' 115 | 116 | namespace :integration do 117 | desc "Remove any cruft generated by manual debugging runs which is .gitignore'd." 118 | task :clean => :integration_environment do 119 | Annotate::Integration.nuke_all_cruft 120 | end 121 | 122 | desc "Reset any changed files, and remove any untracked files in spec/integration/*/, plus run integration:clean." 123 | task :clobber => [:integration_environment, :'integration:clean'] do 124 | Annotate::Integration.reset_dirty_files 125 | Annotate::Integration.clear_untracked_files 126 | end 127 | 128 | task :symlink => [:integration_environment] do 129 | require 'digest/md5' 130 | 131 | integration_dir = File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'integration')) 132 | fixture_dir = File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'fixtures')) 133 | target_dir = File.expand_path(ENV['TARGET']) if(ENV['TARGET']) 134 | raise "Must specify TARGET=x, where x is an integration test scenario!" unless(target_dir && Dir.exist?(target_dir)) 135 | raise "TARGET directory must be within spec/integration/!" unless(target_dir.start_with?(integration_dir)) 136 | candidates = {} 137 | FileList[ 138 | "#{target_dir}/.rvmrc", 139 | "#{target_dir}/**/*" 140 | ].select { |fname| !(File.symlink?(fname) || File.directory?(fname)) }. 141 | map { |fname| fname.sub(integration_dir, '') }. 142 | reject do |fname| 143 | fname =~ /\/\.gitkeep$/ || 144 | fname =~ /\/app\/models\// || 145 | fname =~ /\/routes\.rb$/ || 146 | fname =~ /\/fixtures\// || 147 | fname =~ /\/factories\// || 148 | fname =~ /\.sqlite3$/ || 149 | (fname =~ /\/test\// && fname !~ /_helper\.rb$/) || 150 | (fname =~ /\/spec\// && fname !~ /_helper\.rb$/) 151 | end. 152 | map { |fname| "#{integration_dir}#{fname}"}. 153 | each do |fname| 154 | digest = Digest::MD5.hexdigest(File.read(fname)) 155 | candidates[digest] ||= [] 156 | candidates[digest] << fname 157 | end 158 | fixtures = {} 159 | FileList["spec/fixtures/**/*"].each do |fname| 160 | fixtures[Digest::MD5.hexdigest(File.read(fname))] = File.expand_path(fname) 161 | end 162 | 163 | candidates.keys.each do |digest| 164 | if(fixtures.has_key?(digest)) 165 | candidates[digest].each do |fname| 166 | # Double-check contents in case of hash collision... 167 | if(FileUtils.identical?(fname, fixtures[digest])) 168 | destination_dir = Pathname.new(File.dirname(fname)) 169 | relative_target = Pathname.new(fixtures[digest]).relative_path_from(destination_dir) 170 | Dir.chdir(destination_dir) do 171 | sh("ln", "-sfn", relative_target.to_s, File.basename(fname)) 172 | end 173 | end 174 | end 175 | end 176 | end 177 | end 178 | end 179 | task :clobber => :'integration:clobber' 180 | 181 | require 'yard' 182 | YARD::Rake::YardocTask.new do |t| 183 | # t.files = ['features/**/*.feature', 'features/**/*.rb', 'lib/**/*.rb'] 184 | # t.options = ['--any', '--extra', '--opts'] # optional 185 | end 186 | 187 | namespace :yard do 188 | task :clobber do 189 | FileUtils.rm_f(".yardoc") 190 | FileUtils.rm_f("doc") 191 | end 192 | end 193 | task :clobber => :'yard:clobber' 194 | 195 | namespace :rubinius do 196 | task :clobber do 197 | FileList["**/*.rbc"].each { |fname| FileUtils.rm_f(fname) } 198 | FileList[".rbx/**/*"].each { |fname| FileUtils.rm_f(fname) } 199 | end 200 | end 201 | task :clobber => :'rubinius:clobber' 202 | 203 | # want other tests/tasks run by default? Add them to the list 204 | task :default => [:spec] 205 | -------------------------------------------------------------------------------- /CHANGELOG.rdoc: -------------------------------------------------------------------------------- 1 | == 2.6.0.beta1 2 | 3 | * It's now possible to use Annotate in standalone ActiveRecord (non-Rails) 4 | projects again. 5 | * Adding note that Markdown is actually MultiMarkdown, and recommending the use 6 | of the `kramdown` engine for parsing it. 7 | * Improved Markdown formatting considerably. 8 | * Bugfix: Needed to use inline-code tag for column and table names, otherwise 9 | underscores would cause havok with the formatting. 10 | * Bugfix: Markdown syntax was incorrect (can't have trailing spaces before the 11 | closing marker for an emphasis tag). 12 | * Bugfix: Remove-annotations wasn't properly finding test/spec files, and 13 | wasn't even looking for FactoryGirl factories under the new naming 14 | convention. 15 | * Bugfix: Load the Rakefile from the current directory, not the first Rakefile 16 | in our load path. 17 | * Added support for new FactoryGirl naming convention. 18 | * Fix behavior of route annotations in newer versions of Rake that don't spit 19 | out the CWD as their first line of output. 20 | * Overhauled integration testing system to be much easier to work with, better 21 | compartmentalized, and so forth -- at the cost that you must be using RVM to 22 | utilize it. (It'll spit out appropriate pending messages if you don't.) 23 | Also includes a mode for "tinkering" by hand with a scenario, and won't let 24 | you run it through rspect if the repo is in a dirty state. Added appropriate 25 | rake tasks to help with all of this. 26 | * Routes can now be appended, pre-pended, or removed -- and do sane things in 27 | all cases. 28 | * Expose all `position_*` variables as CLI params. 29 | * Make `ENV ['position']` work as a default for all the `ENV ['position_*']` 30 | variables. 31 | * Make rake tasks more resilient to unusual circumstances / code loading 32 | behavior. 33 | * Resolve annotate vs. annotate_models ambiguity once and for all by settling 34 | on `annotate_models` _and_ `annotate_routes`. This avoids a name collision 35 | with RMagick while not needlessly overloading the term. 36 | * Fixed that schema kept prepending additional newlines 37 | * Updates to make annotate smarter about when to touch a model 38 | * Recognize column+type, and don't change a file unless the column+type 39 | combination of the new schema are different than that of the old (i.e., don't 40 | regenerate if columns happen to be in a different order. That's just how life 41 | is sometimes) 42 | * Change annotate to use options hash instead of ENV. 43 | 44 | == 2.5.0 45 | 46 | * Works better with Rails 3 47 | * Bugfix: schema kept prepending additional newlines 48 | * Updates to make annotate smarter about when to touch a model 49 | * Recognize column+type, and don't change a file unless the column+type combination of the new schema are different than that of the old (i.e., don't regenerate if columns happen to be in a different order. That's just how life is sometimes.) 50 | * Grab old specification even if it has \r\n as line endings rather than pure \ns 51 | * Various warning and specification fixes 52 | * Fix "no such file to load -- annotate/annotate_models (MissingSourceFile)" 53 | error (require statements in tasks now use full path to lib files) 54 | * warn about macros, to mitigate when we're included during a production run, 55 | not just a rakefile run -- possibly at the expense of too much noise 56 | * Adding rake as a runtime dependency 57 | * If the schema is already in the model file, it will be replaced into the same 58 | location. If it didn't previously exist, it'll be placed according to the 59 | "position", as before. 60 | * Allow task loading from Rakefile for gems (plugin installation already 61 | auto-detects). 62 | * Add skip_on_db_migrate option as well for people that don't want it 63 | * Fix options parsing to convert strings to proper booleans 64 | * Add support for Fabrication fabricators 65 | * Leave magic encoding comment intact 66 | * Fix issue #14 - RuntimeError: Already memoized 67 | * Count a model as 'annotated' if any of its tests/fixtures are annotated 68 | * Support FactoryGirl 69 | * Support :change migrations (Rails 3.1) 70 | * Allow models with non-standard capitalization 71 | * Widen type column so we can handle longtexts with chopping things off. 72 | * Skip trying to get list of models from commandline when running via Rake (was 73 | preventing the use of multiple rake tasks in one command if one of them was 74 | db:migrate). 75 | * Add ability to skip annotations for a model by adding 76 | '# -*- SkipSchemaAnnotations' anywhere in the file. 77 | * Don't show column limits for integer and boolean types. 78 | * Add sorting for columns and indexes. (Helpful for out-of-order migration 79 | execution. Use --sort if you want this.) 80 | * Annotate unit tests in subfolders. 81 | * Add generator to install rakefile that automatically annotates on db:migrate. 82 | * Correct Gemfile to clarify which environments need which gems. 83 | * Add an .rvmrc to facilitate clean development. 84 | * Refactor out ActiveRecord monkey-patch to permit extending without 85 | side-effects. 86 | * Use ObjectSpace to locate models to facilitate handling of models with 87 | non-standard capitalization. 88 | Note that this still requires that the inflector be configured to understand 89 | the special case. 90 | * Shore up test cases a bit. 91 | * Merge against many of the older branches on Github whose functionality is 92 | already reflected to reduce confusion about what is and is not implemented 93 | here. 94 | * Accept String or Symbol for :position (et al) options. 95 | * Add RDoc output formatting as an option. 96 | * Add Markdown output formatting as an option. 97 | * Add option to force annotation regeneration. 98 | * Add new configuration option for controlling where info is placed in 99 | fixtures/factories. 100 | * Fix for models without tables. 101 | * Fix gemspec generation now that Jeweler looks at Gemfile. 102 | * Fix warning: `NOTE: Gem::Specification#default_executable= is deprecated with 103 | no replacement. It will be removed on or after 2011-10-01.` 104 | * Fix handling of files with no trailing newline when putting annotations at 105 | the end of the file. 106 | * Now works on tables with no primary key. 107 | * --format=markdown option 108 | * --trace option to help debug "Unable to annotate" errors 109 | * "Table name" annotation (if table name is different from model name) 110 | * "Human name" annotation (enabling translation to non-English locales) 111 | * Fix JRuby ObjectSpace compatibility bug (https://github.com/ctran/annotate_models/pull/85) 112 | * Fix FactoryGirl compatibility bug (https://github.com/ctran/annotate_models/pull/82) 113 | 114 | == 2.4.2 2009-11-21 115 | 116 | * Annotates (spec|test)/factories/_factory.rb files 117 | 118 | == 2.4.1 2009-11-20 119 | 120 | * Annotates thoughtbot's factory_girl factories (test/factories/_factory.rb) 121 | * Move default annotation position back to top 122 | 123 | == 2.4.0 2009-12-13 124 | 125 | * Incorporated lots of patches from the Github community, including support for 126 | Blueprints fixtures 127 | * Several bug fixes 128 | 129 | == 2.1 2009-10-18 130 | 131 | * New options 132 | * -R to require additional files before loading the models 133 | * -i to show database indexes in annotations 134 | * -e to exclude annotating tests or fixtures 135 | * -m to include the migration version number in the annotation 136 | * --model-dir to annotate model files stored a different place than app/models 137 | * Ignore unknown macros ('acts_as_whatever') 138 | 139 | == 2.0 2009-02-03 140 | 141 | * Add annotate_models plugin fork additions 142 | * Annotates Rspec and Test Unit models 143 | * Annotates Object Daddy exemplars 144 | * Annotates geometrical columns 145 | * Add AnnotateRoutes rake task 146 | * Up gem structure to newgem defaults 147 | 148 | == 1.0.4 2008-09-04 149 | 150 | * Only update modified models since last run, thanks to sant0sk1 151 | 152 | == 1.0.3 2008-05-02 153 | 154 | * Add misc changes from Dustin Sallings and Henrik N 155 | * Remove trailing whitespace 156 | * More intuitive info messages 157 | * Update README file with update-to-date example 158 | 159 | == 1.0.2 2008-03-22 160 | 161 | * Add contributions from Michael Bumann (http://github.com/bumi) 162 | * added an option "position" to choose to put the annotation, 163 | * spec/fixtures now also get annotated 164 | * added a task to remove the annotations 165 | * these options can be specified from command line as -d and -p [before|after] 166 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == Annotate (aka AnnotateModels) 2 | 3 | IMPORTANT: If you're upgrading from a previous version, including 2.5.0, 4 | re-run the generator task! 5 | 6 | Add a comment summarizing the current schema to the top or bottom of each of 7 | your... 8 | 9 | - ActiveRecord models 10 | - Fixture files 11 | - Tests and Specs 12 | - Object Daddy exemplars 13 | - Machinist blueprints 14 | - Fabrication fabricators 15 | - Thoughtbot's factory_girl factories, i.e. the (spec|test)/factories/_factory.rb files 16 | - routes.rb file (for Rails projects) 17 | 18 | The schema comment looks like this: 19 | 20 | # == Schema Info 21 | # 22 | # Table name: line_items 23 | # 24 | # id :integer(11) not null, primary key 25 | # quantity :integer(11) not null 26 | # product_id :integer(11) not null 27 | # unit_price :float 28 | # order_id :integer(11) 29 | # 30 | 31 | class LineItem < ActiveRecord::Base 32 | belongs_to :product 33 | . . . 34 | 35 | It also annotates geometrical columns, geom type and srid, when using 36 | `SpatialAdapter` or `PostgisAdapter`: 37 | 38 | # == Schema Info 39 | # 40 | # Table name: trips 41 | # 42 | # local :geometry point, 4326 43 | # path :geometry line_string, 4326 44 | 45 | Also, if you pass the -r option, it'll annotate routes.rb with the output of 46 | `rake routes`. 47 | 48 | 49 | == Install 50 | 51 | Into Gemfile from rubygems.org: 52 | 53 | gem 'annotate', ">=2.5.0" 54 | 55 | Into Gemfile from Github: 56 | 57 | gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git' 58 | 59 | Into environment gems from rubygems.org: 60 | 61 | gem install annotate 62 | 63 | Into environment gems from Github checkout: 64 | 65 | git clone git://github.com/ctran/annotate_models.git annotate_models 66 | cd annotate_models 67 | rake build 68 | gem install pkg/annotate-*.gem 69 | 70 | 71 | == Usage 72 | 73 | (If you used the Gemfile install, prefix the below commands with `bundle exec`.) 74 | 75 | === Usage in Rails 76 | 77 | To annotate all your models, tests, fixtures, and factories: 78 | 79 | cd /path/to/app 80 | annotate 81 | 82 | To annotate just your models, tests, and factories: 83 | 84 | annotate --exclude fixtures 85 | 86 | To annotate just your models: 87 | 88 | annotate --exclude tests,fixtures,factories 89 | 90 | To annotate routes.rb: 91 | 92 | annotate --routes 93 | 94 | To remove model/test/fixture/factory annotations: 95 | 96 | annotate --delete 97 | 98 | To remove routes.rb annotations: 99 | 100 | annotate --routes --delete 101 | 102 | 103 | == Configuration 104 | 105 | 106 | === Usage Outside of Rails 107 | 108 | Everything above applies, except that --routes is not meaningful, and you will 109 | probably need to explicitly set one or more `--require` option(s), and/or one 110 | or more `--model-dir` options to inform annotate about the structure of your 111 | project and help it bootstrap and load the relevant code. 112 | 113 | 114 | 115 | == Configuration 116 | 117 | If you want to always skip annotations on a particular model, add this string 118 | anywhere in the file: 119 | 120 | # -*- SkipSchemaAnnotations 121 | 122 | To generate a configuration file (in the form of a `.rake` file), to set 123 | default options: 124 | 125 | rails g annotate:install 126 | 127 | Edit this file to control things like output format, where annotations are 128 | added (top or bottom of file), and in which artifacts. 129 | 130 | 131 | === Configuration in Rails 132 | 133 | To generate a configuration file (in the form of a `.rake` file), to set 134 | default options: 135 | 136 | rails g annotate:install 137 | 138 | Edit this file to control things like output format, where annotations are 139 | added (top or bottom of file), and in which artifacts. 140 | == Rails Integration 141 | 142 | By default, once you've generated a configuration file, annotate will be 143 | executed whenever you run `rake db:migrate` (but only in development mode). 144 | If you want to disable this behavior permanently, edit the `.rake` file and 145 | change: 146 | 147 | 'skip_on_db_migrate' => "false", 148 | 149 | To: 150 | 151 | 'skip_on_db_migrate' => "try", 152 | 153 | If you want to run `rake db:migrate` as a one-off without running annotate, 154 | you can do so with a simple environment variable, instead of editing the 155 | `.rake` file: 156 | 157 | skip_on_db_migrate=1 rake db:migrate 158 | 159 | 160 | == Options 161 | 162 | Usage: annotate [options] [model_file]* 163 | -d, --delete Remove annotations from all model files or the routes.rb file 164 | -p, --position [before|after] Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory/routes file(s) 165 | --pc, --position-in-class [before|after] 166 | Place the annotations at the top (before) or the bottom (after) of the model file 167 | --pf, --position-in-factory [before|after] 168 | Place the annotations at the top (before) or the bottom (after) of any factory files 169 | --px, --position-in-fixture [before|after] 170 | Place the annotations at the top (before) or the bottom (after) of any fixture files 171 | --pt, --position-in-test [before|after] 172 | Place the annotations at the top (before) or the bottom (after) of any test files 173 | --pr, --position-in-routes [before|after] 174 | Place the annotations at the top (before) or the bottom (after) of the routes.rb file 175 | -r, --routes Annotate routes.rb with the output of 'rake routes' 176 | -v, --version Show the current version of this gem 177 | -m, --show-migration Include the migration version number in the annotation 178 | -i, --show-indexes List the table's database indexes in the annotation 179 | -s, --simple-indexes Concat the column's related indexes in the annotation 180 | --model-dir dir Annotate model files stored in dir rather than app/models 181 | --ignore-model-subdirects Ignore subdirectories of the models directory 182 | --sort Sort columns alphabetically, rather than in creation order 183 | -R, --require path Additional file to require before loading models, may be used multiple times 184 | -e [tests,fixtures,factories], Do not annotate fixtures, test files, and/or factories 185 | --exclude 186 | -f [bare|rdoc|markdown], Render Schema Infomation as plain/RDoc/Markdown 187 | --format 188 | --force Force new annotations even if there are no changes. 189 | --trace If unable to annotate a file, print the full stack trace, not just the exception message. 190 | 191 | 192 | == Sorting 193 | 194 | By default, columns will be sorted in database order (i.e. the order in which 195 | migrations were run). 196 | 197 | If you prefer to sort alphabetically so that the results of 198 | annotation are consistent regardless of what order migrations are executed in, 199 | use --sort. 200 | 201 | 202 | == Markdown 203 | 204 | The format produced is actually MultiMarkdown, making use of the syntax 205 | extension for tables. It's recommended you use `kramdown` as your parser if 206 | you want to use this format. If you're using `yard` to generate documentation, 207 | specify a format of markdown with `kramdown` as the provider by adding this to 208 | your `.yardopts` file: 209 | 210 | --markup markdown 211 | --markup-provider kramdown 212 | 213 | Be sure to add this to your `Gemfile` as well: 214 | 215 | gem 'kramdown', :groups => [:development], :require => false 216 | 217 | 218 | == WARNING 219 | 220 | Note that this code will blow away the initial/final comment block in your 221 | models if it looks like it was previously added by this gem, so you don't want 222 | to add additional text to an automatically created comment block. 223 | 224 | BACK UP YOUR MODELS BEFORE USING THIS TOOL! 225 | 226 | 227 | == Links 228 | 229 | - Factory Girl: http://github.com/thoughtbot/factory_girl 230 | - Object Daddy: http://github.com/flogic/object_daddy 231 | - Machinist: http://github.com/notahat/machinist 232 | - Fabrication: http://github.com/paulelliott/fabrication 233 | - SpatialAdapter: http://github.com/pdeffendol/spatial_adapter 234 | - PostgisAdapter: http://github.com/nofxx/postgis_adapter 235 | 236 | 237 | == License 238 | 239 | Released under the same license as Ruby. No Support. No Warranty. 240 | 241 | 242 | == Authors 243 | 244 | - Original code by: Dave Thomas -- Pragmatic Programmers, LLC 245 | - Overhauled by: Alex Chaffee alex@stinky.com 246 | - Gemmed by: Cuong Tran ctran@pragmaquest.com 247 | - Maintained by: Alex Chaffee and Cuong Tran 248 | - Homepage: http://github.com/ctran/annotate_models 249 | 250 | With help from: 251 | 252 | - Jack Danger - http://github.com/JackDanger 253 | - Michael Bumann - http://github.com/bumi 254 | - Henrik Nyh - http://github.com/henrik 255 | - Marcos Piccinini - http://github.com/nofxx 256 | - Neal Clark - http://github.com/nclark 257 | - Jacqui Maher - http://github.com/jacqui 258 | - Nick Plante - http://github.com/zapnap - http://blog.zerosum.org 259 | - Pedro Visintin - http://github.com/peterpunk - http://www.pedrovisintin.com 260 | - Bob Potter - http://github.com/bpot 261 | - Gavin Montague - http://github.com/govan 262 | - Alexander Semyonov - http://github.com/rotuka 263 | - Nathan Brazil - http://github.com/bitaxis 264 | - Ian Duggan http://github.com/ijcd 265 | - Jon Frisby http://github.com/mrjoy 266 | - Tsutomu Kuroda 267 | - Kevin Moore 268 | - Philip Hallstrom 269 | - Brent Greeff 270 | - Paul Alexander 271 | - Dmitry Lihachev 272 | - qichunren 273 | 274 | and many others that I may have forgotten to add. 275 | -------------------------------------------------------------------------------- /spec/annotate/annotate_models_spec.rb: -------------------------------------------------------------------------------- 1 | #encoding: utf-8 2 | require File.dirname(__FILE__) + '/../spec_helper.rb' 3 | require 'annotate/annotate_models' 4 | require 'annotate/active_record_patch' 5 | 6 | describe AnnotateModels do 7 | def mock_class(table_name, primary_key, columns) 8 | options = { 9 | :connection => mock("Conn", :indexes => []), 10 | :table_name => table_name, 11 | :primary_key => primary_key && primary_key.to_s, 12 | :column_names => columns.map { |col| col.name.to_s }, 13 | :columns => columns 14 | } 15 | 16 | mock("An ActiveRecord class", options) 17 | end 18 | 19 | def mock_column(name, type, options={}) 20 | default_options = { 21 | :limit => nil, 22 | :null => false, 23 | :default => nil 24 | } 25 | 26 | stubs = default_options.dup 27 | stubs.merge!(options) 28 | stubs.merge!(:name => name, :type => type) 29 | 30 | mock("Column", stubs) 31 | end 32 | 33 | it { AnnotateModels.quote(nil).should eql("NULL") } 34 | it { AnnotateModels.quote(true).should eql("TRUE") } 35 | it { AnnotateModels.quote(false).should eql("FALSE") } 36 | it { AnnotateModels.quote(25).should eql("25") } 37 | it { AnnotateModels.quote(25.6).should eql("25.6") } 38 | it { AnnotateModels.quote(1e-20).should eql("1.0e-20") } 39 | 40 | it "should get schema info" do 41 | klass = mock_class(:users, :id, [ 42 | mock_column(:id, :integer), 43 | mock_column(:name, :string, :limit => 50) 44 | ]) 45 | 46 | AnnotateModels.get_schema_info(klass, "Schema Info").should eql(<<-EOS) 47 | # Schema Info 48 | # 49 | # Table name: users 50 | # 51 | # id :integer not null, primary key 52 | # name :string(50) not null 53 | # 54 | 55 | EOS 56 | end 57 | 58 | it "should get schema info even if the primary key is not set" do 59 | klass = mock_class(:users, nil, [ 60 | mock_column(:id, :integer), 61 | mock_column(:name, :string, :limit => 50) 62 | ]) 63 | 64 | AnnotateModels.get_schema_info(klass, "Schema Info").should eql(<<-EOS) 65 | # Schema Info 66 | # 67 | # Table name: users 68 | # 69 | # id :integer not null 70 | # name :string(50) not null 71 | # 72 | 73 | EOS 74 | end 75 | 76 | it "should get schema info even if the primary key is array, if using composite_primary_keys" do 77 | klass = mock_class(:users, nil, [ 78 | [mock_column(:a_id, :integer), mock_column(:b_id, :integer)], 79 | mock_column(:name, :string, :limit => 50) 80 | ]) 81 | 82 | AnnotateModels.get_schema_info(klass, "Schema Info").should eql(<<-EOS) 83 | # Schema Info 84 | # 85 | # Table name: users 86 | # 87 | # a_id :integer not null 88 | # b_id :integer not null 89 | # name :string(50) not null 90 | # 91 | 92 | EOS 93 | end 94 | 95 | it "should get schema info as RDoc" do 96 | klass = mock_class(:users, :id, [ 97 | mock_column(:id, :integer), 98 | mock_column(:name, :string, :limit => 50) 99 | ]) 100 | AnnotateModels.get_schema_info(klass, AnnotateModels::PREFIX, :format_rdoc => true).should eql(<<-EOS) 101 | # #{AnnotateModels::PREFIX} 102 | # 103 | # Table name: users 104 | # 105 | # *id*:: integer, not null, primary key 106 | # *name*:: string(50), not null 107 | #-- 108 | # #{AnnotateModels::END_MARK} 109 | #++ 110 | 111 | EOS 112 | end 113 | 114 | describe "#get_model_class" do 115 | require "tmpdir" 116 | 117 | module ::ActiveRecord 118 | class Base 119 | def self.has_many name 120 | end 121 | end 122 | end 123 | 124 | # todo: use 'files' gem instead 125 | def create(file, body="hi") 126 | file_path = File.join(AnnotateModels.model_dir, file) 127 | FileUtils.mkdir_p(File.dirname(file_path)) 128 | 129 | File.open(file_path, "wb") do |f| 130 | f.puts(body) 131 | end 132 | file_path 133 | end 134 | 135 | def check_class_name(file, class_name) 136 | klass = AnnotateModels.get_model_class(file) 137 | 138 | klass.should_not == nil 139 | klass.name.should == class_name 140 | end 141 | 142 | before :each do 143 | AnnotateModels.model_dir = Dir.mktmpdir 'annotate_models' 144 | end 145 | 146 | it "should work" do 147 | create 'foo.rb', <<-EOS 148 | class Foo < ActiveRecord::Base 149 | end 150 | EOS 151 | check_class_name 'foo.rb', 'Foo' 152 | end 153 | 154 | it "should find models with non standard capitalization" do 155 | create 'foo_with_capitals.rb', <<-EOS 156 | class FooWithCAPITALS < ActiveRecord::Base 157 | end 158 | EOS 159 | check_class_name 'foo_with_capitals.rb', 'FooWithCAPITALS' 160 | end 161 | 162 | it "should find models inside modules" do 163 | create 'bar/foo_inside_bar.rb', <<-EOS 164 | module Bar 165 | class FooInsideBar < ActiveRecord::Base 166 | end 167 | end 168 | EOS 169 | check_class_name 'bar/foo_inside_bar.rb', 'Bar::FooInsideBar' 170 | end 171 | 172 | it "should not care about unknown macros" do 173 | create 'foo_with_macro.rb', <<-EOS 174 | class FooWithMacro < ActiveRecord::Base 175 | acts_as_awesome :yah 176 | end 177 | EOS 178 | check_class_name 'foo_with_macro.rb', 'FooWithMacro' 179 | end 180 | 181 | it "should not care about known macros" do 182 | create('foo_with_known_macro.rb', <<-EOS) 183 | class FooWithKnownMacro < ActiveRecord::Base 184 | has_many :yah 185 | end 186 | EOS 187 | check_class_name 'foo_with_known_macro.rb', 'FooWithKnownMacro' 188 | end 189 | 190 | it "should work with class names with ALL CAPS segments" do 191 | create('foo_with_capitals.rb', <<-EOS) 192 | class FooWithCAPITALS < ActiveRecord::Base 193 | acts_as_awesome :yah 194 | end 195 | EOS 196 | check_class_name 'foo_with_capitals.rb', 'FooWithCAPITALS' 197 | end 198 | 199 | it "should not complain of invalid multibyte char (USASCII)" do 200 | create 'foo_with_utf8.rb', <<-EOS 201 | #encoding: utf-8 202 | class FooWithUtf8 < ActiveRecord::Base 203 | UTF8STRINGS = %w[résumé façon âge] 204 | end 205 | EOS 206 | check_class_name 'foo_with_utf8.rb', 'FooWithUtf8' 207 | end 208 | 209 | it "should find models inside modules with non standard capitalization" do 210 | create 'bar/foo_inside_capitals_bar.rb', <<-EOS 211 | module BAR 212 | class FooInsideCapitalsBAR < ActiveRecord::Base 213 | end 214 | end 215 | EOS 216 | check_class_name 'bar/foo_inside_capitals_bar.rb', 'BAR::FooInsideCapitalsBAR' 217 | end 218 | 219 | it "should find non-namespaced models inside subdirectories" do 220 | create 'bar/non_namespaced_foo_inside_bar.rb', <<-EOS 221 | class NonNamespacedFooInsideBar < ActiveRecord::Base 222 | end 223 | EOS 224 | check_class_name 'bar/non_namespaced_foo_inside_bar.rb', 'NonNamespacedFooInsideBar' 225 | end 226 | 227 | it "should find non-namespaced models with non standard capitalization inside subdirectories" do 228 | create 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', <<-EOS 229 | class NonNamespacedFooWithCapitalsInsideBar < ActiveRecord::Base 230 | end 231 | EOS 232 | check_class_name 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', 'NonNamespacedFooWithCapitalsInsideBar' 233 | end 234 | 235 | it "should allow known macros" do 236 | create('foo_with_known_macro.rb', <<-EOS) 237 | class FooWithKnownMacro < ActiveRecord::Base 238 | has_many :yah 239 | end 240 | EOS 241 | capturing(:stderr) do 242 | check_class_name 'foo_with_known_macro.rb', 'FooWithKnownMacro' 243 | end.should == "" 244 | end 245 | end 246 | 247 | describe "#remove_annotation_of_file" do 248 | require "tmpdir" 249 | 250 | def create(file, body="hi") 251 | path = File.join(@dir, file) 252 | File.open(path, "w") do |f| 253 | f.puts(body) 254 | end 255 | return path 256 | end 257 | 258 | def content(path) 259 | File.read(path) 260 | end 261 | 262 | before :each do 263 | @dir = Dir.mktmpdir 'annotate_models' 264 | end 265 | 266 | it "should remove before annotate" do 267 | path = create "before.rb", <<-EOS 268 | # == Schema Information 269 | # 270 | # Table name: foo 271 | # 272 | # id :integer not null, primary key 273 | # created_at :datetime 274 | # updated_at :datetime 275 | # 276 | 277 | class Foo < ActiveRecord::Base 278 | end 279 | EOS 280 | 281 | AnnotateModels.remove_annotation_of_file(path) 282 | 283 | content(path).should == <<-EOS 284 | class Foo < ActiveRecord::Base 285 | end 286 | EOS 287 | end 288 | 289 | it "should remove after annotate" do 290 | path = create "after.rb", <<-EOS 291 | class Foo < ActiveRecord::Base 292 | end 293 | 294 | # == Schema Information 295 | # 296 | # Table name: foo 297 | # 298 | # id :integer not null, primary key 299 | # created_at :datetime 300 | # updated_at :datetime 301 | # 302 | 303 | EOS 304 | 305 | AnnotateModels.remove_annotation_of_file(path) 306 | 307 | content(path).should == <<-EOS 308 | class Foo < ActiveRecord::Base 309 | end 310 | EOS 311 | end 312 | end 313 | 314 | describe "annotating a file" do 315 | before do 316 | @model_dir = Dir.mktmpdir('annotate_models') 317 | (@model_file_name, @file_content) = write_model "user.rb", <<-EOS 318 | class User < ActiveRecord::Base 319 | end 320 | EOS 321 | 322 | @klass = mock_class(:users, :id, [ 323 | mock_column(:id, :integer), 324 | mock_column(:name, :string, :limit => 50) 325 | ]) 326 | @schema_info = AnnotateModels.get_schema_info(@klass, "== Schema Info") 327 | end 328 | 329 | def write_model file_name, file_content 330 | fname = File.join(@model_dir, file_name) 331 | FileUtils.mkdir_p(File.dirname(fname)) 332 | File.open(fname, "wb") { |f| f.write file_content } 333 | return fname, file_content 334 | end 335 | 336 | def annotate_one_file options = {} 337 | Annotate.set_defaults(options) 338 | options = Annotate.setup_options(options) 339 | AnnotateModels.annotate_one_file(@model_file_name, @schema_info, :position_in_class, options) 340 | 341 | # Wipe settings so the next call will pick up new values... 342 | Annotate.instance_variable_set('@has_set_defaults', false) 343 | Annotate::POSITION_OPTIONS.each { |key| ENV[key.to_s] = '' } 344 | Annotate::FLAG_OPTIONS.each { |key| ENV[key.to_s] = '' } 345 | Annotate::PATH_OPTIONS.each { |key| ENV[key.to_s] = '' } 346 | end 347 | 348 | it "should annotate the file before the model if position == 'before'" do 349 | annotate_one_file :position => "before" 350 | File.read(@model_file_name).should == "#{@schema_info}#{@file_content}" 351 | end 352 | 353 | it "should annotate before if given :position => :before" do 354 | annotate_one_file :position => :before 355 | File.read(@model_file_name).should == "#{@schema_info}#{@file_content}" 356 | end 357 | 358 | it "should annotate after if given :position => :after" do 359 | annotate_one_file :position => :after 360 | File.read(@model_file_name).should == "#{@file_content}\n#{@schema_info}" 361 | end 362 | 363 | it "should update annotate position" do 364 | annotate_one_file :position => :before 365 | 366 | another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]), 367 | "== Schema Info") 368 | 369 | @schema_info = another_schema_info 370 | annotate_one_file :position => :after 371 | 372 | File.read(@model_file_name).should == "#{@file_content}\n#{another_schema_info}" 373 | end 374 | 375 | it "works with namespaced models (i.e. models inside modules/subdirectories)" do 376 | (model_file_name, file_content) = write_model "foo/user.rb", <<-EOS 377 | class Foo::User < ActiveRecord::Base 378 | end 379 | EOS 380 | 381 | klass = mock_class(:'foo_users', :id, [ 382 | mock_column(:id, :integer), 383 | mock_column(:name, :string, :limit => 50) 384 | ]) 385 | schema_info = AnnotateModels.get_schema_info(klass, "== Schema Info") 386 | AnnotateModels.annotate_one_file(model_file_name, schema_info, :position => :before) 387 | File.read(model_file_name).should == "#{schema_info}#{file_content}" 388 | end 389 | 390 | describe "if a file can't be annotated" do 391 | before do 392 | write_model('user.rb', <<-EOS) 393 | class User < ActiveRecord::Base 394 | raise "oops" 395 | end 396 | EOS 397 | end 398 | 399 | it "displays an error message" do 400 | capturing(:stdout) { 401 | AnnotateModels.do_annotations :model_dir => @model_dir, :is_rake => true 402 | }.should include("Unable to annotate user.rb: oops") 403 | end 404 | 405 | it "displays the full stack trace with --trace" do 406 | capturing(:stdout) { 407 | AnnotateModels.do_annotations :model_dir => @model_dir, :trace => true, :is_rake => true 408 | }.should include("/spec/annotate/annotate_models_spec.rb:") 409 | end 410 | 411 | it "omits the full stack trace without --trace" do 412 | capturing(:stdout) { 413 | AnnotateModels.do_annotations :model_dir => @model_dir, :trace => false, :is_rake => true 414 | }.should_not include("/spec/annotate/annotate_models_spec.rb:") 415 | end 416 | end 417 | 418 | describe "if a file can't be deannotated" do 419 | before do 420 | write_model('user.rb', <<-EOS) 421 | class User < ActiveRecord::Base 422 | raise "oops" 423 | end 424 | EOS 425 | end 426 | 427 | it "displays an error message" do 428 | capturing(:stdout) { 429 | AnnotateModels.remove_annotations :model_dir => @model_dir, :is_rake => true 430 | }.should include("Unable to deannotate user.rb: oops") 431 | end 432 | 433 | it "displays the full stack trace" do 434 | capturing(:stdout) { 435 | AnnotateModels.remove_annotations :model_dir => @model_dir, :trace => true, :is_rake => true 436 | }.should include("/user.rb:2:in `'") 437 | end 438 | 439 | it "omits the full stack trace without --trace" do 440 | capturing(:stdout) { 441 | AnnotateModels.remove_annotations :model_dir => @model_dir, :trace => false, :is_rake => true 442 | }.should_not include("/user.rb:2:in `'") 443 | end 444 | end 445 | end 446 | end 447 | -------------------------------------------------------------------------------- /lib/annotate/annotate_models.rb: -------------------------------------------------------------------------------- 1 | module AnnotateModels 2 | # Annotate Models plugin use this header 3 | COMPAT_PREFIX = "== Schema Info" 4 | COMPAT_PREFIX_MD = "## Schema Info" 5 | PREFIX = "== Schema Information" 6 | PREFIX_MD = "## Schema Information" 7 | END_MARK = "== Schema Information End" 8 | PATTERN = /^\n?# (?:#{COMPAT_PREFIX}|#{COMPAT_PREFIX_MD}).*?\n(#.*\n)*\n/ 9 | 10 | # File.join for windows reverse bar compat? 11 | # I dont use windows, can`t test 12 | UNIT_TEST_DIR = File.join("test", "unit") 13 | SPEC_MODEL_DIR = File.join("spec", "models") 14 | FIXTURE_TEST_DIR = File.join("test", "fixtures") 15 | FIXTURE_SPEC_DIR = File.join("spec", "fixtures") 16 | 17 | # Object Daddy http://github.com/flogic/object_daddy/tree/master 18 | EXEMPLARS_TEST_DIR = File.join("test", "exemplars") 19 | EXEMPLARS_SPEC_DIR = File.join("spec", "exemplars") 20 | 21 | # Machinist http://github.com/notahat/machinist 22 | BLUEPRINTS_TEST_DIR = File.join("test", "blueprints") 23 | BLUEPRINTS_SPEC_DIR = File.join("spec", "blueprints") 24 | 25 | # Factory Girl http://github.com/thoughtbot/factory_girl 26 | FACTORY_GIRL_TEST_DIR = File.join("test", "factories") 27 | FACTORY_GIRL_SPEC_DIR = File.join("spec", "factories") 28 | 29 | # Fabrication https://github.com/paulelliott/fabrication.git 30 | FABRICATORS_TEST_DIR = File.join("test", "fabricators") 31 | FABRICATORS_SPEC_DIR = File.join("spec", "fabricators") 32 | 33 | TEST_PATTERNS = [ 34 | [UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"], 35 | [SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"], 36 | ] 37 | 38 | FIXTURE_PATTERNS = [ 39 | File.join(FIXTURE_TEST_DIR, "%TABLE_NAME%.yml"), 40 | File.join(FIXTURE_SPEC_DIR, "%TABLE_NAME%.yml"), 41 | ] 42 | 43 | FACTORY_PATTERNS = [ 44 | File.join(EXEMPLARS_TEST_DIR, "%MODEL_NAME%_exemplar.rb"), 45 | File.join(EXEMPLARS_SPEC_DIR, "%MODEL_NAME%_exemplar.rb"), 46 | File.join(BLUEPRINTS_TEST_DIR, "%MODEL_NAME%_blueprint.rb"), 47 | File.join(BLUEPRINTS_SPEC_DIR, "%MODEL_NAME%_blueprint.rb"), 48 | File.join(FACTORY_GIRL_TEST_DIR, "%MODEL_NAME%_factory.rb"), # (old style) 49 | File.join(FACTORY_GIRL_SPEC_DIR, "%MODEL_NAME%_factory.rb"), # (old style) 50 | File.join(FACTORY_GIRL_TEST_DIR, "%TABLE_NAME%.rb"), # (new style) 51 | File.join(FACTORY_GIRL_SPEC_DIR, "%TABLE_NAME%.rb"), # (new style) 52 | File.join(FABRICATORS_TEST_DIR, "%MODEL_NAME%_fabricator.rb"), 53 | File.join(FABRICATORS_SPEC_DIR, "%MODEL_NAME%_fabricator.rb"), 54 | ] 55 | 56 | # Don't show limit (#) on these column types 57 | # Example: show "integer" instead of "integer(4)" 58 | NO_LIMIT_COL_TYPES = ["integer", "boolean"] 59 | 60 | class << self 61 | def model_dir 62 | @model_dir || "app/models" 63 | end 64 | 65 | def model_dir=(dir) 66 | @model_dir = dir 67 | end 68 | 69 | # Simple quoting for the default column value 70 | def quote(value) 71 | case value 72 | when NilClass then "NULL" 73 | when TrueClass then "TRUE" 74 | when FalseClass then "FALSE" 75 | when Float, Fixnum, Bignum then value.to_s 76 | # BigDecimals need to be output in a non-normalized form and quoted. 77 | when BigDecimal then value.to_s('F') 78 | else 79 | value.inspect 80 | end 81 | end 82 | 83 | # Use the column information in an ActiveRecord class 84 | # to create a comment block containing a line for 85 | # each column. The line contains the column name, 86 | # the type (and length), and any optional attributes 87 | def get_schema_info(klass, header, options = {}) 88 | info = "# #{header}\n" 89 | info<< "#\n" 90 | if(options[:format_markdown]) 91 | info<< "# Table name: `#{klass.table_name}`\n" 92 | info<< "#\n" 93 | info<< "# ### Columns\n" 94 | else 95 | info<< "# Table name: #{klass.table_name}\n" 96 | end 97 | info<< "#\n" 98 | 99 | max_size = klass.column_names.map{|name| name.size}.max || 0 100 | max_size += options[:format_rdoc] ? 5 : 1 101 | md_names_overhead = 6 102 | md_type_allowance = 18 103 | bare_type_allowance = 16 104 | 105 | if(options[:format_markdown]) 106 | info<< sprintf( "# %-#{max_size + md_names_overhead}.#{max_size + md_names_overhead}s | %-#{md_type_allowance}.#{md_type_allowance}s | %s\n", 'Name', 'Type', 'Attributes' ) 107 | info<< "# #{ '-' * ( max_size + md_names_overhead ) } | #{'-' * md_type_allowance} | #{ '-' * 27 }\n" 108 | end 109 | 110 | cols = klass.columns 111 | cols = cols.sort_by(&:name) if(options[:sort]) 112 | cols.each do |col| 113 | attrs = [] 114 | attrs << "default(#{quote(col.default)})" unless col.default.nil? 115 | attrs << "not null" unless col.null 116 | attrs << "primary key" if klass.primary_key && (klass.primary_key.is_a?(Array) ? klass.primary_key.collect{|c|c.to_sym}.include?(col.name.to_sym) : col.name.to_sym == klass.primary_key.to_sym) 117 | 118 | col_type = (col.type || col.sql_type).to_s 119 | if col_type == "decimal" 120 | col_type << "(#{col.precision}, #{col.scale})" 121 | else 122 | if (col.limit) 123 | col_type << "(#{col.limit})" unless NO_LIMIT_COL_TYPES.include?(col_type) 124 | end 125 | end 126 | 127 | # Check out if we got a geometric column 128 | # and print the type and SRID 129 | if col.respond_to?(:geometry_type) 130 | attrs << "#{col.geometry_type}, #{col.srid}" 131 | end 132 | 133 | # Check if the column has indices and print "indexed" if true 134 | # If the index includes another column, print it too. 135 | if options[:simple_indexes] && klass.table_exists?# Check out if this column is indexed 136 | indices = klass.connection.indexes(klass.table_name) 137 | if indices = indices.select { |ind| ind.columns.include? col.name } 138 | indices.each do |ind| 139 | ind = ind.columns.reject! { |i| i == col.name } 140 | attrs << (ind.length == 0 ? "indexed" : "indexed => [#{ind.join(", ")}]") 141 | end 142 | end 143 | end 144 | 145 | if options[:format_rdoc] 146 | info << sprintf("# %-#{max_size}.#{max_size}s%s", "*#{col.name}*::", attrs.unshift(col_type).join(", ")).rstrip + "\n" 147 | elsif options[:format_markdown] 148 | name_remainder = max_size - col.name.length 149 | type_remainder = (md_type_allowance - 2) - col_type.length 150 | info << (sprintf("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`", col.name, " ", col_type, " ", attrs.join(", ").rstrip)).gsub('``', ' ').rstrip + "\n" 151 | else 152 | info << sprintf("# %-#{max_size}.#{max_size}s:%-#{bare_type_allowance}.#{bare_type_allowance}s %s", col.name, col_type, attrs.join(", ")).rstrip + "\n" 153 | end 154 | end 155 | 156 | if options[:show_indexes] && klass.table_exists? 157 | info << get_index_info(klass, options) 158 | end 159 | 160 | if options[:format_rdoc] 161 | info << "#--\n" 162 | info << "# #{END_MARK}\n" 163 | info << "#++\n\n" 164 | else 165 | info << "#\n\n" 166 | end 167 | end 168 | 169 | def get_index_info(klass, options={}) 170 | if(options[:format_markdown]) 171 | index_info = "#\n# ### Indexes\n#\n" 172 | else 173 | index_info = "#\n# Indexes\n#\n" 174 | end 175 | 176 | indexes = klass.connection.indexes(klass.table_name) 177 | return "" if indexes.empty? 178 | 179 | max_size = indexes.collect{|index| index.name.size}.max + 1 180 | indexes.sort_by{|index| index.name}.each do |index| 181 | if(options[:format_markdown]) 182 | index_info << sprintf("# * `%s`%s:\n# * **`%s`**\n", index.name, index.unique ? " (_unique_)" : "", index.columns.join("`**\n# * **`")) 183 | else 184 | index_info << sprintf("# %-#{max_size}.#{max_size}s %s %s", index.name, "(#{index.columns.join(",")})", index.unique ? "UNIQUE" : "").rstrip + "\n" 185 | end 186 | end 187 | return index_info 188 | end 189 | 190 | # Add a schema block to a file. If the file already contains 191 | # a schema info block (a comment starting with "== Schema Information"), check if it 192 | # matches the block that is already there. If so, leave it be. If not, remove the old 193 | # info block and write a new one. 194 | # Returns true or false depending on whether the file was modified. 195 | # 196 | # === Options (opts) 197 | # :force:: whether to update the file even if it doesn't seem to need it. 198 | # :position_in_*:: where to place the annotated section in fixture or model file, 199 | # :before or :after. Default is :before. 200 | # 201 | def annotate_one_file(file_name, info_block, position, options={}) 202 | if File.exist?(file_name) 203 | old_content = File.read(file_name) 204 | return false if(old_content =~ /# -\*- SkipSchemaAnnotations.*\n/) 205 | 206 | # Ignore the Schema version line because it changes with each migration 207 | header_pattern = /(^# Table name:.*?\n(#.*[\r]?\n)*[\r]?\n)/ 208 | old_header = old_content.match(header_pattern).to_s 209 | new_header = info_block.match(header_pattern).to_s 210 | 211 | column_pattern = /^#[\t ]+\w+[\t ]+.+$/ 212 | old_columns = old_header && old_header.scan(column_pattern).sort 213 | new_columns = new_header && new_header.scan(column_pattern).sort 214 | 215 | encoding = Regexp.new(/(^#\s*encoding:.*\n)|(^# coding:.*\n)|(^# -\*- coding:.*\n)/) 216 | encoding_header = old_content.match(encoding).to_s 217 | 218 | if old_columns == new_columns && !options[:force] 219 | return false 220 | else 221 | 222 | # todo: figure out if we need to extract any logic from this merge chunk 223 | # <<<<<<< HEAD 224 | # # Replace the old schema info with the new schema info 225 | # new_content = old_content.sub(/^# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n*/, info_block) 226 | # # But, if there *was* no old schema info, we simply need to insert it 227 | # if new_content == old_content 228 | # old_content.sub!(encoding, '') 229 | # new_content = options[:position] == 'after' ? 230 | # (encoding_header + (old_content =~ /\n$/ ? old_content : old_content + "\n") + info_block) : 231 | # (encoding_header + info_block + old_content) 232 | # end 233 | # ======= 234 | 235 | # Strip the old schema info, and insert new schema info. 236 | old_content.sub!(encoding, '') 237 | old_content.sub!(PATTERN, '') 238 | 239 | new_content = options[position].to_s == 'after' ? 240 | (encoding_header + (old_content.rstrip + "\n\n" + info_block)) : 241 | (encoding_header + info_block + old_content) 242 | 243 | File.open(file_name, "wb") { |f| f.puts new_content } 244 | return true 245 | end 246 | else 247 | return false 248 | end 249 | end 250 | 251 | def remove_annotation_of_file(file_name) 252 | if File.exist?(file_name) 253 | content = File.read(file_name) 254 | 255 | content.sub!(PATTERN, '') 256 | 257 | File.open(file_name, "wb") { |f| f.puts content } 258 | 259 | return true 260 | else 261 | return false 262 | end 263 | end 264 | 265 | # Given the name of an ActiveRecord class, create a schema 266 | # info block (basically a comment containing information 267 | # on the columns and their types) and put it at the front 268 | # of the model and fixture source files. 269 | # Returns true or false depending on whether the source 270 | # files were modified. 271 | # 272 | # === Options (opts) 273 | # :position_in_class:: where to place the annotated section in model file 274 | # :position_in_test:: where to place the annotated section in test/spec file(s) 275 | # :position_in_fixture:: where to place the annotated section in fixture file 276 | # :position_in_factory:: where to place the annotated section in factory file 277 | # :exclude_tests:: whether to skip modification of test/spec files 278 | # :exclude_fixtures:: whether to skip modification of fixture files 279 | # :exclude_factories:: whether to skip modification of factory files 280 | # 281 | def annotate(klass, file, header, options={}) 282 | begin 283 | info = get_schema_info(klass, header, options) 284 | did_annotate = false 285 | model_name = klass.name.underscore 286 | table_name = klass.table_name 287 | model_file_name = File.join(model_dir, file) 288 | 289 | if annotate_one_file(model_file_name, info, :position_in_class, options_with_position(options, :position_in_class)) 290 | did_annotate = true 291 | end 292 | 293 | unless options[:exclude_tests] 294 | did_annotate = TEST_PATTERNS. 295 | map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)] }. 296 | map { |pat| find_test_file(*pat) }. 297 | map { |file| annotate_one_file(file, info, :position_in_test, options_with_position(options, :position_in_test)) }. 298 | detect { |result| result } || did_annotate 299 | end 300 | 301 | unless options[:exclude_fixtures] 302 | did_annotate = FIXTURE_PATTERNS. 303 | map { |file| resolve_filename(file, model_name, table_name) }. 304 | map { |file| annotate_one_file(file, info, :position_in_fixture, options_with_position(options, :position_in_fixture)) }. 305 | detect { |result| result } || did_annotate 306 | end 307 | 308 | unless options[:exclude_factories] 309 | did_annotate = FACTORY_PATTERNS. 310 | map { |file| resolve_filename(file, model_name, table_name) }. 311 | map { |file| annotate_one_file(file, info, :position_in_factory, options_with_position(options, :position_in_factory)) }. 312 | detect { |result| result } || did_annotate 313 | end 314 | 315 | return did_annotate 316 | rescue Exception => e 317 | puts "Unable to annotate #{file}: #{e.message}" 318 | puts "\t" + e.backtrace.join("\n\t") if options[:trace] 319 | end 320 | end 321 | 322 | # position = :position_in_fixture or :position_in_class 323 | def options_with_position(options, position_in) 324 | options.merge(:position=>(options[position_in] || options[:position])) 325 | end 326 | 327 | # Return a list of the model files to annotate. If we have 328 | # command line arguments, they're assumed to be either 329 | # the underscore or CamelCase versions of model names. 330 | # Otherwise we take all the model files in the 331 | # model_dir directory. 332 | def get_model_files(options) 333 | if(!options[:is_rake]) 334 | models = ARGV.dup 335 | models.shift 336 | else 337 | models = [] 338 | end 339 | models.reject!{|m| m.match(/^(.*)=/)} 340 | if models.empty? 341 | begin 342 | Dir.chdir(model_dir) do 343 | models = if options[:ignore_model_sub_dir] 344 | Dir["*.rb"] 345 | else 346 | Dir["**/*.rb"] 347 | end 348 | end 349 | rescue SystemCallError 350 | puts "No models found in directory '#{model_dir}'." 351 | puts "Either specify models on the command line, or use the --model-dir option." 352 | puts "Call 'annotate --help' for more info." 353 | exit 1 354 | end 355 | end 356 | models 357 | end 358 | 359 | # Retrieve the classes belonging to the model names we're asked to process 360 | # Check for namespaced models in subdirectories as well as models 361 | # in subdirectories without namespacing. 362 | def get_model_class(file) 363 | # this is for non-rails projects, which don't get Rails auto-require magic 364 | require File.expand_path("#{model_dir}/#{file}") unless Module.const_defined?(:Rails) 365 | model_path = file.gsub(/\.rb$/, '') 366 | get_loaded_model(model_path) || get_loaded_model(model_path.split('/').last) 367 | end 368 | 369 | # Retrieve loaded model class by path to the file where it's supposed to be defined. 370 | def get_loaded_model(model_path) 371 | ObjectSpace.each_object(::Class). 372 | select do |c| 373 | Class === c and # note: we use === to avoid a bug in activesupport 2.3.14 OptionMerger vs. is_a? 374 | c.ancestors.respond_to?(:include?) and # to fix FactoryGirl bug, see https://github.com/ctran/annotate_models/pull/82 375 | c.ancestors.include?(ActiveRecord::Base) 376 | end. 377 | detect { |c| ActiveSupport::Inflector.underscore(c) == model_path } 378 | end 379 | 380 | # We're passed a name of things that might be 381 | # ActiveRecord models. If we can find the class, and 382 | # if its a subclass of ActiveRecord::Base, 383 | # then pass it to the associated block 384 | def do_annotations(options={}) 385 | header = options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup 386 | 387 | if options[:include_version] 388 | version = ActiveRecord::Migrator.current_version rescue 0 389 | if version > 0 390 | header << "\n# Schema version: #{version}" 391 | end 392 | end 393 | 394 | self.model_dir = options[:model_dir] if options[:model_dir] 395 | 396 | annotated = [] 397 | get_model_files(options).each do |file| 398 | annotate_model_file(annotated, file, header, options) 399 | end 400 | if annotated.empty? 401 | puts "Nothing annotated." 402 | else 403 | puts "Annotated (#{annotated.length}): #{annotated.join(', ')}" 404 | end 405 | end 406 | 407 | def annotate_model_file(annotated, file, header, options) 408 | begin 409 | klass = get_model_class(file) 410 | if klass && klass < ActiveRecord::Base && !klass.abstract_class? 411 | if annotate(klass, file, header, options) 412 | annotated << klass 413 | end 414 | end 415 | rescue Exception => e 416 | puts "Unable to annotate #{file}: #{e.message}" 417 | puts "\t" + e.backtrace.join("\n\t") if options[:trace] 418 | end 419 | end 420 | 421 | def remove_annotations(options={}) 422 | 423 | self.model_dir = options[:model_dir] if options[:model_dir] 424 | deannotated = [] 425 | deannotated_klass = false 426 | get_model_files(options).each do |file| 427 | begin 428 | klass = get_model_class(file) 429 | if klass < ActiveRecord::Base && !klass.abstract_class? 430 | model_name = klass.name.underscore 431 | table_name = klass.table_name 432 | model_file_name = File.join(model_dir, file) 433 | deannotated_klass = true if(remove_annotation_of_file(model_file_name)) 434 | 435 | TEST_PATTERNS. 436 | map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)]}. 437 | map { |pat| find_test_file(*pat) }.each do |file| 438 | if(File.exist?(file)) 439 | remove_annotation_of_file(file) 440 | deannotated_klass = true 441 | end 442 | end 443 | 444 | (FIXTURE_PATTERNS + FACTORY_PATTERNS). 445 | map { |file| resolve_filename(file, model_name, table_name) }. 446 | each do |file| 447 | if File.exist?(file) 448 | remove_annotation_of_file(file) 449 | deannotated_klass = true 450 | end 451 | end 452 | end 453 | deannotated << klass if(deannotated_klass) 454 | rescue Exception => e 455 | puts "Unable to deannotate #{file}: #{e.message}" 456 | puts "\t" + e.backtrace.join("\n\t") if options[:trace] 457 | end 458 | end 459 | puts "Removed annotations from: #{deannotated.join(', ')}" 460 | end 461 | 462 | def find_test_file(dir, file_name) 463 | Dir.glob(File.join(dir, "**", file_name)).first || File.join(dir, file_name) 464 | end 465 | 466 | def resolve_filename(filename_template, model_name, table_name) 467 | return filename_template. 468 | gsub('%MODEL_NAME%', model_name). 469 | gsub('%TABLE_NAME%', table_name || model_name.pluralize) 470 | end 471 | end 472 | end 473 | --------------------------------------------------------------------------------