aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Rakefile3
-rw-r--r--activesupport/lib/active_support/mini.rb4
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo-0.3.13/tzinfo/ruby_core_support.rb110
-rw-r--r--railties/Rakefile204
-rwxr-xr-xrailties/bin/rails13
-rw-r--r--railties/lib/commands/destroy.rb12
-rwxr-xr-xrailties/lib/commands/generate.rb12
-rw-r--r--railties/lib/commands/update.rb12
-rw-r--r--railties/lib/generators.rb300
-rw-r--r--railties/lib/generators/action_orm.rb74
-rw-r--r--railties/lib/generators/actions.rb263
-rw-r--r--railties/lib/generators/active_record.rb57
-rw-r--r--railties/lib/generators/active_record/migration/migration_generator.rb25
-rw-r--r--railties/lib/generators/active_record/migration/templates/migration.rb (renamed from railties/lib/rails_generator/generators/components/migration/templates/migration.rb)2
-rw-r--r--railties/lib/generators/active_record/model/model_generator.rb35
-rw-r--r--railties/lib/generators/active_record/model/templates/migration.rb (renamed from railties/lib/rails_generator/generators/components/model/templates/migration.rb)4
-rw-r--r--railties/lib/generators/active_record/model/templates/model.rb (renamed from railties/lib/rails_generator/generators/components/model/templates/model.rb)2
-rw-r--r--railties/lib/generators/active_record/observer/observer_generator.rb15
-rw-r--r--railties/lib/generators/active_record/observer/templates/observer.rb (renamed from railties/lib/rails_generator/generators/components/observer/templates/observer.rb)0
-rw-r--r--railties/lib/generators/active_record/session_migration/session_migration_generator.rb20
-rw-r--r--railties/lib/generators/active_record/session_migration/templates/migration.rb (renamed from railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb)2
-rw-r--r--railties/lib/generators/base.rb302
-rw-r--r--railties/lib/generators/erb.rb8
-rw-r--r--railties/lib/generators/erb/controller/controller_generator.rb21
-rw-r--r--railties/lib/generators/erb/controller/templates/view.html.erb2
-rw-r--r--railties/lib/generators/erb/mailer/mailer_generator.rb20
-rw-r--r--railties/lib/generators/erb/mailer/templates/view.erb3
-rw-r--r--railties/lib/generators/erb/scaffold/scaffold_generator.rb54
-rw-r--r--railties/lib/generators/erb/scaffold/templates/edit.html.erb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb)0
-rw-r--r--railties/lib/generators/erb/scaffold/templates/index.html.erb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb)4
-rw-r--r--railties/lib/generators/erb/scaffold/templates/layout.html.erb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb)0
-rw-r--r--railties/lib/generators/erb/scaffold/templates/new.html.erb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb)0
-rw-r--r--railties/lib/generators/erb/scaffold/templates/show.html.erb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb)4
-rw-r--r--railties/lib/generators/generated_attribute.rb (renamed from railties/lib/rails_generator/generated_attribute.rb)16
-rw-r--r--railties/lib/generators/migration.rb65
-rw-r--r--railties/lib/generators/named_base.rb162
-rw-r--r--railties/lib/generators/rails/app/USAGE (renamed from railties/lib/rails_generator/generators/applications/app/USAGE)0
-rw-r--r--railties/lib/generators/rails/app/app_generator.rb210
-rw-r--r--railties/lib/generators/rails/app/templates/README243
-rwxr-xr-xrailties/lib/generators/rails/app/templates/Rakefile (renamed from railties/fresh_rakefile)0
-rw-r--r--railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb (renamed from railties/helpers/application_controller.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb (renamed from railties/helpers/application_helper.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/app/models/.empty_directory (renamed from railties/configs/empty.log)0
-rw-r--r--railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory (renamed from railties/html/favicon.ico)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/boot.rb (renamed from railties/environments/boot.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/frontbase.yml (renamed from railties/configs/databases/frontbase.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml (renamed from railties/configs/databases/ibm_db.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/mysql.yml (renamed from railties/configs/databases/mysql.yml)12
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/oracle.yml (renamed from railties/configs/databases/oracle.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/postgresql.yml (renamed from railties/configs/databases/postgresql.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/sqlite2.yml (renamed from railties/configs/databases/sqlite2.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml (renamed from railties/configs/databases/sqlite3.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/environment.rb (renamed from railties/environments/environment.rb)16
-rw-r--r--railties/lib/generators/rails/app/templates/config/environments/development.rb (renamed from railties/environments/development.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/environments/production.rb (renamed from railties/environments/production.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/environments/test.rb (renamed from railties/environments/test.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb (renamed from railties/configs/initializers/backtrace_silencers.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/initializers/inflections.rb (renamed from railties/configs/initializers/inflections.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb (renamed from railties/configs/initializers/mime_types.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/initializers/new_rails_defaults.rb (renamed from railties/configs/initializers/new_rails_defaults.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt (renamed from railties/configs/initializers/session_store.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/locales/en.yml (renamed from railties/configs/locales/en.yml)0
-rw-r--r--railties/lib/generators/rails/app/templates/config/routes.rb (renamed from railties/configs/routes.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/db/seeds.rb (renamed from railties/configs/seeds.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/dispatchers/config.ru (renamed from railties/dispatches/config.ru)0
-rwxr-xr-xrailties/lib/generators/rails/app/templates/dispatchers/dispatch.fcgi (renamed from railties/dispatches/dispatch.fcgi)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/dispatchers/dispatch.rb (renamed from railties/dispatches/dispatch.rb)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/dispatchers/gateway.cgi (renamed from railties/dispatches/gateway.cgi)2
-rw-r--r--railties/lib/generators/rails/app/templates/doc/README_FOR_APP (renamed from railties/doc/README_FOR_APP)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/404.html (renamed from railties/html/404.html)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/422.html (renamed from railties/html/422.html)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/500.html (renamed from railties/html/500.html)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/favicon.ico (renamed from railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/images/rails.png (renamed from railties/html/images/rails.png)bin6646 -> 6646 bytes
-rw-r--r--railties/lib/generators/rails/app/templates/public/index.html (renamed from railties/html/index.html)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/application.js (renamed from railties/html/javascripts/application.js)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/controls.js (renamed from railties/html/javascripts/controls.js)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js (renamed from railties/html/javascripts/dragdrop.js)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/effects.js (renamed from railties/html/javascripts/effects.js)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/javascripts/prototype.js (renamed from railties/html/javascripts/prototype.js)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/robots.txt (renamed from railties/html/robots.txt)0
-rw-r--r--railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory (renamed from railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml)0
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/about.tt (renamed from railties/bin/about)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/console.tt (renamed from railties/bin/console)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/dbconsole.tt (renamed from railties/bin/dbconsole)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/destroy.tt (renamed from railties/bin/destroy)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/generate.tt (renamed from railties/bin/generate)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/performance/benchmarker.tt (renamed from railties/bin/performance/benchmarker)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/performance/profiler.tt (renamed from railties/bin/performance/profiler)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/plugin.tt (renamed from railties/bin/plugin)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/runner.tt (renamed from railties/bin/runner)2
-rwxr-xr-xrailties/lib/generators/rails/app/templates/script/server.tt (renamed from railties/bin/server)2
-rw-r--r--railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory (renamed from railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/test/functional/.empty_directory (renamed from railties/test/fixtures/lib/generators/missing_class/templates/.gitignore)0
-rw-r--r--railties/lib/generators/rails/app/templates/test/integration/.empty_directory (renamed from railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore)0
-rw-r--r--railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb (renamed from railties/helpers/performance_test.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/test/test_helper.rb (renamed from railties/helpers/test_helper.rb)0
-rw-r--r--railties/lib/generators/rails/app/templates/test/unit/.empty_directory (renamed from railties/test/fixtures/lib/generators/missing_templates/.gitignore)0
-rw-r--r--railties/lib/generators/rails/controller/USAGE18
-rw-r--r--railties/lib/generators/rails/controller/controller_generator.rb14
-rw-r--r--railties/lib/generators/rails/controller/templates/controller.rb (renamed from railties/lib/rails_generator/generators/components/controller/templates/controller.rb)0
-rw-r--r--railties/lib/generators/rails/generator/USAGE11
-rw-r--r--railties/lib/generators/rails/generator/generator_generator.rb25
-rw-r--r--railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt5
-rw-r--r--railties/lib/generators/rails/generator/templates/USAGE.tt (renamed from railties/lib/rails_generator/generators/components/plugin/templates/USAGE)0
-rw-r--r--railties/lib/generators/rails/generator/templates/templates/.empty_directory0
-rw-r--r--railties/lib/generators/rails/helper/USAGE17
-rw-r--r--railties/lib/generators/rails/helper/helper_generator.rb13
-rw-r--r--railties/lib/generators/rails/helper/templates/helper.rb (renamed from railties/lib/rails_generator/generators/components/controller/templates/helper.rb)0
-rw-r--r--railties/lib/generators/rails/integration_test/USAGE (renamed from railties/lib/rails_generator/generators/components/integration_test/USAGE)6
-rw-r--r--railties/lib/generators/rails/integration_test/integration_test_generator.rb7
-rw-r--r--railties/lib/generators/rails/mailer/USAGE (renamed from railties/lib/rails_generator/generators/components/mailer/USAGE)5
-rw-r--r--railties/lib/generators/rails/mailer/mailer_generator.rb14
-rw-r--r--railties/lib/generators/rails/mailer/templates/mailer.rb (renamed from railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb)0
-rw-r--r--railties/lib/generators/rails/metal/USAGE (renamed from railties/lib/rails_generator/generators/components/metal/USAGE)0
-rw-r--r--railties/lib/generators/rails/metal/metal_generator.rb11
-rw-r--r--railties/lib/generators/rails/metal/templates/metal.rb (renamed from railties/lib/rails_generator/generators/components/metal/templates/metal.rb)0
-rw-r--r--railties/lib/generators/rails/migration/USAGE (renamed from railties/lib/rails_generator/generators/components/migration/USAGE)4
-rw-r--r--railties/lib/generators/rails/migration/migration_generator.rb8
-rw-r--r--railties/lib/generators/rails/model/USAGE (renamed from railties/lib/rails_generator/generators/components/model/USAGE)15
-rw-r--r--railties/lib/generators/rails/model/model_generator.rb8
-rw-r--r--railties/lib/generators/rails/model_subclass/model_subclass_generator.rb11
-rw-r--r--railties/lib/generators/rails/observer/USAGE (renamed from railties/lib/rails_generator/generators/components/observer/USAGE)7
-rw-r--r--railties/lib/generators/rails/observer/observer_generator.rb7
-rw-r--r--railties/lib/generators/rails/performance_test/USAGE (renamed from railties/lib/rails_generator/generators/components/performance_test/USAGE)6
-rw-r--r--railties/lib/generators/rails/performance_test/performance_test_generator.rb7
-rw-r--r--railties/lib/generators/rails/plugin/USAGE13
-rw-r--r--railties/lib/generators/rails/plugin/plugin_generator.rb47
-rw-r--r--railties/lib/generators/rails/plugin/templates/MIT-LICENSE (renamed from railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/README (renamed from railties/lib/rails_generator/generators/components/plugin/templates/README)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/Rakefile (renamed from railties/lib/rails_generator/generators/components/plugin/templates/Rakefile)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/init.rb (renamed from railties/lib/rails_generator/generators/components/plugin/templates/init.rb)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/install.rb (renamed from railties/lib/rails_generator/generators/components/plugin/templates/install.rb)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt (renamed from railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/tasks/%file_name%_tasks.rake.tt (renamed from railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake)0
-rw-r--r--railties/lib/generators/rails/plugin/templates/uninstall.rb (renamed from railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb)0
-rw-r--r--railties/lib/generators/rails/resource/USAGE (renamed from railties/lib/rails_generator/generators/components/resource/USAGE)8
-rw-r--r--railties/lib/generators/rails/resource/resource_generator.rb40
-rw-r--r--railties/lib/generators/rails/scaffold/USAGE (renamed from railties/lib/rails_generator/generators/components/scaffold/USAGE)2
-rw-r--r--railties/lib/generators/rails/scaffold/scaffold_generator.rb12
-rw-r--r--railties/lib/generators/rails/scaffold_controller/USAGE20
-rw-r--r--railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb26
-rw-r--r--railties/lib/generators/rails/scaffold_controller/templates/controller.rb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb)26
-rw-r--r--railties/lib/generators/rails/session_migration/USAGE8
-rw-r--r--railties/lib/generators/rails/session_migration/session_migration_generator.rb8
-rw-r--r--railties/lib/generators/rails/stylesheets/USAGE5
-rw-r--r--railties/lib/generators/rails/stylesheets/stylesheets_generator.rb9
-rw-r--r--railties/lib/generators/rails/stylesheets/templates/scaffold.css (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/style.css)0
-rw-r--r--railties/lib/generators/test_unit.rb8
-rw-r--r--railties/lib/generators/test_unit/controller/controller_generator.rb14
-rw-r--r--railties/lib/generators/test_unit/controller/templates/functional_test.rb (renamed from railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/helper/helper_generator.rb13
-rw-r--r--railties/lib/generators/test_unit/helper/templates/helper_test.rb (renamed from railties/lib/rails_generator/generators/components/controller/templates/helper_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/integration/integration_generator.rb13
-rw-r--r--railties/lib/generators/test_unit/integration/templates/integration_test.rb (renamed from railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/mailer/mailer_generator.rb21
-rw-r--r--railties/lib/generators/test_unit/mailer/templates/fixture3
-rw-r--r--railties/lib/generators/test_unit/mailer/templates/unit_test.rb (renamed from railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/model/model_generator.rb24
-rw-r--r--railties/lib/generators/test_unit/model/templates/fixtures.yml (renamed from railties/lib/rails_generator/generators/components/model/templates/fixtures.yml)0
-rw-r--r--railties/lib/generators/test_unit/model/templates/unit_test.rb (renamed from railties/lib/rails_generator/generators/components/model/templates/unit_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/observer/observer_generator.rb13
-rw-r--r--railties/lib/generators/test_unit/observer/templates/unit_test.rb (renamed from railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/performance/performance_generator.rb13
-rw-r--r--railties/lib/generators/test_unit/performance/templates/performance_test.rb (renamed from railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/plugin/plugin_generator.rb13
-rw-r--r--railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt (renamed from railties/lib/rails_generator/generators/components/model_subclass/templates/unit_test.rb)0
-rw-r--r--railties/lib/generators/test_unit/plugin/templates/test_helper.rb (renamed from railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb)0
-rw-r--r--railties/lib/generators/test_unit/scaffold/scaffold_generator.rb17
-rw-r--r--railties/lib/generators/test_unit/scaffold/templates/functional_test.rb (renamed from railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb)2
-rw-r--r--railties/lib/initializer.rb9
-rw-r--r--railties/lib/rails/configuration.rb48
-rw-r--r--railties/lib/rails_generator.rb38
-rw-r--r--railties/lib/rails_generator/base.rb266
-rw-r--r--railties/lib/rails_generator/commands.rb621
-rw-r--r--railties/lib/rails_generator/generators/applications/app/app_generator.rb263
-rw-r--r--railties/lib/rails_generator/generators/applications/app/scm/git.rb16
-rw-r--r--railties/lib/rails_generator/generators/applications/app/scm/scm.rb8
-rw-r--r--railties/lib/rails_generator/generators/applications/app/scm/svn.rb7
-rw-r--r--railties/lib/rails_generator/generators/applications/app/template_runner.rb401
-rw-r--r--railties/lib/rails_generator/generators/components/controller/USAGE30
-rw-r--r--railties/lib/rails_generator/generators/components/controller/controller_generator.rb43
-rw-r--r--railties/lib/rails_generator/generators/components/controller/templates/view.html.erb2
-rw-r--r--railties/lib/rails_generator/generators/components/helper/USAGE24
-rw-r--r--railties/lib/rails_generator/generators/components/helper/helper_generator.rb25
-rw-r--r--railties/lib/rails_generator/generators/components/helper/templates/helper.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/helper/templates/helper_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb16
-rw-r--r--railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb30
-rw-r--r--railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb3
-rw-r--r--railties/lib/rails_generator/generators/components/mailer/templates/view.erb3
-rw-r--r--railties/lib/rails_generator/generators/components/metal/metal_generator.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/migration/migration_generator.rb20
-rw-r--r--railties/lib/rails_generator/generators/components/model/model_generator.rb45
-rw-r--r--railties/lib/rails_generator/generators/components/model_subclass/USAGE13
-rw-r--r--railties/lib/rails_generator/generators/components/model_subclass/model_subclass_generator.rb32
-rw-r--r--railties/lib/rails_generator/generators/components/model_subclass/templates/model.rb3
-rw-r--r--railties/lib/rails_generator/generators/components/observer/observer_generator.rb16
-rw-r--r--railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb16
-rw-r--r--railties/lib/rails_generator/generators/components/plugin/USAGE25
-rw-r--r--railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb39
-rw-r--r--railties/lib/rails_generator/generators/components/plugin/templates/generator.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/resource/resource_generator.rb76
-rw-r--r--railties/lib/rails_generator/generators/components/resource/templates/controller.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb8
-rw-r--r--railties/lib/rails_generator/generators/components/resource/templates/helper.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb102
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb2
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb4
-rw-r--r--railties/lib/rails_generator/generators/components/session_migration/USAGE10
-rw-r--r--railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb18
-rw-r--r--railties/lib/rails_generator/lookup.rb249
-rw-r--r--railties/lib/rails_generator/manifest.rb53
-rw-r--r--railties/lib/rails_generator/options.rb150
-rw-r--r--railties/lib/rails_generator/scripts.rb89
-rw-r--r--railties/lib/rails_generator/scripts/destroy.rb29
-rw-r--r--railties/lib/rails_generator/scripts/generate.rb7
-rw-r--r--railties/lib/rails_generator/scripts/update.rb12
-rw-r--r--railties/lib/rails_generator/secret_key_generator.rb24
-rw-r--r--railties/lib/rails_generator/simple_logger.rb46
-rw-r--r--railties/lib/rails_generator/spec.rb44
-rw-r--r--railties/lib/tasks/databases.rake6
-rw-r--r--railties/lib/tasks/documentation.rake2
-rw-r--r--railties/lib/tasks/framework.rake68
-rw-r--r--railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc75
-rw-r--r--railties/lib/vendor/thor-0.11.3/LICENSE20
-rw-r--r--railties/lib/vendor/thor-0.11.3/README.markdown247
-rwxr-xr-xrailties/lib/vendor/thor-0.11.3/bin/rake2thor87
-rwxr-xr-xrailties/lib/vendor/thor-0.11.3/bin/thor7
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor.rb240
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb270
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb102
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb87
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb133
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb195
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb78
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/base.rb516
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb75
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb102
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/error.rb27
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/group.rb263
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb172
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb4
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb67
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb145
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb132
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb142
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb291
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb72
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb216
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb106
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/task.rb108
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb4
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb35
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb31
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb70
-rw-r--r--railties/lib/vendor/thor-0.11.3/lib/thor/util.rb229
-rw-r--r--railties/test/boot_test.rb2
-rw-r--r--railties/test/fixtures/lib/generators/active_record/fixjour/fixjour_generator.rb8
-rw-r--r--railties/test/fixtures/lib/generators/fixjour_generator.rb2
-rw-r--r--railties/test/fixtures/lib/generators/rails/javascripts_generator.rb4
-rw-r--r--railties/test/fixtures/lib/generators/working/working_generator.rb2
-rw-r--r--railties/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb4
-rw-r--r--railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb2
-rw-r--r--railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb3
-rw-r--r--railties/test/generator_lookup_test.rb42
-rw-r--r--railties/test/generators/actions_test.rb177
-rw-r--r--railties/test/generators/app_generator_test.rb182
-rw-r--r--railties/test/generators/controller_generator_test.rb80
-rw-r--r--railties/test/generators/generator_generator_test.rb26
-rw-r--r--railties/test/generators/generator_test_helper.rb303
-rw-r--r--railties/test/generators/generators_test_helper.rb101
-rw-r--r--railties/test/generators/helper_generator_test.rb60
-rw-r--r--railties/test/generators/integration_test_generator_test.rb18
-rw-r--r--railties/test/generators/mailer_generator_test.rb52
-rw-r--r--railties/test/generators/metal_generator_test.rb23
-rw-r--r--railties/test/generators/migration_generator_test.rb59
-rw-r--r--railties/test/generators/model_generator_test.rb137
-rw-r--r--railties/test/generators/named_base_test.rb42
-rw-r--r--railties/test/generators/observer_generator_test.rb33
-rw-r--r--railties/test/generators/performance_test_generator_test.rb18
-rw-r--r--railties/test/generators/plugin_generator_test.rb56
-rw-r--r--railties/test/generators/rails_controller_generator_test.rb44
-rw-r--r--railties/test/generators/rails_helper_generator_test.rb36
-rw-r--r--railties/test/generators/rails_mailer_generator_test.rb29
-rw-r--r--railties/test/generators/rails_model_generator_test.rb48
-rw-r--r--railties/test/generators/rails_model_subclass_generator_test.rb15
-rw-r--r--railties/test/generators/rails_resource_generator_test.rb29
-rw-r--r--railties/test/generators/rails_scaffold_generator_test.rb150
-rw-r--r--railties/test/generators/rails_template_runner_test.rb216
-rw-r--r--railties/test/generators/resource_generator_test.rb106
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb112
-rw-r--r--railties/test/generators/scaffold_generator_test.rb129
-rw-r--r--railties/test/generators/session_migration_generator_test.rb23
-rw-r--r--railties/test/generators/stylesheets_generator_test.rb24
-rw-r--r--railties/test/generators_test.rb156
-rw-r--r--railties/test/initializer_test.rb93
-rw-r--r--railties/test/rails_generator_test.rb148
-rw-r--r--railties/test/secret_key_generation_test.rb38
302 files changed, 8766 insertions, 4449 deletions
diff --git a/.gitignore b/.gitignore
index 5357fbe481..2d879499fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,8 @@ actionmailer/pkg
activesupport/pkg
railties/pkg
railties/test/500.html
+railties/test/fixtures/tmp
+railties/test/initializer/root/log
railties/doc/guides/html/images
railties/doc/guides/html/stylesheets
benches
diff --git a/Rakefile b/Rakefile
index fbb7f2213c..5dd9f40310 100644
--- a/Rakefile
+++ b/Rakefile
@@ -38,7 +38,8 @@ Rake::RDocTask.new do |rdoc|
rdoc.rdoc_files.include('railties/CHANGELOG')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
rdoc.rdoc_files.include('railties/README')
- rdoc.rdoc_files.include('railties/lib/{*.rb,commands/*.rb,rails/*.rb,rails_generator/*.rb}')
+ rdoc.rdoc_files.include('railties/lib/{*.rb,commands/*.rb,rails/*.rb,generators/*.rb}')
+ rdoc.rdoc_files.exclude('railties/lib/vendor/*')
rdoc.rdoc_files.include('activerecord/README')
rdoc.rdoc_files.include('activerecord/CHANGELOG')
diff --git a/activesupport/lib/active_support/mini.rb b/activesupport/lib/active_support/mini.rb
index fe7ba48e58..b787650655 100644
--- a/activesupport/lib/active_support/mini.rb
+++ b/activesupport/lib/active_support/mini.rb
@@ -1,9 +1,9 @@
$LOAD_PATH.unshift File.dirname(__FILE__)
-require "core_ext/blank"
# whole object.rb pulls up rarely used introspection extensions
+require "core_ext/object/blank"
require "core_ext/object/metaclass"
require 'core_ext/array'
require 'core_ext/hash'
require 'core_ext/module/attribute_accessors'
-require 'core_ext/string/inflections' \ No newline at end of file
+require 'core_ext/string/inflections'
diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.13/tzinfo/ruby_core_support.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.13/tzinfo/ruby_core_support.rb
index 9a0441206b..b65eeaaae7 100644
--- a/activesupport/lib/active_support/vendor/tzinfo-0.3.13/tzinfo/ruby_core_support.rb
+++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.13/tzinfo/ruby_core_support.rb
@@ -1,56 +1,56 @@
-#--
-# Copyright (c) 2008 Philip Ross
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#++
-
-require 'date'
-require 'rational'
-
-module TZInfo
-
- # Methods to support different versions of Ruby.
- module RubyCoreSupport #:nodoc:
-
- # Use Rational.new! for performance reasons in Ruby 1.8.
- # This has been removed from 1.9, but Rational performs better.
- if Rational.respond_to? :new!
- def self.rational_new!(numerator, denominator = 1)
- Rational.new!(numerator, denominator)
- end
- else
- def self.rational_new!(numerator, denominator = 1)
- Rational(numerator, denominator)
- end
- end
-
- # Ruby 1.8.6 introduced new! and deprecated new0.
- # Ruby 1.9.0 removed new0.
- # We still need to support new0 for older versions of Ruby.
- if DateTime.respond_to? :new!
- def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
- DateTime.new!(ajd, of, sg)
- end
- else
- def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
- DateTime.new0(ajd, of, sg)
- end
- end
- end
+#--
+# Copyright (c) 2008 Philip Ross
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#++
+
+require 'date'
+require 'rational'
+
+module TZInfo
+
+ # Methods to support different versions of Ruby.
+ module RubyCoreSupport #:nodoc:
+
+ # Use Rational.new! for performance reasons in Ruby 1.8.
+ # This has been removed from 1.9, but Rational performs better.
+ if Rational.respond_to? :new!
+ def self.rational_new!(numerator, denominator = 1)
+ Rational.new!(numerator, denominator)
+ end
+ else
+ def self.rational_new!(numerator, denominator = 1)
+ Rational(numerator, denominator)
+ end
+ end
+
+ # Ruby 1.8.6 introduced new! and deprecated new0.
+ # Ruby 1.9.0 removed new0.
+ # We still need to support new0 for older versions of Ruby.
+ if DateTime.respond_to? :new!
+ def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
+ DateTime.new!(ajd, of, sg)
+ end
+ else
+ def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
+ DateTime.new0(ajd, of, sg)
+ end
+ end
+ end
end \ No newline at end of file
diff --git a/railties/Rakefile b/railties/Rakefile
index 61c094150a..3212bf3a4f 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -26,7 +26,8 @@ task :default => :test
## below passes. It's not ideal, but at least
## we can see the failures
task :test do
- Dir['test/**/*_test.rb'].all? do |file|
+ dir = ENV["TEST_DIR"] || "**"
+ Dir["test/#{dir}/*_test.rb"].all? do |file|
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
system(ruby, '-Itest', "-I#{File.dirname(__FILE__)}/../activesupport/lib", file)
end or raise "Failures"
@@ -40,56 +41,22 @@ Rake::TestTask.new("regular_test") do |t|
t.verbose = true
end
-
-BASE_DIRS = %w(
- app
- config/environments
- config/initializers
- config/locales
- db
- doc
- log
- lib
- lib/tasks
- public
- script
- script/performance
- test
- vendor
- vendor/plugins
- tmp/sessions
- tmp/cache
- tmp/sockets
- tmp/pids
-)
-
-APP_DIRS = %w( models controllers helpers views views/layouts )
-PUBLIC_DIRS = %w( images javascripts stylesheets )
-TEST_DIRS = %w( fixtures unit functional mocks mocks/development mocks/test )
-
-LOG_FILES = %w( server.log development.log test.log production.log )
-HTML_FILES = %w( 422.html 404.html 500.html index.html robots.txt favicon.ico images/rails.png
- javascripts/prototype.js javascripts/application.js
- javascripts/effects.js javascripts/dragdrop.js javascripts/controls.js )
-BIN_FILES = %w( about console destroy generate performance/benchmarker performance/profiler runner server plugin )
-
VENDOR_LIBS = %w( actionpack activerecord actionmailer activesupport activeresource railties )
-
desc "Generates a fresh Rails package with documentation"
-task :fresh_rails => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content, :generate_documentation ]
+task :fresh_rails => [ :clean, :create_rails, :copy_vendor_libraries, :generate_documentation ]
desc "Generates a fresh Rails package using GEMs with documentation"
-task :fresh_gem_rails => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_ties_content, :copy_gem_environment ]
+task :fresh_gem_rails => [ :clean, :create_rails ]
desc "Generates a fresh Rails package without documentation (faster)"
-task :fresh_rails_without_docs => [ :clean, :make_dir_structure, :initialize_file_stubs, :copy_vendor_libraries, :copy_ties_content ]
+task :fresh_rails_without_docs => [ :clean, :create_rails, :copy_vendor_libraries ]
-desc "Generates a fresh Rails package without documentation (faster)"
-task :fresh_rails_without_docs_using_links => [ :clean, :make_dir_structure, :initialize_file_stubs, :link_vendor_libraries, :copy_ties_content ]
+desc "Generates a fresh Rails package without documentation using links (faster)"
+task :fresh_rails_without_docs_using_links => [ :clean, :create_rails, :link_vendor_libraries ]
desc "Generates minimal Rails package using symlinks"
-task :dev => [ :clean, :make_dir_structure, :initialize_file_stubs, :link_vendor_libraries, :copy_ties_content ]
+task :dev => [ :clean, :create_rails, :link_vendor_libraries ]
desc "Packages the fresh Rails package with documentation"
task :package => [ :clean, :fresh_rails ] do
@@ -101,54 +68,31 @@ task :clean do
rm_rf PKG_DESTINATION
end
-# Get external spinoffs -------------------------------------------------------------------
+# Update spinoffs -------------------------------------------------------------------
-desc "Updates railties to the latest version of the javascript spinoffs"
-task :update_js do
- for js in %w( prototype controls dragdrop effects )
- rm "html/javascripts/#{js}.js"
- cp "./../actionpack/lib/action_view/helpers/javascripts/#{js}.js", "html/javascripts"
- end
+desc "Updates application README to the latest version Railties README"
+task :update_readme do
+ readme = "lib/generators/rails/app/templates/README"
+ rm readme
+ cp "./README", readme
end
-# Make directory structure ----------------------------------------------------------------
-
-def make_dest_dirs(dirs, path = '.')
- mkdir_p dirs.map { |dir| File.join(PKG_DESTINATION, path.to_s, dir) }
-end
-
-desc "Make the directory structure for the new Rails application"
-task :make_dir_structure => [ :make_base_dirs, :make_app_dirs, :make_public_dirs, :make_test_dirs ]
-
-task(:make_base_dirs) { make_dest_dirs BASE_DIRS }
-task(:make_app_dirs) { make_dest_dirs APP_DIRS, 'app' }
-task(:make_public_dirs) { make_dest_dirs PUBLIC_DIRS, 'public' }
-task(:make_test_dirs) { make_dest_dirs TEST_DIRS, 'test' }
-
-
-# Initialize file stubs -------------------------------------------------------------------
-
-desc "Initialize empty file stubs (such as for logging)"
-task :initialize_file_stubs => [ :initialize_log_files ]
+# Run application generator -------------------------------------------------------------
-task :initialize_log_files do
- log_dir = File.join(PKG_DESTINATION, 'log')
- chmod 0777, log_dir
- LOG_FILES.each do |log_file|
- log_path = File.join(log_dir, log_file)
- touch log_path
- chmod 0666, log_path
- end
+task :create_rails do
+ require File.join(File.dirname(__FILE__), 'lib', 'generators')
+ require 'generators/rails/app/app_generator'
+ Rails::Generators::AppGenerator.start [ File.basename(PKG_DESTINATION), "--quiet" ],
+ :destination_root => File.expand_path(File.dirname(PKG_DESTINATION))
end
-
# Copy Vendors ----------------------------------------------------------------------------
desc "Copy in all the Rails packages to vendor"
task :copy_vendor_libraries do
mkdir File.join(PKG_DESTINATION, 'vendor', 'rails')
VENDOR_LIBS.each { |dir| cp_r File.join('..', dir), File.join(PKG_DESTINATION, 'vendor', 'rails', dir) }
- FileUtils.rm_r(Dir.glob(File.join(PKG_DESTINATION, 'vendor', 'rails', "**", ".svn")))
+ FileUtils.rm_r(Dir.glob(File.join(PKG_DESTINATION, 'vendor', 'rails', "**", ".git")))
end
desc "Link in all the Rails packages to vendor"
@@ -158,96 +102,6 @@ task :link_vendor_libraries do
end
-# Copy Ties Content -----------------------------------------------------------------------
-
-desc "Make copies of all the default content of ties"
-task :copy_ties_content => [
- :copy_rootfiles, :copy_dispatches, :copy_html_files, :copy_application,
- :copy_configs, :copy_binfiles, :copy_test_helpers, :copy_app_doc_readme ]
-
-task :copy_dispatches do
- copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.rb")
- chmod 0755, "#{PKG_DESTINATION}/public/dispatch.rb"
-
- copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.cgi")
- chmod 0755, "#{PKG_DESTINATION}/public/dispatch.cgi"
-
- copy_with_rewritten_ruby_path("dispatches/dispatch.fcgi", "#{PKG_DESTINATION}/public/dispatch.fcgi")
- chmod 0755, "#{PKG_DESTINATION}/public/dispatch.fcgi"
-end
-
-task :copy_html_files do
- HTML_FILES.each { |file| cp File.join('html', file), File.join(PKG_DESTINATION, 'public', file) }
-end
-
-task :copy_application do
- cp "helpers/application_controller.rb", "#{PKG_DESTINATION}/app/controllers/application_controller.rb"
- cp "helpers/application_helper.rb", "#{PKG_DESTINATION}/app/helpers/application_helper.rb"
-end
-
-task :copy_configs do
- app_name = "rails"
- socket = nil
- require 'erb'
- File.open("#{PKG_DESTINATION}/config/database.yml", 'w') {|f| f.write ERB.new(IO.read("configs/databases/sqlite3.yml"), nil, '-').result(binding)}
-
- cp "configs/routes.rb", "#{PKG_DESTINATION}/config/routes.rb"
-
- cp "configs/initializers/backtrace_silencers.rb", "#{PKG_DESTINATION}/config/initializers/backtrace_silencers.rb"
- cp "configs/initializers/inflections.rb", "#{PKG_DESTINATION}/config/initializers/inflections.rb"
- cp "configs/initializers/mime_types.rb", "#{PKG_DESTINATION}/config/initializers/mime_types.rb"
- cp "configs/initializers/new_rails_defaults.rb", "#{PKG_DESTINATION}/config/initializers/new_rails_defaults.rb"
-
- cp "configs/locales/en.yml", "#{PKG_DESTINATION}/config/locales/en.yml"
-
- cp "configs/seeds.rb", "#{PKG_DESTINATION}/db/seeds.rb"
-
- cp "environments/boot.rb", "#{PKG_DESTINATION}/config/boot.rb"
- cp "environments/environment.rb", "#{PKG_DESTINATION}/config/environment.rb"
- cp "environments/production.rb", "#{PKG_DESTINATION}/config/environments/production.rb"
- cp "environments/development.rb", "#{PKG_DESTINATION}/config/environments/development.rb"
- cp "environments/test.rb", "#{PKG_DESTINATION}/config/environments/test.rb"
-
-end
-
-task :copy_binfiles do
- BIN_FILES.each do |file|
- dest_file = File.join(PKG_DESTINATION, 'script', file)
- copy_with_rewritten_ruby_path(File.join('bin', file), dest_file)
- chmod 0755, dest_file
- end
-end
-
-task :copy_rootfiles do
- cp "fresh_rakefile", "#{PKG_DESTINATION}/Rakefile"
- cp "README", "#{PKG_DESTINATION}/README"
- cp "CHANGELOG", "#{PKG_DESTINATION}/CHANGELOG"
-end
-
-task :copy_test_helpers do
- cp "helpers/test_helper.rb", "#{PKG_DESTINATION}/test/test_helper.rb"
-end
-
-task :copy_app_doc_readme do
- cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
-end
-
-def copy_with_rewritten_ruby_path(src_file, dest_file)
- ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
-
- File.open(dest_file, 'w') do |df|
- File.open(src_file) do |sf|
- line = sf.gets
- if (line =~ /#!.+ruby\s*/) != nil
- df.puts("#!#{ruby}")
- else
- df.puts(line)
- end
- df.write(sf.read)
- end
- end
-end
-
desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"'
task :generate_guides do
ENV["WARN_BROKEN_LINKS"] = "1" # authors can't disable this
@@ -265,7 +119,6 @@ task :generate_rails_framework_doc do
end
task :generate_app_doc do
- cp "doc/README_FOR_APP", "#{PKG_DESTINATION}/doc/README_FOR_APP"
system %{cd #{PKG_DESTINATION}; rake doc:app}
end
@@ -278,30 +131,17 @@ Rake::RDocTask.new { |rdoc|
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/*.rb')
rdoc.rdoc_files.include('lib/rails/*.rb')
- rdoc.rdoc_files.include('lib/rails_generator/*.rb')
+ rdoc.rdoc_files.include('lib/generators/*.rb')
rdoc.rdoc_files.include('lib/commands/**/*.rb')
}
# Generate GEM ----------------------------------------------------------------------------
-task :copy_gem_environment do
- cp "environments/environment.rb", "#{PKG_DESTINATION}/config/environment.rb"
- chmod 0755, dest_file
-end
-
-
PKG_FILES = FileList[
'[a-zA-Z]*',
'bin/**/*',
'builtin/**/*',
- 'configs/**/*',
- 'doc/**/*',
- 'dispatches/**/*',
- 'environments/**/*',
'guides/**/*',
- 'helpers/**/*',
- 'generators/**/*',
- 'html/**/*',
'lib/**/*'
] - [ 'test' ]
diff --git a/railties/bin/rails b/railties/bin/rails
index 6a0c675206..538d0cbc84 100755
--- a/railties/bin/rails
+++ b/railties/bin/rails
@@ -7,14 +7,9 @@ if %w(--version -v).include? ARGV.first
exit(0)
end
-freeze = ARGV.any? { |option| %w(--freeze -f).include?(option) }
+ARGV << "--help" if ARGV.empty?
-app_path = ARGV.first
+require File.dirname(__FILE__) + '/../lib/generators'
+require 'generators/rails/app/app_generator'
-require File.dirname(__FILE__) + '/../lib/rails_generator'
-
-require 'rails_generator/scripts/generate'
-Rails::Generator::Base.use_application_sources!
-Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app')
-
-Dir.chdir(app_path) { `rake rails:freeze:gems`; puts "froze" } if freeze \ No newline at end of file
+Rails::Generators::AppGenerator.start
diff --git a/railties/lib/commands/destroy.rb b/railties/lib/commands/destroy.rb
index f4b81d6511..5013d30b83 100644
--- a/railties/lib/commands/destroy.rb
+++ b/railties/lib/commands/destroy.rb
@@ -1,6 +1,10 @@
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'generators'))
require "#{RAILS_ROOT}/config/environment"
-require 'rails_generator'
-require 'rails_generator/scripts/destroy'
-ARGV.shift if ['--help', '-h'].include?(ARGV[0])
-Rails::Generator::Scripts::Destroy.new.run(ARGV)
+if ARGV.size == 0
+ Rails::Generators.help
+ exit
+end
+
+name = ARGV.shift
+Rails::Generators.invoke name, ARGV, :behavior => :revoke
diff --git a/railties/lib/commands/generate.rb b/railties/lib/commands/generate.rb
index 3d3db3d856..32cabcab10 100755
--- a/railties/lib/commands/generate.rb
+++ b/railties/lib/commands/generate.rb
@@ -1,6 +1,10 @@
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'generators'))
require "#{RAILS_ROOT}/config/environment"
-require 'rails_generator'
-require 'rails_generator/scripts/generate'
-ARGV.shift if ['--help', '-h'].include?(ARGV[0])
-Rails::Generator::Scripts::Generate.new.run(ARGV)
+if ARGV.size == 0
+ Rails::Generators.help
+ exit
+end
+
+name = ARGV.shift
+Rails::Generators.invoke name, ARGV, :behavior => :invoke
diff --git a/railties/lib/commands/update.rb b/railties/lib/commands/update.rb
index 83ef833300..f3b3ad0775 100644
--- a/railties/lib/commands/update.rb
+++ b/railties/lib/commands/update.rb
@@ -1,4 +1,10 @@
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'generators'))
require "#{RAILS_ROOT}/config/environment"
-require 'rails_generator'
-require 'rails_generator/scripts/update'
-Rails::Generator::Scripts::Update.new.run(ARGV)
+
+if ARGV.size == 0
+ Rails::Generators.help
+ exit
+end
+
+name = ARGV.shift
+Rails::Generators.invoke name, ARGV, :behavior => :skip
diff --git a/railties/lib/generators.rb b/railties/lib/generators.rb
new file mode 100644
index 0000000000..64ec808ee4
--- /dev/null
+++ b/railties/lib/generators.rb
@@ -0,0 +1,300 @@
+activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+$:.unshift(activesupport_path) if File.directory?(activesupport_path)
+
+begin
+ require 'active_support/mini'
+rescue LoadError
+ require 'rubygems'
+ gem 'activesupport'
+ require 'active_support/mini'
+end
+
+$:.unshift(File.dirname(__FILE__))
+
+require 'vendor/thor-0.11.3/lib/thor'
+require 'generators/base'
+require 'generators/named_base'
+
+module Rails
+ module Generators
+ DEFAULT_ALIASES = {
+ :rails => {
+ :actions => '-a',
+ :orm => '-o',
+ :resource_controller => '-c',
+ :scaffold_controller => '-c',
+ :stylesheets => '-y',
+ :template_engine => '-e',
+ :test_framework => '-t'
+ },
+
+ :test_unit => {
+ :fixture_replacement => '-r',
+ },
+
+ :plugin => {
+ :generator => '-g',
+ :tasks => '-r'
+ }
+ }
+
+ DEFAULT_OPTIONS = {
+ :active_record => {
+ :migration => true,
+ :timestamps => true
+ },
+
+ :erb => {
+ :form => false,
+ :layout => true
+ },
+
+ :rails => {
+ :force_plural => false,
+ :helper => true,
+ :layout => true,
+ :orm => :active_record,
+ :integration_tool => :test_unit,
+ :performance_tool => :test_unit,
+ :resource_controller => :controller,
+ :scaffold_controller => :scaffold_controller,
+ :singleton => false,
+ :stylesheets => true,
+ :template_engine => :erb,
+ :test_framework => :test_unit
+ },
+
+ :test_unit => {
+ :fixture => true,
+ :fixture_replacement => nil
+ },
+
+ :plugin => {
+ :generator => false,
+ :tasks => false
+ }
+ }
+
+ def self.aliases #:nodoc:
+ @@aliases ||= DEFAULT_ALIASES.dup
+ end
+
+ def self.options #:nodoc:
+ @@options ||= DEFAULT_OPTIONS.dup
+ end
+
+ # Hold configured generators fallbacks. If a plugin developer wants a
+ # generator group to fallback to another group in case of missing generators,
+ # they can add a fallback.
+ #
+ # For example, shoulda is considered a test_framework and is an extension
+ # of test_unit. However, most part of shoulda generators are similar to
+ # test_unit ones.
+ #
+ # Shoulda then can tell generators to search for test_unit generators when
+ # some of them are not available by adding a fallback:
+ #
+ # Rails::Generators.fallbacks[:shoulda] = :test_unit
+ #
+ def self.fallbacks
+ @@fallbacks ||= {}
+ end
+
+ # Remove the color from output.
+ #
+ def self.no_color!
+ Thor::Base.shell = Thor::Shell::Basic
+ end
+
+ # Generators load paths used on lookup. The lookup happens as:
+ #
+ # 1) builtin generators
+ # 2) frozen gems generators
+ # 3) rubygems gems generators (not available yet)
+ # 4) plugin generators
+ # 5) lib generators
+ # 6) ~/rails/generators
+ #
+ # TODO Add Rubygems generators (depends on dependencies system rework)
+ # TODO Remove hardcoded paths for all, except (1).
+ #
+ def self.load_path
+ @@load_path ||= begin
+ paths = []
+ paths << File.expand_path(File.join(File.dirname(__FILE__), "generators"))
+ if defined?(RAILS_ROOT)
+ paths += Dir[File.join(RAILS_ROOT, "vendor", "gems", "*", "lib", "generators")]
+ paths += Dir[File.join(RAILS_ROOT, "vendor", "plugins", "*", "lib", "generators")]
+ paths << File.join(RAILS_ROOT, "lib", "generators")
+ end
+ paths << File.join(Thor::Util.user_home, ".rails", "generators")
+ paths
+ end
+ end
+ load_path # Cache load paths. Needed to avoid __FILE__ pointing to wrong paths.
+
+ # Receives a namespace and tries different combinations to find a generator.
+ #
+ # ==== Examples
+ #
+ # find_by_namespace :webrat, :rails, :integration
+ #
+ # Will search for the following generators:
+ #
+ # "rails:generators:webrat", "webrat:generators:integration", "webrat"
+ #
+ # If the namespace has ":" included we consider that a absolute namespace
+ # was given and the lookup above does not happen. Just the name is searched.
+ #
+ # Finally, it deals with one kind of shortcut:
+ #
+ # find_by_namespace "test_unit:model"
+ #
+ # It will search for generators at:
+ #
+ # "test_unit:generators:model", "test_unit:model"
+ #
+ def self.find_by_namespace(name, base=nil, context=nil) #:nodoc:
+ name, attempts = name.to_s, []
+
+ case name.count(':')
+ when 1
+ base, name = name.split(':')
+ return find_by_namespace(name, base)
+ when 0
+ attempts << "#{base}:generators:#{name}" if base
+ attempts << "#{name}:generators:#{context}" if context
+ end
+
+ attempts << name
+ unloaded = attempts - namespaces
+ lookup(unloaded)
+
+ attempts.each do |namespace|
+ klass = Thor::Util.find_by_namespace(namespace)
+ return klass if klass
+ end
+
+ invoke_fallbacks_for(name, base)
+ end
+
+ # Receives a namespace, arguments and the behavior to invoke the generator.
+ # It's used as the default entry point for generate, destroy and update
+ # commands.
+ #
+ def self.invoke(namespace, args=ARGV, config={})
+ if klass = find_by_namespace(namespace, "rails")
+ args << "--help" if klass.arguments.any? { |a| a.required? } && args.empty?
+ klass.start args, config
+ else
+ puts "Could not find generator #{namespace}."
+ end
+ end
+
+ # Show help message with available generators.
+ #
+ def self.help
+ rails = Rails::Generators.builtin.map do |group, name|
+ name if group == "rails"
+ end
+ rails.compact!
+ rails.sort!
+
+ puts "Please select a generator."
+ puts "Builtin: #{rails.join(', ')}."
+
+ # Load paths and remove builtin
+ paths, others = load_path.dup, []
+ paths.shift
+
+ paths.each do |path|
+ tail = [ "*", "*", "*_generator.rb" ]
+
+ until tail.empty?
+ others += Dir[File.join(path, *tail)].collect do |file|
+ file.split('/')[-tail.size, 2].join(':').sub(/_generator\.rb$/, '')
+ end
+ tail.shift
+ end
+ end
+
+ others.sort!
+ puts "Others: #{others.join(', ')}." unless others.empty?
+ end
+
+ protected
+
+ # Return all defined namespaces.
+ #
+ def self.namespaces #:nodoc:
+ Thor::Base.subclasses.map{ |klass| klass.namespace }
+ end
+
+ # Keep builtin generators in an Array[Array[group, name]].
+ #
+ def self.builtin #:nodoc:
+ Dir[File.dirname(__FILE__) + '/generators/*/*'].collect do |file|
+ file.split('/')[-2, 2]
+ end
+ end
+
+ # Try callbacks for the given base.
+ #
+ def self.invoke_fallbacks_for(name, base)
+ return nil unless base && fallbacks[base.to_sym]
+
+ invoked_fallbacks = []
+
+ Array(fallbacks[base.to_sym]).each do |fallback|
+ next if invoked_fallbacks.include?(fallback)
+ invoked_fallbacks << fallback
+
+ klass = find_by_namespace(name, fallback)
+ return klass if klass
+ end
+
+ nil
+ end
+
+ # Receives namespaces in an array and tries to find matching generators
+ # in the load path. Each path is traversed into directory lookups. For
+ # example:
+ #
+ # rails:generators:model
+ #
+ # Becomes:
+ #
+ # generators/rails/model/model_generator.rb
+ # generators/rails/model_generator.rb
+ # generators/model_generator.rb
+ #
+ def self.lookup(attempts) #:nodoc:
+ attempts.each do |attempt|
+ generators_path = ['.']
+
+ paths = attempt.gsub(':generators:', ':').split(':')
+ name = "#{paths.last}_generator.rb"
+
+ until paths.empty?
+ generators_path.unshift File.join(*paths)
+ paths.pop
+ end
+
+ generators_path.uniq!
+ generators_path = "{#{generators_path.join(',')}}"
+
+ self.load_path.each do |path|
+ Dir[File.join(path, generators_path, name)].each do |file|
+ begin
+ require file
+ rescue Exception => e
+ warn "[WARNING] Could not load generator at #{file.inspect}. Error: #{e.message}"
+ end
+ end
+ end
+ end
+ end
+
+ end
+end
+
diff --git a/railties/lib/generators/action_orm.rb b/railties/lib/generators/action_orm.rb
new file mode 100644
index 0000000000..69cf227fd7
--- /dev/null
+++ b/railties/lib/generators/action_orm.rb
@@ -0,0 +1,74 @@
+module Rails
+ module Generators
+ # ActionORM is a class to be implemented by each ORM to allow Rails to
+ # generate customized controller code.
+ #
+ # The API has the same methods as ActiveRecord, but each method returns a
+ # string that matches the ORM API.
+ #
+ # For example:
+ #
+ # ActiveRecord::Generators::ActionORM.find(Foo, "params[:id]")
+ # #=> "Foo.find(params[:id])"
+ #
+ # Datamapper::Generators::ActionORM.find(Foo, "params[:id]")
+ # #=> "Foo.get(params[:id])"
+ #
+ # On initialization, the ActionORM accepts the instance name that will
+ # receive the calls:
+ #
+ # builder = ActiveRecord::Generators::ActionORM.new "@foo"
+ # builder.save #=> "@foo.save"
+ #
+ # The only exception in ActionORM for ActiveRecord is the use of self.build
+ # instead of self.new.
+ #
+ class ActionORM
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ # GET index
+ def self.all(klass)
+ raise NotImplementedError
+ end
+
+ # GET show
+ # GET edit
+ # PUT update
+ # DELETE destroy
+ def self.find(klass, params=nil)
+ raise NotImplementedError
+ end
+
+ # GET new
+ # POST create
+ def self.build(klass, params=nil)
+ raise NotImplementedError
+ end
+
+ # POST create
+ def save
+ raise NotImplementedError
+ end
+
+ # PUT update
+ def update_attributes(params=nil)
+ raise NotImplementedError
+ end
+
+ # POST create
+ # PUT update
+ def errors
+ raise NotImplementedError
+ end
+
+ # DELETE destroy
+ def destroy
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/actions.rb b/railties/lib/generators/actions.rb
new file mode 100644
index 0000000000..55ef212abb
--- /dev/null
+++ b/railties/lib/generators/actions.rb
@@ -0,0 +1,263 @@
+require 'open-uri'
+
+module Rails
+ module Generators
+ module Actions
+
+ # Install a plugin. You must provide either a Subversion url or Git url.
+ # For a Git-hosted plugin, you can specify if it should be added as a submodule instead of cloned.
+ #
+ # ==== Examples
+ #
+ # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git'
+ # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git', :submodule => true
+ # plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
+ #
+ def plugin(name, options)
+ log :plugin, name
+
+ if options[:git] && options[:submodule]
+ in_root do
+ run "git submodule add #{options[:git]} vendor/plugins/#{name}", :verbose => false
+ end
+ elsif options[:git] || options[:svn]
+ in_root do
+ run_ruby_script "script/plugin install #{options[:svn] || options[:git]}", :verbose => false
+ end
+ else
+ log "! no git or svn provided for #{name}. Skipping..."
+ end
+ end
+
+ # Adds an entry into config/environment.rb for the supplied gem. If env
+ # is specified, add the gem to the given environment.
+ #
+ # ==== Example
+ #
+ # gem "rspec", :env => :test
+ # gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/"
+ #
+ def gem(name, options={})
+ log :gem, name
+ env = options.delete(:env)
+
+ gems_code = "config.gem '#{name}'"
+
+ if options.any?
+ opts = options.inject([]) {|result, h| result << [":#{h[0]} => #{h[1].inspect.gsub('"',"'")}"] }.sort.join(", ")
+ gems_code << ", #{opts}"
+ end
+
+ environment gems_code, :env => env
+ end
+
+ # Adds a line inside the Initializer block for config/environment.rb.
+ #
+ # If options :env is specified, the line is appended to the corresponding
+ # file in config/environments.
+ #
+ def environment(data=nil, options={}, &block)
+ sentinel = "Rails::Initializer.run do |config|"
+ data = block.call if !data && block_given?
+
+ in_root do
+ if options[:env].nil?
+ inject_into_file 'config/environment.rb', "\n #{data}", :after => sentinel, :verbose => false
+ else
+ Array.wrap(options[:env]).each do|env|
+ append_file "config/environments/#{env}.rb", "\n#{data}", :verbose => false
+ end
+ end
+ end
+ end
+
+ # Run a command in git.
+ #
+ # ==== Examples
+ #
+ # git :init
+ # git :add => "this.file that.rb"
+ # git :add => "onefile.rb", :rm => "badfile.cxx"
+ #
+ def git(command={})
+ in_root do
+ if command.is_a?(Symbol)
+ run "git #{command}"
+ else
+ command.each do |command, options|
+ run "git #{command} #{options}"
+ end
+ end
+ end
+ end
+
+ # Create a new file in the vendor/ directory. Code can be specified
+ # in a block or a data string can be given.
+ #
+ # ==== Examples
+ #
+ # vendor("sekrit.rb") do
+ # sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
+ # "salt = '#{sekrit_salt}'"
+ # end
+ #
+ # vendor("foreign.rb", "# Foreign code is fun")
+ #
+ def vendor(filename, data=nil, &block)
+ log :vendor, filename
+ create_file("vendor/#{filename}", data, :verbose => false, &block)
+ end
+
+ # Create a new file in the lib/ directory. Code can be specified
+ # in a block or a data string can be given.
+ #
+ # ==== Examples
+ #
+ # lib("crypto.rb") do
+ # "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
+ # end
+ #
+ # lib("foreign.rb", "# Foreign code is fun")
+ #
+ def lib(filename, data=nil, &block)
+ log :lib, filename
+ create_file("lib/#{filename}", data, :verbose => false, &block)
+ end
+
+ # Create a new Rakefile with the provided code (either in a block or a string).
+ #
+ # ==== Examples
+ #
+ # rakefile("bootstrap.rake") do
+ # project = ask("What is the UNIX name of your project?")
+ #
+ # <<-TASK
+ # namespace :#{project} do
+ # task :bootstrap do
+ # puts "i like boots!"
+ # end
+ # end
+ # TASK
+ # end
+ #
+ # rakefile("seed.rake", "puts 'im plantin ur seedz'")
+ #
+ def rakefile(filename, data=nil, &block)
+ log :rakefile, filename
+ create_file("lib/tasks/#{filename}", data, :verbose => false, &block)
+ end
+
+ # Create a new initializer with the provided code (either in a block or a string).
+ #
+ # ==== Examples
+ #
+ # initializer("globals.rb") do
+ # data = ""
+ #
+ # ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do
+ # data << "#{const} = :entp"
+ # end
+ #
+ # data
+ # end
+ #
+ # initializer("api.rb", "API_KEY = '123456'")
+ #
+ def initializer(filename, data=nil, &block)
+ log :initializer, filename
+ create_file("config/initializers/#{filename}", data, :verbose => false, &block)
+ end
+
+ # Generate something using a generator from Rails or a plugin.
+ # The second parameter is the argument string that is passed to
+ # the generator or an Array that is joined.
+ #
+ # ==== Example
+ #
+ # generate(:authenticated, "user session")
+ #
+ def generate(what, *args)
+ log :generate, what
+ argument = args.map {|arg| arg.to_s }.flatten.join(" ")
+
+ in_root { run_ruby_script("script/generate #{what} #{argument}", :verbose => false) }
+ end
+
+ # Runs the supplied rake task
+ #
+ # ==== Example
+ #
+ # rake("db:migrate")
+ # rake("db:migrate", :env => "production")
+ # rake("gems:install", :sudo => true)
+ #
+ def rake(command, options={})
+ log :rake, command
+ env = options[:env] || 'development'
+ sudo = options[:sudo] && RUBY_PLATFORM !~ /mswin|mingw/ ? 'sudo ' : ''
+ in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
+ end
+
+ # Just run the capify command in root
+ #
+ # ==== Example
+ #
+ # capify!
+ #
+ def capify!
+ log :capify, ""
+ in_root { run("#{extify(:capify)} .", :verbose => false) }
+ end
+
+ # Add Rails to /vendor/rails
+ #
+ # ==== Example
+ #
+ # freeze!
+ #
+ def freeze!(args = {})
+ log :vendor, "rails"
+ in_root { run("#{extify(:rake)} rails:freeze:edge", :verbose => false) }
+ end
+
+ # Make an entry in Rails routing file conifg/routes.rb
+ #
+ # === Example
+ #
+ # route "map.root :controller => :welcome"
+ #
+ def route(routing_code)
+ log :route, routing_code
+ sentinel = "ActionController::Routing::Routes.draw do |map|"
+
+ in_root do
+ inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false }
+ end
+ end
+
+ protected
+
+ # Define log for backwards compatibility. If just one argument is sent,
+ # invoke say, otherwise invoke say_status.
+ #
+ def log(*args)
+ if args.size == 1
+ say args.first.to_s
+ else
+ say_status *args
+ end
+ end
+
+ # Add an extension to the given name based on the platform.
+ #
+ def extify(name)
+ if RUBY_PLATFORM =~ /mswin|mingw/
+ "#{name}.bat"
+ else
+ name
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/generators/active_record.rb b/railties/lib/generators/active_record.rb
new file mode 100644
index 0000000000..64bee3904e
--- /dev/null
+++ b/railties/lib/generators/active_record.rb
@@ -0,0 +1,57 @@
+require 'generators/named_base'
+require 'generators/migration'
+require 'generators/action_orm'
+require 'active_record'
+
+module ActiveRecord
+ module Generators
+ class Base < Rails::Generators::NamedBase #:nodoc:
+ include Rails::Generators::Migration
+
+ protected
+ # Implement the required interface for Rails::Generators::Migration.
+ #
+ def next_migration_number(dirname) #:nodoc:
+ if ActiveRecord::Base.timestamped_migrations
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
+ else
+ "%.3d" % (current_migration_number(dirname) + 1)
+ end
+ end
+ end
+
+ class ActionORM < Rails::Generators::ActionORM #:nodoc:
+ def self.all(klass)
+ "#{klass}.all"
+ end
+
+ def self.find(klass, params=nil)
+ "#{klass}.find(#{params})"
+ end
+
+ def self.build(klass, params=nil)
+ if params
+ "#{klass}.new(#{params})"
+ else
+ "#{klass}.new"
+ end
+ end
+
+ def save
+ "#{name}.save"
+ end
+
+ def update_attributes(params=nil)
+ "#{name}.update_attributes(#{params})"
+ end
+
+ def errors
+ "#{name}.errors"
+ end
+
+ def destroy
+ "#{name}.destroy"
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/active_record/migration/migration_generator.rb b/railties/lib/generators/active_record/migration/migration_generator.rb
new file mode 100644
index 0000000000..7939977f72
--- /dev/null
+++ b/railties/lib/generators/active_record/migration/migration_generator.rb
@@ -0,0 +1,25 @@
+require 'generators/active_record'
+
+module ActiveRecord
+ module Generators
+ class MigrationGenerator < Base
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+
+ def create_migration_file
+ set_local_assigns!
+ migration_template "migration.rb", "db/migrate/#{file_name}.rb"
+ end
+
+ protected
+ attr_reader :migration_action
+
+ def set_local_assigns!
+ if file_name =~ /^(add|remove)_.*_(?:to|from)_(.*)/
+ @migration_action = $1
+ @table_name = $2.pluralize
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/migration/templates/migration.rb b/railties/lib/generators/active_record/migration/templates/migration.rb
index ca35a43229..bbb7c53d86 100644
--- a/railties/lib/rails_generator/generators/components/migration/templates/migration.rb
+++ b/railties/lib/generators/active_record/migration/templates/migration.rb
@@ -1,4 +1,4 @@
-class <%= class_name.underscore.camelize %> < ActiveRecord::Migration
+class <%= migration_class_name %> < ActiveRecord::Migration
def self.up<% attributes.each do |attribute| %>
<%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%>
<%- end %>
diff --git a/railties/lib/generators/active_record/model/model_generator.rb b/railties/lib/generators/active_record/model/model_generator.rb
new file mode 100644
index 0000000000..54187aede0
--- /dev/null
+++ b/railties/lib/generators/active_record/model/model_generator.rb
@@ -0,0 +1,35 @@
+require 'generators/active_record'
+
+module ActiveRecord
+ module Generators
+ class ModelGenerator < Base
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+
+ check_class_collision
+
+ class_option :migration, :type => :boolean
+ class_option :timestamps, :type => :boolean
+ class_option :parent, :type => :string, :desc => "The parent class for the generated model"
+
+ def create_migration_file
+ if options[:migration] && options[:parent].nil?
+ file_name = "create_#{file_path.gsub(/\//, '_').pluralize}"
+ migration_template "migration.rb", "db/migrate/#{file_name}.rb"
+ end
+ end
+
+ def create_model_file
+ template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
+ end
+
+ hook_for :test_framework
+
+ protected
+
+ def parent_class_name
+ options[:parent] || "ActiveRecord::Base"
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/model/templates/migration.rb b/railties/lib/generators/active_record/model/templates/migration.rb
index 382fd1156e..1f68487304 100644
--- a/railties/lib/rails_generator/generators/components/model/templates/migration.rb
+++ b/railties/lib/generators/active_record/model/templates/migration.rb
@@ -1,10 +1,10 @@
-class <%= migration_name %> < ActiveRecord::Migration
+class <%= migration_class_name %> < ActiveRecord::Migration
def self.up
create_table :<%= table_name %> do |t|
<% for attribute in attributes -%>
t.<%= attribute.type %> :<%= attribute.name %>
<% end -%>
-<% unless options[:skip_timestamps] %>
+<% if options[:timestamps] %>
t.timestamps
<% end -%>
end
diff --git a/railties/lib/rails_generator/generators/components/model/templates/model.rb b/railties/lib/generators/active_record/model/templates/model.rb
index 0656b06dfe..21ae29e9f2 100644
--- a/railties/lib/rails_generator/generators/components/model/templates/model.rb
+++ b/railties/lib/generators/active_record/model/templates/model.rb
@@ -1,4 +1,4 @@
-class <%= class_name %> < ActiveRecord::Base
+class <%= class_name %> < <%= parent_class_name.classify %>
<% attributes.select {|attr| attr.reference? }.each do |attribute| -%>
belongs_to :<%= attribute.name %>
<% end -%>
diff --git a/railties/lib/generators/active_record/observer/observer_generator.rb b/railties/lib/generators/active_record/observer/observer_generator.rb
new file mode 100644
index 0000000000..a6b57423b8
--- /dev/null
+++ b/railties/lib/generators/active_record/observer/observer_generator.rb
@@ -0,0 +1,15 @@
+require 'generators/active_record'
+
+module ActiveRecord
+ module Generators
+ class ObserverGenerator < Base
+ check_class_collision :suffix => "Observer"
+
+ def create_observer_file
+ template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb")
+ end
+
+ hook_for :test_framework
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/observer/templates/observer.rb b/railties/lib/generators/active_record/observer/templates/observer.rb
index b9a3004161..b9a3004161 100644
--- a/railties/lib/rails_generator/generators/components/observer/templates/observer.rb
+++ b/railties/lib/generators/active_record/observer/templates/observer.rb
diff --git a/railties/lib/generators/active_record/session_migration/session_migration_generator.rb b/railties/lib/generators/active_record/session_migration/session_migration_generator.rb
new file mode 100644
index 0000000000..d60da5c0a5
--- /dev/null
+++ b/railties/lib/generators/active_record/session_migration/session_migration_generator.rb
@@ -0,0 +1,20 @@
+require 'generators/active_record'
+
+module ActiveRecord
+ module Generators
+ class SessionMigrationGenerator < Base
+ argument :name, :type => :string, :default => "add_sessions_table"
+
+ def create_migration_file
+ migration_template "migration.rb", "db/migrate/#{file_name}.rb"
+ end
+
+ protected
+
+ def session_table_name
+ ActiveRecord::Base.pluralize_table_names ? 'session'.pluralize : 'session'
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb b/railties/lib/generators/active_record/session_migration/templates/migration.rb
index ca220a5f23..919822af7b 100644
--- a/railties/lib/rails_generator/generators/components/session_migration/templates/migration.rb
+++ b/railties/lib/generators/active_record/session_migration/templates/migration.rb
@@ -1,4 +1,4 @@
-class <%= class_name %> < ActiveRecord::Migration
+class <%= migration_class_name %> < ActiveRecord::Migration
def self.up
create_table :<%= session_table_name %> do |t|
t.string :session_id, :null => false
diff --git a/railties/lib/generators/base.rb b/railties/lib/generators/base.rb
new file mode 100644
index 0000000000..cbe9c0a49d
--- /dev/null
+++ b/railties/lib/generators/base.rb
@@ -0,0 +1,302 @@
+require 'generators/actions'
+
+module Rails
+ module Generators
+ class Error < Thor::Error
+ end
+
+ class Base < Thor::Group
+ include Thor::Actions
+ include Rails::Generators::Actions
+
+ # Automatically sets the source root based on the class name.
+ #
+ def self.source_root
+ @_rails_source_root ||= File.expand_path(File.join(File.dirname(__FILE__),
+ base_name, generator_name, 'templates'))
+ end
+
+ # Tries to get the description from a USAGE file one folder above the source
+ # root otherwise uses a default description.
+ #
+ def self.desc(description=nil)
+ return super if description
+ usage = File.expand_path(File.join(source_root, "..", "USAGE"))
+
+ @desc ||= if File.exist?(usage)
+ File.read(usage)
+ else
+ "Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
+ end
+ end
+
+ # Convenience method to get the namespace from the class name. It's the
+ # same as Thor default except that the Generator at the end of the class
+ # is removed.
+ #
+ def self.namespace(name=nil)
+ return super if name
+ @namespace ||= super.sub(/_generator$/, '')
+ end
+
+ # Invoke a generator based on the value supplied by the user to the
+ # given option named "name". A class option is created when this method
+ # is invoked and you can set a hash to customize it.
+ #
+ # ==== Examples
+ #
+ # class ControllerGenerator < Rails::Generators::Base
+ # hook_for :test_framework, :aliases => "-t"
+ # end
+ #
+ # The example above will create a test framework option and will invoke
+ # a generator based on the user supplied value.
+ #
+ # For example, if the user invoke the controller generator as:
+ #
+ # ruby script/generate controller Account --test-framework=test_unit
+ #
+ # The controller generator will then try to invoke the following generators:
+ #
+ # "rails:generators:test_unit", "test_unit:generators:controller", "test_unit"
+ #
+ # In this case, the "test_unit:generators:controller" is available and is
+ # invoked. This allows any test framework to hook into Rails as long as it
+ # provides any of the hooks above.
+ #
+ # Finally, if the user don't want to use any test framework, he can do:
+ #
+ # ruby script/generate controller Account --skip-test-framework
+ #
+ # Or similarly:
+ #
+ # ruby script/generate controller Account --no-test-framework
+ #
+ # ==== Boolean hooks
+ #
+ # In some cases, you want to provide a boolean hook. For example, webrat
+ # developers might want to have webrat available on controller generator.
+ # This can be achieved as:
+ #
+ # Rails::Generators::ControllerGenerator.hook_for :webrat, :type => :boolean
+ #
+ # Then, if you want, webrat to be invoked, just supply:
+ #
+ # ruby script/generate controller Account --webrat
+ #
+ # The hooks lookup is similar as above:
+ #
+ # "rails:generators:webrat", "webrat:generators:controller", "webrat"
+ #
+ # ==== Custom invocations
+ #
+ # You can also supply a block to hook_for to customize how the hook is
+ # going to be invoked. The block receives two parameters, an instance
+ # of the current class and the klass to be invoked.
+ #
+ # For example, in the resource generator, the controller should be invoked
+ # with a pluralized class name. By default, it is invoked with the same
+ # name as the resource generator, which is singular. To change this, we
+ # can give a block to customize how the controller can be invoked.
+ #
+ # hook_for :resource_controller do |instance, controller|
+ # instance.invoke controller, [ instance.name.pluralize ]
+ # end
+ #
+ def self.hook_for(*names, &block)
+ options = names.extract_options!
+ in_base = options.delete(:in) || base_name
+ as_hook = options.delete(:as) || generator_name
+
+ names.each do |name|
+ defaults = if options[:type] == :boolean
+ { }
+ elsif [true, false].include?(default_value_for_option(name, options))
+ { :banner => "" }
+ else
+ { :desc => "#{name.to_s.humanize} to be invoked", :banner => "NAME" }
+ end
+
+ unless class_options.key?(name)
+ class_option name, defaults.merge!(options)
+ end
+
+ hooks[name] = [ in_base, as_hook ]
+ invoke_from_option name, options, &block
+ end
+ end
+
+ # Remove a previously added hook.
+ #
+ # ==== Examples
+ #
+ # remove_hook_for :orm
+ #
+ def self.remove_hook_for(*names)
+ remove_invocation *names
+
+ names.each do |name|
+ hooks.delete(name)
+ end
+ end
+
+ # Make class option aware of Rails::Generators.options and Rails::Generators.aliases.
+ #
+ def self.class_option(name, options={}) #:nodoc:
+ options[:desc] = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc)
+ options[:aliases] = default_aliases_for_option(name, options)
+ options[:default] = default_value_for_option(name, options)
+ super(name, options)
+ end
+
+ # Cache source root and add lib/generators/base/generator/templates to
+ # source paths.
+ #
+ def self.inherited(base) #:nodoc:
+ super
+ base.source_root # Cache source root
+
+ if defined?(RAILS_ROOT) && base.name !~ /Base$/
+ path = File.expand_path(File.join(RAILS_ROOT, 'lib', 'templates'))
+ if base.name.include?('::')
+ base.source_paths << File.join(path, base.base_name, base.generator_name)
+ else
+ base.source_paths << File.join(path, base.generator_name)
+ end
+ end
+ end
+
+ protected
+
+ # Check whether the given class names are already taken by user
+ # application or Ruby on Rails.
+ #
+ def class_collisions(*class_names) #:nodoc:
+ return unless behavior == :invoke
+
+ class_names.flatten.each do |class_name|
+ class_name = class_name.to_s
+ next if class_name.strip.empty?
+
+ # Split the class from its module nesting
+ nesting = class_name.split('::')
+ last_name = nesting.pop
+
+ # Hack to limit const_defined? to non-inherited on 1.9
+ extra = []
+ extra << false unless Object.method(:const_defined?).arity == 1
+
+ # Extract the last Module in the nesting
+ last = nesting.inject(Object) do |last, nest|
+ break unless last.const_defined?(nest, *extra)
+ last.const_get(nest)
+ end
+
+ if last && last.const_defined?(last_name.camelize, *extra)
+ raise Error, "The name '#{class_name}' is either already used in your application " <<
+ "or reserved by Ruby on Rails. Please choose an alternative and run " <<
+ "this generator again."
+ end
+ end
+ end
+
+ # Use Rails default banner.
+ #
+ def self.banner
+ "#{$0} #{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]"
+ end
+
+ # Sets the base_name taking into account the current class namespace.
+ #
+ def self.base_name
+ @base_name ||= self.name.split('::').first.underscore
+ end
+
+ # Removes the namespaces and get the generator name. For example,
+ # Rails::Generators::MetalGenerator will return "metal" as generator name.
+ #
+ def self.generator_name
+ @generator_name ||= begin
+ klass_name = self.name.split('::').last
+ klass_name.sub!(/Generator$/, '')
+ klass_name.underscore
+ end
+ end
+
+ # Return the default value for the option name given doing a lookup in
+ # Rails::Generators.options.
+ #
+ def self.default_value_for_option(name, options)
+ config = Rails::Generators.options
+ generator, base = generator_name.to_sym, base_name.to_sym
+
+ if config[generator] && config[generator].key?(name)
+ config[generator][name]
+ elsif config[base] && config[base].key?(name)
+ config[base][name]
+ elsif config[:rails].key?(name)
+ config[:rails][name]
+ else
+ options[:default]
+ end
+ end
+
+ # Return default aliases for the option name given doing a lookup in
+ # Rails::Generators.aliases.
+ #
+ def self.default_aliases_for_option(name, options)
+ config = Rails::Generators.aliases
+ generator, base = generator_name.to_sym, base_name.to_sym
+
+ if config[generator] && config[generator].key?(name)
+ config[generator][name]
+ elsif config[base] && config[base].key?(name)
+ config[base][name]
+ elsif config[:rails].key?(name)
+ config[:rails][name]
+ else
+ options[:aliases]
+ end
+ end
+
+ # Keep hooks configuration that are used on prepare_for_invocation.
+ #
+ def self.hooks #:nodoc:
+ @hooks ||= from_superclass(:hooks, {})
+ end
+
+ # Prepare class invocation to search on Rails namespace if a previous
+ # added hook is being used.
+ #
+ def self.prepare_for_invocation(name, value) #:nodoc:
+ if value && constants = self.hooks[name]
+ Rails::Generators.find_by_namespace(value, *constants)
+ else
+ super
+ end
+ end
+
+ # Small macro to add ruby as an option to the generator with proper
+ # default value plus an instance helper method called shebang.
+ #
+ def self.add_shebang_option!
+ class_option :ruby, :type => :string, :aliases => "-r", :default => Thor::Util.ruby_command,
+ :desc => "Path to the Ruby binary of your choice", :banner => "PATH"
+
+ no_tasks {
+ define_method :shebang do
+ @shebang ||= begin
+ command = if options[:ruby] == Thor::Util.ruby_command
+ "/usr/bin/env #{File.basename(Thor::Util.ruby_command)}"
+ else
+ options[:ruby]
+ end
+ "#!#{command}"
+ end
+ end
+ }
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/generators/erb.rb b/railties/lib/generators/erb.rb
new file mode 100644
index 0000000000..43d47109c7
--- /dev/null
+++ b/railties/lib/generators/erb.rb
@@ -0,0 +1,8 @@
+require 'generators/named_base'
+
+module Erb
+ module Generators
+ class Base < Rails::Generators::NamedBase #:nodoc:
+ end
+ end
+end
diff --git a/railties/lib/generators/erb/controller/controller_generator.rb b/railties/lib/generators/erb/controller/controller_generator.rb
new file mode 100644
index 0000000000..ab7b273662
--- /dev/null
+++ b/railties/lib/generators/erb/controller/controller_generator.rb
@@ -0,0 +1,21 @@
+require 'generators/erb'
+
+module Erb
+ module Generators
+ class ControllerGenerator < Base
+ argument :actions, :type => :array, :default => [], :banner => "action action"
+
+ def create_view_files
+ base_path = File.join("app/views", class_path, file_name)
+ empty_directory base_path
+
+ actions.each do |action|
+ @action = action
+ @path = File.join(base_path, "#{action}.html.erb")
+
+ template 'view.html.erb', @path
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/erb/controller/templates/view.html.erb b/railties/lib/generators/erb/controller/templates/view.html.erb
new file mode 100644
index 0000000000..cd54d13d83
--- /dev/null
+++ b/railties/lib/generators/erb/controller/templates/view.html.erb
@@ -0,0 +1,2 @@
+<h1><%= class_name %>#<%= @action %></h1>
+<p>Find me in <%= @path %></p>
diff --git a/railties/lib/generators/erb/mailer/mailer_generator.rb b/railties/lib/generators/erb/mailer/mailer_generator.rb
new file mode 100644
index 0000000000..4ec2f4c9f4
--- /dev/null
+++ b/railties/lib/generators/erb/mailer/mailer_generator.rb
@@ -0,0 +1,20 @@
+require 'generators/erb'
+
+module Erb
+ module Generators
+ class MailerGenerator < Base
+ argument :actions, :type => :array, :default => [], :banner => "method method"
+
+ def create_view_folder
+ empty_directory File.join("app/views", file_path)
+ end
+
+ def create_view_files
+ actions.each do |action|
+ @action, @path = action, File.join(file_path, action)
+ template "view.erb", File.join("app/views", "#{@path}.erb")
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/erb/mailer/templates/view.erb b/railties/lib/generators/erb/mailer/templates/view.erb
new file mode 100644
index 0000000000..fcce7bd805
--- /dev/null
+++ b/railties/lib/generators/erb/mailer/templates/view.erb
@@ -0,0 +1,3 @@
+<%= class_name %>#<%= @action %>
+
+Find me in app/views/<%= @path %>
diff --git a/railties/lib/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/generators/erb/scaffold/scaffold_generator.rb
new file mode 100644
index 0000000000..955f22192a
--- /dev/null
+++ b/railties/lib/generators/erb/scaffold/scaffold_generator.rb
@@ -0,0 +1,54 @@
+require 'generators/erb'
+
+module Erb
+ module Generators
+ class ScaffoldGenerator < Base
+ include Rails::Generators::ScaffoldBase
+
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+
+ class_option :form, :type => :boolean
+ class_option :layout, :type => :boolean
+ class_option :singleton, :type => :boolean, :desc => "Supply to skip index view"
+
+ def create_root_folder
+ empty_directory File.join("app/views", controller_file_path)
+ end
+
+ def copy_index_file
+ return if options[:singleton]
+ copy_view :index
+ end
+
+ def copy_edit_file
+ copy_view :edit
+ end
+
+ def copy_show_file
+ copy_view :show
+ end
+
+ def copy_new_file
+ copy_view :new
+ end
+
+ def copy_form_file
+ return unless options[:form]
+ copy_view :_form
+ end
+
+ def copy_layout_file
+ return unless options[:layout]
+ template "layout.html.erb",
+ File.join("app/views/layouts", controller_class_path, "#{controller_file_name}.html.erb")
+ end
+
+ protected
+
+ def copy_view(view)
+ template "#{view}.html.erb", File.join("app/views", controller_file_path, "#{view}.html.erb")
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb b/railties/lib/generators/erb/scaffold/templates/edit.html.erb
index cca1d61c68..cca1d61c68 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
+++ b/railties/lib/generators/erb/scaffold/templates/edit.html.erb
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb b/railties/lib/generators/erb/scaffold/templates/index.html.erb
index 69beb388db..5e6a4af9e0 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb
+++ b/railties/lib/generators/erb/scaffold/templates/index.html.erb
@@ -3,7 +3,7 @@
<table>
<tr>
<% for attribute in attributes -%>
- <th><%= attribute.column.human_name %></th>
+ <th><%= attribute.human_name %></th>
<% end -%>
<th></th>
<th></th>
@@ -24,4 +24,4 @@
<br />
-<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %> \ No newline at end of file
+<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %>
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb b/railties/lib/generators/erb/scaffold/templates/layout.html.erb
index aacfbe4a8f..aacfbe4a8f 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb
+++ b/railties/lib/generators/erb/scaffold/templates/layout.html.erb
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb b/railties/lib/generators/erb/scaffold/templates/new.html.erb
index 96c89fc50e..96c89fc50e 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
+++ b/railties/lib/generators/erb/scaffold/templates/new.html.erb
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb b/railties/lib/generators/erb/scaffold/templates/show.html.erb
index adecaf70c6..25567957be 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb
+++ b/railties/lib/generators/erb/scaffold/templates/show.html.erb
@@ -1,10 +1,10 @@
<% for attribute in attributes -%>
<p>
- <b><%= attribute.column.human_name %>:</b>
+ <b><%= attribute.human_name %>:</b>
<%%=h @<%= singular_name %>.<%= attribute.name %> %>
</p>
<% end -%>
<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
-<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/railties/lib/rails_generator/generated_attribute.rb b/railties/lib/generators/generated_attribute.rb
index a3d4a01142..e962308585 100644
--- a/railties/lib/rails_generator/generated_attribute.rb
+++ b/railties/lib/generators/generated_attribute.rb
@@ -1,13 +1,10 @@
-require 'optparse'
-
module Rails
- module Generator
+ module Generators
class GeneratedAttribute
- attr_accessor :name, :type, :column
+ attr_accessor :name, :type
def initialize(name, type)
@name, @type = name, type.to_sym
- @column = ActiveRecord::ConnectionAdapters::Column.new(name, nil, @type)
end
def field_type
@@ -20,7 +17,7 @@ module Rails
when :boolean then :check_box
else
:text_field
- end
+ end
end
def default
@@ -33,9 +30,14 @@ module Rails
when :string then "MyString"
when :text then "MyText"
when :boolean then false
+ when :references, :belongs_to then nil
else
""
- end
+ end
+ end
+
+ def human_name
+ name.to_s.humanize
end
def reference?
diff --git a/railties/lib/generators/migration.rb b/railties/lib/generators/migration.rb
new file mode 100644
index 0000000000..0a9151ecdf
--- /dev/null
+++ b/railties/lib/generators/migration.rb
@@ -0,0 +1,65 @@
+module Rails
+ module Generators
+ # Holds common methods for migrations. It assumes that migrations has the
+ # [0-9]*_name format and can be used by another frameworks (like Sequel)
+ # just by implementing the next migration number method.
+ #
+ module Migration
+ def self.included(base) #:nodoc:
+ base.send :attr_reader, :migration_number,
+ :migration_file_name,
+ :migration_class_name
+ end
+
+ # Creates a migration template at the given destination. The difference
+ # to the default template method is that the migration number is appended
+ # to the destination file name.
+ #
+ # The migration number, migration file name, migration class name are
+ # available as instance variables in the template to be rendered.
+ #
+ # ==== Examples
+ #
+ # migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb"
+ #
+ def migration_template(source, destination=nil, config={})
+ destination = File.expand_path(destination || source, self.destination_root)
+
+ migration_dir = File.dirname(destination)
+ @migration_number = next_migration_number(migration_dir)
+ @migration_file_name = File.basename(destination).sub(/\.rb$/, '')
+ @migration_class_name = @migration_file_name.camelize
+
+ destination = migration_exists?(migration_dir, @migration_file_name)
+
+ if behavior == :invoke
+ raise Error, "Another migration is already named #{@migration_file_name}: #{destination}" if destination
+ destination = File.join(migration_dir, "#{@migration_number}_#{@migration_file_name}.rb")
+ end
+
+ template(source, destination, config)
+ end
+
+ protected
+
+ def migration_lookup_at(dirname) #:nodoc:
+ Dir.glob("#{dirname}/[0-9]*_*.rb")
+ end
+
+ def migration_exists?(dirname, file_name) #:nodoc:
+ migration_lookup_at(dirname).grep(/\d+_#{file_name}.rb$/).first
+ end
+
+ def current_migration_number(dirname) #:nodoc:
+ migration_lookup_at(dirname).collect do |file|
+ File.basename(file).split("_").first.to_i
+ end.max.to_i
+ end
+
+ def next_migration_number(dirname) #:nodoc:
+ raise NotImplementError
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/generators/named_base.rb b/railties/lib/generators/named_base.rb
new file mode 100644
index 0000000000..699b8ed651
--- /dev/null
+++ b/railties/lib/generators/named_base.rb
@@ -0,0 +1,162 @@
+require 'generators/base'
+require 'generators/generated_attribute'
+
+module Rails
+ module Generators
+ class NamedBase < Base
+ argument :name, :type => :string
+
+ attr_reader :class_name, :singular_name, :plural_name, :table_name,
+ :class_path, :file_path, :class_nesting_depth
+
+ alias :file_name :singular_name
+
+ def initialize(*args) #:nodoc:
+ super
+ assign_names!(self.name)
+ parse_attributes! if respond_to?(:attributes)
+ end
+
+ protected
+
+ def assign_names!(given_name) #:nodoc:
+ base_name, @class_path, @file_path, class_nesting, @class_nesting_depth = extract_modules(given_name)
+ class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
+
+ @table_name = if pluralize_table_names?
+ plural_name
+ else
+ singular_name
+ end
+ @table_name.gsub! '/', '_'
+
+ if class_nesting.empty?
+ @class_name = class_name_without_nesting
+ else
+ @table_name = class_nesting.underscore << "_" << @table_name
+ @class_name = "#{class_nesting}::#{class_name_without_nesting}"
+ end
+ end
+
+ # Convert attributes hash into an array with GeneratedAttribute objects.
+ #
+ def parse_attributes! #:nodoc:
+ self.attributes = (attributes || []).map do |key_value|
+ name, type = key_value.split(':')
+ Rails::Generators::GeneratedAttribute.new(name, type)
+ end
+ end
+
+ # Extract modules from filesystem-style or ruby-style path. Both
+ # good/fun/stuff and Good::Fun::Stuff produce the same results.
+ #
+ def extract_modules(name) #:nodoc:
+ modules = name.include?('/') ? name.split('/') : name.split('::')
+ name = modules.pop
+ path = modules.map { |m| m.underscore }
+
+ file_path = (path + [name.underscore]).join('/')
+ nesting = modules.map { |m| m.camelize }.join('::')
+
+ [name, path, file_path, nesting, modules.size]
+ end
+
+ # Receives name and return camelized, underscored and pluralized names.
+ #
+ def inflect_names(name) #:nodoc:
+ camel = name.camelize
+ under = camel.underscore
+ plural = under.pluralize
+ [camel, under, plural]
+ end
+
+ def pluralize_table_names?
+ !defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names
+ end
+
+ # Add a class collisions name to be checked on class initialization. You
+ # can supply a hash with a :prefix or :suffix to be tested.
+ #
+ # ==== Examples
+ #
+ # check_class_collision :suffix => "Observer"
+ #
+ # If the generator is invoked with class name Admin, it will check for
+ # the presence of "AdminObserver".
+ #
+ def self.check_class_collision(options={})
+ define_method :check_class_collision do
+ name = if self.respond_to?(:controller_class_name) # for ScaffoldBase
+ controller_class_name
+ else
+ class_name
+ end
+
+ class_collisions "#{options[:prefix]}#{name}#{options[:suffix]}"
+ end
+ end
+ end
+
+ # Deal with controller names on scaffold. Also provide helpers to deal with
+ # ActionORM.
+ #
+ module ScaffoldBase
+ def self.included(base) #:nodoc:
+ base.send :attr_reader, :controller_name, :controller_class_name, :controller_file_name,
+ :controller_class_path, :controller_file_path
+ end
+
+ # Set controller variables on initialization.
+ #
+ def initialize(*args) #:nodoc:
+ super
+ @controller_name = name.pluralize
+
+ base_name, @controller_class_path, @controller_file_path, class_nesting, class_nesting_depth = extract_modules(@controller_name)
+ class_name_without_nesting, @controller_file_name, controller_plural_name = inflect_names(base_name)
+
+ @controller_class_name = if class_nesting.empty?
+ class_name_without_nesting
+ else
+ "#{class_nesting}::#{class_name_without_nesting}"
+ end
+ end
+
+ protected
+
+ # Loads the ORM::Generators::ActionORM class. This class is responsable
+ # to tell scaffold entities how to generate an specific method for the
+ # ORM. Check Rails::Generators::ActionORM for more information.
+ #
+ def orm_class
+ @orm_class ||= begin
+ # Raise an error if the class_option :orm was not defined.
+ unless self.class.class_options[:orm]
+ raise "You need to have :orm as class option to invoke orm_class and orm_instance"
+ end
+
+ action_orm = "#{options[:orm].to_s.classify}::Generators::ActionORM"
+
+ # If the orm was not loaded, try to load it at "generators/orm",
+ # for example "generators/active_record" or "generators/sequel".
+ begin
+ klass = action_orm.constantize
+ rescue NameError
+ require "generators/#{options[:orm]}"
+ end
+
+ # Try once again after loading the file with success.
+ klass ||= action_orm.constantize
+ rescue Exception => e
+ raise Error, "Could not load #{action_orm}, skipping controller. Error: #{e.message}."
+ end
+ end
+
+ # Initialize ORM::Generators::ActionORM to access instance methods.
+ #
+ def orm_instance(name=file_name)
+ @orm_instance ||= @orm_class.new(name)
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/applications/app/USAGE b/railties/lib/generators/rails/app/USAGE
index 36d6061a59..36d6061a59 100644
--- a/railties/lib/rails_generator/generators/applications/app/USAGE
+++ b/railties/lib/generators/rails/app/USAGE
diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/generators/rails/app/app_generator.rb
new file mode 100644
index 0000000000..c8044d13b1
--- /dev/null
+++ b/railties/lib/generators/rails/app/app_generator.rb
@@ -0,0 +1,210 @@
+require 'digest/md5'
+require 'active_support/secure_random'
+require 'rails/version' unless defined?(Rails::VERSION)
+
+module Rails::Generators
+ class AppGenerator < Base
+ DATABASES = %w( mysql oracle postgresql sqlite2 sqlite3 frontbase ibm_db )
+ add_shebang_option!
+
+ argument :app_path, :type => :string
+
+ class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
+ :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"
+
+ class_option :freeze, :type => :boolean, :aliases => "-F", :default => false,
+ :desc => "Freeze Rails in vendor/rails from the gems"
+
+ class_option :template, :type => :string, :aliases => "-m",
+ :desc => "Path to an application template (can be a filesystem path or URL)."
+
+ class_option :with_dispatchers, :type => :boolean, :aliases => "-D", :default => false,
+ :desc => "Add CGI/FastCGI/mod_ruby dispatchers code"
+
+ class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false,
+ :desc => "Skip ActiveRecord files"
+
+ class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false,
+ :desc => "Skip TestUnit files"
+
+ class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false,
+ :desc => "Skip Prototype files"
+
+ # Add Rails options
+ #
+ class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
+ :desc => "Show Rails version number and quit"
+
+ class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
+ :desc => "Show this help message and quit"
+
+ def initialize(*args)
+ super
+ if !options[:no_activerecord] && !DATABASES.include?(options[:database])
+ raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
+ end
+ end
+
+ def create_root
+ self.destination_root = File.expand_path(app_path, destination_root)
+ empty_directory '.'
+
+ app_name # Sets the app name
+ FileUtils.cd(destination_root)
+ end
+
+ def create_root_files
+ copy_file "Rakefile"
+ copy_file "README"
+ end
+
+ def create_app_files
+ directory "app"
+ end
+
+ def create_config_files
+ empty_directory "config"
+
+ inside "config" do
+ copy_file "routes.rb"
+ template "environment.rb"
+
+ directory "environments"
+ directory "initializers"
+ directory "locales"
+ end
+ end
+
+ def create_boot_file
+ copy_file "config/boot.rb"
+ end
+
+ def create_activerecord_files
+ return if options[:skip_activerecord]
+ template "config/databases/#{options[:database]}.yml", "config/database.yml"
+ end
+
+ def create_db_files
+ directory "db"
+ end
+
+ def create_doc_files
+ directory "doc"
+ end
+
+ def create_lib_files
+ empty_directory "lib"
+ empty_directory "lib/tasks"
+ end
+
+ def create_log_files
+ empty_directory "log"
+
+ inside "log" do
+ %w( server production development test ).each do |file|
+ create_file "#{file}.log"
+ chmod "#{file}.log", 0666, :verbose => false
+ end
+ end
+ end
+
+ def create_public_files
+ directory "public", "public", :recursive => false # Do small steps, so anyone can overwrite it.
+ end
+
+ def create_dispatch_files
+ return unless options[:with_dispatchers]
+ copy_file "dispatchers/config.ru", "config.ru"
+
+ template "dispatchers/dispatch.rb", "public/dispatch.rb"
+ chmod "public/dispatch.rb", 0755, :verbose => false
+
+ template "dispatchers/dispatch.rb", "public/dispatch.cgi"
+ chmod "public/dispatch.cgi", 0755, :verbose => false
+
+ template "dispatchers/dispatch.fcgi", "public/dispatch.fcgi"
+ chmod "public/dispatch.fcgi", 0755, :verbose => false
+ end
+
+ def create_public_image_files
+ directory "public/images"
+ end
+
+ def create_public_stylesheets_files
+ directory "public/stylesheets"
+ end
+
+ def create_prototype_files
+ return if options[:skip_prototype]
+ directory "public/javascripts"
+ end
+
+ def create_script_files
+ directory "script"
+ chmod "script", 0755, :verbose => false
+ end
+
+ def create_test_files
+ return if options[:skip_testunit]
+ directory "test"
+ end
+
+ def create_tmp_files
+ empty_directory "tmp"
+
+ inside "tmp" do
+ %w(sessions sockets cache pids).each do |dir|
+ empty_directory dir
+ end
+ end
+ end
+
+ def create_vendor_files
+ empty_directory "vendor/plugins"
+ end
+
+ def apply_rails_template
+ apply options[:template] if options[:template]
+ rescue Thor::Error, LoadError, Errno::ENOENT => e
+ raise Error, "The template [#{options[:template]}] could not be loaded. Error: #{e}"
+ end
+
+ def freeze?
+ freeze! if options[:freeze]
+ end
+
+ protected
+
+ # Define file as an alias to create_file for backwards compatibility.
+ #
+ def file(*args, &block)
+ create_file(*args, &block)
+ end
+
+ def app_name
+ @app_name ||= File.basename(destination_root)
+ end
+
+ def app_secret
+ ActiveSupport::SecureRandom.hex(64)
+ end
+
+ def self.banner
+ "#{$0} #{self.arguments.map(&:usage).join(' ')} [options]"
+ end
+
+ def mysql_socket
+ @mysql_socket ||= [
+ "/tmp/mysql.sock", # default
+ "/var/run/mysqld/mysqld.sock", # debian/gentoo
+ "/var/tmp/mysql.sock", # freebsd
+ "/var/lib/mysql/mysql.sock", # fedora
+ "/opt/local/lib/mysql/mysql.sock", # fedora
+ "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
+ "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
+ "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
+ "/opt/lampp/var/mysql/mysql.sock" # xampp for linux
+ ].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/app/templates/README b/railties/lib/generators/rails/app/templates/README
new file mode 100644
index 0000000000..37ec8ea211
--- /dev/null
+++ b/railties/lib/generators/rails/app/templates/README
@@ -0,0 +1,243 @@
+== Welcome to Rails
+
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
+
+This pattern splits the view (also called the presentation) into "dumb" templates
+that are primarily responsible for inserting pre-built data in between HTML tags.
+The model contains the "smart" domain objects (such as Account, Product, Person,
+Post) that holds all the business logic and knows how to persist themselves to
+a database. The controller handles the incoming requests (such as Save New Account,
+Update Product, Show Post) by manipulating the model and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting Started
+
+1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
+ and your application name. Ex: rails myapp
+2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
+3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
+4. Follow the guidelines to start developing your application
+
+
+== Web Servers
+
+By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
+with a variety of other web servers.
+
+Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
+suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
+getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
+More info at: http://mongrel.rubyforge.org
+
+Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
+Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
+FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
+
+== Apache .htaccess example for FCGI/CGI
+
+# General Apache options
+AddHandler fastcgi-script .fcgi
+AddHandler cgi-script .cgi
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
+
+
+== Debugging Rails
+
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
+
+First area to check is the application log files. Have "tail -f" commands running
+on the server.log and development.log. Rails will automatically display debugging
+and runtime information to these files. Debugging info will also be shown in the
+browser on requests from 127.0.0.1.
+
+You can also log your own messages directly into the log file from your code using
+the Ruby logger class from inside your controllers. Example:
+
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
+
+The result will be a message in your log file along the lines of:
+
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
+
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+
+Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
+
+* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two online (and free) books will bring you up to speed on the Ruby language
+and also on programming in general.
+
+
+== Debugger
+
+Debugger support is available through the debugger command when you start your Mongrel or
+Webrick server with --debugger. This means that you can break out of execution at any point
+in the code, investigate and change the model, AND then resume execution!
+You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
+Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find(:all)
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better is that you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you enter "cont"
+
+
+== Console
+
+You can interact with the domain model by starting the console through <tt>script/console</tt>.
+Here you'll have all parts of the application configured, just like it is when the
+application is running. You can inspect domain models, change values, and save to the
+database. Starting the script without arguments will launch it in the development environment.
+Passing an argument will specify a different environment, like <tt>script/console production</tt>.
+
+To reload your controllers and models after launching the console run <tt>reload!</tt>
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
+You would be connected to the database with the credentials defined in database.yml.
+Starting the script without arguments will connect you to the development database. Passing an
+argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
+Currently works for mysql, postgresql and sqlite.
+
+== Description of Contents
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from ApplicationController
+ which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb.
+ Most models will descend from ActiveRecord::Base.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
+ syntax.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the common
+ header/footer method of wrapping views. In your views, define a layout using the
+ <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
+ call <% yield %> to render the view using this layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are generated
+ for you automatically when using script/generate for controllers. Helpers can be used to
+ wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database, and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all
+ the sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when generated
+ using <tt>rake doc:app</tt>
+
+lib
+ Application specific libraries. Basically, any kind of custom code that doesn't
+ belong under controllers, models, or helpers. This directory is in the load path.
+
+public
+ The directory available for the web server. Contains subdirectories for images, stylesheets,
+ and javascripts. Also contains the dispatchers and the default HTML files. This should be
+ set as the DOCUMENT_ROOT of your web server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the script/generate scripts, template
+ test files will be generated for you and placed in this directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins subdirectory.
+ If the app has frozen rails, those gems also go here, under vendor/rails/.
+ This directory is in the load path.
diff --git a/railties/fresh_rakefile b/railties/lib/generators/rails/app/templates/Rakefile
index 3bb0e8592a..3bb0e8592a 100755
--- a/railties/fresh_rakefile
+++ b/railties/lib/generators/rails/app/templates/Rakefile
diff --git a/railties/helpers/application_controller.rb b/railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb
index 6635a3f487..6635a3f487 100644
--- a/railties/helpers/application_controller.rb
+++ b/railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb
diff --git a/railties/helpers/application_helper.rb b/railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb
index 22a7940eb2..22a7940eb2 100644
--- a/railties/helpers/application_helper.rb
+++ b/railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb
diff --git a/railties/configs/empty.log b/railties/lib/generators/rails/app/templates/app/models/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/configs/empty.log
+++ b/railties/lib/generators/rails/app/templates/app/models/.empty_directory
diff --git a/railties/html/favicon.ico b/railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/html/favicon.ico
+++ b/railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory
diff --git a/railties/environments/boot.rb b/railties/lib/generators/rails/app/templates/config/boot.rb
index 0ad0f787f8..0ad0f787f8 100644
--- a/railties/environments/boot.rb
+++ b/railties/lib/generators/rails/app/templates/config/boot.rb
diff --git a/railties/configs/databases/frontbase.yml b/railties/lib/generators/rails/app/templates/config/databases/frontbase.yml
index c0c3588be1..c0c3588be1 100644
--- a/railties/configs/databases/frontbase.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/frontbase.yml
diff --git a/railties/configs/databases/ibm_db.yml b/railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml
index a9716ddb44..a9716ddb44 100644
--- a/railties/configs/databases/ibm_db.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml
diff --git a/railties/configs/databases/mysql.yml b/railties/lib/generators/rails/app/templates/config/databases/mysql.yml
index 1a14bfb332..6bf2f7b1fd 100644
--- a/railties/configs/databases/mysql.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/mysql.yml
@@ -22,8 +22,8 @@ development:
pool: 5
username: root
password:
-<% if socket -%>
- socket: <%= socket %>
+<% if mysql_socket -%>
+ socket: <%= mysql_socket %>
<% else -%>
host: localhost
<% end -%>
@@ -39,8 +39,8 @@ test:
pool: 5
username: root
password:
-<% if socket -%>
- socket: <%= socket %>
+<% if mysql_socket -%>
+ socket: <%= mysql_socket %>
<% else -%>
host: localhost
<% end -%>
@@ -53,8 +53,8 @@ production:
pool: 5
username: root
password:
-<% if socket -%>
- socket: <%= socket %>
+<% if mysql_socket -%>
+ socket: <%= mysql_socket %>
<% else -%>
host: localhost
<% end -%>
diff --git a/railties/configs/databases/oracle.yml b/railties/lib/generators/rails/app/templates/config/databases/oracle.yml
index a1883f6256..a1883f6256 100644
--- a/railties/configs/databases/oracle.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/oracle.yml
diff --git a/railties/configs/databases/postgresql.yml b/railties/lib/generators/rails/app/templates/config/databases/postgresql.yml
index f600e054cf..f600e054cf 100644
--- a/railties/configs/databases/postgresql.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/postgresql.yml
diff --git a/railties/configs/databases/sqlite2.yml b/railties/lib/generators/rails/app/templates/config/databases/sqlite2.yml
index 46f01cb42c..46f01cb42c 100644
--- a/railties/configs/databases/sqlite2.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/sqlite2.yml
diff --git a/railties/configs/databases/sqlite3.yml b/railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml
index 025d62a8d8..025d62a8d8 100644
--- a/railties/configs/databases/sqlite3.yml
+++ b/railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml
diff --git a/railties/environments/environment.rb b/railties/lib/generators/rails/app/templates/config/environment.rb
index 4a2df36307..94c90475c6 100644
--- a/railties/environments/environment.rb
+++ b/railties/lib/generators/rails/app/templates/config/environment.rb
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file
# Specifies gem version of Rails to use when vendor/rails is not present
-<%= '# ' if freeze %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>' unless defined? RAILS_GEM_VERSION
+<%= '# ' if options[:freeze] %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>' unless defined? RAILS_GEM_VERSION
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
@@ -26,10 +26,14 @@ Rails::Initializer.run do |config|
# Skip frameworks you're not going to use. To use Rails without a database,
# you must remove the Active Record framework.
+<% if options[:skip_activerecord] -%>
+ config.frameworks -= [ :active_record ]
+<% else -%>
# config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+<% end -%>
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names.
@@ -38,4 +42,12 @@ Rails::Initializer.run do |config|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
# config.i18n.default_locale = :de
-end \ No newline at end of file
+
+ # Configure generators values. Many other options are available, be sure to
+ # check the documentation.
+ config.generators do |g|
+ g.orm :active_record
+ g.template_engine :erb
+ g.test_framework :test_unit, :fixture => true
+ end
+end
diff --git a/railties/environments/development.rb b/railties/lib/generators/rails/app/templates/config/environments/development.rb
index 85c9a6080e..85c9a6080e 100644
--- a/railties/environments/development.rb
+++ b/railties/lib/generators/rails/app/templates/config/environments/development.rb
diff --git a/railties/environments/production.rb b/railties/lib/generators/rails/app/templates/config/environments/production.rb
index 1fc9f6b923..1fc9f6b923 100644
--- a/railties/environments/production.rb
+++ b/railties/lib/generators/rails/app/templates/config/environments/production.rb
diff --git a/railties/environments/test.rb b/railties/lib/generators/rails/app/templates/config/environments/test.rb
index 496eb9572b..496eb9572b 100644
--- a/railties/environments/test.rb
+++ b/railties/lib/generators/rails/app/templates/config/environments/test.rb
diff --git a/railties/configs/initializers/backtrace_silencers.rb b/railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb
index 839d4cde19..839d4cde19 100644
--- a/railties/configs/initializers/backtrace_silencers.rb
+++ b/railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb
diff --git a/railties/configs/initializers/inflections.rb b/railties/lib/generators/rails/app/templates/config/initializers/inflections.rb
index d531b8bb82..d531b8bb82 100644
--- a/railties/configs/initializers/inflections.rb
+++ b/railties/lib/generators/rails/app/templates/config/initializers/inflections.rb
diff --git a/railties/configs/initializers/mime_types.rb b/railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb
index 72aca7e441..72aca7e441 100644
--- a/railties/configs/initializers/mime_types.rb
+++ b/railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb
diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/lib/generators/rails/app/templates/config/initializers/new_rails_defaults.rb
index 8ec3186c84..8ec3186c84 100644
--- a/railties/configs/initializers/new_rails_defaults.rb
+++ b/railties/lib/generators/rails/app/templates/config/initializers/new_rails_defaults.rb
diff --git a/railties/configs/initializers/session_store.rb b/railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt
index 4499ab84b6..4499ab84b6 100644
--- a/railties/configs/initializers/session_store.rb
+++ b/railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt
diff --git a/railties/configs/locales/en.yml b/railties/lib/generators/rails/app/templates/config/locales/en.yml
index f265c068d8..f265c068d8 100644
--- a/railties/configs/locales/en.yml
+++ b/railties/lib/generators/rails/app/templates/config/locales/en.yml
diff --git a/railties/configs/routes.rb b/railties/lib/generators/rails/app/templates/config/routes.rb
index ea14ce1bfc..ea14ce1bfc 100644
--- a/railties/configs/routes.rb
+++ b/railties/lib/generators/rails/app/templates/config/routes.rb
diff --git a/railties/configs/seeds.rb b/railties/lib/generators/rails/app/templates/db/seeds.rb
index bc8695e6f0..bc8695e6f0 100644
--- a/railties/configs/seeds.rb
+++ b/railties/lib/generators/rails/app/templates/db/seeds.rb
diff --git a/railties/dispatches/config.ru b/railties/lib/generators/rails/app/templates/dispatchers/config.ru
index acbfe4e9ae..acbfe4e9ae 100644
--- a/railties/dispatches/config.ru
+++ b/railties/lib/generators/rails/app/templates/dispatchers/config.ru
diff --git a/railties/dispatches/dispatch.fcgi b/railties/lib/generators/rails/app/templates/dispatchers/dispatch.fcgi
index 664dbbbee8..f5b3b71875 100755
--- a/railties/dispatches/dispatch.fcgi
+++ b/railties/lib/generators/rails/app/templates/dispatchers/dispatch.fcgi
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+<%= shebang %>
#
# You may specify the path to the FastCGI crash log (a log of unhandled
# exceptions which forced the FastCGI instance to exit, great for debugging)
diff --git a/railties/dispatches/dispatch.rb b/railties/lib/generators/rails/app/templates/dispatchers/dispatch.rb
index 32fa3b2665..48e888113a 100755
--- a/railties/dispatches/dispatch.rb
+++ b/railties/lib/generators/rails/app/templates/dispatchers/dispatch.rb
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
diff --git a/railties/dispatches/gateway.cgi b/railties/lib/generators/rails/app/templates/dispatchers/gateway.cgi
index 0305b7f810..bdc1055a22 100755
--- a/railties/dispatches/gateway.cgi
+++ b/railties/lib/generators/rails/app/templates/dispatchers/gateway.cgi
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require 'drb'
diff --git a/railties/doc/README_FOR_APP b/railties/lib/generators/rails/app/templates/doc/README_FOR_APP
index fe41f5cc24..fe41f5cc24 100644
--- a/railties/doc/README_FOR_APP
+++ b/railties/lib/generators/rails/app/templates/doc/README_FOR_APP
diff --git a/railties/html/404.html b/railties/lib/generators/rails/app/templates/public/404.html
index 88ee108e90..88ee108e90 100644
--- a/railties/html/404.html
+++ b/railties/lib/generators/rails/app/templates/public/404.html
diff --git a/railties/html/422.html b/railties/lib/generators/rails/app/templates/public/422.html
index 9c3c96670b..9c3c96670b 100644
--- a/railties/html/422.html
+++ b/railties/lib/generators/rails/app/templates/public/422.html
diff --git a/railties/html/500.html b/railties/lib/generators/rails/app/templates/public/500.html
index f71c86e652..f71c86e652 100644
--- a/railties/html/500.html
+++ b/railties/lib/generators/rails/app/templates/public/500.html
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml b/railties/lib/generators/rails/app/templates/public/favicon.ico
index e69de29bb2..e69de29bb2 100644
--- a/railties/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml
+++ b/railties/lib/generators/rails/app/templates/public/favicon.ico
diff --git a/railties/html/images/rails.png b/railties/lib/generators/rails/app/templates/public/images/rails.png
index d5edc04e65..d5edc04e65 100644
--- a/railties/html/images/rails.png
+++ b/railties/lib/generators/rails/app/templates/public/images/rails.png
Binary files differ
diff --git a/railties/html/index.html b/railties/lib/generators/rails/app/templates/public/index.html
index ff2dfd3193..ff2dfd3193 100644
--- a/railties/html/index.html
+++ b/railties/lib/generators/rails/app/templates/public/index.html
diff --git a/railties/html/javascripts/application.js b/railties/lib/generators/rails/app/templates/public/javascripts/application.js
index fe4577696b..fe4577696b 100644
--- a/railties/html/javascripts/application.js
+++ b/railties/lib/generators/rails/app/templates/public/javascripts/application.js
diff --git a/railties/html/javascripts/controls.js b/railties/lib/generators/rails/app/templates/public/javascripts/controls.js
index ca29aefdd1..ca29aefdd1 100644
--- a/railties/html/javascripts/controls.js
+++ b/railties/lib/generators/rails/app/templates/public/javascripts/controls.js
diff --git a/railties/html/javascripts/dragdrop.js b/railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js
index 07229f986f..07229f986f 100644
--- a/railties/html/javascripts/dragdrop.js
+++ b/railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js
diff --git a/railties/html/javascripts/effects.js b/railties/lib/generators/rails/app/templates/public/javascripts/effects.js
index 5a639d2dea..5a639d2dea 100644
--- a/railties/html/javascripts/effects.js
+++ b/railties/lib/generators/rails/app/templates/public/javascripts/effects.js
diff --git a/railties/html/javascripts/prototype.js b/railties/lib/generators/rails/app/templates/public/javascripts/prototype.js
index dfe8ab4e13..dfe8ab4e13 100644
--- a/railties/html/javascripts/prototype.js
+++ b/railties/lib/generators/rails/app/templates/public/javascripts/prototype.js
diff --git a/railties/html/robots.txt b/railties/lib/generators/rails/app/templates/public/robots.txt
index 085187fa58..085187fa58 100644
--- a/railties/html/robots.txt
+++ b/railties/lib/generators/rails/app/templates/public/robots.txt
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml b/railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/lib/rails_generator/generators/components/mailer/templates/view.rhtml
+++ b/railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory
diff --git a/railties/bin/about b/railties/lib/generators/rails/app/templates/script/about.tt
index 1eeb6eb915..afbab8b533 100755
--- a/railties/bin/about
+++ b/railties/lib/generators/rails/app/templates/script/about.tt
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
$LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
require 'commands/about'
diff --git a/railties/bin/console b/railties/lib/generators/rails/app/templates/script/console.tt
index 235a1f2780..2f8b95c923 100755
--- a/railties/bin/console
+++ b/railties/lib/generators/rails/app/templates/script/console.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/console'
diff --git a/railties/bin/dbconsole b/railties/lib/generators/rails/app/templates/script/dbconsole.tt
index 83c8436a9d..7dce6d16dd 100755
--- a/railties/bin/dbconsole
+++ b/railties/lib/generators/rails/app/templates/script/dbconsole.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/dbconsole'
diff --git a/railties/bin/destroy b/railties/lib/generators/rails/app/templates/script/destroy.tt
index 88d295f7aa..053d3dea39 100755
--- a/railties/bin/destroy
+++ b/railties/lib/generators/rails/app/templates/script/destroy.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/destroy'
diff --git a/railties/bin/generate b/railties/lib/generators/rails/app/templates/script/generate.tt
index 62a8a4c0c5..ea4a0efd43 100755
--- a/railties/bin/generate
+++ b/railties/lib/generators/rails/app/templates/script/generate.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/generate'
diff --git a/railties/bin/performance/benchmarker b/railties/lib/generators/rails/app/templates/script/performance/benchmarker.tt
index 3bff809fb3..da9df7fab9 100755
--- a/railties/bin/performance/benchmarker
+++ b/railties/lib/generators/rails/app/templates/script/performance/benchmarker.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../../config/boot', __FILE__)
require 'commands/performance/benchmarker'
diff --git a/railties/bin/performance/profiler b/railties/lib/generators/rails/app/templates/script/performance/profiler.tt
index 07640575cd..5a0e2b0c28 100755
--- a/railties/bin/performance/profiler
+++ b/railties/lib/generators/rails/app/templates/script/performance/profiler.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../../config/boot', __FILE__)
require 'commands/performance/profiler'
diff --git a/railties/bin/plugin b/railties/lib/generators/rails/app/templates/script/plugin.tt
index b82201fa83..68b2148bba 100755
--- a/railties/bin/plugin
+++ b/railties/lib/generators/rails/app/templates/script/plugin.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/plugin'
diff --git a/railties/bin/runner b/railties/lib/generators/rails/app/templates/script/runner.tt
index be4c5d4572..a2b313fa32 100755
--- a/railties/bin/runner
+++ b/railties/lib/generators/rails/app/templates/script/runner.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/runner'
diff --git a/railties/bin/server b/railties/lib/generators/rails/app/templates/script/server.tt
index b9fcb71793..c8868155f3 100755
--- a/railties/bin/server
+++ b/railties/lib/generators/rails/app/templates/script/server.tt
@@ -1,3 +1,3 @@
-#!/usr/bin/env ruby
+<%= shebang %>
require File.expand_path('../../config/boot', __FILE__)
require 'commands/server'
diff --git a/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb b/railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_class/missing_class_generator.rb
+++ b/railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory
diff --git a/railties/test/fixtures/lib/generators/missing_class/templates/.gitignore b/railties/lib/generators/rails/app/templates/test/functional/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_class/templates/.gitignore
+++ b/railties/lib/generators/rails/app/templates/test/functional/.empty_directory
diff --git a/railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore b/railties/lib/generators/rails/app/templates/test/integration/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore
+++ b/railties/lib/generators/rails/app/templates/test/integration/.empty_directory
diff --git a/railties/helpers/performance_test.rb b/railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb
index 4b60558b43..4b60558b43 100644
--- a/railties/helpers/performance_test.rb
+++ b/railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb
diff --git a/railties/helpers/test_helper.rb b/railties/lib/generators/rails/app/templates/test/test_helper.rb
index b9fe2517c8..b9fe2517c8 100644
--- a/railties/helpers/test_helper.rb
+++ b/railties/lib/generators/rails/app/templates/test/test_helper.rb
diff --git a/railties/test/fixtures/lib/generators/missing_templates/.gitignore b/railties/lib/generators/rails/app/templates/test/unit/.empty_directory
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_templates/.gitignore
+++ b/railties/lib/generators/rails/app/templates/test/unit/.empty_directory
diff --git a/railties/lib/generators/rails/controller/USAGE b/railties/lib/generators/rails/controller/USAGE
new file mode 100644
index 0000000000..6ed4b2edfc
--- /dev/null
+++ b/railties/lib/generators/rails/controller/USAGE
@@ -0,0 +1,18 @@
+Description:
+ Stubs out a new controller and its views. Pass the controller name, either
+ CamelCased or under_scored, and a list of views as arguments.
+
+ To create a controller within a module, specify the controller name as a
+ path like 'parent_module/controller_name'.
+
+ This generates a controller class in app/controllers and invokes helper,
+ template engine and test framework generators.
+
+Example:
+ `./script/generate controller CreditCard open debit credit close`
+
+ Credit card controller with URLs like /credit_card/debit.
+ Controller: app/controllers/credit_card_controller.rb
+ Functional Test: test/functional/credit_card_controller_test.rb
+ Views: app/views/credit_card/debit.html.erb [...]
+ Helper: app/helpers/credit_card_helper.rb
diff --git a/railties/lib/generators/rails/controller/controller_generator.rb b/railties/lib/generators/rails/controller/controller_generator.rb
new file mode 100644
index 0000000000..91470be833
--- /dev/null
+++ b/railties/lib/generators/rails/controller/controller_generator.rb
@@ -0,0 +1,14 @@
+module Rails
+ module Generators
+ class ControllerGenerator < NamedBase
+ argument :actions, :type => :array, :default => [], :banner => "action action"
+ check_class_collision :suffix => "Controller"
+
+ def create_controller_files
+ template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb")
+ end
+
+ hook_for :template_engine, :test_framework, :helper
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/controller.rb b/railties/lib/generators/rails/controller/templates/controller.rb
index cda2659e69..cda2659e69 100644
--- a/railties/lib/rails_generator/generators/components/controller/templates/controller.rb
+++ b/railties/lib/generators/rails/controller/templates/controller.rb
diff --git a/railties/lib/generators/rails/generator/USAGE b/railties/lib/generators/rails/generator/USAGE
new file mode 100644
index 0000000000..ca7d3f62d0
--- /dev/null
+++ b/railties/lib/generators/rails/generator/USAGE
@@ -0,0 +1,11 @@
+Description:
+ Stubs out a new generator at lib/generators. Pass the generator name, either
+ CamelCased or under_scored, as an argument.
+
+Example:
+ `./script/generate generator Awesome`
+
+ creates a standard awesome generator:
+ lib/generators/awesome/
+ lib/generators/awesome/awesome_generator.rb
+ lib/generators/awesome/templates/
diff --git a/railties/lib/generators/rails/generator/generator_generator.rb b/railties/lib/generators/rails/generator/generator_generator.rb
new file mode 100644
index 0000000000..2fc97b20d3
--- /dev/null
+++ b/railties/lib/generators/rails/generator/generator_generator.rb
@@ -0,0 +1,25 @@
+module Rails
+ module Generators
+ class GeneratorGenerator < NamedBase
+ check_class_collision :suffix => "Generator"
+
+ class_option :namespace, :type => :boolean, :default => true,
+ :desc => "Namespace generator under lib/generators/name"
+
+ def craete_generator_files
+ directory '.', generator_dir
+ end
+
+ protected
+
+ def generator_dir
+ if options[:namespace]
+ File.join("lib", "generators", file_name)
+ else
+ File.join("lib", "generators")
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt
new file mode 100644
index 0000000000..675f00043f
--- /dev/null
+++ b/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt
@@ -0,0 +1,5 @@
+class <%= class_name %>Generator < Rails::Generators::NamedBase
+ def self.source_root
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/USAGE b/railties/lib/generators/rails/generator/templates/USAGE.tt
index ea9f4f12cc..ea9f4f12cc 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/USAGE
+++ b/railties/lib/generators/rails/generator/templates/USAGE.tt
diff --git a/railties/lib/generators/rails/generator/templates/templates/.empty_directory b/railties/lib/generators/rails/generator/templates/templates/.empty_directory
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/railties/lib/generators/rails/generator/templates/templates/.empty_directory
diff --git a/railties/lib/generators/rails/helper/USAGE b/railties/lib/generators/rails/helper/USAGE
new file mode 100644
index 0000000000..531c9b390a
--- /dev/null
+++ b/railties/lib/generators/rails/helper/USAGE
@@ -0,0 +1,17 @@
+Description:
+ Stubs out a new helper. Pass the helper name, either CamelCased
+ or under_scored.
+
+ To create a helper within a module, specify the helper name as a
+ path like 'parent_module/helper_name'.
+
+ This generates a helper class in app/helpers and invokes the configured
+ test framework.
+
+Example:
+ `./script/generate helper CreditCard`
+
+ Credit card helper.
+ Helper: app/helpers/credit_card_helper.rb
+ Test: test/unit/helpers/credit_card_helper_test.rb
+
diff --git a/railties/lib/generators/rails/helper/helper_generator.rb b/railties/lib/generators/rails/helper/helper_generator.rb
new file mode 100644
index 0000000000..ad66388591
--- /dev/null
+++ b/railties/lib/generators/rails/helper/helper_generator.rb
@@ -0,0 +1,13 @@
+module Rails
+ module Generators
+ class HelperGenerator < NamedBase
+ check_class_collision :suffix => "Helper"
+
+ def create_helper_files
+ template 'helper.rb', File.join('app/helpers', class_path, "#{file_name}_helper.rb")
+ end
+
+ hook_for :test_framework
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/helper.rb b/railties/lib/generators/rails/helper/templates/helper.rb
index 3fe2ecdc74..3fe2ecdc74 100644
--- a/railties/lib/rails_generator/generators/components/controller/templates/helper.rb
+++ b/railties/lib/generators/rails/helper/templates/helper.rb
diff --git a/railties/lib/rails_generator/generators/components/integration_test/USAGE b/railties/lib/generators/rails/integration_test/USAGE
index 09e2691f69..b76c35a702 100644
--- a/railties/lib/rails_generator/generators/components/integration_test/USAGE
+++ b/railties/lib/generators/rails/integration_test/USAGE
@@ -1,7 +1,9 @@
Description:
Stubs out a new integration test. Pass the name of the test, either
- CamelCased or under_scored, as an argument. The new test class is
- generated in test/integration/testname_test.rb
+ CamelCased or under_scored, as an argument.
+
+ This generator invokes the current integration tool, which defaults to
+ TestUnit.
Example:
`./script/generate integration_test GeneralStories` creates a GeneralStories
diff --git a/railties/lib/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/generators/rails/integration_test/integration_test_generator.rb
new file mode 100644
index 0000000000..363a327fcb
--- /dev/null
+++ b/railties/lib/generators/rails/integration_test/integration_test_generator.rb
@@ -0,0 +1,7 @@
+module Rails
+ module Generators
+ class IntegrationTestGenerator < NamedBase
+ hook_for :integration_tool, :as => :integration
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/mailer/USAGE b/railties/lib/generators/rails/mailer/USAGE
index 61a649ed4d..c56095b2c8 100644
--- a/railties/lib/rails_generator/generators/components/mailer/USAGE
+++ b/railties/lib/generators/rails/mailer/USAGE
@@ -2,9 +2,8 @@ Description:
Stubs out a new mailer and its views. Pass the mailer name, either
CamelCased or under_scored, and an optional list of emails as arguments.
- This generates a mailer class in app/models, view templates in
- app/views/mailer_name, a unit test in test/unit, and fixtures in
- test/fixtures.
+ This generates a mailer class in app/models and invokes your template
+ engine and test framework generators.
Example:
`./script/generate mailer Notifications signup forgot_password invoice`
diff --git a/railties/lib/generators/rails/mailer/mailer_generator.rb b/railties/lib/generators/rails/mailer/mailer_generator.rb
new file mode 100644
index 0000000000..33f1665b83
--- /dev/null
+++ b/railties/lib/generators/rails/mailer/mailer_generator.rb
@@ -0,0 +1,14 @@
+module Rails
+ module Generators
+ class MailerGenerator < NamedBase
+ argument :actions, :type => :array, :default => [], :banner => "method method"
+ check_class_collision
+
+ def create_mailer_file
+ template "mailer.rb", File.join('app/models', class_path, "#{file_name}.rb")
+ end
+
+ hook_for :template_engine, :test_framework
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb b/railties/lib/generators/rails/mailer/templates/mailer.rb
index ce15ae9de9..ce15ae9de9 100644
--- a/railties/lib/rails_generator/generators/components/mailer/templates/mailer.rb
+++ b/railties/lib/generators/rails/mailer/templates/mailer.rb
diff --git a/railties/lib/rails_generator/generators/components/metal/USAGE b/railties/lib/generators/rails/metal/USAGE
index 123ec6c03f..123ec6c03f 100644
--- a/railties/lib/rails_generator/generators/components/metal/USAGE
+++ b/railties/lib/generators/rails/metal/USAGE
diff --git a/railties/lib/generators/rails/metal/metal_generator.rb b/railties/lib/generators/rails/metal/metal_generator.rb
new file mode 100644
index 0000000000..fe4f945cad
--- /dev/null
+++ b/railties/lib/generators/rails/metal/metal_generator.rb
@@ -0,0 +1,11 @@
+module Rails
+ module Generators
+ class MetalGenerator < NamedBase
+ check_class_collision
+
+ def create_metal_file
+ template "metal.rb", "app/metal/#{file_name}.rb"
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/metal/templates/metal.rb b/railties/lib/generators/rails/metal/templates/metal.rb
index e94982b69a..e94982b69a 100644
--- a/railties/lib/rails_generator/generators/components/metal/templates/metal.rb
+++ b/railties/lib/generators/rails/metal/templates/metal.rb
diff --git a/railties/lib/rails_generator/generators/components/migration/USAGE b/railties/lib/generators/rails/migration/USAGE
index b83c657963..d91127aac3 100644
--- a/railties/lib/rails_generator/generators/components/migration/USAGE
+++ b/railties/lib/generators/rails/migration/USAGE
@@ -14,7 +14,7 @@ Example:
db/migrate/20080514090912_add_ssl_flag.rb
`./script/generate migration AddTitleBodyToPost title:string body:text published:boolean`
-
+
This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with
this in the Up migration:
@@ -23,7 +23,7 @@ Example:
add_column :posts, :published, :boolean
And this in the Down migration:
-
+
remove_column :posts, :published
remove_column :posts, :body
remove_column :posts, :title
diff --git a/railties/lib/generators/rails/migration/migration_generator.rb b/railties/lib/generators/rails/migration/migration_generator.rb
new file mode 100644
index 0000000000..39fa5b63b1
--- /dev/null
+++ b/railties/lib/generators/rails/migration/migration_generator.rb
@@ -0,0 +1,8 @@
+module Rails
+ module Generators
+ class MigrationGenerator < NamedBase #metagenerator
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ hook_for :orm, :required => true
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/model/USAGE b/railties/lib/generators/rails/model/USAGE
index 24b03b4d4a..b056d5df8b 100644
--- a/railties/lib/rails_generator/generators/components/model/USAGE
+++ b/railties/lib/generators/rails/model/USAGE
@@ -2,21 +2,24 @@ Description:
Stubs out a new model. Pass the model name, either CamelCased or
under_scored, and an optional list of attribute pairs as arguments.
- Attribute pairs are column_name:sql_type arguments specifying the
+ Attribute pairs are field:type arguments specifying the
model's attributes. Timestamps are added by default, so you don't have to
specify them by hand as 'created_at:datetime updated_at:datetime'.
You don't have to think up every attribute up front, but it helps to
sketch out a few so you can start working with the model immediately.
- This generates a model class in app/models, a unit test in test/unit,
- a test fixture in test/fixtures/singular_name.yml, and a migration in
- db/migrate.
+ This generator invokes your configured ORM and test framework, which
+ defaults to ActiveRecord and TestUnit.
+
+ Finally, if --parent option is given, it's used as superclass of the
+ created model. This allows you create Single Table Inheritance models.
Examples:
`./script/generate model account`
- creates an Account model, test, fixture, and migration:
+ For ActiveRecord and TestUnit it creates:
+
Model: app/models/account.rb
Test: test/unit/account_test.rb
Fixtures: test/fixtures/accounts.yml
@@ -24,4 +27,4 @@ Examples:
`./script/generate model post title:string body:text published:boolean`
- creates a Post model with a string title, text body, and published flag.
+ Creates a Post model with a string title, text body, and published flag.
diff --git a/railties/lib/generators/rails/model/model_generator.rb b/railties/lib/generators/rails/model/model_generator.rb
new file mode 100644
index 0000000000..629d5eed3f
--- /dev/null
+++ b/railties/lib/generators/rails/model/model_generator.rb
@@ -0,0 +1,8 @@
+module Rails
+ module Generators
+ class ModelGenerator < NamedBase #metagenerator
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ hook_for :orm, :required => true
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb b/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb
new file mode 100644
index 0000000000..4649709780
--- /dev/null
+++ b/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb
@@ -0,0 +1,11 @@
+module Rails
+ module Generators
+ class ModelSubclassGenerator < Base
+ desc "model_subclass is deprecated. Invoke model with --parent option instead."
+
+ def say_deprecation_warn
+ say self.class.desc
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/observer/USAGE b/railties/lib/generators/rails/observer/USAGE
index a5d744a3c2..9a20f55a89 100644
--- a/railties/lib/rails_generator/generators/components/observer/USAGE
+++ b/railties/lib/generators/rails/observer/USAGE
@@ -2,12 +2,11 @@ Description:
Stubs out a new observer. Pass the observer name, either CamelCased or
under_scored, as an argument.
- The generator creates an observer class in app/models and a unit test in
- test/unit.
+ This generator only invokes your ORM and test framework generators.
Example:
`./script/generate observer Account`
- creates an Account observer and unit test:
+ For ActiveRecord and TestUnit it creates:
Observer: app/models/account_observer.rb
- Test: test/unit/account_observer_test.rb
+ TestUnit: test/unit/account_observer_test.rb
diff --git a/railties/lib/generators/rails/observer/observer_generator.rb b/railties/lib/generators/rails/observer/observer_generator.rb
new file mode 100644
index 0000000000..f5cedee91f
--- /dev/null
+++ b/railties/lib/generators/rails/observer/observer_generator.rb
@@ -0,0 +1,7 @@
+module Rails
+ module Generators
+ class ObserverGenerator < NamedBase #metagenerator
+ hook_for :orm, :required => true
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/USAGE b/railties/lib/generators/rails/performance_test/USAGE
index d84051eb02..ee82578cdb 100644
--- a/railties/lib/rails_generator/generators/components/performance_test/USAGE
+++ b/railties/lib/generators/rails/performance_test/USAGE
@@ -1,7 +1,9 @@
Description:
Stubs out a new performance test. Pass the name of the test, either
- CamelCased or under_scored, as an argument. The new test class is
- generated in test/performance/testname_test.rb
+ CamelCased or under_scored, as an argument.
+
+ This generator invokes the current performance tool, which defaults to
+ TestUnit.
Example:
`./script/generate performance_test GeneralStories` creates a GeneralStories
diff --git a/railties/lib/generators/rails/performance_test/performance_test_generator.rb b/railties/lib/generators/rails/performance_test/performance_test_generator.rb
new file mode 100644
index 0000000000..d1c71ab8ed
--- /dev/null
+++ b/railties/lib/generators/rails/performance_test/performance_test_generator.rb
@@ -0,0 +1,7 @@
+module Rails
+ module Generators
+ class PerformanceTestGenerator < NamedBase
+ hook_for :performance_tool, :as => :performance
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/plugin/USAGE b/railties/lib/generators/rails/plugin/USAGE
new file mode 100644
index 0000000000..8a17fa4dec
--- /dev/null
+++ b/railties/lib/generators/rails/plugin/USAGE
@@ -0,0 +1,13 @@
+Description:
+ Stubs out a new plugin at vendor/plugins. Pass the plugin name, either
+ CamelCased or under_scored, as an argument.
+
+Example:
+ `./script/generate plugin BrowserFilters`
+
+ creates a standard browser_filters plugin:
+ vendor/plugins/browser_filters/README
+ vendor/plugins/browser_filters/init.rb
+ vendor/plugins/browser_filters/install.rb
+ vendor/plugins/browser_filters/lib/browser_filters.rb
+ vendor/plugins/browser_filters/test/browser_filters_test.rb
diff --git a/railties/lib/generators/rails/plugin/plugin_generator.rb b/railties/lib/generators/rails/plugin/plugin_generator.rb
new file mode 100644
index 0000000000..ee785caf7d
--- /dev/null
+++ b/railties/lib/generators/rails/plugin/plugin_generator.rb
@@ -0,0 +1,47 @@
+require 'generators/rails/generator/generator_generator'
+
+module Rails
+ module Generators
+ class PluginGenerator < NamedBase
+ class_option :tasks, :desc => "When supplied creates tasks base files."
+
+ check_class_collision
+
+ def create_root_files
+ directory '.', plugin_dir, :recursive => false
+ end
+
+ def create_lib_files
+ directory 'lib', plugin_dir('lib'), :recursive => false
+ end
+
+ def create_tasks_files
+ return unless options[:tasks]
+ directory 'tasks', plugin_dir('tasks')
+ end
+
+ hook_for :generator do |instance, generator|
+ instance.inside instance.send(:plugin_dir), :verbose => true do
+ instance.invoke generator, [ instance.name ], :namespace => false
+ end
+ end
+
+ hook_for :test_framework do |instance, test_framework|
+ instance.inside instance.send(:plugin_dir), :verbose => true do
+ instance.invoke test_framework
+ end
+ end
+
+ protected
+
+ def plugin_dir(join=nil)
+ if join
+ File.join(plugin_dir, join)
+ else
+ "vendor/plugins/#{file_name}"
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE b/railties/lib/generators/rails/plugin/templates/MIT-LICENSE
index 8717df053d..8717df053d 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE
+++ b/railties/lib/generators/rails/plugin/templates/MIT-LICENSE
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/README b/railties/lib/generators/rails/plugin/templates/README
index 702db07cb1..702db07cb1 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/README
+++ b/railties/lib/generators/rails/plugin/templates/README
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile b/railties/lib/generators/rails/plugin/templates/Rakefile
index 85e8ff1834..85e8ff1834 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/Rakefile
+++ b/railties/lib/generators/rails/plugin/templates/Rakefile
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/init.rb b/railties/lib/generators/rails/plugin/templates/init.rb
index 3c19a743c9..3c19a743c9 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/init.rb
+++ b/railties/lib/generators/rails/plugin/templates/init.rb
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/install.rb b/railties/lib/generators/rails/plugin/templates/install.rb
index f7732d3796..f7732d3796 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/install.rb
+++ b/railties/lib/generators/rails/plugin/templates/install.rb
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb b/railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt
index d8d908a959..d8d908a959 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/plugin.rb
+++ b/railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake b/railties/lib/generators/rails/plugin/templates/tasks/%file_name%_tasks.rake.tt
index 72920a9d3a..72920a9d3a 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/tasks.rake
+++ b/railties/lib/generators/rails/plugin/templates/tasks/%file_name%_tasks.rake.tt
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb b/railties/lib/generators/rails/plugin/templates/uninstall.rb
index 9738333463..9738333463 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/uninstall.rb
+++ b/railties/lib/generators/rails/plugin/templates/uninstall.rb
diff --git a/railties/lib/rails_generator/generators/components/resource/USAGE b/railties/lib/generators/rails/resource/USAGE
index e6043f1de1..936619b0db 100644
--- a/railties/lib/rails_generator/generators/components/resource/USAGE
+++ b/railties/lib/generators/rails/resource/USAGE
@@ -4,15 +4,15 @@ Description:
either CamelCased or under_scored, as the first argument, and an optional
list of attribute pairs.
- Attribute pairs are column_name:sql_type arguments specifying the
+ Attribute pairs are field:type arguments specifying the
model's attributes. Timestamps are added by default, so you don't have to
specify them by hand as 'created_at:datetime updated_at:datetime'.
You don't have to think up every attribute up front, but it helps to
- sketch out a few so you can start working with the resource immediately.
+ sketch out a few so you can start working with the model immediately.
- This creates a model, controller, helper, tests and fixtures for all of them,
- and the corresponding map.resources declaration in config/routes.rb
+ This generator invokes your configured ORM and test framework, besides
+ creating helpers and add routes to config/routes.rb.
Unlike the scaffold generator, the resource generator does not create
views or add any methods to the generated controller.
diff --git a/railties/lib/generators/rails/resource/resource_generator.rb b/railties/lib/generators/rails/resource/resource_generator.rb
new file mode 100644
index 0000000000..70babc0550
--- /dev/null
+++ b/railties/lib/generators/rails/resource/resource_generator.rb
@@ -0,0 +1,40 @@
+require 'generators/rails/model/model_generator'
+
+module Rails
+ module Generators
+ class ResourceGenerator < ModelGenerator #metagenerator
+ hook_for :resource_controller, :required => true do |base, controller|
+ base.invoke controller, [ base.name.pluralize, base.options[:actions] ]
+ end
+
+ class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [],
+ :desc => "Actions for the resource controller"
+
+ class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller"
+ class_option :force_plural, :type => :boolean, :desc => "Forces the use of a plural ModelName"
+
+ def initialize(*args)
+ super
+ if name == name.pluralize && !options[:force_plural]
+ say "Plural version of the model detected, using singularized version. Override with --force-plural."
+ name.replace name.singularize
+ end
+ end
+
+ def add_resource_route
+ route "map.resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}"
+ end
+
+ protected
+
+ def pluralize?(name)
+ if options[:singleton]
+ name
+ else
+ name.pluralize
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/USAGE b/railties/lib/generators/rails/scaffold/USAGE
index 810aea16f1..71edd2f469 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/USAGE
+++ b/railties/lib/generators/rails/scaffold/USAGE
@@ -7,7 +7,7 @@ Description:
under_scored, as the first argument, and an optional list of attribute
pairs.
- Attribute pairs are column_name:sql_type arguments specifying the
+ Attribute pairs are field:type arguments specifying the
model's attributes. Timestamps are added by default, so you don't have to
specify them by hand as 'created_at:datetime updated_at:datetime'.
diff --git a/railties/lib/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/generators/rails/scaffold/scaffold_generator.rb
new file mode 100644
index 0000000000..af44c8ba65
--- /dev/null
+++ b/railties/lib/generators/rails/scaffold/scaffold_generator.rb
@@ -0,0 +1,12 @@
+require 'generators/rails/resource/resource_generator'
+
+module Rails
+ module Generators
+ class ScaffoldGenerator < ResourceGenerator #metagenerator
+ remove_hook_for :actions, :resource_controller
+
+ hook_for :scaffold_controller, :required => true
+ hook_for :stylesheets
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/scaffold_controller/USAGE b/railties/lib/generators/rails/scaffold_controller/USAGE
new file mode 100644
index 0000000000..d60a3c3680
--- /dev/null
+++ b/railties/lib/generators/rails/scaffold_controller/USAGE
@@ -0,0 +1,20 @@
+Description:
+ Stubs out a scaffolded controller and its views. Pass the model name,
+ either CamelCased or under_scored, and a list of views as arguments.
+ The controller name is retrieved as a pluralized version of the model
+ name.
+
+ To create a controller within a module, specify the model name as a
+ path like 'parent_module/controller_name'.
+
+ This generates a controller class in app/controllers and invokes helper,
+ template engine and test framework generators.
+
+Example:
+ `./script/generate scaffold_controller CreditCard`
+
+ Credit card controller with URLs like /credit_card/debit.
+ Controller: app/controllers/credit_cards_controller.rb
+ Functional Test: test/functional/credit_cards_controller_test.rb
+ Views: app/views/credit_cards/index.html.erb [...]
+ Helper: app/helpers/credit_cards_helper.rb
diff --git a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb
new file mode 100644
index 0000000000..972be5a33b
--- /dev/null
+++ b/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb
@@ -0,0 +1,26 @@
+module Rails
+ module Generators
+ class ScaffoldControllerGenerator < NamedBase
+ # Add controller methods and ActionORM settings.
+ include ScaffoldBase
+
+ check_class_collision :suffix => "Controller"
+
+ class_option :orm, :banner => "NAME", :type => :string, :required => true,
+ :desc => "ORM to generate the controller for"
+
+ class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller"
+
+ def create_controller_files
+ template 'controller.rb', File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb")
+ end
+
+ hook_for :template_engine, :test_framework, :as => :scaffold
+
+ # Invoke the helper using the controller (pluralized) name.
+ hook_for :helper, :as => :scaffold do |base, invoked|
+ base.invoke invoked, [ base.controller_name ]
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb b/railties/lib/generators/rails/scaffold_controller/templates/controller.rb
index 4d190b9362..3cc8bbf8e7 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb
+++ b/railties/lib/generators/rails/scaffold_controller/templates/controller.rb
@@ -1,19 +1,21 @@
class <%= controller_class_name %>Controller < ApplicationController
+<% unless options[:singleton] -%>
# GET /<%= table_name %>
# GET /<%= table_name %>.xml
def index
- @<%= table_name %> = <%= class_name %>.all
+ @<%= table_name %> = <%= orm_class.all(class_name) %>
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @<%= table_name %> }
end
end
+<% end -%>
# GET /<%= table_name %>/1
# GET /<%= table_name %>/1.xml
def show
- @<%= file_name %> = <%= class_name %>.find(params[:id])
+ @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %>
respond_to do |format|
format.html # show.html.erb
@@ -24,7 +26,7 @@ class <%= controller_class_name %>Controller < ApplicationController
# GET /<%= table_name %>/new
# GET /<%= table_name %>/new.xml
def new
- @<%= file_name %> = <%= class_name %>.new
+ @<%= file_name %> = <%= orm_class.build(class_name) %>
respond_to do |format|
format.html # new.html.erb
@@ -34,22 +36,22 @@ class <%= controller_class_name %>Controller < ApplicationController
# GET /<%= table_name %>/1/edit
def edit
- @<%= file_name %> = <%= class_name %>.find(params[:id])
+ @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %>
end
# POST /<%= table_name %>
# POST /<%= table_name %>.xml
def create
- @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
+ @<%= file_name %> = <%= orm_class.build(class_name, "params[:#{file_name}]") %>
respond_to do |format|
- if @<%= file_name %>.save
+ if @<%= orm_instance.save %>
flash[:notice] = '<%= class_name %> was successfully created.'
format.html { redirect_to(@<%= file_name %>) }
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
else
format.html { render :action => "new" }
- format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
+ format.xml { render :xml => @<%= orm_instance.errors %>, :status => :unprocessable_entity }
end
end
end
@@ -57,16 +59,16 @@ class <%= controller_class_name %>Controller < ApplicationController
# PUT /<%= table_name %>/1
# PUT /<%= table_name %>/1.xml
def update
- @<%= file_name %> = <%= class_name %>.find(params[:id])
+ @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %>
respond_to do |format|
- if @<%= file_name %>.update_attributes(params[:<%= file_name %>])
+ if @<%= orm_instance.update_attributes("params[:#{file_name}]") %>
flash[:notice] = '<%= class_name %> was successfully updated.'
format.html { redirect_to(@<%= file_name %>) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
- format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
+ format.xml { render :xml => @<%= orm_instance.errors %>, :status => :unprocessable_entity }
end
end
end
@@ -74,8 +76,8 @@ class <%= controller_class_name %>Controller < ApplicationController
# DELETE /<%= table_name %>/1
# DELETE /<%= table_name %>/1.xml
def destroy
- @<%= file_name %> = <%= class_name %>.find(params[:id])
- @<%= file_name %>.destroy
+ @<%= file_name %> = <%= orm_class.find(class_name, "params[:id]") %>
+ @<%= orm_instance.destroy %>
respond_to do |format|
format.html { redirect_to(<%= table_name %>_url) }
diff --git a/railties/lib/generators/rails/session_migration/USAGE b/railties/lib/generators/rails/session_migration/USAGE
new file mode 100644
index 0000000000..e106f6ecc8
--- /dev/null
+++ b/railties/lib/generators/rails/session_migration/USAGE
@@ -0,0 +1,8 @@
+Description:
+ Creates a migration to add the sessions table used by the ORM session store.
+ Pass the migration name, either CamelCased or under_scored, as an argument.
+
+ Before invoking this generator, be sure that your ORM supports session stores.
+
+Example:
+ `./script/generate session_migration CreateSessionTable`
diff --git a/railties/lib/generators/rails/session_migration/session_migration_generator.rb b/railties/lib/generators/rails/session_migration/session_migration_generator.rb
new file mode 100644
index 0000000000..258cc5b4a0
--- /dev/null
+++ b/railties/lib/generators/rails/session_migration/session_migration_generator.rb
@@ -0,0 +1,8 @@
+module Rails
+ module Generators
+ class SessionMigrationGenerator < NamedBase #metagenerator
+ argument :name, :type => :string, :default => "add_sessions_table"
+ hook_for :orm, :required => true
+ end
+ end
+end
diff --git a/railties/lib/generators/rails/stylesheets/USAGE b/railties/lib/generators/rails/stylesheets/USAGE
new file mode 100644
index 0000000000..d6a81e51d0
--- /dev/null
+++ b/railties/lib/generators/rails/stylesheets/USAGE
@@ -0,0 +1,5 @@
+Description:
+ Copies scaffold stylesheets to public/stylesheets/.
+
+Examples:
+ `./script/generate stylesheets`
diff --git a/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb b/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb
new file mode 100644
index 0000000000..ce68443c39
--- /dev/null
+++ b/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb
@@ -0,0 +1,9 @@
+module Rails
+ module Generators
+ class StylesheetsGenerator < Base
+ def copy_stylesheets_file
+ template "scaffold.css", "public/stylesheets/scaffold.css" if behavior == :invoke
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/style.css b/railties/lib/generators/rails/stylesheets/templates/scaffold.css
index 093c20994d..093c20994d 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/style.css
+++ b/railties/lib/generators/rails/stylesheets/templates/scaffold.css
diff --git a/railties/lib/generators/test_unit.rb b/railties/lib/generators/test_unit.rb
new file mode 100644
index 0000000000..2763feb017
--- /dev/null
+++ b/railties/lib/generators/test_unit.rb
@@ -0,0 +1,8 @@
+require 'generators/named_base'
+
+module TestUnit
+ module Generators
+ class Base < Rails::Generators::NamedBase #:nodoc:
+ end
+ end
+end
diff --git a/railties/lib/generators/test_unit/controller/controller_generator.rb b/railties/lib/generators/test_unit/controller/controller_generator.rb
new file mode 100644
index 0000000000..b57a6e794f
--- /dev/null
+++ b/railties/lib/generators/test_unit/controller/controller_generator.rb
@@ -0,0 +1,14 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class ControllerGenerator < Base
+ check_class_collision :suffix => "ControllerTest"
+
+ def create_test_files
+ template 'functional_test.rb',
+ File.join('test/functional', class_path, "#{file_name}_controller_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb b/railties/lib/generators/test_unit/controller/templates/functional_test.rb
index 62fa5d86fd..62fa5d86fd 100644
--- a/railties/lib/rails_generator/generators/components/controller/templates/functional_test.rb
+++ b/railties/lib/generators/test_unit/controller/templates/functional_test.rb
diff --git a/railties/lib/generators/test_unit/helper/helper_generator.rb b/railties/lib/generators/test_unit/helper/helper_generator.rb
new file mode 100644
index 0000000000..9ecfaa45ab
--- /dev/null
+++ b/railties/lib/generators/test_unit/helper/helper_generator.rb
@@ -0,0 +1,13 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class HelperGenerator < Base
+ check_class_collision :suffix => "HelperTest"
+
+ def create_helper_files
+ template 'helper_test.rb', File.join('test/unit/helpers', class_path, "#{file_name}_helper_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/helper_test.rb b/railties/lib/generators/test_unit/helper/templates/helper_test.rb
index 591e40900e..591e40900e 100644
--- a/railties/lib/rails_generator/generators/components/controller/templates/helper_test.rb
+++ b/railties/lib/generators/test_unit/helper/templates/helper_test.rb
diff --git a/railties/lib/generators/test_unit/integration/integration_generator.rb b/railties/lib/generators/test_unit/integration/integration_generator.rb
new file mode 100644
index 0000000000..d9d9b3bf1d
--- /dev/null
+++ b/railties/lib/generators/test_unit/integration/integration_generator.rb
@@ -0,0 +1,13 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class IntegrationGenerator < Base
+ check_class_collision :suffix => "Test"
+
+ def create_test_files
+ template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb b/railties/lib/generators/test_unit/integration/templates/integration_test.rb
index 2c57158b1c..2c57158b1c 100644
--- a/railties/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb
+++ b/railties/lib/generators/test_unit/integration/templates/integration_test.rb
diff --git a/railties/lib/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/generators/test_unit/mailer/mailer_generator.rb
new file mode 100644
index 0000000000..ef350a6224
--- /dev/null
+++ b/railties/lib/generators/test_unit/mailer/mailer_generator.rb
@@ -0,0 +1,21 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class MailerGenerator < Base
+ argument :actions, :type => :array, :default => [], :banner => "method method"
+ check_class_collision :suffix => "Test"
+
+ def create_test_files
+ template "unit_test.rb", File.join('test/unit', class_path, "#{file_name}_test.rb")
+ end
+
+ def create_fixtures_files
+ actions.each do |action|
+ @action, @path = action, File.join(file_path, action)
+ template "fixture", File.join("test/fixtures", @path)
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/test_unit/mailer/templates/fixture b/railties/lib/generators/test_unit/mailer/templates/fixture
new file mode 100644
index 0000000000..fcce7bd805
--- /dev/null
+++ b/railties/lib/generators/test_unit/mailer/templates/fixture
@@ -0,0 +1,3 @@
+<%= class_name %>#<%= @action %>
+
+Find me in app/views/<%= @path %>
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb b/railties/lib/generators/test_unit/mailer/templates/unit_test.rb
index 4de94076e9..4de94076e9 100644
--- a/railties/lib/rails_generator/generators/components/mailer/templates/unit_test.rb
+++ b/railties/lib/generators/test_unit/mailer/templates/unit_test.rb
diff --git a/railties/lib/generators/test_unit/model/model_generator.rb b/railties/lib/generators/test_unit/model/model_generator.rb
new file mode 100644
index 0000000000..469306e6c5
--- /dev/null
+++ b/railties/lib/generators/test_unit/model/model_generator.rb
@@ -0,0 +1,24 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class ModelGenerator < Base
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ class_option :fixture, :type => :boolean
+
+ check_class_collision :suffix => "Test"
+
+ def create_test_file
+ template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
+ end
+
+ hook_for :fixture_replacement
+
+ def create_fixture_file
+ if options[:fixture] && options[:fixture_replacement].nil?
+ template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml")
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml b/railties/lib/generators/test_unit/model/templates/fixtures.yml
index c21035113e..c21035113e 100644
--- a/railties/lib/rails_generator/generators/components/model/templates/fixtures.yml
+++ b/railties/lib/generators/test_unit/model/templates/fixtures.yml
diff --git a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb b/railties/lib/generators/test_unit/model/templates/unit_test.rb
index 3e0bc29d3a..3e0bc29d3a 100644
--- a/railties/lib/rails_generator/generators/components/model/templates/unit_test.rb
+++ b/railties/lib/generators/test_unit/model/templates/unit_test.rb
diff --git a/railties/lib/generators/test_unit/observer/observer_generator.rb b/railties/lib/generators/test_unit/observer/observer_generator.rb
new file mode 100644
index 0000000000..14181f4e49
--- /dev/null
+++ b/railties/lib/generators/test_unit/observer/observer_generator.rb
@@ -0,0 +1,13 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class ObserverGenerator < Base
+ check_class_collision :suffix => "ObserverTest"
+
+ def create_test_files
+ template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_observer_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb b/railties/lib/generators/test_unit/observer/templates/unit_test.rb
index 03f6d5666e..03f6d5666e 100644
--- a/railties/lib/rails_generator/generators/components/observer/templates/unit_test.rb
+++ b/railties/lib/generators/test_unit/observer/templates/unit_test.rb
diff --git a/railties/lib/generators/test_unit/performance/performance_generator.rb b/railties/lib/generators/test_unit/performance/performance_generator.rb
new file mode 100644
index 0000000000..0d9c646b26
--- /dev/null
+++ b/railties/lib/generators/test_unit/performance/performance_generator.rb
@@ -0,0 +1,13 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class PerformanceGenerator < Base
+ check_class_collision :suffix => "Test"
+
+ def create_test_files
+ template 'performance_test.rb', File.join('test/performance', class_path, "#{file_name}_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb b/railties/lib/generators/test_unit/performance/templates/performance_test.rb
index 27c91b0fca..27c91b0fca 100644
--- a/railties/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb
+++ b/railties/lib/generators/test_unit/performance/templates/performance_test.rb
diff --git a/railties/lib/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/generators/test_unit/plugin/plugin_generator.rb
new file mode 100644
index 0000000000..05adf58c4f
--- /dev/null
+++ b/railties/lib/generators/test_unit/plugin/plugin_generator.rb
@@ -0,0 +1,13 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class PluginGenerator < Base
+ check_class_collision :suffix => "Test"
+
+ def create_test_files
+ directory '.', 'test'
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/model_subclass/templates/unit_test.rb b/railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt
index 3e0bc29d3a..3e0bc29d3a 100644
--- a/railties/lib/rails_generator/generators/components/model_subclass/templates/unit_test.rb
+++ b/railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb b/railties/lib/generators/test_unit/plugin/templates/test_helper.rb
index cf148b8b47..cf148b8b47 100644
--- a/railties/lib/rails_generator/generators/components/plugin/templates/test_helper.rb
+++ b/railties/lib/generators/test_unit/plugin/templates/test_helper.rb
diff --git a/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb
new file mode 100644
index 0000000000..78fcea1e9c
--- /dev/null
+++ b/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb
@@ -0,0 +1,17 @@
+require 'generators/test_unit'
+
+module TestUnit
+ module Generators
+ class ScaffoldGenerator < Base
+ include Rails::Generators::ScaffoldBase
+
+ class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller"
+ check_class_collision :suffix => "ControllerTest"
+
+ def create_test_files
+ template 'functional_test.rb',
+ File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb b/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb
index cd2fc578bf..e4bf4035da 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb
+++ b/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb
@@ -1,11 +1,13 @@
require 'test_helper'
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
+<% unless options[:singleton] -%>
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:<%= table_name %>)
end
+<% end -%>
test "should get new" do
get :new
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index f0fb78c8f4..bb04dfa370 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -568,4 +568,13 @@ Run `rake gems:install` to install the missing gems.
ActiveSupport::Dependencies.unhook!
end
end
+
+ # Configure generators if they were already loaded
+ Initializer.default.add :initialize_generators do
+ if defined?(Rails::Generators)
+ Rails::Generators.no_color! unless config.generators.colorize_logging
+ Rails::Generators.aliases.deep_merge! config.generators.aliases
+ Rails::Generators.options.deep_merge! config.generators.options
+ end
+ end
end
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index 1a2f217d20..fe3cb67d3a 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -249,5 +249,51 @@ module Rails
def reload_plugins?
@reload_plugins
end
+
+ # Holds generators configuration:
+ #
+ # config.generators do |g|
+ # g.orm :datamapper, :migration => true
+ # g.template_engine :haml
+ # g.test_framework :rspec
+ # end
+ #
+ # If you want to disable color in console, do:
+ #
+ # config.generators.colorize_logging = false
+ #
+ def generators
+ @generators ||= Generators.new
+ if block_given?
+ yield @generators
+ else
+ @generators
+ end
+ end
+
+ class Generators #:nodoc:
+ attr_accessor :aliases, :options, :colorize_logging
+
+ def initialize
+ @aliases = Hash.new { |h,k| h[k] = {} }
+ @options = Hash.new { |h,k| h[k] = {} }
+ @colorize_logging = true
+ end
+
+ def method_missing(method, *args)
+ method = method.to_s.sub(/=$/, '').to_sym
+ namespace = args.first.is_a?(Symbol) ? args.shift : nil
+ configuration = args.first.is_a?(Hash) ? args.shift : nil
+
+ @options[:rails][method] = namespace if namespace
+ namespace ||= method
+
+ if configuration
+ aliases = configuration.delete(:aliases)
+ @aliases[namespace].merge!(aliases) if aliases
+ @options[namespace].merge!(configuration)
+ end
+ end
+ end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails_generator.rb b/railties/lib/rails_generator.rb
deleted file mode 100644
index 85400932dd..0000000000
--- a/railties/lib/rails_generator.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-#--
-# Copyright (c) 2004 Jeremy Kemper
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#++
-
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
-$:.unshift(activesupport_path) if File.directory?(activesupport_path)
-require 'active_support/all'
-
-$:.unshift(File.dirname(__FILE__))
-require 'rails_generator/base'
-require 'rails_generator/lookup'
-require 'rails_generator/commands'
-
-Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
-Rails::Generator::Base.send(:include, Rails::Generator::Commands)
-
-# Set up a default logger for convenience.
-require 'rails_generator/simple_logger'
-Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
diff --git a/railties/lib/rails_generator/base.rb b/railties/lib/rails_generator/base.rb
deleted file mode 100644
index aa7081f8da..0000000000
--- a/railties/lib/rails_generator/base.rb
+++ /dev/null
@@ -1,266 +0,0 @@
-require File.dirname(__FILE__) + '/options'
-require File.dirname(__FILE__) + '/manifest'
-require File.dirname(__FILE__) + '/spec'
-require File.dirname(__FILE__) + '/generated_attribute'
-
-module Rails
- # Rails::Generator is a code generation platform tailored for the Rails
- # web application framework. Generators are easily invoked within Rails
- # applications to add and remove components such as models and controllers.
- # New generators are easy to create and may be distributed as RubyGems,
- # tarballs, or Rails plugins for inclusion system-wide, per-user,
- # or per-application.
- #
- # For actual examples see the rails_generator/generators directory in the
- # Rails source (or the +railties+ directory if you have frozen the Rails
- # source in your application).
- #
- # Generators may subclass other generators to provide variations that
- # require little or no new logic but replace the template files.
- #
- # For a RubyGem, put your generator class and templates in the +lib+
- # directory. For a Rails plugin, make a +generators+ directory at the
- # root of your plugin.
- #
- # The layout of generator files can be seen in the built-in
- # +controller+ generator:
- #
- # generators/
- # components/
- # controller/
- # controller_generator.rb
- # templates/
- # controller.rb
- # functional_test.rb
- # helper.rb
- # view.html.erb
- #
- # The directory name (+controller+) matches the name of the generator file
- # (controller_generator.rb) and class (ControllerGenerator). The files
- # that will be copied or used as templates are stored in the +templates+
- # directory.
- #
- # The filenames of the templates don't matter, but choose something that
- # will be self-explanatory since you will be referencing these in the
- # +manifest+ method inside your generator subclass.
- #
- #
- module Generator
- class GeneratorError < StandardError; end
- class UsageError < GeneratorError; end
-
-
- # The base code generator is bare-bones. It sets up the source and
- # destination paths and tells the logger whether to keep its trap shut.
- #
- # It's useful for copying files such as stylesheets, images, or
- # javascripts.
- #
- # For more comprehensive template-based passive code generation with
- # arguments, you'll want Rails::Generator::NamedBase.
- #
- # Generators create a manifest of the actions they perform then hand
- # the manifest to a command which replays the actions to do the heavy
- # lifting (such as checking for existing files or creating directories
- # if needed). Create, destroy, and list commands are included. Since a
- # single manifest may be used by any command, creating new generators is
- # as simple as writing some code templates and declaring what you'd like
- # to do with them.
- #
- # The manifest method must be implemented by subclasses, returning a
- # Rails::Generator::Manifest. The +record+ method is provided as a
- # convenience for manifest creation. Example:
- #
- # class StylesheetGenerator < Rails::Generator::Base
- # def manifest
- # record do |m|
- # m.directory('public/stylesheets')
- # m.file('application.css', 'public/stylesheets/application.css')
- # end
- # end
- # end
- #
- # See Rails::Generator::Commands::Create for a list of methods available
- # to the manifest.
- class Base
- include Options
-
- # Declare default options for the generator. These options
- # are inherited to subclasses.
- default_options :collision => :ask, :quiet => false
-
- # A logger instance available everywhere in the generator.
- cattr_accessor :logger
-
- # Every generator that is dynamically looked up is tagged with a
- # Spec describing where it was found.
- class_inheritable_accessor :spec
-
- attr_reader :source_root, :destination_root, :args
-
- def initialize(runtime_args, runtime_options = {})
- @args = runtime_args
- parse!(@args, runtime_options)
-
- # Derive source and destination paths.
- @source_root = options[:source] || File.join(spec.path, 'templates')
- if options[:destination]
- @destination_root = options[:destination]
- elsif defined? ::RAILS_ROOT
- @destination_root = ::RAILS_ROOT
- end
-
- # Silence the logger if requested.
- logger.quiet = options[:quiet]
-
- # Raise usage error if help is requested.
- usage if options[:help]
- end
-
- # Generators must provide a manifest. Use the +record+ method to create
- # a new manifest and record your generator's actions.
- def manifest
- raise NotImplementedError, "No manifest for '#{spec.name}' generator."
- end
-
- # Return the full path from the source root for the given path.
- # Example for source_root = '/source':
- # source_path('some/path.rb') == '/source/some/path.rb'
- #
- # The given path may include a colon ':' character to indicate that
- # the file belongs to another generator. This notation allows any
- # generator to borrow files from another. Example:
- # source_path('model:fixture.yml') = '/model/source/path/fixture.yml'
- def source_path(relative_source)
- # Check whether we're referring to another generator's file.
- name, path = relative_source.split(':', 2)
-
- # If not, return the full path to our source file.
- if path.nil?
- File.join(source_root, name)
-
- # Otherwise, ask our referral for the file.
- else
- # FIXME: this is broken, though almost always true. Others'
- # source_root are not necessarily the templates dir.
- File.join(self.class.lookup(name).path, 'templates', path)
- end
- end
-
- # Return the full path from the destination root for the given path.
- # Example for destination_root = '/dest':
- # destination_path('some/path.rb') == '/dest/some/path.rb'
- def destination_path(relative_destination)
- File.join(destination_root, relative_destination)
- end
-
- def after_generate
- end
-
- protected
- # Convenience method for generator subclasses to record a manifest.
- def record
- Rails::Generator::Manifest.new(self) { |m| yield m }
- end
-
- # Override with your own usage banner.
- def banner
- "Usage: #{$0} #{spec.name} [options]"
- end
-
- # Read USAGE from file in generator base path.
- def usage_message
- File.read(File.join(spec.path, 'USAGE')) rescue ''
- end
- end
-
-
- # The base generator for named components: models, controllers, mailers,
- # etc. The target name is taken as the first argument and inflected to
- # singular, plural, class, file, and table forms for your convenience.
- # The remaining arguments are aliased to +actions+ as an array for
- # controller and mailer convenience.
- #
- # Several useful local variables and methods are populated in the
- # +initialize+ method. See below for a list of Attributes and
- # External Aliases available to both the manifest and to all templates.
- #
- # If no name is provided, the generator raises a usage error with content
- # optionally read from the USAGE file in the generator's base path.
- #
- # For example, the +controller+ generator takes the first argument as
- # the name of the class and subsequent arguments as the names of
- # actions to be generated:
- #
- # ./script/generate controller Article index new create
- #
- # See Rails::Generator::Base for a discussion of manifests,
- # Rails::Generator::Commands::Create for methods available to the manifest,
- # and Rails::Generator for a general discussion of generators.
- class NamedBase < Base
- attr_reader :name, :class_name, :singular_name, :plural_name, :table_name
- attr_reader :class_path, :file_path, :class_nesting, :class_nesting_depth
- alias_method :file_name, :singular_name
- alias_method :actions, :args
-
- def initialize(runtime_args, runtime_options = {})
- super
-
- # Name argument is required.
- usage if runtime_args.empty?
-
- @args = runtime_args.dup
- base_name = @args.shift
- assign_names!(base_name)
- end
-
- protected
- # Override with your own usage banner.
- def banner
- "Usage: #{$0} #{spec.name} #{spec.name.camelize}Name [options]"
- end
-
- def attributes
- @attributes ||= @args.collect do |attribute|
- Rails::Generator::GeneratedAttribute.new(*attribute.split(":"))
- end
- end
-
-
- private
- def assign_names!(name)
- @name = name
- base_name, @class_path, @file_path, @class_nesting, @class_nesting_depth = extract_modules(@name)
- @class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
- @table_name = (!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? plural_name : singular_name
- @table_name.gsub! '/', '_'
- if @class_nesting.empty?
- @class_name = @class_name_without_nesting
- else
- @table_name = @class_nesting.underscore << "_" << @table_name
- @class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
- end
- end
-
- # Extract modules from filesystem-style or ruby-style path:
- # good/fun/stuff
- # Good::Fun::Stuff
- # produce the same results.
- def extract_modules(name)
- modules = name.include?('/') ? name.split('/') : name.split('::')
- name = modules.pop
- path = modules.map { |m| m.underscore }
- file_path = (path + [name.underscore]).join('/')
- nesting = modules.map { |m| m.camelize }.join('::')
- [name, path, file_path, nesting, modules.size]
- end
-
- def inflect_names(name)
- camel = name.camelize
- under = camel.underscore
- plural = under.pluralize
- [camel, under, plural]
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb
deleted file mode 100644
index b684dc92be..0000000000
--- a/railties/lib/rails_generator/commands.rb
+++ /dev/null
@@ -1,621 +0,0 @@
-require 'delegate'
-require 'optparse'
-require 'fileutils'
-require 'tempfile'
-require 'erb'
-
-module Rails
- module Generator
- module Commands
- # Here's a convenient way to get a handle on generator commands.
- # Command.instance('destroy', my_generator) instantiates a Destroy
- # delegate of my_generator ready to do your dirty work.
- def self.instance(command, generator)
- const_get(command.to_s.camelize).new(generator)
- end
-
- # Even more convenient access to commands. Include Commands in
- # the generator Base class to get a nice #command instance method
- # which returns a delegate for the requested command.
- def self.included(base)
- base.send(:define_method, :command) do |command|
- Commands.instance(command, self)
- end
- end
-
-
- # Generator commands delegate Rails::Generator::Base and implement
- # a standard set of actions. Their behavior is defined by the way
- # they respond to these actions: Create brings life; Destroy brings
- # death; List passively observes.
- #
- # Commands are invoked by replaying (or rewinding) the generator's
- # manifest of actions. See Rails::Generator::Manifest and
- # Rails::Generator::Base#manifest method that generator subclasses
- # are required to override.
- #
- # Commands allows generators to "plug in" invocation behavior, which
- # corresponds to the GoF Strategy pattern.
- class Base < DelegateClass(Rails::Generator::Base)
- # Replay action manifest. RewindBase subclass rewinds manifest.
- def invoke!
- manifest.replay(self)
- after_generate
- end
-
- def dependency(generator_name, args, runtime_options = {})
- logger.dependency(generator_name) do
- self.class.new(instance(generator_name, args, full_options(runtime_options))).invoke!
- end
- end
-
- # Does nothing for all commands except Create.
- def class_collisions(*class_names)
- end
-
- # Does nothing for all commands except Create.
- def readme(*args)
- end
-
- protected
- def current_migration_number
- Dir.glob("#{RAILS_ROOT}/#{@migration_directory}/[0-9]*_*.rb").inject(0) do |max, file_path|
- n = File.basename(file_path).split('_', 2).first.to_i
- if n > max then n else max end
- end
- end
-
- def next_migration_number
- current_migration_number + 1
- end
-
- def migration_directory(relative_path)
- directory(@migration_directory = relative_path)
- end
-
- def existing_migrations(file_name)
- Dir.glob("#{@migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
- end
-
- def migration_exists?(file_name)
- not existing_migrations(file_name).empty?
- end
-
- def next_migration_string(padding = 3)
- if ActiveRecord::Base.timestamped_migrations
- Time.now.utc.strftime("%Y%m%d%H%M%S")
- else
- "%.#{padding}d" % next_migration_number
- end
- end
-
- def gsub_file(relative_destination, regexp, *args, &block)
- path = destination_path(relative_destination)
- content = File.read(path).gsub(regexp, *args, &block)
- File.open(path, 'wb') { |file| file.write(content) }
- end
-
- private
- # Ask the user interactively whether to force collision.
- def force_file_collision?(destination, src, dst, file_options = {}, &block)
- $stdout.print "overwrite #{destination}? (enter \"h\" for help) [Ynaqdh] "
- case $stdin.gets.chomp
- when /\Ad\z/i
- Tempfile.open(File.basename(destination), File.dirname(dst)) do |temp|
- temp.write render_file(src, file_options, &block)
- temp.rewind
- $stdout.puts `#{diff_cmd} "#{dst}" "#{temp.path}"`
- end
- puts "retrying"
- raise 'retry diff'
- when /\Aa\z/i
- $stdout.puts "forcing #{spec.name}"
- options[:collision] = :force
- when /\Aq\z/i
- $stdout.puts "aborting #{spec.name}"
- raise SystemExit
- when /\An\z/i then :skip
- when /\Ay\z/i then :force
- else
- $stdout.puts <<-HELP
-Y - yes, overwrite
-n - no, do not overwrite
-a - all, overwrite this and all others
-q - quit, abort
-d - diff, show the differences between the old and the new
-h - help, show this help
-HELP
- raise 'retry'
- end
- rescue
- retry
- end
-
- def diff_cmd
- ENV['RAILS_DIFF'] || 'diff -u'
- end
-
- def render_template_part(template_options)
- # Getting Sandbox to evaluate part template in it
- part_binding = template_options[:sandbox].call.sandbox_binding
- part_rel_path = template_options[:insert]
- part_path = source_path(part_rel_path)
-
- # Render inner template within Sandbox binding
- rendered_part = ERB.new(File.readlines(part_path).join, nil, '-').result(part_binding)
- begin_mark = template_part_mark(template_options[:begin_mark], template_options[:mark_id])
- end_mark = template_part_mark(template_options[:end_mark], template_options[:mark_id])
- begin_mark + rendered_part + end_mark
- end
-
- def template_part_mark(name, id)
- "<!--[#{name}:#{id}]-->\n"
- end
- end
-
- # Base class for commands which handle generator actions in reverse, such as Destroy.
- class RewindBase < Base
- # Rewind action manifest.
- def invoke!
- manifest.rewind(self)
- end
- end
-
-
- # Create is the premier generator command. It copies files, creates
- # directories, renders templates, and more.
- class Create < Base
-
- # Check whether the given class names are already taken by
- # Ruby or Rails. In the future, expand to check other namespaces
- # such as the rest of the user's app.
- def class_collisions(*class_names)
- path = class_names.shift
- class_names.flatten.each do |class_name|
- # Convert to string to allow symbol arguments.
- class_name = class_name.to_s
-
- # Skip empty strings.
- next if class_name.strip.empty?
-
- # Split the class from its module nesting.
- nesting = class_name.split('::')
- name = nesting.pop
-
- # Hack to limit const_defined? to non-inherited on 1.9.
- extra = []
- extra << false unless Object.method(:const_defined?).arity == 1
-
- # Extract the last Module in the nesting.
- last = nesting.inject(Object) { |last, nest|
- break unless last.const_defined?(nest, *extra)
- last.const_get(nest)
- }
-
- # If the last Module exists, check whether the given
- # class exists and raise a collision if so.
- if last and last.const_defined?(name.camelize, *extra)
- raise_class_collision(class_name)
- end
- end
- end
-
- # Copy a file from source to destination with collision checking.
- #
- # The file_options hash accepts :chmod and :shebang and :collision options.
- # :chmod sets the permissions of the destination file:
- # file 'config/empty.log', 'log/test.log', :chmod => 0664
- # :shebang sets the #!/usr/bin/ruby line for scripts
- # file 'bin/generate.rb', 'script/generate', :chmod => 0755, :shebang => '/usr/bin/env ruby'
- # :collision sets the collision option only for the destination file:
- # file 'settings/server.yml', 'config/server.yml', :collision => :skip
- #
- # Collisions are handled by checking whether the destination file
- # exists and either skipping the file, forcing overwrite, or asking
- # the user what to do.
- def file(relative_source, relative_destination, file_options = {}, &block)
- # Determine full paths for source and destination files.
- source = source_path(relative_source)
- destination = destination_path(relative_destination)
- destination_exists = File.exist?(destination)
-
- # If source and destination are identical then we're done.
- if destination_exists and identical?(source, destination, &block)
- return logger.identical(relative_destination)
- end
-
- # Check for and resolve file collisions.
- if destination_exists
-
- # Make a choice whether to overwrite the file. :force and
- # :skip already have their mind made up, but give :ask a shot.
- choice = case (file_options[:collision] || options[:collision]).to_sym #|| :ask
- when :ask then force_file_collision?(relative_destination, source, destination, file_options, &block)
- when :force then :force
- when :skip then :skip
- else raise "Invalid collision option: #{options[:collision].inspect}"
- end
-
- # Take action based on our choice. Bail out if we chose to
- # skip the file; otherwise, log our transgression and continue.
- case choice
- when :force then logger.force(relative_destination)
- when :skip then return(logger.skip(relative_destination))
- else raise "Invalid collision choice: #{choice}.inspect"
- end
-
- # File doesn't exist so log its unbesmirched creation.
- else
- logger.create relative_destination
- end
-
- # If we're pretending, back off now.
- return if options[:pretend]
-
- # Write destination file with optional shebang. Yield for content
- # if block given so templaters may render the source file. If a
- # shebang is requested, replace the existing shebang or insert a
- # new one.
- File.open(destination, 'wb') do |dest|
- dest.write render_file(source, file_options, &block)
- end
-
- # Optionally change permissions.
- if file_options[:chmod]
- FileUtils.chmod(file_options[:chmod], destination)
- end
-
- # Optionally add file to subversion or git
- system("svn add #{destination}") if options[:svn]
- system("git add -v #{relative_destination}") if options[:git]
- end
-
- # Checks if the source and the destination file are identical. If
- # passed a block then the source file is a template that needs to first
- # be evaluated before being compared to the destination.
- def identical?(source, destination, &block)
- return false if File.directory? destination
- source = block_given? ? File.open(source) {|sf| yield(sf)} : IO.read(source)
- destination = IO.read(destination)
- source == destination
- end
-
- # Generate a file for a Rails application using an ERuby template.
- # Looks up and evaluates a template by name and writes the result.
- #
- # The ERB template uses explicit trim mode to best control the
- # proliferation of whitespace in generated code. <%- trims leading
- # whitespace; -%> trims trailing whitespace including one newline.
- #
- # A hash of template options may be passed as the last argument.
- # The options accepted by the file are accepted as well as :assigns,
- # a hash of variable bindings. Example:
- # template 'foo', 'bar', :assigns => { :action => 'view' }
- #
- # Template is implemented in terms of file. It calls file with a
- # block which takes a file handle and returns its rendered contents.
- def template(relative_source, relative_destination, template_options = {})
- file(relative_source, relative_destination, template_options) do |file|
- # Evaluate any assignments in a temporary, throwaway binding.
- vars = template_options[:assigns] || {}
- b = template_options[:binding] || binding
- vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
-
- # Render the source file with the temporary binding.
- ERB.new(file.read, nil, '-').result(b)
- end
- end
-
- def complex_template(relative_source, relative_destination, template_options = {})
- options = template_options.dup
- options[:assigns] ||= {}
- options[:assigns]['template_for_inclusion'] = render_template_part(template_options)
- template(relative_source, relative_destination, options)
- end
-
- # Create a directory including any missing parent directories.
- # Always skips directories which exist.
- def directory(relative_path)
- path = destination_path(relative_path)
- if File.exist?(path)
- logger.exists relative_path
- else
- logger.create relative_path
- unless options[:pretend]
- FileUtils.mkdir_p(path)
- # git doesn't require adding the paths, adding the files later will
- # automatically do a path add.
-
- # Subversion doesn't do path adds, so we need to add
- # each directory individually.
- # So stack up the directory tree and add the paths to
- # subversion in order without recursion.
- if options[:svn]
- stack = [relative_path]
- until File.dirname(stack.last) == stack.last # dirname('.') == '.'
- stack.push File.dirname(stack.last)
- end
- stack.reverse_each do |rel_path|
- svn_path = destination_path(rel_path)
- system("svn add -N #{svn_path}") unless File.directory?(File.join(svn_path, '.svn'))
- end
- end
- end
- end
- end
-
- # Display a README.
- def readme(*relative_sources)
- relative_sources.flatten.each do |relative_source|
- logger.readme relative_source
- puts File.read(source_path(relative_source)) unless options[:pretend]
- end
- end
-
- # When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
- def migration_template(relative_source, relative_destination, template_options = {})
- migration_directory relative_destination
- migration_file_name = template_options[:migration_file_name] || file_name
- raise "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}" if migration_exists?(migration_file_name)
- template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
- end
-
- def route_resources(*resources)
- resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
- sentinel = 'ActionController::Routing::Routes.draw do |map|'
-
- logger.route "map.resources #{resource_list}"
- unless options[:pretend]
- gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
- "#{match}\n map.resources #{resource_list}\n"
- end
- end
- end
-
- private
- def render_file(path, options = {})
- File.open(path, 'rb') do |file|
- if block_given?
- yield file
- else
- content = ''
- if shebang = options[:shebang]
- content << "#!#{shebang}\n"
- if line = file.gets
- content << "line\n" if line !~ /^#!/
- end
- end
- content << file.read
- end
- end
- end
-
- # Raise a usage error with an informative WordNet suggestion.
- # Thanks to Florian Gross (flgr).
- def raise_class_collision(class_name)
- message = <<end_message
- The name '#{class_name}' is either already used in your application or reserved by Ruby on Rails.
- Please choose an alternative and run this generator again.
-end_message
- if suggest = find_synonyms(class_name)
- if suggest.any?
- message << "\n Suggestions: \n\n"
- message << suggest.join("\n")
- end
- end
- raise UsageError, message
- end
-
- SYNONYM_LOOKUP_URI = "http://wordnet.princeton.edu/perl/webwn?s=%s"
-
- # Look up synonyms on WordNet. Thanks to Florian Gross (flgr).
- def find_synonyms(word)
- require 'open-uri'
- require 'timeout'
- timeout(5) do
- open(SYNONYM_LOOKUP_URI % word) do |stream|
- # Grab words linked to dictionary entries as possible synonyms
- data = stream.read.gsub("&nbsp;", " ").scan(/<a href="webwn.*?">([\w ]*?)<\/a>/s).uniq
- end
- end
- rescue Exception
- return nil
- end
- end
-
-
- # Undo the actions performed by a generator. Rewind the action
- # manifest and attempt to completely erase the results of each action.
- class Destroy < RewindBase
- # Remove a file if it exists and is a file.
- def file(relative_source, relative_destination, file_options = {})
- destination = destination_path(relative_destination)
- if File.exist?(destination)
- logger.rm relative_destination
- unless options[:pretend]
- if options[:svn]
- # If the file has been marked to be added
- # but has not yet been checked in, revert and delete
- if options[:svn][relative_destination]
- system("svn revert #{destination}")
- FileUtils.rm(destination)
- else
- # If the directory is not in the status list, it
- # has no modifications so we can simply remove it
- system("svn rm #{destination}")
- end
- elsif options[:git]
- if options[:git][:new][relative_destination]
- # file has been added, but not committed
- system("git reset HEAD #{relative_destination}")
- FileUtils.rm(destination)
- elsif options[:git][:modified][relative_destination]
- # file is committed and modified
- system("git rm -f #{relative_destination}")
- else
- # If the directory is not in the status list, it
- # has no modifications so we can simply remove it
- system("git rm #{relative_destination}")
- end
- else
- FileUtils.rm(destination)
- end
- end
- else
- logger.missing relative_destination
- return
- end
- end
-
- # Templates are deleted just like files and the actions take the
- # same parameters, so simply alias the file method.
- alias_method :template, :file
-
- # Remove each directory in the given path from right to left.
- # Remove each subdirectory if it exists and is a directory.
- def directory(relative_path)
- parts = relative_path.split('/')
- until parts.empty?
- partial = File.join(parts)
- path = destination_path(partial)
- if File.exist?(path)
- if Dir[File.join(path, '*')].empty?
- logger.rmdir partial
- unless options[:pretend]
- if options[:svn]
- # If the directory has been marked to be added
- # but has not yet been checked in, revert and delete
- if options[:svn][relative_path]
- system("svn revert #{path}")
- FileUtils.rmdir(path)
- else
- # If the directory is not in the status list, it
- # has no modifications so we can simply remove it
- system("svn rm #{path}")
- end
- # I don't think git needs to remove directories?..
- # or maybe they have special consideration...
- else
- FileUtils.rmdir(path)
- end
- end
- else
- logger.notempty partial
- end
- else
- logger.missing partial
- end
- parts.pop
- end
- end
-
- def complex_template(*args)
- # nothing should be done here
- end
-
- # When deleting a migration, it knows to delete every file named "[0-9]*_#{file_name}".
- def migration_template(relative_source, relative_destination, template_options = {})
- migration_directory relative_destination
-
- migration_file_name = template_options[:migration_file_name] || file_name
- unless migration_exists?(migration_file_name)
- puts "There is no migration named #{migration_file_name}"
- return
- end
-
-
- existing_migrations(migration_file_name).each do |file_path|
- file(relative_source, file_path, template_options)
- end
- end
-
- def route_resources(*resources)
- resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
- look_for = "\n map.resources #{resource_list}\n"
- logger.route "map.resources #{resource_list}"
- gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
- end
- end
-
-
- # List a generator's action manifest.
- class List < Base
- def dependency(generator_name, args, options = {})
- logger.dependency "#{generator_name}(#{args.join(', ')}, #{options.inspect})"
- end
-
- def class_collisions(*class_names)
- logger.class_collisions class_names.join(', ')
- end
-
- def file(relative_source, relative_destination, options = {})
- logger.file relative_destination
- end
-
- def template(relative_source, relative_destination, options = {})
- logger.template relative_destination
- end
-
- def complex_template(relative_source, relative_destination, options = {})
- logger.template "#{options[:insert]} inside #{relative_destination}"
- end
-
- def directory(relative_path)
- logger.directory "#{destination_path(relative_path)}/"
- end
-
- def readme(*args)
- logger.readme args.join(', ')
- end
-
- def migration_template(relative_source, relative_destination, options = {})
- migration_directory relative_destination
- logger.migration_template file_name
- end
-
- def route_resources(*resources)
- resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
- logger.route "map.resources #{resource_list}"
- end
- end
-
- # Update generator's action manifest.
- class Update < Create
- def file(relative_source, relative_destination, options = {})
- # logger.file relative_destination
- end
-
- def template(relative_source, relative_destination, options = {})
- # logger.template relative_destination
- end
-
- def complex_template(relative_source, relative_destination, template_options = {})
-
- begin
- dest_file = destination_path(relative_destination)
- source_to_update = File.readlines(dest_file).join
- rescue Errno::ENOENT
- logger.missing relative_destination
- return
- end
-
- logger.refreshing "#{template_options[:insert].gsub(/\.erb/,'')} inside #{relative_destination}"
-
- begin_mark = Regexp.quote(template_part_mark(template_options[:begin_mark], template_options[:mark_id]))
- end_mark = Regexp.quote(template_part_mark(template_options[:end_mark], template_options[:mark_id]))
-
- # Refreshing inner part of the template with freshly rendered part.
- rendered_part = render_template_part(template_options)
- source_to_update.gsub!(/#{begin_mark}.*?#{end_mark}/m, rendered_part)
-
- File.open(dest_file, 'w') { |file| file.write(source_to_update) }
- end
-
- def directory(relative_path)
- # logger.directory "#{destination_path(relative_path)}/"
- end
- end
-
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/applications/app/app_generator.rb b/railties/lib/rails_generator/generators/applications/app/app_generator.rb
deleted file mode 100644
index c8c2239f34..0000000000
--- a/railties/lib/rails_generator/generators/applications/app/app_generator.rb
+++ /dev/null
@@ -1,263 +0,0 @@
-require 'rbconfig'
-require File.dirname(__FILE__) + '/template_runner'
-require 'digest/md5'
-require 'active_support/secure_random'
-
-class AppGenerator < Rails::Generator::Base
- DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
-
- DATABASES = %w( mysql oracle postgresql sqlite2 sqlite3 frontbase ibm_db )
- DEFAULT_DATABASE = 'sqlite3'
-
- mandatory_options :source => "#{File.dirname(__FILE__)}/../../../../.."
- default_options :db => (ENV["RAILS_DEFAULT_DATABASE"] || DEFAULT_DATABASE),
- :shebang => DEFAULT_SHEBANG, :with_dispatchers => false, :freeze => false
-
-
- def initialize(runtime_args, runtime_options = {})
- super
-
- usage if args.empty?
- usage("Databases supported for preconfiguration are: #{DATABASES.join(", ")}") if (options[:db] && !DATABASES.include?(options[:db]))
-
- @destination_root = args.shift
- @app_name = File.basename(File.expand_path(@destination_root))
- end
-
- def manifest
- record do |m|
- create_directories(m)
- create_root_files(m)
- create_app_files(m)
- create_config_files(m)
- create_script_files(m)
- create_test_files(m)
- create_public_files(m)
- create_documentation_file(m)
- create_log_files(m)
- end
- end
-
- def after_generate
- if options[:template]
- Rails::TemplateRunner.new(options[:template], @destination_root)
- end
- end
-
- protected
- def banner
- "Usage: #{$0} /path/to/your/app [options]"
- end
-
- def add_options!(opt)
- opt.separator ''
- opt.separator 'Options:'
- opt.on("-r", "--ruby=path", String,
- "Path to the Ruby binary of your choice (otherwise scripts use env, dispatchers current path).",
- "Default: #{DEFAULT_SHEBANG}") { |v| options[:shebang] = v }
-
- opt.on("-d", "--database=name", String,
- "Preconfigure for selected database (options: #{DATABASES.join('/')}).",
- "Default: #{DEFAULT_DATABASE}") { |v| options[:db] = v }
-
- opt.on("-D", "--with-dispatchers",
- "Add CGI/FastCGI/mod_ruby dispatches code to generated application skeleton",
- "Default: false") { |v| options[:with_dispatchers] = v }
-
- opt.on("-f", "--freeze",
- "Freeze Rails in vendor/rails from the gems generating the skeleton",
- "Default: false") { |v| options[:freeze] = v }
-
- opt.on("-m", "--template=path", String,
- "Use an application template that lives at path (can be a filesystem path or URL).",
- "Default: (none)") { |v| options[:template] = v }
-
- end
-
-
- private
- def create_directories(m)
- m.directory ''
-
- # Intermediate directories are automatically created so don't sweat their absence here.
- %w(
- app/controllers
- app/helpers
- app/models
- app/views/layouts
- config/environments
- config/initializers
- config/locales
- db
- doc
- lib
- lib/tasks
- log
- public/images
- public/javascripts
- public/stylesheets
- script/performance
- test/fixtures
- test/functional
- test/integration
- test/performance
- test/unit
- vendor
- vendor/plugins
- tmp/sessions
- tmp/sockets
- tmp/cache
- tmp/pids
- ).each { |path| m.directory(path) }
- end
-
- def create_root_files(m)
- m.file "fresh_rakefile", "Rakefile"
- m.file "README", "README"
- end
-
- def create_app_files(m)
- m.file "helpers/application_controller.rb", "app/controllers/application_controller.rb"
- m.file "helpers/application_helper.rb", "app/helpers/application_helper.rb"
- end
-
- def create_config_files(m)
- create_database_configuration_file(m)
- create_routes_file(m)
- create_locale_file(m)
- create_seeds_file(m)
- create_initializer_files(m)
- create_environment_files(m)
- end
-
- def create_documentation_file(m)
- m.file "doc/README_FOR_APP", "doc/README_FOR_APP"
- end
-
- def create_log_files(m)
- %w( server production development test ).each do |file|
- m.file "configs/empty.log", "log/#{file}.log", :chmod => 0666
- end
- end
-
- def create_public_files(m)
- create_dispatch_files(m)
- create_error_files(m)
- create_welcome_file(m)
- create_browser_convention_files(m)
- create_rails_image(m)
- create_javascript_files(m)
- end
-
- def create_script_files(m)
- %w(
- about console dbconsole destroy generate runner server plugin
- performance/benchmarker performance/profiler
- ).each do |file|
- m.file "bin/#{file}", "script/#{file}", {
- :chmod => 0755,
- :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang]
- }
- end
- end
-
- def create_test_files(m)
- m.file "helpers/test_helper.rb", "test/test_helper.rb"
- m.file "helpers/performance_test.rb", "test/performance/browsing_test.rb"
- end
-
-
- def create_database_configuration_file(m)
- m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
- :app_name => @app_name,
- :socket => options[:db] == "mysql" ? mysql_socket_location : nil }
- end
-
- def create_routes_file(m)
- m.file "configs/routes.rb", "config/routes.rb"
- end
-
- def create_seeds_file(m)
- m.file "configs/seeds.rb", "db/seeds.rb"
- end
-
- def create_initializer_files(m)
- %w(
- backtrace_silencers
- inflections
- mime_types
- new_rails_defaults
- ).each do |initializer|
- m.file "configs/initializers/#{initializer}.rb", "config/initializers/#{initializer}.rb"
- end
-
- m.template "configs/initializers/session_store.rb", "config/initializers/session_store.rb",
- :assigns => { :app_name => @app_name, :app_secret => ActiveSupport::SecureRandom.hex(64) }
- end
-
- def create_locale_file(m)
- m.file "configs/locales/en.yml", "config/locales/en.yml"
- end
-
- def create_environment_files(m)
- m.template "environments/environment.rb", "config/environment.rb",
- :assigns => { :freeze => options[:freeze] }
-
- m.file "environments/boot.rb", "config/boot.rb"
- m.file "environments/production.rb", "config/environments/production.rb"
- m.file "environments/development.rb", "config/environments/development.rb"
- m.file "environments/test.rb", "config/environments/test.rb"
- end
-
-
- def create_dispatch_files(m)
- if options[:with_dispatchers]
- dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
-
- m.file "dispatches/config.ru", "config.ru"
- m.file "dispatches/dispatch.rb", "public/dispatch.rb", dispatcher_options
- m.file "dispatches/dispatch.rb", "public/dispatch.cgi", dispatcher_options
- m.file "dispatches/dispatch.fcgi", "public/dispatch.fcgi", dispatcher_options
- end
- end
-
- def create_error_files(m)
- %w( 404 422 500 ).each do |file|
- m.file "html/#{file}.html", "public/#{file}.html"
- end
- end
-
- def create_welcome_file(m)
- m.file 'html/index.html', 'public/index.html'
- end
-
- def create_browser_convention_files(m)
- m.file "html/favicon.ico", "public/favicon.ico"
- m.file "html/robots.txt", "public/robots.txt"
- end
-
- def create_rails_image(m)
- m.file "html/images/rails.png", "public/images/rails.png"
- end
-
- def create_javascript_files(m)
- %w( prototype effects dragdrop controls application ).each do |javascript|
- m.file "html/javascripts/#{javascript}.js", "public/javascripts/#{javascript}.js"
- end
- end
-
-
- def mysql_socket_location
- [
- "/tmp/mysql.sock", # default
- "/var/run/mysqld/mysqld.sock", # debian/gentoo
- "/var/tmp/mysql.sock", # freebsd
- "/var/lib/mysql/mysql.sock", # fedora
- "/opt/local/lib/mysql/mysql.sock", # fedora
- "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
- "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
- "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
- "/opt/lampp/var/mysql/mysql.sock" # xampp for linux
- ].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails_generator/generators/applications/app/scm/git.rb b/railties/lib/rails_generator/generators/applications/app/scm/git.rb
deleted file mode 100644
index 445de6ab42..0000000000
--- a/railties/lib/rails_generator/generators/applications/app/scm/git.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module Rails
- class Git < Scm
- def self.clone(repos, branch=nil)
- `git clone #{repos}`
-
- if branch
- `cd #{repos.split('/').last}/`
- `git checkout #{branch}`
- end
- end
-
- def self.run(command)
- `git #{command}`
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails_generator/generators/applications/app/scm/scm.rb b/railties/lib/rails_generator/generators/applications/app/scm/scm.rb
deleted file mode 100644
index f6c08cad39..0000000000
--- a/railties/lib/rails_generator/generators/applications/app/scm/scm.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-module Rails
- class Scm
- private
- def self.hash_to_parameters(hash)
- hash.collect { |key, value| "--#{key} #{(value.kind_of?(String) ? value : "")}"}.join(" ")
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails_generator/generators/applications/app/scm/svn.rb b/railties/lib/rails_generator/generators/applications/app/scm/svn.rb
deleted file mode 100644
index 22b5966d25..0000000000
--- a/railties/lib/rails_generator/generators/applications/app/scm/svn.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module Rails
- class Svn < Scm
- def self.checkout(repos, branch = nil)
- `svn checkout #{repos}/#{branch || "trunk"}`
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails_generator/generators/applications/app/template_runner.rb b/railties/lib/rails_generator/generators/applications/app/template_runner.rb
deleted file mode 100644
index 0e24d11950..0000000000
--- a/railties/lib/rails_generator/generators/applications/app/template_runner.rb
+++ /dev/null
@@ -1,401 +0,0 @@
-require File.dirname(__FILE__) + '/scm/scm'
-require File.dirname(__FILE__) + '/scm/git'
-require File.dirname(__FILE__) + '/scm/svn'
-
-require 'open-uri'
-require 'fileutils'
-
-module Rails
- class TemplateRunner
- attr_reader :root
- attr_writer :logger
-
- def initialize(template, root = '') # :nodoc:
- @root = File.expand_path(File.directory?(root) ? root : File.join(Dir.pwd, root))
-
- log 'applying', "template: #{template}"
-
- load_template(template)
-
- log 'applied', "#{template}"
- end
-
- def load_template(template)
- begin
- code = open(template).read
- in_root { self.instance_eval(code) }
- rescue LoadError, Errno::ENOENT => e
- raise "The template [#{template}] could not be loaded. Error: #{e}"
- end
- end
-
- # Create a new file in the Rails project folder. Specify the
- # relative path from RAILS_ROOT. Data is the return value of a block
- # or a data string.
- #
- # ==== Examples
- #
- # file("lib/fun_party.rb") do
- # hostname = ask("What is the virtual hostname I should use?")
- # "vhost.name = #{hostname}"
- # end
- #
- # file("config/apach.conf", "your apache config")
- #
- def file(filename, data = nil, log_action = true, &block)
- log 'file', filename if log_action
- dir, file = [File.dirname(filename), File.basename(filename)]
-
- inside(dir) do
- File.open(file, "w") do |f|
- if block_given?
- f.write(block.call)
- else
- f.write(data)
- end
- end
- end
- end
-
- # Install a plugin. You must provide either a Subversion url or Git url.
- # For a Git-hosted plugin, you can specify if it should be added as a submodule instead of cloned.
- #
- # ==== Examples
- #
- # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git'
- # plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git', :submodule => true
- # plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
- #
- def plugin(name, options)
- log 'plugin', name
-
- if options[:git] && options[:submodule]
- in_root do
- Git.run("submodule add #{options[:git]} vendor/plugins/#{name}")
- end
- elsif options[:git] || options[:svn]
- in_root do
- run_ruby_script("script/plugin install #{options[:svn] || options[:git]}", false)
- end
- else
- log "! no git or svn provided for #{name}. skipping..."
- end
- end
-
- # Adds an entry into config/environment.rb for the supplied gem :
- def gem(name, options = {})
- log 'gem', name
- env = options.delete(:env)
-
- gems_code = "config.gem '#{name}'"
-
- if options.any?
- opts = options.inject([]) {|result, h| result << [":#{h[0]} => #{h[1].inspect.gsub('"',"'")}"] }.sort.join(", ")
- gems_code << ", #{opts}"
- end
-
- environment gems_code, :env => env
- end
-
- # Adds a line inside the Initializer block for config/environment.rb. Used by #gem
- # If options :env is specified, the line is appended to the corresponding
- # file in config/environments/#{env}.rb
- def environment(data = nil, options = {}, &block)
- sentinel = 'Rails::Initializer.run do |config|'
-
- data = block.call if !data && block_given?
-
- in_root do
- if options[:env].nil?
- gsub_file 'config/environment.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
- "#{match}\n " << data
- end
- else
- Array.wrap(options[:env]).each do|env|
- append_file "config/environments/#{env}.rb", "\n#{data}"
- end
- end
- end
- end
-
- # Run a command in git.
- #
- # ==== Examples
- #
- # git :init
- # git :add => "this.file that.rb"
- # git :add => "onefile.rb", :rm => "badfile.cxx"
- #
- def git(command = {})
- in_root do
- if command.is_a?(Symbol)
- log 'running', "git #{command}"
- Git.run(command.to_s)
- else
- command.each do |command, options|
- log 'running', "git #{command} #{options}"
- Git.run("#{command} #{options}")
- end
- end
- end
- end
-
- # Create a new file in the vendor/ directory. Code can be specified
- # in a block or a data string can be given.
- #
- # ==== Examples
- #
- # vendor("sekrit.rb") do
- # sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
- # "salt = '#{sekrit_salt}'"
- # end
- #
- # vendor("foreign.rb", "# Foreign code is fun")
- #
- def vendor(filename, data = nil, &block)
- log 'vendoring', filename
- file("vendor/#{filename}", data, false, &block)
- end
-
- # Create a new file in the lib/ directory. Code can be specified
- # in a block or a data string can be given.
- #
- # ==== Examples
- #
- # lib("crypto.rb") do
- # "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
- # end
- #
- # lib("foreign.rb", "# Foreign code is fun")
- #
- def lib(filename, data = nil, &block)
- log 'lib', filename
- file("lib/#{filename}", data, false, &block)
- end
-
- # Create a new Rakefile with the provided code (either in a block or a string).
- #
- # ==== Examples
- #
- # rakefile("bootstrap.rake") do
- # project = ask("What is the UNIX name of your project?")
- #
- # <<-TASK
- # namespace :#{project} do
- # task :bootstrap do
- # puts "i like boots!"
- # end
- # end
- # TASK
- # end
- #
- # rakefile("seed.rake", "puts 'im plantin ur seedz'")
- #
- def rakefile(filename, data = nil, &block)
- log 'rakefile', filename
- file("lib/tasks/#{filename}", data, false, &block)
- end
-
- # Create a new initializer with the provided code (either in a block or a string).
- #
- # ==== Examples
- #
- # initializer("globals.rb") do
- # data = ""
- #
- # ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do
- # data << "#{const} = :entp"
- # end
- #
- # data
- # end
- #
- # initializer("api.rb", "API_KEY = '123456'")
- #
- def initializer(filename, data = nil, &block)
- log 'initializer', filename
- file("config/initializers/#{filename}", data, false, &block)
- end
-
- # Generate something using a generator from Rails or a plugin.
- # The second parameter is the argument string that is passed to
- # the generator or an Array that is joined.
- #
- # ==== Example
- #
- # generate(:authenticated, "user session")
- #
- def generate(what, *args)
- log 'generating', what
- argument = args.map {|arg| arg.to_s }.flatten.join(" ")
-
- in_root { run_ruby_script("script/generate #{what} #{argument}", false) }
- end
-
- # Executes a command
- #
- # ==== Example
- #
- # inside('vendor') do
- # run('ln -s ~/edge rails)
- # end
- #
- def run(command, log_action = true)
- log 'executing', "#{command} from #{Dir.pwd}" if log_action
- `#{command}`
- end
-
- # Executes a ruby script (taking into account WIN32 platform quirks)
- def run_ruby_script(command, log_action = true)
- ruby_command = RUBY_PLATFORM=~ /win32/ ? 'ruby ' : ''
- run("#{ruby_command}#{command}", log_action)
- end
-
- # Runs the supplied rake task
- #
- # ==== Example
- #
- # rake("db:migrate")
- # rake("db:migrate", :env => "production")
- # rake("gems:install", :sudo => true)
- #
- def rake(command, options = {})
- log 'rake', command
- env = options[:env] || 'development'
- sudo = options[:sudo] ? 'sudo ' : ''
- in_root { run("#{sudo}rake #{command} RAILS_ENV=#{env}", false) }
- end
-
- # Just run the capify command in root
- #
- # ==== Example
- #
- # capify!
- #
- def capify!
- log 'capifying'
- in_root { run('capify .', false) }
- end
-
- # Add Rails to /vendor/rails
- #
- # ==== Example
- #
- # freeze!
- #
- def freeze!(args = {})
- log 'vendor', 'rails edge'
- in_root { run('rake rails:freeze:edge', false) }
- end
-
- # Make an entry in Rails routing file conifg/routes.rb
- #
- # === Example
- #
- # route "map.root :controller => :welcome"
- #
- def route(routing_code)
- log 'route', routing_code
- sentinel = 'ActionController::Routing::Routes.draw do |map|'
-
- in_root do
- gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
- "#{match}\n #{routing_code}\n"
- end
- end
- end
-
- protected
-
- # Get a user's input
- #
- # ==== Example
- #
- # answer = ask("Should I freeze the latest Rails?")
- # freeze! if ask("Should I freeze the latest Rails?") == "yes"
- #
- def ask(string)
- log '', string
- STDIN.gets.strip
- end
-
- # Do something in the root of the Rails application or
- # a provided subfolder; the full path is yielded to the block you provide.
- # The path is set back to the previous path when the method exits.
- def inside(dir = '', &block)
- folder = File.join(root, dir)
- FileUtils.mkdir_p(folder) unless File.exist?(folder)
- FileUtils.cd(folder) { block.arity == 1 ? yield(folder) : yield }
- end
-
- def in_root
- FileUtils.cd(root) { yield }
- end
-
- # Helper to test if the user says yes(y)?
- #
- # ==== Example
- #
- # freeze! if yes?("Should I freeze the latest Rails?")
- #
- def yes?(question)
- answer = ask(question).downcase
- answer == "y" || answer == "yes"
- end
-
- # Helper to test if the user does NOT say yes(y)?
- #
- # ==== Example
- #
- # capify! if no?("Will you be using vlad to deploy your application?")
- #
- def no?(question)
- !yes?(question)
- end
-
- # Run a regular expression replacement on a file
- #
- # ==== Example
- #
- # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
- #
- def gsub_file(relative_destination, regexp, *args, &block)
- path = destination_path(relative_destination)
- content = File.read(path).gsub(regexp, *args, &block)
- File.open(path, 'wb') { |file| file.write(content) }
- end
-
- # Append text to a file
- #
- # ==== Example
- #
- # append_file 'config/environments/test.rb', 'config.gem "rspec"'
- #
- def append_file(relative_destination, data)
- path = destination_path(relative_destination)
- File.open(path, 'ab') { |file| file.write(data) }
- end
-
- def destination_path(relative_destination)
- File.join(root, relative_destination)
- end
-
- def log(action, message = '')
- logger.log(action, message)
- end
-
- def logger
- @logger ||= Rails::Generator::Base.logger
- end
-
- def logger
- @logger ||= if defined?(Rails::Generator::Base)
- Rails::Generator::Base.logger
- else
- require 'rails_generator/simple_logger'
- Rails::Generator::SimpleLogger.new(STDOUT)
- end
- end
-
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/controller/USAGE b/railties/lib/rails_generator/generators/components/controller/USAGE
deleted file mode 100644
index 362872e84a..0000000000
--- a/railties/lib/rails_generator/generators/components/controller/USAGE
+++ /dev/null
@@ -1,30 +0,0 @@
-Description:
- Stubs out a new controller and its views. Pass the controller name, either
- CamelCased or under_scored, and a list of views as arguments.
-
- To create a controller within a module, specify the controller name as a
- path like 'parent_module/controller_name'.
-
- This generates a controller class in app/controllers, view templates in
- app/views/controller_name, a helper class in app/helpers, a functional
- test suite in test/functional and a helper test suite in test/unit/helpers.
-
-Example:
- `./script/generate controller CreditCard open debit credit close`
-
- Credit card controller with URLs like /credit_card/debit.
- Controller: app/controllers/credit_card_controller.rb
- Functional Test: test/functional/credit_card_controller_test.rb
- Views: app/views/credit_card/debit.html.erb [...]
- Helper: app/helpers/credit_card_helper.rb
- Helper Test: test/unit/helpers/credit_card_helper_test.rb
-
-Modules Example:
- `./script/generate controller 'admin/credit_card' suspend late_fee`
-
- Credit card admin controller with URLs /admin/credit_card/suspend.
- Controller: app/controllers/admin/credit_card_controller.rb
- Functional Test: test/functional/admin/credit_card_controller_test.rb
- Views: app/views/admin/credit_card/debit.html.erb [...]
- Helper: app/helpers/admin/credit_card_helper.rb
- Helper Test: test/unit/helpers/admin/credit_card_helper_test.rb
diff --git a/railties/lib/rails_generator/generators/components/controller/controller_generator.rb b/railties/lib/rails_generator/generators/components/controller/controller_generator.rb
deleted file mode 100644
index dc126e8a98..0000000000
--- a/railties/lib/rails_generator/generators/components/controller/controller_generator.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-class ControllerGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper", "#{class_name}HelperTest"
-
- # Controller, helper, views, and test directories.
- m.directory File.join('app/controllers', class_path)
- m.directory File.join('app/helpers', class_path)
- m.directory File.join('app/views', class_path, file_name)
- m.directory File.join('test/functional', class_path)
- m.directory File.join('test/unit/helpers', class_path)
-
- # Controller class, functional test, and helper class.
- m.template 'controller.rb',
- File.join('app/controllers',
- class_path,
- "#{file_name}_controller.rb")
-
- m.template 'functional_test.rb',
- File.join('test/functional',
- class_path,
- "#{file_name}_controller_test.rb")
-
- m.template 'helper.rb',
- File.join('app/helpers',
- class_path,
- "#{file_name}_helper.rb")
-
- m.template 'helper_test.rb',
- File.join('test/unit/helpers',
- class_path,
- "#{file_name}_helper_test.rb")
-
- # View template for each action.
- actions.each do |action|
- path = File.join('app/views', class_path, file_name, "#{action}.html.erb")
- m.template 'view.html.erb', path,
- :assigns => { :action => action, :path => path }
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb b/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb
deleted file mode 100644
index ad85431f98..0000000000
--- a/railties/lib/rails_generator/generators/components/controller/templates/view.html.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-<h1><%= class_name %>#<%= action %></h1>
-<p>Find me in <%= path %></p>
diff --git a/railties/lib/rails_generator/generators/components/helper/USAGE b/railties/lib/rails_generator/generators/components/helper/USAGE
deleted file mode 100644
index ef27ca617e..0000000000
--- a/railties/lib/rails_generator/generators/components/helper/USAGE
+++ /dev/null
@@ -1,24 +0,0 @@
-Description:
- Stubs out a new helper. Pass the helper name, either
- CamelCased or under_scored.
-
- To create a helper within a module, specify the helper name as a
- path like 'parent_module/helper_name'.
-
- This generates a helper class in app/helpers and a helper test
- suite in test/unit/helpers.
-
-Example:
- `./script/generate helper CreditCard`
-
- Credit card helper.
- Helper: app/helpers/credit_card_helper.rb
- Test: test/unit/helpers/credit_card_helper_test.rb
-
-Modules Example:
- `./script/generate helper 'admin/credit_card'`
-
- Credit card admin helper.
- Helper: app/helpers/admin/credit_card_helper.rb
- Test: test/unit/helpers/admin/credit_card_helper_test.rb
-
diff --git a/railties/lib/rails_generator/generators/components/helper/helper_generator.rb b/railties/lib/rails_generator/generators/components/helper/helper_generator.rb
deleted file mode 100644
index f7831f7c7a..0000000000
--- a/railties/lib/rails_generator/generators/components/helper/helper_generator.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class HelperGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_path, "#{class_name}Helper", "#{class_name}HelperTest"
-
- # Helper and helper test directories.
- m.directory File.join('app/helpers', class_path)
- m.directory File.join('test/unit/helpers', class_path)
-
- # Helper and helper test class.
-
- m.template 'helper.rb',
- File.join('app/helpers',
- class_path,
- "#{file_name}_helper.rb")
-
- m.template 'helper_test.rb',
- File.join('test/unit/helpers',
- class_path,
- "#{file_name}_helper_test.rb")
-
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/helper/templates/helper.rb b/railties/lib/rails_generator/generators/components/helper/templates/helper.rb
deleted file mode 100644
index 3fe2ecdc74..0000000000
--- a/railties/lib/rails_generator/generators/components/helper/templates/helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module <%= class_name %>Helper
-end
diff --git a/railties/lib/rails_generator/generators/components/helper/templates/helper_test.rb b/railties/lib/rails_generator/generators/components/helper/templates/helper_test.rb
deleted file mode 100644
index 591e40900e..0000000000
--- a/railties/lib/rails_generator/generators/components/helper/templates/helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class <%= class_name %>HelperTest < ActionView::TestCase
-end
diff --git a/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb b/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb
deleted file mode 100644
index 44323f28ca..0000000000
--- a/railties/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class IntegrationTestGenerator < Rails::Generator::NamedBase
- default_options :skip_migration => false
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name, "#{class_name}Test"
-
- # integration test directory
- m.directory File.join('test/integration', class_path)
-
- # integration test stub
- m.template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb")
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb b/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb
deleted file mode 100644
index ba6d60cac6..0000000000
--- a/railties/lib/rails_generator/generators/components/mailer/mailer_generator.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class MailerGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name, "#{class_name}Test"
-
- # Mailer, view, test, and fixture directories.
- m.directory File.join('app/models', class_path)
- m.directory File.join('app/views', file_path)
- m.directory File.join('test/unit', class_path)
- m.directory File.join('test/fixtures', file_path)
-
- # Mailer class and unit test.
- m.template "mailer.rb", File.join('app/models', class_path, "#{file_name}.rb")
- m.template "unit_test.rb", File.join('test/unit', class_path, "#{file_name}_test.rb")
-
- # View template and fixture for each action.
- actions.each do |action|
- relative_path = File.join(file_path, action)
- view_path = File.join('app/views', "#{relative_path}.erb")
- fixture_path = File.join('test/fixtures', relative_path)
-
- m.template "view.erb", view_path,
- :assigns => { :action => action, :path => view_path }
- m.template "fixture.erb", fixture_path,
- :assigns => { :action => action, :path => view_path }
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb b/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb
deleted file mode 100644
index 6899257ddc..0000000000
--- a/railties/lib/rails_generator/generators/components/mailer/templates/fixture.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= class_name %>#<%= action %>
-
-Find me in <%= path %>
diff --git a/railties/lib/rails_generator/generators/components/mailer/templates/view.erb b/railties/lib/rails_generator/generators/components/mailer/templates/view.erb
deleted file mode 100644
index 6899257ddc..0000000000
--- a/railties/lib/rails_generator/generators/components/mailer/templates/view.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= class_name %>#<%= action %>
-
-Find me in <%= path %>
diff --git a/railties/lib/rails_generator/generators/components/metal/metal_generator.rb b/railties/lib/rails_generator/generators/components/metal/metal_generator.rb
deleted file mode 100644
index 64f49d929d..0000000000
--- a/railties/lib/rails_generator/generators/components/metal/metal_generator.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class MetalGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- m.directory 'app/metal'
- m.template 'metal.rb', File.join('app/metal', "#{file_name}.rb")
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/migration/migration_generator.rb b/railties/lib/rails_generator/generators/components/migration/migration_generator.rb
deleted file mode 100644
index acf41e07df..0000000000
--- a/railties/lib/rails_generator/generators/components/migration/migration_generator.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class MigrationGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- m.migration_template 'migration.rb', 'db/migrate', :assigns => get_local_assigns
- end
- end
-
-
- private
- def get_local_assigns
- returning(assigns = {}) do
- if class_name.underscore =~ /^(add|remove)_.*_(?:to|from)_(.*)/
- assigns[:migration_action] = $1
- assigns[:table_name] = $2.pluralize
- else
- assigns[:attributes] = []
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/model/model_generator.rb b/railties/lib/rails_generator/generators/components/model/model_generator.rb
deleted file mode 100644
index 582a28922f..0000000000
--- a/railties/lib/rails_generator/generators/components/model/model_generator.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-class ModelGenerator < Rails::Generator::NamedBase
- default_options :skip_timestamps => false, :skip_migration => false, :skip_fixture => false
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name, "#{class_name}Test"
-
- # Model, test, and fixture directories.
- m.directory File.join('app/models', class_path)
- m.directory File.join('test/unit', class_path)
- m.directory File.join('test/fixtures', class_path)
-
- # Model class, unit test, and fixtures.
- m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
- m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
-
- unless options[:skip_fixture]
- m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml")
- end
-
- unless options[:skip_migration]
- m.migration_template 'migration.rb', 'db/migrate', :assigns => {
- :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
- }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
- end
- end
- end
-
- protected
- def banner
- "Usage: #{$0} #{spec.name} ModelName [field:type, field:type]"
- end
-
- def add_options!(opt)
- opt.separator ''
- opt.separator 'Options:'
- opt.on("--skip-timestamps",
- "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
- opt.on("--skip-migration",
- "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
- opt.on("--skip-fixture",
- "Don't generation a fixture file for this model") { |v| options[:skip_fixture] = v}
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/model_subclass/USAGE b/railties/lib/rails_generator/generators/components/model_subclass/USAGE
deleted file mode 100644
index a4b558a401..0000000000
--- a/railties/lib/rails_generator/generators/components/model_subclass/USAGE
+++ /dev/null
@@ -1,13 +0,0 @@
-Description:
- Create a model subclass of parent, used for Single Table Inheritance.
-
- Both subclass and parent name can be either CamelCased or under_scored.
-
- This generates a model class in app/models and a unit test in test/unit.
-
-Examples:
- `./script/generate model_subclass admin user`
-
- creates an Admin model, which will inheritate from User model, test:
- Model: app/models/admin.rb
- Test: test/unit/admin_test.rb
diff --git a/railties/lib/rails_generator/generators/components/model_subclass/model_subclass_generator.rb b/railties/lib/rails_generator/generators/components/model_subclass/model_subclass_generator.rb
deleted file mode 100644
index e8ac3da2cd..0000000000
--- a/railties/lib/rails_generator/generators/components/model_subclass/model_subclass_generator.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class ModelSubclassGenerator < Rails::Generator::NamedBase
- default_options :skip_unit_test => false
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name, "#{class_name}Test"
-
- # Model and test directories.
- m.directory File.join('app/models', class_path)
- m.directory File.join('test/unit', class_path)
-
- # Model class and unit test
- m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb"), :assigns => assigns
- m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb"), :assigns => assigns
-
- end
- end
-
- protected
- def banner
- "Usage: #{$0} #{spec.name} Subclass Parent"
- end
-
- def assigns
- {:parent_class_name => parent_class_name}
- end
-
- def parent_class_name
- @args.first.try(:camelize) || usage
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/model_subclass/templates/model.rb b/railties/lib/rails_generator/generators/components/model_subclass/templates/model.rb
deleted file mode 100644
index d0037b322b..0000000000
--- a/railties/lib/rails_generator/generators/components/model_subclass/templates/model.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class <%= class_name %> < <%= parent_class_name %>
-
-end \ No newline at end of file
diff --git a/railties/lib/rails_generator/generators/components/observer/observer_generator.rb b/railties/lib/rails_generator/generators/components/observer/observer_generator.rb
deleted file mode 100644
index 3c4b330a80..0000000000
--- a/railties/lib/rails_generator/generators/components/observer/observer_generator.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class ObserverGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions "#{class_name}Observer", "#{class_name}ObserverTest"
-
- # Observer, and test directories.
- m.directory File.join('app/models', class_path)
- m.directory File.join('test/unit', class_path)
-
- # Observer class and unit test fixtures.
- m.template 'observer.rb', File.join('app/models', class_path, "#{file_name}_observer.rb")
- m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_observer_test.rb")
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb b/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
deleted file mode 100644
index 83ce8ac674..0000000000
--- a/railties/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class PerformanceTestGenerator < Rails::Generator::NamedBase
- default_options :skip_migration => false
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name, "#{class_name}Test"
-
- # performance test directory
- m.directory File.join('test/performance', class_path)
-
- # performance test stub
- m.template 'performance_test.rb', File.join('test/performance', class_path, "#{file_name}_test.rb")
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/plugin/USAGE b/railties/lib/rails_generator/generators/components/plugin/USAGE
deleted file mode 100644
index d2ecfc2d59..0000000000
--- a/railties/lib/rails_generator/generators/components/plugin/USAGE
+++ /dev/null
@@ -1,25 +0,0 @@
-Description:
- Stubs out a new plugin. Pass the plugin name, either CamelCased or
- under_scored, as an argument. Pass --with-generator to add an example
- generator also.
-
- This creates a plugin in vendor/plugins including an init.rb and README
- as well as standard lib, task, and test directories.
-
-Example:
- `./script/generate plugin BrowserFilters`
-
- creates a standard browser_filters plugin:
- vendor/plugins/browser_filters/README
- vendor/plugins/browser_filters/init.rb
- vendor/plugins/browser_filters/install.rb
- vendor/plugins/browser_filters/lib/browser_filters.rb
- vendor/plugins/browser_filters/test/browser_filters_test.rb
- vendor/plugins/browser_filters/tasks/browser_filters_tasks.rake
-
- ./script/generate plugin BrowserFilters --with-generator
-
- creates a browser_filters generator also:
- vendor/plugins/browser_filters/generators/browser_filters/browser_filters_generator.rb
- vendor/plugins/browser_filters/generators/browser_filters/USAGE
- vendor/plugins/browser_filters/generators/browser_filters/templates/
diff --git a/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb b/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb
deleted file mode 100644
index 6826998252..0000000000
--- a/railties/lib/rails_generator/generators/components/plugin/plugin_generator.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-class PluginGenerator < Rails::Generator::NamedBase
- attr_reader :plugin_path
-
- def initialize(runtime_args, runtime_options = {})
- @with_generator = runtime_args.delete("--with-generator")
- super
- @plugin_path = "vendor/plugins/#{file_name}"
- end
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions class_name
-
- m.directory "#{plugin_path}/lib"
- m.directory "#{plugin_path}/tasks"
- m.directory "#{plugin_path}/test"
-
- m.template 'README', "#{plugin_path}/README"
- m.template 'MIT-LICENSE', "#{plugin_path}/MIT-LICENSE"
- m.template 'Rakefile', "#{plugin_path}/Rakefile"
- m.template 'init.rb', "#{plugin_path}/init.rb"
- m.template 'install.rb', "#{plugin_path}/install.rb"
- m.template 'uninstall.rb', "#{plugin_path}/uninstall.rb"
- m.template 'plugin.rb', "#{plugin_path}/lib/#{file_name}.rb"
- m.template 'tasks.rake', "#{plugin_path}/tasks/#{file_name}_tasks.rake"
- m.template 'unit_test.rb', "#{plugin_path}/test/#{file_name}_test.rb"
- m.template 'test_helper.rb', "#{plugin_path}/test/test_helper.rb"
- if @with_generator
- m.directory "#{plugin_path}/generators"
- m.directory "#{plugin_path}/generators/#{file_name}"
- m.directory "#{plugin_path}/generators/#{file_name}/templates"
-
- m.template 'generator.rb', "#{plugin_path}/generators/#{file_name}/#{file_name}_generator.rb"
- m.template 'USAGE', "#{plugin_path}/generators/#{file_name}/USAGE"
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb b/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb
deleted file mode 100644
index 3e800df6c5..0000000000
--- a/railties/lib/rails_generator/generators/components/plugin/templates/generator.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class <%= class_name %>Generator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- # m.directory "lib"
- # m.template 'README', "README"
- end
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb b/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
deleted file mode 100644
index 3e0bc29d3a..0000000000
--- a/railties/lib/rails_generator/generators/components/plugin/templates/unit_test.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require 'test_helper'
-
-class <%= class_name %>Test < ActiveSupport::TestCase
- # Replace this with your real tests.
- test "the truth" do
- assert true
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/resource/resource_generator.rb b/railties/lib/rails_generator/generators/components/resource/resource_generator.rb
deleted file mode 100644
index 4ee2fbff63..0000000000
--- a/railties/lib/rails_generator/generators/components/resource/resource_generator.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-class ResourceGenerator < Rails::Generator::NamedBase
- default_options :skip_timestamps => false, :skip_migration => false
-
- attr_reader :controller_name,
- :controller_class_path,
- :controller_file_path,
- :controller_class_nesting,
- :controller_class_nesting_depth,
- :controller_class_name,
- :controller_singular_name,
- :controller_plural_name
- alias_method :controller_file_name, :controller_singular_name
- alias_method :controller_table_name, :controller_plural_name
-
- def initialize(runtime_args, runtime_options = {})
- super
-
- @controller_name = @name.pluralize
-
- base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
- @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
-
- if @controller_class_nesting.empty?
- @controller_class_name = @controller_class_name_without_nesting
- else
- @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
- end
- end
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions("#{controller_class_name}Controller", "#{controller_class_name}Helper")
- m.class_collisions(class_name)
-
- # Controller, helper, views, and test directories.
- m.directory(File.join('app/models', class_path))
- m.directory(File.join('app/controllers', controller_class_path))
- m.directory(File.join('app/helpers', controller_class_path))
- m.directory(File.join('app/views', controller_class_path, controller_file_name))
- m.directory(File.join('test/functional', controller_class_path))
- m.directory(File.join('test/unit', class_path))
- m.directory(File.join('test/unit/helpers', class_path))
-
- m.dependency 'model', [name] + @args, :collision => :skip
-
- m.template(
- 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
- )
-
- m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
- m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
- m.template('helper_test.rb', File.join('test/unit/helpers', controller_class_path, "#{controller_file_name}_helper_test.rb"))
-
- m.route_resources controller_file_name
- end
- end
-
- protected
- def banner
- "Usage: #{$0} resource ModelName [field:type, field:type]"
- end
-
- def add_options!(opt)
- opt.separator ''
- opt.separator 'Options:'
- opt.on("--skip-timestamps",
- "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
- opt.on("--skip-migration",
- "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
- end
-
- def model_name
- class_name.demodulize
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/resource/templates/controller.rb b/railties/lib/rails_generator/generators/components/resource/templates/controller.rb
deleted file mode 100644
index 765a942694..0000000000
--- a/railties/lib/rails_generator/generators/components/resource/templates/controller.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class <%= controller_class_name %>Controller < ApplicationController
-end
diff --git a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
deleted file mode 100644
index b1bb1dacbf..0000000000
--- a/railties/lib/rails_generator/generators/components/resource/templates/functional_test.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require 'test_helper'
-
-class <%= controller_class_name %>ControllerTest < ActionController::TestCase
- # Replace this with your real tests.
- test "the truth" do
- assert true
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/resource/templates/helper.rb b/railties/lib/rails_generator/generators/components/resource/templates/helper.rb
deleted file mode 100644
index 9bd821b1b2..0000000000
--- a/railties/lib/rails_generator/generators/components/resource/templates/helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module <%= controller_class_name %>Helper
-end
diff --git a/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb b/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb
deleted file mode 100644
index 061f64a5e3..0000000000
--- a/railties/lib/rails_generator/generators/components/resource/templates/helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class <%= controller_class_name %>HelperTest < ActionView::TestCase
-end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
deleted file mode 100644
index 2a5edeedb6..0000000000
--- a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-class ScaffoldGenerator < Rails::Generator::NamedBase
- default_options :skip_timestamps => false, :skip_migration => false, :force_plural => false
-
- attr_reader :controller_name,
- :controller_class_path,
- :controller_file_path,
- :controller_class_nesting,
- :controller_class_nesting_depth,
- :controller_class_name,
- :controller_underscore_name,
- :controller_singular_name,
- :controller_plural_name
- alias_method :controller_file_name, :controller_underscore_name
- alias_method :controller_table_name, :controller_plural_name
-
- def initialize(runtime_args, runtime_options = {})
- super
-
- if @name == @name.pluralize && !options[:force_plural]
- logger.warning "Plural version of the model detected, using singularized version. Override with --force-plural."
- @name = @name.singularize
- end
-
- @controller_name = @name.pluralize
-
- base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
- @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
- @controller_singular_name=base_name.singularize
- if @controller_class_nesting.empty?
- @controller_class_name = @controller_class_name_without_nesting
- else
- @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
- end
- end
-
- def manifest
- record do |m|
- # Check for class naming collisions.
- m.class_collisions("#{controller_class_name}Controller", "#{controller_class_name}Helper")
- m.class_collisions(class_name)
-
- # Controller, helper, views, test and stylesheets directories.
- m.directory(File.join('app/models', class_path))
- m.directory(File.join('app/controllers', controller_class_path))
- m.directory(File.join('app/helpers', controller_class_path))
- m.directory(File.join('app/views', controller_class_path, controller_file_name))
- m.directory(File.join('app/views/layouts', controller_class_path))
- m.directory(File.join('test/functional', controller_class_path))
- m.directory(File.join('test/unit', class_path))
- m.directory(File.join('test/unit/helpers', class_path))
- m.directory(File.join('public/stylesheets', class_path))
-
- for action in scaffold_views
- m.template(
- "view_#{action}.html.erb",
- File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.erb")
- )
- end
-
- # Layout and stylesheet.
- m.template('layout.html.erb', File.join('app/views/layouts', controller_class_path, "#{controller_file_name}.html.erb"))
- m.template('style.css', 'public/stylesheets/scaffold.css')
-
- m.template(
- 'controller.rb', File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
- )
-
- m.template('functional_test.rb', File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
- m.template('helper.rb', File.join('app/helpers', controller_class_path, "#{controller_file_name}_helper.rb"))
- m.template('helper_test.rb', File.join('test/unit/helpers', controller_class_path, "#{controller_file_name}_helper_test.rb"))
-
- m.route_resources controller_file_name
-
- m.dependency 'model', [name] + @args, :collision => :skip
- end
- end
-
- protected
- # Override with your own usage banner.
- def banner
- "Usage: #{$0} scaffold ModelName [field:type, field:type]"
- end
-
- def add_options!(opt)
- opt.separator ''
- opt.separator 'Options:'
- opt.on("--skip-timestamps",
- "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
- opt.on("--skip-migration",
- "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
- opt.on("--force-plural",
- "Forces the generation of a plural ModelName") { |v| options[:force_plural] = v }
- end
-
- def scaffold_views
- %w[ index show new edit ]
- end
-
- def model_name
- class_name.demodulize
- end
-end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb
deleted file mode 100644
index 9bd821b1b2..0000000000
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module <%= controller_class_name %>Helper
-end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb b/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb
deleted file mode 100644
index 061f64a5e3..0000000000
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'test_helper'
-
-class <%= controller_class_name %>HelperTest < ActionView::TestCase
-end
diff --git a/railties/lib/rails_generator/generators/components/session_migration/USAGE b/railties/lib/rails_generator/generators/components/session_migration/USAGE
deleted file mode 100644
index 87117a3cb6..0000000000
--- a/railties/lib/rails_generator/generators/components/session_migration/USAGE
+++ /dev/null
@@ -1,10 +0,0 @@
-Description:
- Creates a migration to add the sessions table used by the Active Record
- session store. Pass the migration name, either CamelCased or under_scored,
- as an argument.
-
-Example:
- `./script/generate session_migration CreateSessionTable`
-
- With 4 existing migrations, this creates the AddSessionTable migration
- in db/migrate/005_add_session_table.rb
diff --git a/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb b/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb
deleted file mode 100644
index 2e177033a1..0000000000
--- a/railties/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class SessionMigrationGenerator < Rails::Generator::NamedBase
- def initialize(runtime_args, runtime_options = {})
- runtime_args << 'add_session_table' if runtime_args.empty?
- super
- end
-
- def manifest
- record do |m|
- m.migration_template 'migration.rb', 'db/migrate',
- :assigns => { :session_table_name => default_session_table_name }
- end
- end
-
- protected
- def default_session_table_name
- ActiveRecord::Base.pluralize_table_names ? 'session'.pluralize : 'session'
- end
-end
diff --git a/railties/lib/rails_generator/lookup.rb b/railties/lib/rails_generator/lookup.rb
deleted file mode 100644
index a3525364a2..0000000000
--- a/railties/lib/rails_generator/lookup.rb
+++ /dev/null
@@ -1,249 +0,0 @@
-require 'pathname'
-
-require File.dirname(__FILE__) + '/spec'
-
-class Object
- class << self
- # Lookup missing generators using const_missing. This allows any
- # generator to reference another without having to know its location:
- # RubyGems, ~/.rails/generators, and RAILS_ROOT/generators.
- def lookup_missing_generator(class_id)
- if md = /(.+)Generator$/.match(class_id.to_s)
- name = md.captures.first.demodulize.underscore
- Rails::Generator::Base.lookup(name).klass
- else
- const_missing_before_generators(class_id)
- end
- end
-
- unless respond_to?(:const_missing_before_generators)
- alias_method :const_missing_before_generators, :const_missing
- alias_method :const_missing, :lookup_missing_generator
- end
- end
-end
-
-# User home directory lookup adapted from RubyGems.
-def Dir.user_home
- if ENV['HOME']
- ENV['HOME']
- elsif ENV['USERPROFILE']
- ENV['USERPROFILE']
- elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
- "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
- else
- File.expand_path '~'
- end
-end
-
-
-module Rails
- module Generator
-
- # Generator lookup is managed by a list of sources which return specs
- # describing where to find and how to create generators. This module
- # provides class methods for manipulating the source list and looking up
- # generator specs, and an #instance wrapper for quickly instantiating
- # generators by name.
- #
- # A spec is not a generator: it's a description of where to find
- # the generator and how to create it. A source is anything that
- # yields generators from #each. PathSource and GemGeneratorSource are provided.
- module Lookup
- def self.included(base)
- base.extend(ClassMethods)
- base.use_component_sources!
- end
-
- # Convenience method to instantiate another generator.
- def instance(generator_name, args, runtime_options = {})
- self.class.instance(generator_name, args, runtime_options)
- end
-
- module ClassMethods
- # The list of sources where we look, in order, for generators.
- def sources
- read_inheritable_attribute(:sources) or use_component_sources!
- end
-
- # Add a source to the end of the list.
- def append_sources(*args)
- sources.concat(args.flatten)
- invalidate_cache!
- end
-
- # Add a source to the beginning of the list.
- def prepend_sources(*args)
- write_inheritable_array(:sources, args.flatten + sources)
- invalidate_cache!
- end
-
- # Reset the source list.
- def reset_sources
- write_inheritable_attribute(:sources, [])
- invalidate_cache!
- end
-
- # Use application generators (app, ?).
- def use_application_sources!
- reset_sources
- sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/applications")
- end
-
- # Use component generators (model, controller, etc).
- # 1. Rails application. If RAILS_ROOT is defined we know we're
- # generating in the context of a Rails application, so search
- # RAILS_ROOT/generators.
- # 2. Look in plugins, either for generators/ or rails_generators/
- # directories within each plugin
- # 3. User home directory. Search ~/.rails/generators.
- # 4. RubyGems. Search for gems named *_generator, and look for
- # generators within any RubyGem's
- # /rails_generators/<generator_name>_generator.rb file.
- # 5. Builtins. Model, controller, mailer, scaffold, and so on.
- def use_component_sources!
- reset_sources
- if defined? ::RAILS_ROOT
- sources << PathSource.new(:lib, "#{::RAILS_ROOT}/lib/generators")
- sources << PathSource.new(:vendor, "#{::RAILS_ROOT}/vendor/generators")
- Rails.configuration.plugin_paths.each do |path|
- relative_path = Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(::RAILS_ROOT))
- sources << PathSource.new(:"plugins (#{relative_path})", "#{path}/*/**/{,rails_}generators")
- end
- end
- sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
- if Object.const_defined?(:Gem)
- sources << GemGeneratorSource.new
- sources << GemPathSource.new
- end
- sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")
- end
-
- # Lookup knows how to find generators' Specs from a list of Sources.
- # Searches the sources, in order, for the first matching name.
- def lookup(generator_name)
- @found ||= {}
- generator_name = generator_name.to_s.downcase
- @found[generator_name] ||= cache.find { |spec| spec.name == generator_name }
- unless @found[generator_name]
- chars = generator_name.scan(/./).map{|c|"#{c}.*?"}
- rx = /^#{chars}$/
- gns = cache.select{|spec| spec.name =~ rx }
- @found[generator_name] ||= gns.first if gns.length == 1
- raise GeneratorError, "Pattern '#{generator_name}' matches more than one generator: #{gns.map{|sp|sp.name}.join(', ')}" if gns.length > 1
- end
- @found[generator_name] or raise GeneratorError, "Couldn't find '#{generator_name}' generator"
- end
-
- # Convenience method to lookup and instantiate a generator.
- def instance(generator_name, args = [], runtime_options = {})
- lookup(generator_name).klass.new(args, full_options(runtime_options))
- end
-
- private
- # Lookup and cache every generator from the source list.
- def cache
- @cache ||= sources.inject([]) { |cache, source| cache + source.to_a }
- end
-
- # Clear the cache whenever the source list changes.
- def invalidate_cache!
- @cache = nil
- end
- end
- end
-
- # Sources enumerate (yield from #each) generator specs which describe
- # where to find and how to create generators. Enumerable is mixed in so,
- # for example, source.collect will retrieve every generator.
- # Sources may be assigned a label to distinguish them.
- class Source
- include Enumerable
-
- attr_reader :label
- def initialize(label)
- @label = label
- end
-
- # The each method must be implemented in subclasses.
- # The base implementation raises an error.
- def each
- raise NotImplementedError
- end
-
- # Return a convenient sorted list of all generator names.
- def names
- map { |spec| spec.name }.sort
- end
- end
-
-
- # PathSource looks for generators in a filesystem directory.
- class PathSource < Source
- attr_reader :path
-
- def initialize(label, path)
- super label
- @path = path
- end
-
- # Yield each eligible subdirectory.
- def each
- Dir["#{path}/[a-z]*"].each do |dir|
- if File.directory?(dir)
- yield Spec.new(File.basename(dir), dir, label)
- end
- end
- end
- end
-
- class AbstractGemSource < Source
- def initialize
- super :RubyGems
- end
- end
-
- # GemGeneratorSource hits the mines to quarry for generators. The latest versions
- # of gems named *_generator are selected.
- class GemGeneratorSource < AbstractGemSource
- # Yield latest versions of generator gems.
- def each
- dependency = Gem::Dependency.new(/_generator$/, Gem::Requirement.default)
- Gem::cache.search(dependency).inject({}) { |latest, gem|
- hem = latest[gem.name]
- latest[gem.name] = gem if hem.nil? or gem.version > hem.version
- latest
- }.values.each { |gem|
- yield Spec.new(gem.name.sub(/_generator$/, ''), gem.full_gem_path, label)
- }
- end
- end
-
- # GemPathSource looks for generators within any RubyGem's /rails_generators/<generator_name>_generator.rb file.
- class GemPathSource < AbstractGemSource
- # Yield each generator within rails_generator subdirectories.
- def each
- generator_full_paths.each do |generator|
- yield Spec.new(File.basename(generator).sub(/_generator.rb$/, ''), File.dirname(generator), label)
- end
- end
-
- private
- def generator_full_paths
- @generator_full_paths ||=
- Gem::cache.inject({}) do |latest, name_gem|
- name, gem = name_gem
- hem = latest[gem.name]
- latest[gem.name] = gem if hem.nil? or gem.version > hem.version
- latest
- end.values.inject([]) do |mem, gem|
- Dir[gem.full_gem_path + '/{rails_,}generators/**/*_generator.rb'].each do |generator|
- mem << generator
- end
- mem
- end
- end
- end
-
- end
-end
diff --git a/railties/lib/rails_generator/manifest.rb b/railties/lib/rails_generator/manifest.rb
deleted file mode 100644
index 702effa76f..0000000000
--- a/railties/lib/rails_generator/manifest.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-module Rails
- module Generator
-
- # Manifest captures the actions a generator performs. Instantiate
- # a manifest with an optional target object, hammer it with actions,
- # then replay or rewind on the object of your choice.
- #
- # Example:
- # manifest = Manifest.new { |m|
- # m.make_directory '/foo'
- # m.create_file '/foo/bar.txt'
- # }
- # manifest.replay(creator)
- # manifest.rewind(destroyer)
- class Manifest
- attr_reader :target
-
- # Take a default action target. Yield self if block given.
- def initialize(target = nil)
- @target, @actions = target, []
- yield self if block_given?
- end
-
- # Record an action.
- def method_missing(action, *args, &block)
- @actions << [action, args, block]
- end
-
- # Replay recorded actions.
- def replay(target = nil)
- send_actions(target || @target, @actions)
- end
-
- # Rewind recorded actions.
- def rewind(target = nil)
- send_actions(target || @target, @actions.reverse)
- end
-
- # Erase recorded actions.
- def erase
- @actions = []
- end
-
- private
- def send_actions(target, actions)
- actions.each do |method, args, block|
- target.send(method, *args, &block)
- end
- end
- end
-
- end
-end
diff --git a/railties/lib/rails_generator/options.rb b/railties/lib/rails_generator/options.rb
deleted file mode 100644
index 5f6aefa921..0000000000
--- a/railties/lib/rails_generator/options.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-require 'optparse'
-
-module Rails
- module Generator
- module Options
- def self.included(base)
- base.extend(ClassMethods)
- class << base
- if respond_to?(:inherited)
- alias_method :inherited_without_options, :inherited
- end
- alias_method :inherited, :inherited_with_options
- end
- end
-
- module ClassMethods
- def inherited_with_options(sub)
- inherited_without_options(sub) if respond_to?(:inherited_without_options)
- sub.extend(Rails::Generator::Options::ClassMethods)
- end
-
- def mandatory_options(options = nil)
- if options
- write_inheritable_attribute(:mandatory_options, options)
- else
- read_inheritable_attribute(:mandatory_options) or write_inheritable_attribute(:mandatory_options, {})
- end
- end
-
- def default_options(options = nil)
- if options
- write_inheritable_attribute(:default_options, options)
- else
- read_inheritable_attribute(:default_options) or write_inheritable_attribute(:default_options, {})
- end
- end
-
- # Merge together our class options. In increasing precedence:
- # default_options (class default options)
- # runtime_options (provided as argument)
- # mandatory_options (class mandatory options)
- def full_options(runtime_options = {})
- default_options.merge(runtime_options).merge(mandatory_options)
- end
-
- end
-
- # Each instance has an options hash that's populated by #parse.
- def options
- @options ||= {}
- end
- attr_writer :options
-
- protected
- # Convenient access to class mandatory options.
- def mandatory_options
- self.class.mandatory_options
- end
-
- # Convenient access to class default options.
- def default_options
- self.class.default_options
- end
-
- # Merge together our instance options. In increasing precedence:
- # default_options (class default options)
- # options (instance options)
- # runtime_options (provided as argument)
- # mandatory_options (class mandatory options)
- def full_options(runtime_options = {})
- self.class.full_options(options.merge(runtime_options))
- end
-
- # Parse arguments into the options hash. Classes may customize
- # parsing behavior by overriding these methods:
- # #banner Usage: ./script/generate [options]
- # #add_options! Options:
- # some options..
- # #add_general_options! General Options:
- # general options..
- def parse!(args, runtime_options = {})
- self.options = {}
-
- @option_parser = OptionParser.new do |opt|
- opt.banner = banner
- add_options!(opt)
- add_general_options!(opt)
- opt.parse!(args)
- end
-
- return args
- ensure
- self.options = full_options(runtime_options)
- end
-
- # Raise a usage error. Override usage_message to provide a blurb
- # after the option parser summary.
- def usage(message = usage_message)
- raise UsageError, "#{@option_parser}\n#{message}"
- end
-
- def usage_message
- ''
- end
-
- # Override with your own usage banner.
- def banner
- "Usage: #{$0} [options]"
- end
-
- # Override to add your options to the parser:
- # def add_options!(opt)
- # opt.on('-v', '--verbose') { |value| options[:verbose] = value }
- # end
- def add_options!(opt)
- end
-
- # Adds general options like -h and --quiet. Usually don't override.
- def add_general_options!(opt)
- opt.separator ''
- opt.separator 'Rails Info:'
- opt.on('-v', '--version', 'Show the Rails version number and quit.')
- opt.on('-h', '--help', 'Show this help message and quit.') { |v| options[:help] = v }
-
- opt.separator ''
- opt.separator 'General Options:'
-
- opt.on('-p', '--pretend', 'Run but do not make any changes.') { |v| options[:pretend] = v }
- opt.on('-f', '--force', 'Overwrite files that already exist.') { options[:collision] = :force }
- opt.on('-s', '--skip', 'Skip files that already exist.') { options[:collision] = :skip }
- opt.on('-q', '--quiet', 'Suppress normal output.') { |v| options[:quiet] = v }
- opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |v| options[:backtrace] = v }
- opt.on('-c', '--svn', 'Modify files with subversion. (Note: svn must be in path)') do
- options[:svn] = `svn status`.inject({}) do |opt, e|
- opt[e.chomp[7..-1]] = true
- opt
- end
- end
- opt.on('-g', '--git', 'Modify files with git. (Note: git must be in path)') do
- options[:git] = `git status`.inject({:new => {}, :modified => {}}) do |opt, e|
- opt[:new][e.chomp[14..-1]] = true if e =~ /new file:/
- opt[:modified][e.chomp[14..-1]] = true if e =~ /modified:/
- opt
- end
- end
- end
-
- end
- end
-end
diff --git a/railties/lib/rails_generator/scripts.rb b/railties/lib/rails_generator/scripts.rb
deleted file mode 100644
index 3763b75dba..0000000000
--- a/railties/lib/rails_generator/scripts.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-require File.dirname(__FILE__) + '/options'
-
-module Rails
- module Generator
- module Scripts
-
- # Generator scripts handle command-line invocation. Each script
- # responds to an invoke! class method which handles option parsing
- # and generator invocation.
- class Base
- include Options
- default_options :collision => :ask, :quiet => false
-
- # Run the generator script. Takes an array of unparsed arguments
- # and a hash of parsed arguments, takes the generator as an option
- # or first remaining argument, and invokes the requested command.
- def run(args = [], runtime_options = {})
- begin
- parse!(args.dup, runtime_options)
- rescue OptionParser::InvalidOption => e
- # Don't cry, script. Generators want what you think is invalid.
- end
-
- # Generator name is the only required option.
- unless options[:generator]
- usage if args.empty?
- options[:generator] ||= args.shift
- end
-
- # Look up generator instance and invoke command on it.
- Rails::Generator::Base.instance(options[:generator], args, options).command(options[:command]).invoke!
- rescue => e
- puts e
- puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
- raise SystemExit
- end
-
- protected
- # Override with your own script usage banner.
- def banner
- "Usage: #{$0} generator [options] [args]"
- end
-
- def usage_message
- usage = "\nInstalled Generators\n"
- Rails::Generator::Base.sources.inject([]) do |mem, source|
- # Using an association list instead of a hash to preserve order,
- # for aesthetic reasons more than anything else.
- label = source.label.to_s.capitalize
- pair = mem.assoc(label)
- mem << (pair = [label, []]) if pair.nil?
- pair[1] |= source.names
- mem
- end.each do |label, names|
- usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
- end
-
- usage << <<end_blurb
-
-You can also install additional generators for your own use:
- 1. Download, for example, login_generator.zip
- 2. Unzip to directory #{Dir.user_home}/.rails/generators/login
- to use the generator with all your Rails apps
-end_blurb
-
- if Object.const_defined?(:RAILS_ROOT)
- usage << <<end_blurb
- or to #{File.expand_path(RAILS_ROOT)}/lib/generators/login
- to use with this app only.
-end_blurb
- end
-
- usage << <<end_blurb
- 3. Run generate with no arguments for usage information
- #{$0} login
-
-Generator gems are also available:
- 1. gem search -r generator
- 2. gem install login_generator
- 3. #{$0} login
-
-end_blurb
- return usage
- end
- end # Base
-
- end
- end
-end
diff --git a/railties/lib/rails_generator/scripts/destroy.rb b/railties/lib/rails_generator/scripts/destroy.rb
deleted file mode 100644
index a7c2a14751..0000000000
--- a/railties/lib/rails_generator/scripts/destroy.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require File.dirname(__FILE__) + '/../scripts'
-
-module Rails::Generator::Scripts
- class Destroy < Base
- mandatory_options :command => :destroy
-
- protected
- def usage_message
- usage = "\nInstalled Generators\n"
- Rails::Generator::Base.sources.each do |source|
- label = source.label.to_s.capitalize
- names = source.names
- usage << " #{label}: #{names.join(', ')}\n" unless names.empty?
- end
-
- usage << <<end_blurb
-
-script/generate command. For instance, 'script/destroy migration CreatePost'
-will delete the appropriate XXX_create_post.rb migration file in db/migrate,
-while 'script/destroy scaffold Post' will delete the posts controller and
-views, post model and migration, all associated tests, and the map.resources
-:posts line in config/routes.rb.
-
-For instructions on finding new generators, run script/generate.
-end_blurb
- return usage
- end
- end
-end
diff --git a/railties/lib/rails_generator/scripts/generate.rb b/railties/lib/rails_generator/scripts/generate.rb
deleted file mode 100644
index 1fe2f54ab3..0000000000
--- a/railties/lib/rails_generator/scripts/generate.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require File.dirname(__FILE__) + '/../scripts'
-
-module Rails::Generator::Scripts
- class Generate < Base
- mandatory_options :command => :create
- end
-end
diff --git a/railties/lib/rails_generator/scripts/update.rb b/railties/lib/rails_generator/scripts/update.rb
deleted file mode 100644
index 53a9faa366..0000000000
--- a/railties/lib/rails_generator/scripts/update.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require File.dirname(__FILE__) + '/../scripts'
-
-module Rails::Generator::Scripts
- class Update < Base
- mandatory_options :command => :update
-
- protected
- def banner
- "Usage: #{$0} [options] scaffold"
- end
- end
-end
diff --git a/railties/lib/rails_generator/secret_key_generator.rb b/railties/lib/rails_generator/secret_key_generator.rb
deleted file mode 100644
index 7dd495a2f5..0000000000
--- a/railties/lib/rails_generator/secret_key_generator.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'active_support/deprecation'
-
-module Rails
- # A class for creating random secret keys. This class will do its best to create a
- # random secret key that's as secure as possible, using whatever methods are
- # available on the current platform. For example:
- #
- # generator = Rails::SecretKeyGenerator("some unique identifier, such as the application name")
- # generator.generate_secret # => "f3f1be90053fa851... (some long string)"
- #
- # This class is *deprecated* in Rails 2.2 in favor of ActiveSupport::SecureRandom.
- # It is currently a wrapper around ActiveSupport::SecureRandom.
- class SecretKeyGenerator
- def initialize(identifier)
- end
-
- # Generate a random secret key with the best possible method available on
- # the current platform.
- def generate_secret
- ActiveSupport::SecureRandom.hex(64)
- end
- deprecate :generate_secret=>"You should use ActiveSupport::SecureRandom.hex(64)"
- end
-end
diff --git a/railties/lib/rails_generator/simple_logger.rb b/railties/lib/rails_generator/simple_logger.rb
deleted file mode 100644
index d750f07b84..0000000000
--- a/railties/lib/rails_generator/simple_logger.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-module Rails
- module Generator
- class SimpleLogger # :nodoc:
- attr_reader :out
- attr_accessor :quiet
-
- def initialize(out = $stdout)
- @out = out
- @quiet = false
- @level = 0
- end
-
- def log(status, message, &block)
- @out.print("%12s %s%s\n" % [status, ' ' * @level, message]) unless quiet
- indent(&block) if block_given?
- end
-
- def indent(&block)
- @level += 1
- if block_given?
- begin
- block.call
- ensure
- outdent
- end
- end
- end
-
- def outdent
- @level -= 1
- if block_given?
- begin
- block.call
- ensure
- indent
- end
- end
- end
-
- private
- def method_missing(method, *args, &block)
- log(method.to_s, args.first, &block)
- end
- end
- end
-end
diff --git a/railties/lib/rails_generator/spec.rb b/railties/lib/rails_generator/spec.rb
deleted file mode 100644
index 9d780b7ac5..0000000000
--- a/railties/lib/rails_generator/spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module Rails
- module Generator
- # A spec knows where a generator was found and how to instantiate it.
- # Metadata include the generator's name, its base path, and the source
- # which yielded it (PathSource, GemPathSource, etc.)
- class Spec
- attr_reader :name, :path, :source
-
- def initialize(name, path, source)
- @name, @path, @source = name, path, source
- end
-
- # Look up the generator class. Require its class file, find the class
- # in ObjectSpace, tag it with this spec, and return.
- def klass
- unless @klass
- require class_file
- @klass = lookup_class
- @klass.spec = self
- end
- @klass
- end
-
- def class_file
- "#{path}/#{name}_generator.rb"
- end
-
- def class_name
- "#{name.camelize}Generator"
- end
-
- private
- # Search for the first Class descending from Rails::Generator::Base
- # whose name matches the requested class name.
- def lookup_class
- ObjectSpace.each_object(Class) do |obj|
- return obj if obj.ancestors.include?(Rails::Generator::Base) and
- obj.name.split('::').last == class_name
- end
- raise NameError, "Missing #{class_name} class in #{class_file}"
- end
- end
- end
-end
diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake
index 0e256737f9..0d4d658315 100644
--- a/railties/lib/tasks/databases.rake
+++ b/railties/lib/tasks/databases.rake
@@ -411,9 +411,9 @@ namespace :db do
desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
task :create => :environment do
raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
- require 'rails_generator'
- require 'rails_generator/scripts/generate'
- Rails::Generator::Scripts::Generate.new.run(["session_migration", ENV["MIGRATION"] || "CreateSessions"])
+ require 'generators'
+ require 'generators/rails/session_migration/session_migration_generator'
+ Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
end
desc "Clear the sessions table"
diff --git a/railties/lib/tasks/documentation.rake b/railties/lib/tasks/documentation.rake
index 8b41478a93..db1939c45f 100644
--- a/railties/lib/tasks/documentation.rake
+++ b/railties/lib/tasks/documentation.rake
@@ -21,7 +21,7 @@ namespace :doc do
rdoc.rdoc_files.include('vendor/rails/railties/CHANGELOG')
rdoc.rdoc_files.include('vendor/rails/railties/MIT-LICENSE')
rdoc.rdoc_files.include('vendor/rails/railties/README')
- rdoc.rdoc_files.include('vendor/rails/railties/lib/{*.rb,commands/*.rb,rails_generator/*.rb}')
+ rdoc.rdoc_files.include('vendor/rails/railties/lib/{*.rb,commands/*.rb,generators/*.rb}')
rdoc.rdoc_files.include('vendor/rails/activerecord/README')
rdoc.rdoc_files.include('vendor/rails/activerecord/CHANGELOG')
rdoc.rdoc_files.include('vendor/rails/activerecord/lib/active_record/**/*.rb')
diff --git a/railties/lib/tasks/framework.rake b/railties/lib/tasks/framework.rake
index b6f2f2bc18..a084af7e11 100644
--- a/railties/lib/tasks/framework.rake
+++ b/railties/lib/tasks/framework.rake
@@ -78,51 +78,48 @@ namespace :rails do
end
desc "Update both configs, scripts and public/javascripts from Rails"
- task :update => [ "update:scripts", "update:javascripts", "update:configs", "update:application_controller" ]
+ task :update => [ "update:configs", "update:javascripts", "update:scripts", "update:application_controller" ]
desc "Applies the template supplied by LOCATION=/path/to/template"
task :template do
- require 'rails_generator/generators/applications/app/template_runner'
template = ENV["LOCATION"]
template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://}
- Rails::TemplateRunner.new(template)
+
+ require 'generators'
+ generator = Rails::Generators::App.new [ RAILS_ROOT ], {}, :destination_root => RAILS_ROOT
+ generator.apply template, :verbose => false
end
namespace :update do
- desc "Add new scripts to the application script/ directory"
- task :scripts do
- local_base = "script"
- edge_base = "#{File.dirname(__FILE__)}/../../bin"
-
- local = Dir["#{local_base}/**/*"].reject { |path| File.directory?(path) }
- edge = Dir["#{edge_base}/**/*"].reject { |path| File.directory?(path) }
-
- edge.each do |script|
- base_name = script[(edge_base.length+1)..-1]
- next if base_name == "rails"
- next if local.detect { |path| base_name == path[(local_base.length+1)..-1] }
- if !File.directory?("#{local_base}/#{File.dirname(base_name)}")
- mkdir_p "#{local_base}/#{File.dirname(base_name)}"
- end
- install script, "#{local_base}/#{base_name}", :mode => 0755
- end
- end
+ def invoke_from_app_generator(method)
+ require 'generators'
+ require 'generators/rails/app/app_generator'
- desc "Update your javascripts from your current rails install"
- task :javascripts do
- require 'railties_path'
- project_dir = RAILS_ROOT + '/public/javascripts/'
- scripts = Dir[RAILTIES_PATH + '/html/javascripts/*.js']
- scripts.reject!{|s| File.basename(s) == 'application.js'} if File.exist?(project_dir + 'application.js')
- FileUtils.cp(scripts, project_dir)
+ generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
+ :destination_root => RAILS_ROOT
+ generator.invoke(method)
end
desc "Update config/boot.rb from your current rails install"
task :configs do
- require 'railties_path'
- FileUtils.cp(RAILTIES_PATH + '/environments/boot.rb', RAILS_ROOT + '/config/boot.rb')
+ invoke_from_app_generator :create_boot_file
+ end
+
+ desc "Update Prototype javascripts from your current rails install"
+ task :javascripts do
+ invoke_from_app_generator :create_prototype_files
+ end
+
+ desc "Generate dispatcher files in RAILS_ROOT/public"
+ task :generate_dispatchers do
+ invoke_from_app_generator :create_dispatch_files
end
-
+
+ desc "Add new scripts to the application script/ directory"
+ task :scripts do
+ invoke_from_app_generator :create_script_files
+ end
+
desc "Rename application.rb to application_controller.rb"
task :application_controller do
old_style = RAILS_ROOT + '/app/controllers/application.rb'
@@ -132,14 +129,5 @@ namespace :rails do
puts "#{old_style} has been renamed to #{new_style}, update your SCM as necessary"
end
end
-
- desc "Generate dispatcher files in RAILS_ROOT/public"
- task :generate_dispatchers do
- require 'railties_path'
- FileUtils.cp(RAILTIES_PATH + '/dispatches/config.ru', RAILS_ROOT + '/config.ru')
- FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.fcgi', RAILS_ROOT + '/public/dispatch.fcgi')
- FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.rb')
- FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.cgi')
- end
end
end
diff --git a/railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc b/railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc
new file mode 100644
index 0000000000..544dde8c02
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/CHANGELOG.rdoc
@@ -0,0 +1,75 @@
+== TODO
+
+* Improve spec coverage for Thor::Runner
+* Improve help output to list shorthand switches, too
+
+== Current
+
+* BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
+ since it wrong behavior to the invocation system.
+
+* thor help now show information about any class/task. All those calls are
+ possible:
+
+ thor help describe
+ thor help describe:amazing
+
+ Or even with default namespaces:
+
+ thor help :spec
+
+* Thor::Runner now invokes the default task if none is supplied:
+
+ thor describe # invokes the default task, usually help
+
+* Thor::Runner now works with mappings:
+
+ thor describe -h
+
+* Added some documentation and code refactoring.
+
+== 0.9.8, released 2008-10-20
+
+* Fixed some tiny issues that were introduced lately.
+
+== 0.9.7, released 2008-10-13
+
+* Setting global method options on the initialize method works as expected:
+ All other tasks will accept these global options in addition to their own.
+* Added 'group' notion to Thor task sets (class Thor); by default all tasks
+ are in the 'standard' group. Running 'thor -T' will only show the standard
+ tasks - adding --all will show all tasks. You can also filter on a specific
+ group using the --group option: thor -T --group advanced
+
+== 0.9.6, released 2008-09-13
+
+* Generic improvements
+
+== 0.9.5, released 2008-08-27
+
+* Improve Windows compatibility
+* Update (incorrect) README and task.thor sample file
+* Options hash is now frozen (once returned)
+* Allow magic predicates on options object. For instance: `options.force?`
+* Add support for :numeric type
+* BACKWARDS INCOMPATIBLE: Refactor Thor::Options. You cannot access shorthand forms in options hash anymore (for instance, options[:f])
+* Allow specifying optional args with default values: method_options(:user => "mislav")
+* Don't write options for nil or false values. This allows, for example, turning color off when running specs.
+* Exit with the status of the spec command to help CI stuff out some.
+
+== 0.9.4, released 2008-08-13
+
+* Try to add Windows compatibility.
+* BACKWARDS INCOMPATIBLE: options hash is now accessed as a property in your class and is not passed as last argument anymore
+* Allow options at the beginning of the argument list as well as the end.
+* Make options available with symbol keys in addition to string keys.
+* Allow true to be passed to Thor#method_options to denote a boolean option.
+* If loading a thor file fails, don't give up, just print a warning and keep going.
+* Make sure that we re-raise errors if they happened further down the pipe than we care about.
+* Only delete the old file on updating when the installation of the new one is a success
+* Make it Ruby 1.8.5 compatible.
+* Don't raise an error if a boolean switch is defined multiple times.
+* Thor::Options now doesn't parse through things that look like options but aren't.
+* Add URI detection to install task, and make sure we don't append ".thor" to URIs
+* Add rake2thor to the gem binfiles.
+* Make sure local Thorfiles override system-wide ones.
diff --git a/railties/lib/vendor/thor-0.11.3/LICENSE b/railties/lib/vendor/thor-0.11.3/LICENSE
new file mode 100644
index 0000000000..98722da459
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/railties/lib/vendor/thor-0.11.3/README.markdown b/railties/lib/vendor/thor-0.11.3/README.markdown
new file mode 100644
index 0000000000..a1d7259775
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/README.markdown
@@ -0,0 +1,247 @@
+thor
+====
+
+Map options to a class. Simply create a class with the appropriate annotations
+and have options automatically map to functions and parameters.
+
+Example:
+
+ class App < Thor # [1]
+ map "-L" => :list # [2]
+
+ desc "install APP_NAME", "install one of the available apps" # [3]
+ method_options :force => :boolean, :alias => :string # [4]
+ def install(name)
+ user_alias = options[:alias]
+ if options.force?
+ # do something
+ end
+ # other code
+ end
+
+ desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
+ def list(search="")
+ # list everything
+ end
+ end
+
+Thor automatically maps commands as such:
+
+ thor app:install myname --force
+
+That gets converted to:
+
+ App.new.install("myname")
+ # with {'force' => true} as options hash
+
+1. Inherit from Thor to turn a class into an option mapper
+2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
+3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description
+4. Provide any additional options that will be available the instance method options.
+
+Types for `method_options`
+--------------------------
+
+<dl>
+ <dt><code>:boolean</code></dt>
+ <dd>is parsed as --option or --option=true</dd>
+ <dt><code>:string</code></dt>
+ <dd>is parsed as --option=VALUE</dd>
+ <dt><code>:numeric</code></dt>
+ <dd>is parsed as --option=N</dd>
+ <dt><code>:array</code></dt>
+ <dd>is parsed as --option=one two three</dd>
+ <dt><code>:hash</code></dt>
+ <dd>is parsed as --option=key:value key:value key:value</dd>
+</dl>
+
+Besides, method_option allows a default value to be given, examples:
+
+ method_options :force => false
+ #=> Creates a boolean option with default value false
+
+ method_options :alias => "bar"
+ #=> Creates a string option with default value "bar"
+
+ method_options :threshold => 3.0
+ #=> Creates a numeric option with default value 3.0
+
+You can also supply :option => :required to mark an option as required. The
+type is assumed to be string. If you want a required hash with default values
+as option, you can use `method_option` which uses a more declarative style:
+
+ method_option :attributes, :type => :hash, :default => {}, :required => true
+
+All arguments can be set to nil (except required arguments), by suppling a no or
+skip variant. For example:
+
+ thor app name --no-attributes
+
+In previous versions, aliases for options were created automatically, but now
+they should be explicit. You can supply aliases in both short and declarative
+styles:
+
+ method_options %w( force -f ) => :boolean
+
+Or:
+
+ method_option :force, :type => :boolean, :aliases => "-f"
+
+You can supply as many aliases as you want.
+
+NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead.
+
+Namespaces
+----------
+
+By default, your Thor tasks are invoked using Ruby namespace. In the example
+above, tasks are invoked as:
+
+ thor app:install name --force
+
+However, you could namespace your class as:
+
+ module Sinatra
+ class App < Thor
+ # tasks
+ end
+ end
+
+And then you should invoke your tasks as:
+
+ thor sinatra:app:install name --force
+
+If desired, you can change the namespace:
+
+ module Sinatra
+ class App < Thor
+ namespace :myapp
+ # tasks
+ end
+ end
+
+And then your tasks hould be invoked as:
+
+ thor myapp:install name --force
+
+Invocations
+-----------
+
+Thor comes with a invocation-dependency system as well which allows a task to be
+invoked only once. For example:
+
+ class Counter < Thor
+ desc "one", "Prints 1, 2, 3"
+ def one
+ puts 1
+ invoke :two
+ invoke :three
+ end
+
+ desc "two", "Prints 2, 3"
+ def two
+ puts 2
+ invoke :three
+ end
+
+ desc "three", "Prints 3"
+ def three
+ puts 3
+ end
+ end
+
+When invoking the task one:
+
+ thor counter:one
+
+The output is "1 2 3", which means that the three task was invoked only once.
+You can even invoke tasks from another class, so be sure to check the
+documentation.
+
+Thor::Group
+-----------
+
+Thor has a special class called Thor::Group. The main difference to Thor class
+is that it invokes all tasks at once. The example above could be rewritten in
+Thor::Group as this:
+
+ class Counter < Thor::Group
+ desc "Prints 1, 2, 3"
+
+ def one
+ puts 1
+ end
+
+ def two
+ puts 2
+ end
+
+ def three
+ puts 3
+ end
+ end
+
+When invoked:
+
+ thor counter
+
+It prints "1 2 3" as well. Notice you should described (desc) only the class
+and not each task anymore. Thor::Group is a great tool to create generators,
+since you can define several steps which are invoked in the order they are
+defined (Thor::Group is the tool use in generators in Rails 3.0).
+
+Besides, Thor::Group can parse arguments and options as Thor tasks:
+
+ class Counter < Thor::Group
+ # number will be available as attr_accessor
+ argument :number, :type => :numeric, :desc => "The number to start counting"
+ desc "Prints the 'number' given upto 'number+2'"
+
+ def one
+ puts number + 0
+ end
+
+ def two
+ puts number + 1
+ end
+
+ def three
+ puts number + 2
+ end
+ end
+
+The counter above expects one parameter and has the folling outputs:
+
+ thor counter 5
+ # Prints "5 6 7"
+
+ thor counter 11
+ # Prints "11 12 13"
+
+You can also give options to Thor::Group, but instead of using `method_option` and
+`method_options`, you should use `class_option` and `class_options`. Both argument
+and class_options methods are available to Thor class as well.
+
+Actions
+-------
+
+Thor comes with several actions which helps with script and generator tasks. You
+might be familiar with them since some came from Rails Templates. They are: `say`,
+`ask`, `yes?`, `no?`, `add_file`, `remove_file`, `copy_file`, `template`,
+`directory`, `inside`, `run`, `inject_into_file` and a couple more.
+
+To use them, you just need to include Thor::Actions in your Thor classes:
+
+ class App < Thor
+ include Thor::Actions
+ # tasks
+ end
+
+Some actions like copy file requires that a class method called source_root is
+defined in your class. This is the directory where your templates should be
+placed. Be sure to check the documentation.
+
+License
+-------
+
+See MIT LICENSE.
diff --git a/railties/lib/vendor/thor-0.11.3/bin/rake2thor b/railties/lib/vendor/thor-0.11.3/bin/rake2thor
new file mode 100755
index 0000000000..50c7410d80
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/bin/rake2thor
@@ -0,0 +1,87 @@
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'ruby2ruby'
+require 'parse_tree'
+if Ruby2Ruby::VERSION >= "1.2.0"
+ require 'parse_tree_extensions'
+end
+require 'rake'
+
+input = ARGV[0] || 'Rakefile'
+output = ARGV[1] || 'Thorfile'
+
+$requires = []
+
+module Kernel
+ def require_with_record(file)
+ $requires << file if caller[1] =~ /rake2thor:/
+ require_without_record file
+ end
+ alias_method :require_without_record, :require
+ alias_method :require, :require_with_record
+end
+
+load input
+
+@private_methods = []
+
+def file_task_name(name)
+ "compile_" + name.gsub('/', '_slash_').gsub('.', '_dot_').gsub(/\W/, '_')
+end
+
+def method_for_task(task)
+ file_task = task.is_a?(Rake::FileTask)
+ comment = task.instance_variable_get('@comment')
+ prereqs = task.instance_variable_get('@prerequisites').select(&Rake::Task.method(:task_defined?))
+ actions = task.instance_variable_get('@actions')
+ name = task.name.gsub(/^([^:]+:)+/, '')
+ name = file_task_name(name) if file_task
+ meth = ''
+
+ meth << "desc #{name.inspect}, #{comment.inspect}\n" if comment
+ meth << "def #{name}\n"
+
+ meth << prereqs.map do |pre|
+ pre = pre.to_s
+ pre = file_task_name(pre) if Rake::Task[pre].is_a?(Rake::FileTask)
+ ' ' + pre
+ end.join("\n")
+
+ meth << "\n\n" unless prereqs.empty? || actions.empty?
+
+ meth << actions.map do |act|
+ act = act.to_ruby
+ unless act.gsub!(/^proc \{ \|(\w+)\|\n/,
+ " \\1 = Struct.new(:name).new(#{name.inspect}) # A crude mock Rake::Task object\n")
+ act.gsub!(/^proc \{\n/, '')
+ end
+ act.gsub(/\n\}$/, '')
+ end.join("\n")
+
+ meth << "\nend"
+
+ if file_task
+ @private_methods << meth
+ return
+ end
+
+ meth
+end
+
+body = Rake::Task.tasks.map(&method(:method_for_task)).compact.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
+
+unless @private_methods.empty?
+ body << "\n\n private\n\n"
+ body << @private_methods.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
+end
+
+requires = $requires.map { |r| "require #{r.inspect}" }.join("\n")
+
+File.open(output, 'w') { |f| f.write(<<END.lstrip) }
+#{requires}
+
+class Default < Thor
+#{body}
+end
+END
diff --git a/railties/lib/vendor/thor-0.11.3/bin/thor b/railties/lib/vendor/thor-0.11.3/bin/thor
new file mode 100755
index 0000000000..eaf849fb4a
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/bin/thor
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+# -*- mode: ruby -*-
+
+require File.join(File.dirname(__FILE__), '..', 'lib', 'thor')
+require 'thor/runner'
+
+Thor::Runner.start
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor.rb b/railties/lib/vendor/thor-0.11.3/lib/thor.rb
new file mode 100644
index 0000000000..f65455cdda
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor.rb
@@ -0,0 +1,240 @@
+$:.unshift File.expand_path(File.dirname(__FILE__))
+require 'thor/base'
+require 'thor/group'
+require 'thor/actions'
+
+class Thor
+ class << self
+ # Sets the default task when thor is executed without an explicit task to be called.
+ #
+ # ==== Parameters
+ # meth<Symbol>:: name of the defaut task
+ #
+ def default_task(meth=nil)
+ case meth
+ when :none
+ @default_task = 'help'
+ when nil
+ @default_task ||= from_superclass(:default_task, 'help')
+ else
+ @default_task = meth.to_s
+ end
+ end
+
+ # Defines the usage and the description of the next task.
+ #
+ # ==== Parameters
+ # usage<String>
+ # description<String>
+ #
+ def desc(usage, description, options={})
+ if options[:for]
+ task = find_and_refresh_task(options[:for])
+ task.usage = usage if usage
+ task.description = description if description
+ else
+ @usage, @desc = usage, description
+ end
+ end
+
+ # Maps an input to a task. If you define:
+ #
+ # map "-T" => "list"
+ #
+ # Running:
+ #
+ # thor -T
+ #
+ # Will invoke the list task.
+ #
+ # ==== Parameters
+ # Hash[String|Array => Symbol]:: Maps the string or the strings in the array to the given task.
+ #
+ def map(mappings=nil)
+ @map ||= from_superclass(:map, {})
+
+ if mappings
+ mappings.each do |key, value|
+ if key.respond_to?(:each)
+ key.each {|subkey| @map[subkey] = value}
+ else
+ @map[key] = value
+ end
+ end
+ end
+
+ @map
+ end
+
+ # Declares the options for the next task to be declared.
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]:: The hash key is the name of the option and the value
+ # is the type of the option. Can be :string, :array, :hash, :boolean, :numeric
+ # or :required (string). If you give a value, the type of the value is used.
+ #
+ def method_options(options=nil)
+ @method_options ||= {}
+ build_options(options, @method_options) if options
+ @method_options
+ end
+
+ # Adds an option to the set of class options. If :for is given as option,
+ # it allows you to change the options from a previous defined task.
+ #
+ # def previous_task
+ # # magic
+ # end
+ #
+ # method_options :foo => :bar, :for => :previous_task
+ #
+ # def next_task
+ # # magic
+ # end
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc - Description for the argument.
+ # :required - If the argument is required or not.
+ # :default - Default value for this argument. It cannot be required and have default values.
+ # :aliases - Aliases for this option.
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric, :boolean or :default.
+ # Default accepts arguments as booleans (--switch) or as strings (--switch=VALUE).
+ # :group - The group for this options. Use by class options to output options in different levels.
+ # :banner - String to show on usage notes.
+ #
+ def method_option(name, options={})
+ scope = if options[:for]
+ find_and_refresh_task(options[:for]).options
+ else
+ method_options
+ end
+
+ build_option(name, options, scope)
+ end
+
+ # Parses the task and options from the given args, instantiate the class
+ # and invoke the task. This method is used when the arguments must be parsed
+ # from an array. If you are inside Ruby and want to use a Thor class, you
+ # can simply initialize it:
+ #
+ # script = MyScript.new(args, options, config)
+ # script.invoke(:task, first_arg, second_arg, third_arg)
+ #
+ def start(given_args=ARGV, config={})
+ super do
+ meth = normalize_task_name(given_args.shift)
+ task = all_tasks[meth]
+
+ if task
+ args, opts = Thor::Options.split(given_args)
+ config.merge!(:task_options => task.options)
+ else
+ args, opts = given_args, {}
+ end
+
+ task ||= Task.dynamic(meth)
+ trailing = args[Range.new(arguments.size, -1)]
+ new(args, opts, config).invoke(task, trailing || [])
+ end
+ end
+
+ # Prints help information. If a task name is given, it shows information
+ # only about the specific task.
+ #
+ # ==== Parameters
+ # meth<String>:: An optional task name to print usage information about.
+ #
+ # ==== Options
+ # namespace:: When true, shows the namespace in the output before the usage.
+ # skip_inherited:: When true, does not show tasks from superclass.
+ #
+ def help(shell, meth=nil, options={})
+ meth, options = nil, meth if meth.is_a?(Hash)
+
+ if meth
+ task = all_tasks[meth]
+ raise UndefinedTaskError, "task '#{meth}' could not be found in namespace '#{self.namespace}'" unless task
+
+ shell.say "Usage:"
+ shell.say " #{banner(task, options[:namespace])}"
+ shell.say
+ class_options_help(shell, "Class")
+ shell.say task.description
+ else
+ list = (options[:short] ? tasks : all_tasks).map do |_, task|
+ item = [ " " + banner(task, options[:namespace]) ]
+ item << if task.short_description
+ "\n # #{task.short_description}\n"
+ else
+ "\n"
+ end
+ end
+
+ if options[:short]
+ shell.print_table(list)
+ else
+ shell.say "Tasks:"
+ shell.print_table(list)
+ class_options_help(shell, "Class")
+ end
+ end
+ end
+
+ protected
+
+ # The banner for this class. You can customize it if you are invoking the
+ # thor class by another means which is not the Thor::Runner. It receives
+ # the task that is going to be invoked and if the namespace should be
+ # displayed.
+ #
+ def banner(task, namespace=true) #:nodoc:
+ task.formatted_usage(self, namespace)
+ end
+
+ def baseclass #:nodoc:
+ Thor
+ end
+
+ def create_task(meth) #:nodoc:
+ if @usage && @desc
+ tasks[meth.to_s] = Thor::Task.new(meth, @desc, @usage, method_options)
+ @usage, @desc, @method_options = nil
+ true
+ elsif self.all_tasks[meth.to_s] || meth.to_sym == :method_missing
+ true
+ else
+ puts "[WARNING] Attempted to create task #{meth.inspect} without usage or description. " <<
+ "Call desc if you want this method to be available as task or declare it inside a " <<
+ "no_tasks{} block. Invoked from #{caller[1].inspect}."
+ false
+ end
+ end
+
+ def initialize_added #:nodoc:
+ class_options.merge!(method_options)
+ @method_options = nil
+ end
+
+ # Receives a task name (can be nil), and try to get a map from it.
+ # If a map can't be found use the sent name or the default task.
+ #
+ def normalize_task_name(meth) #:nodoc:
+ mapping = map[meth.to_s]
+ meth = mapping || meth || default_task
+ meth.to_s.gsub('-','_') # treat foo-bar > foo_bar
+ end
+ end
+
+ include Thor::Base
+
+ map HELP_MAPPINGS => :help
+
+ desc "help [TASK]", "Describe available tasks or one specific task"
+ def help(task=nil)
+ self.class.help(shell, task, :namespace => task && task.include?(?:))
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb
new file mode 100644
index 0000000000..b8cfde1940
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions.rb
@@ -0,0 +1,270 @@
+require 'fileutils'
+
+Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
+ require action
+end
+
+class Thor
+ module Actions
+ attr_accessor :behavior
+
+ # On inclusion, add some options to base.
+ #
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ return unless base.respond_to?(:class_option)
+
+ base.class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
+ :desc => "Run but do not make any changes"
+
+ base.class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
+ :desc => "Overwrite files that already exist"
+
+ base.class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
+ :desc => "Skip files that already exist"
+
+ base.class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
+ :desc => "Supress status output"
+ end
+
+ module ClassMethods
+ # Hold source paths for one Thor instance. source_paths_for_search is the
+ # method responsible to gather source_paths from this current class,
+ # inherited paths and the source root.
+ #
+ def source_paths
+ @source_paths ||= []
+ end
+
+ # Returns the source paths in the following order:
+ #
+ # 1) This class source paths
+ # 2) Source root
+ # 3) Parents source paths
+ #
+ def source_paths_for_search
+ @source_paths_for_search ||= begin
+ paths = []
+ paths += self.source_paths
+ paths << self.source_root if self.respond_to?(:source_root)
+ paths += from_superclass(:source_paths, [])
+ paths
+ end
+ end
+ end
+
+ # Extends initializer to add more configuration options.
+ #
+ # ==== Configuration
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
+ # It also accepts :force, :skip and :pretend to set the behavior
+ # and the respective option.
+ #
+ # destination_root<String>:: The root directory needed for some actions. It's also known
+ # as destination root.
+ #
+ def initialize(args=[], options={}, config={})
+ self.behavior = case config[:behavior].to_s
+ when "force", "skip"
+ _cleanup_options_and_set(options, config[:behavior])
+ :invoke
+ when "revoke"
+ :revoke
+ else
+ :invoke
+ end
+
+ super
+ self.destination_root = config[:destination_root]
+ end
+
+ # Wraps an action object and call it accordingly to the thor class behavior.
+ #
+ def action(instance)
+ if behavior == :revoke
+ instance.revoke!
+ else
+ instance.invoke!
+ end
+ end
+
+ # Returns the root for this thor class (also aliased as destination root).
+ #
+ def destination_root
+ @destination_stack.last
+ end
+
+ # Sets the root for this thor class. Relatives path are added to the
+ # directory where the script was invoked and expanded.
+ #
+ def destination_root=(root)
+ @destination_stack ||= []
+ @destination_stack[0] = File.expand_path(root || '')
+ end
+
+ # Returns the given path relative to the absolute root (ie, root where
+ # the script started).
+ #
+ def relative_to_original_destination_root(path, remove_dot=true)
+ path = path.gsub(@destination_stack[0], '.')
+ remove_dot ? (path[2..-1] || '') : path
+ end
+
+ # Receives a file or directory and search for it in the source paths.
+ #
+ def find_in_source_paths(file)
+ relative_root = relative_to_original_destination_root(destination_root, false)
+ paths = self.class.source_paths_for_search
+
+ paths.each do |source|
+ source_file = File.expand_path(file, File.join(source, relative_root))
+ return source_file if File.exists?(source_file)
+ end
+
+ if paths.empty?
+ raise Error, "You don't have any source path defined for class #{self.class.name}. To fix this, " <<
+ "you can define a source_root in your class."
+ else
+ raise Error, "Could not find #{file.inspect} in source paths."
+ end
+ end
+
+ # Do something in the root or on a provided subfolder. If a relative path
+ # is given it's referenced from the current root. The full path is yielded
+ # to the block you provide. The path is set back to the previous path when
+ # the method exits.
+ #
+ # ==== Parameters
+ # dir<String>:: the directory to move to.
+ # config<Hash>:: give :verbose => true to log and use padding.
+ #
+ def inside(dir='', config={}, &block)
+ verbose = config.fetch(:verbose, false)
+
+ say_status :inside, dir, verbose
+ shell.padding += 1 if verbose
+ @destination_stack.push File.expand_path(dir, destination_root)
+
+ FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
+
+ @destination_stack.pop
+ shell.padding -= 1 if verbose
+ end
+
+ # Goes to the root and execute the given block.
+ #
+ def in_root
+ inside(@destination_stack.first) { yield }
+ end
+
+ # Loads an external file and execute it in the instance binding.
+ #
+ # ==== Parameters
+ # path<String>:: The path to the file to execute. Can be a web address or
+ # a relative path from the source root.
+ #
+ # ==== Examples
+ #
+ # apply "http://gist.github.com/103208"
+ #
+ # apply "recipes/jquery.rb"
+ #
+ def apply(path, config={})
+ verbose = config.fetch(:verbose, true)
+ path = find_in_source_paths(path) unless path =~ /^http\:\/\//
+
+ say_status :apply, path, verbose
+ shell.padding += 1 if verbose
+ instance_eval(open(path).read)
+ shell.padding -= 1 if verbose
+ end
+
+ # Executes a command.
+ #
+ # ==== Parameters
+ # command<String>:: the command to be executed.
+ # config<Hash>:: give :verbose => false to not log the status. Specify :with
+ # to append an executable to command executation.
+ #
+ # ==== Example
+ #
+ # inside('vendor') do
+ # run('ln -s ~/edge rails')
+ # end
+ #
+ def run(command, config={})
+ return unless behavior == :invoke
+
+ destination = relative_to_original_destination_root(destination_root, false)
+ desc = "#{command} from #{destination.inspect}"
+
+ if config[:with]
+ desc = "#{File.basename(config[:with].to_s)} #{desc}"
+ command = "#{config[:with]} #{command}"
+ end
+
+ say_status :run, desc, config.fetch(:verbose, true)
+ `#{command}` unless options[:pretend]
+ end
+
+ # Executes a ruby script (taking into account WIN32 platform quirks).
+ #
+ # ==== Parameters
+ # command<String>:: the command to be executed.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ def run_ruby_script(command, config={})
+ return unless behavior == :invoke
+ run "#{command}", config.merge(:with => Thor::Util.ruby_command)
+ end
+
+ # Run a thor command. A hash of options can be given and it's converted to
+ # switches.
+ #
+ # ==== Parameters
+ # task<String>:: the task to be invoked
+ # args<Array>:: arguments to the task
+ # config<Hash>:: give :verbose => false to not log the status. Other options
+ # are given as parameter to Thor.
+ #
+ # ==== Examples
+ #
+ # thor :install, "http://gist.github.com/103208"
+ # #=> thor install http://gist.github.com/103208
+ #
+ # thor :list, :all => true, :substring => 'rails'
+ # #=> thor list --all --substring=rails
+ #
+ def thor(task, *args)
+ config = args.last.is_a?(Hash) ? args.pop : {}
+ verbose = config.key?(:verbose) ? config.delete(:verbose) : true
+
+ args.unshift task
+ args.push Thor::Options.to_switches(config)
+ command = args.join(' ').strip
+
+ run command, :with => :thor, :verbose => verbose
+ end
+
+ protected
+
+ # Allow current root to be shared between invocations.
+ #
+ def _shared_configuration #:nodoc:
+ super.merge!(:destination_root => self.destination_root)
+ end
+
+ def _cleanup_options_and_set(options, key) #:nodoc:
+ case options
+ when Array
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
+ options << "--#{key}"
+ when Hash
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
+ options.merge!(key => true)
+ end
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb
new file mode 100644
index 0000000000..8f6badee27
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/create_file.rb
@@ -0,0 +1,102 @@
+require 'thor/actions/empty_directory'
+
+class Thor
+ module Actions
+
+ # Create a new file relative to the destination root with the given data,
+ # which is the return value of a block or a data string.
+ #
+ # ==== Parameters
+ # destination<String>:: the relative path to the destination root.
+ # data<String|NilClass>:: the data to append to the file.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # create_file "lib/fun_party.rb" do
+ # hostname = ask("What is the virtual hostname I should use?")
+ # "vhost.name = #{hostname}"
+ # end
+ #
+ # create_file "config/apach.conf", "your apache config"
+ #
+ def create_file(destination, data=nil, config={}, &block)
+ action CreateFile.new(self, destination, block || data.to_s, config)
+ end
+ alias :add_file :create_file
+
+ # AddFile is a subset of Template, which instead of rendering a file with
+ # ERB, it gets the content from the user.
+ #
+ class CreateFile < EmptyDirectory #:nodoc:
+ attr_reader :data
+
+ def initialize(base, destination, data, config={})
+ @data = data
+ super(base, destination, config)
+ end
+
+ # Checks if the content of the file at the destination is identical to the rendered result.
+ #
+ # ==== Returns
+ # Boolean:: true if it is identical, false otherwise.
+ #
+ def identical?
+ exists? && File.read(destination) == render
+ end
+
+ # Holds the content to be added to the file.
+ #
+ def render
+ @render ||= if data.is_a?(Proc)
+ data.call
+ else
+ data
+ end
+ end
+
+ def invoke!
+ invoke_with_conflict_check do
+ FileUtils.mkdir_p(File.dirname(destination))
+ File.open(destination, 'w'){ |f| f.write render }
+ end
+ end
+
+ protected
+
+ # Now on conflict we check if the file is identical or not.
+ #
+ def on_conflict_behavior(&block)
+ if identical?
+ say_status :identical, :blue
+ else
+ options = base.options.merge(config)
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
+ end
+ end
+
+ # If force is true, run the action, otherwise check if it's not being
+ # skipped. If both are false, show the file_collision menu, if the menu
+ # returns true, force it, otherwise skip.
+ #
+ def force_or_skip_or_conflict(force, skip, &block)
+ if force
+ say_status :force, :yellow
+ block.call unless pretend?
+ elsif skip
+ say_status :skip, :yellow
+ else
+ say_status :conflict, :red
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
+ end
+ end
+
+ # Shows the file collision menu to the user and gets the result.
+ #
+ def force_on_collision?
+ base.shell.file_collision(destination){ render }
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb
new file mode 100644
index 0000000000..e33639f4e5
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/directory.rb
@@ -0,0 +1,87 @@
+require 'thor/actions/empty_directory'
+
+class Thor
+ module Actions
+
+ # Copies interactively the files from source directory to root directory.
+ # If any of the files finishes with .tt, it's considered to be a template
+ # and is placed in the destination without the extension .tt. If any
+ # empty directory is found, it's copied and all .empty_directory files are
+ # ignored. Remember that file paths can also be encoded, let's suppose a doc
+ # directory with the following files:
+ #
+ # doc/
+ # components/.empty_directory
+ # README
+ # rdoc.rb.tt
+ # %app_name%.rb
+ #
+ # When invoked as:
+ #
+ # directory "doc"
+ #
+ # It will create a doc directory in the destination with the following
+ # files (assuming that the app_name is "blog"):
+ #
+ # doc/
+ # components/
+ # README
+ # rdoc.rb
+ # blog.rb
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ # If :recursive => false, does not look for paths recursively.
+ #
+ # ==== Examples
+ #
+ # directory "doc"
+ # directory "doc", "docs", :recursive => false
+ #
+ def directory(source, destination=nil, config={})
+ action Directory.new(self, source, destination || source, config)
+ end
+
+ class Directory < EmptyDirectory #:nodoc:
+ attr_reader :source
+
+ def initialize(base, source, destination=nil, config={})
+ @source = File.expand_path(base.find_in_source_paths(source.to_s))
+ super(base, destination, { :recursive => true }.merge(config))
+ end
+
+ def invoke!
+ base.empty_directory given_destination, config
+ execute!
+ end
+
+ def revoke!
+ execute!
+ end
+
+ protected
+
+ def execute!
+ lookup = config[:recursive] ? File.join(source, '**') : source
+ lookup = File.join(lookup, '{*,.[a-z]*}')
+
+ Dir[lookup].each do |file_source|
+ next if File.directory?(file_source)
+ file_destination = File.join(given_destination, file_source.gsub(source, '.'))
+
+ case file_source
+ when /\.empty_directory$/
+ base.empty_directory(File.dirname(file_destination), config)
+ when /\.tt$/
+ base.template(file_source, file_destination[0..-4], config)
+ else
+ base.copy_file(file_source, file_destination, config)
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb
new file mode 100644
index 0000000000..03c1fe4af1
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/empty_directory.rb
@@ -0,0 +1,133 @@
+class Thor
+ module Actions
+
+ # Creates an empty directory.
+ #
+ # ==== Parameters
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # empty_directory "doc"
+ #
+ def empty_directory(destination, config={})
+ action EmptyDirectory.new(self, destination, config)
+ end
+
+ # Class which holds create directory logic. This is the base class for
+ # other actions like create_file and directory.
+ #
+ # This implementation is based in Templater actions, created by Jonas Nicklas
+ # and Michael S. Klishin under MIT LICENSE.
+ #
+ class EmptyDirectory #:nodoc:
+ attr_reader :base, :destination, :given_destination, :relative_destination, :config
+
+ # Initializes given the source and destination.
+ #
+ # ==== Parameters
+ # base<Thor::Base>:: A Thor::Base instance
+ # source<String>:: Relative path to the source of this file
+ # destination<String>:: Relative path to the destination of this file
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ def initialize(base, destination, config={})
+ @base, @config = base, { :verbose => true }.merge(config)
+ self.destination = destination
+ end
+
+ # Checks if the destination file already exists.
+ #
+ # ==== Returns
+ # Boolean:: true if the file exists, false otherwise.
+ #
+ def exists?
+ ::File.exists?(destination)
+ end
+
+ def invoke!
+ invoke_with_conflict_check do
+ ::FileUtils.mkdir_p(destination)
+ end
+ end
+
+ def revoke!
+ say_status :remove, :red
+ ::FileUtils.rm_rf(destination) if !pretend? && exists?
+ end
+
+ protected
+
+ # Shortcut for pretend.
+ #
+ def pretend?
+ base.options[:pretend]
+ end
+
+ # Sets the absolute destination value from a relative destination value.
+ # It also stores the given and relative destination. Let's suppose our
+ # script is being executed on "dest", it sets the destination root to
+ # "dest". The destination, given_destination and relative_destination
+ # are related in the following way:
+ #
+ # inside "bar" do
+ # empty_directory "baz"
+ # end
+ #
+ # destination #=> dest/bar/baz
+ # relative_destination #=> bar/baz
+ # given_destination #=> baz
+ #
+ def destination=(destination)
+ if destination
+ @given_destination = convert_encoded_instructions(destination.to_s)
+ @destination = ::File.expand_path(@given_destination, base.destination_root)
+ @relative_destination = base.relative_to_original_destination_root(@destination)
+ end
+ end
+
+ # Filenames in the encoded form are converted. If you have a file:
+ #
+ # %class_name%.rb
+ #
+ # It gets the class name from the base and replace it:
+ #
+ # user.rb
+ #
+ def convert_encoded_instructions(filename)
+ filename.gsub(/%(.*?)%/) do |string|
+ instruction = $1.strip
+ base.respond_to?(instruction) ? base.send(instruction) : string
+ end
+ end
+
+ # Receives a hash of options and just execute the block if some
+ # conditions are met.
+ #
+ def invoke_with_conflict_check(&block)
+ if exists?
+ on_conflict_behavior(&block)
+ else
+ say_status :create, :green
+ block.call unless pretend?
+ end
+
+ destination
+ end
+
+ # What to do when the destination file already exists.
+ #
+ def on_conflict_behavior(&block)
+ say_status :exist, :blue
+ end
+
+ # Shortcut to say_status shell method.
+ #
+ def say_status(status, color)
+ base.shell.say_status status, relative_destination, color if config[:verbose]
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb
new file mode 100644
index 0000000000..74c157ba8c
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/file_manipulation.rb
@@ -0,0 +1,195 @@
+require 'erb'
+require 'open-uri'
+
+class Thor
+ module Actions
+
+ # Copies the file from the relative source to the relative destination. If
+ # the destination is not given it's assumed to be equal to the source.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # copy_file "README", "doc/README"
+ #
+ # copy_file "doc/README"
+ #
+ def copy_file(source, destination=nil, config={})
+ destination ||= source
+ source = File.expand_path(find_in_source_paths(source.to_s))
+
+ create_file destination, nil, config do
+ File.read(source)
+ end
+ end
+
+ # Gets the content at the given address and places it at the given relative
+ # destination. If a block is given instead of destination, the content of
+ # the url is yielded and used as location.
+ #
+ # ==== Parameters
+ # source<String>:: the address of the given content.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # get "http://gist.github.com/103208", "doc/README"
+ #
+ # get "http://gist.github.com/103208" do |content|
+ # content.split("\n").first
+ # end
+ #
+ def get(source, destination=nil, config={}, &block)
+ source = File.expand_path(find_in_source_paths(source.to_s)) unless source =~ /^http\:\/\//
+ render = open(source).read
+
+ destination ||= if block_given?
+ block.arity == 1 ? block.call(render) : block.call
+ else
+ File.basename(source)
+ end
+
+ create_file destination, render, config
+ end
+
+ # Gets an ERB template at the relative source, executes it and makes a copy
+ # at the relative destination. If the destination is not given it's assumed
+ # to be equal to the source removing .tt from the filename.
+ #
+ # ==== Parameters
+ # source<String>:: the relative path to the source root.
+ # destination<String>:: the relative path to the destination root.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Examples
+ #
+ # template "README", "doc/README"
+ #
+ # template "doc/README"
+ #
+ def template(source, destination=nil, config={})
+ destination ||= source
+ source = File.expand_path(find_in_source_paths(source.to_s))
+ context = instance_eval('binding')
+
+ create_file destination, nil, config do
+ ERB.new(::File.read(source), nil, '-').result(context)
+ end
+ end
+
+ # Changes the mode of the given file or directory.
+ #
+ # ==== Parameters
+ # mode<Integer>:: the file mode
+ # path<String>:: the name of the file to change mode
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # chmod "script/*", 0755
+ #
+ def chmod(path, mode, config={})
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+ say_status :chmod, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+ FileUtils.chmod_R(mode, path) unless options[:pretend]
+ end
+
+ # Prepend text to a file.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # data<String>:: the data to prepend to the file, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
+ #
+ def prepend_file(path, data=nil, config={}, &block)
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+ say_status :prepend, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+
+ unless options[:pretend]
+ content = data || block.call
+ content << File.read(path)
+ File.open(path, 'wb') { |file| file.write(content) }
+ end
+ end
+
+ # Append text to a file.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # data<String>:: the data to append to the file, can be also given as a block.
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # append_file 'config/environments/test.rb', 'config.gem "rspec"'
+ #
+ def append_file(path, data=nil, config={}, &block)
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+ say_status :append, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+ File.open(path, 'ab') { |file| file.write(data || block.call) } unless options[:pretend]
+ end
+
+ # Run a regular expression replacement on a file.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # flag<Regexp|String>:: the regexp or string to be replaced
+ # replacement<String>:: the replacement, can be also given as a block
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # gsub_file 'app/controllers/application_controller.rb', /#\s*(filter_parameter_logging :password)/, '\1'
+ #
+ # gsub_file 'README', /rake/, :green do |match|
+ # match << " no more. Use thor!"
+ # end
+ #
+ def gsub_file(path, flag, *args, &block)
+ return unless behavior == :invoke
+ config = args.last.is_a?(Hash) ? args.pop : {}
+
+ path = File.expand_path(path, destination_root)
+ say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+
+ unless options[:pretend]
+ content = File.read(path)
+ content.gsub!(flag, *args, &block)
+ File.open(path, 'wb') { |file| file.write(content) }
+ end
+ end
+
+ # Removes a file at the given location.
+ #
+ # ==== Parameters
+ # path<String>:: path of the file to be changed
+ # config<Hash>:: give :verbose => false to not log the status.
+ #
+ # ==== Example
+ #
+ # remove_file 'README'
+ # remove_file 'app/controllers/application_controller.rb'
+ #
+ def remove_file(path, config={})
+ return unless behavior == :invoke
+ path = File.expand_path(path, destination_root)
+
+ say_status :remove, relative_to_original_destination_root(path), config.fetch(:verbose, true)
+ ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
+ end
+ alias :remove_dir :remove_file
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb
new file mode 100644
index 0000000000..089bd894e4
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/actions/inject_into_file.rb
@@ -0,0 +1,78 @@
+require 'thor/actions/empty_directory'
+
+class Thor
+ module Actions
+
+ # Injects the given content into a file. Different from append_file,
+ # prepend_file and gsub_file, this method is reversible. By this reason,
+ # the flag can only be strings. gsub_file is your friend if you need to
+ # deal with more complex cases.
+ #
+ # ==== Parameters
+ # destination<String>:: Relative path to the destination root
+ # data<String>:: Data to add to the file. Can be given as a block.
+ # config<Hash>:: give :verbose => false to not log the status and the flag
+ # for injection (:after or :before).
+ #
+ # ==== Examples
+ #
+ # inject_into_file "config/environment.rb", "config.gem thor", :after => "Rails::Initializer.run do |config|\n"
+ #
+ # inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
+ # gems = ask "Which gems would you like to add?"
+ # gems.split(" ").map{ |gem| " config.gem #{gem}" }.join("\n")
+ # end
+ #
+ def inject_into_file(destination, *args, &block)
+ if block_given?
+ data, config = block, args.shift
+ else
+ data, config = args.shift, args.shift
+ end
+
+ log_status = args.empty? || args.pop
+ action InjectIntoFile.new(self, destination, data, config)
+ end
+
+ class InjectIntoFile < EmptyDirectory
+ attr_reader :flag, :replacement
+
+ def initialize(base, destination, data, config)
+ super(base, destination, { :verbose => true }.merge(config))
+
+ data = data.call if data.is_a?(Proc)
+
+ @replacement = if @config.key?(:after)
+ @flag = @config.delete(:after)
+ @flag + data
+ else
+ @flag = @config.delete(:before)
+ data + @flag
+ end
+ end
+
+ def invoke!
+ say_status :inject, config[:verbose]
+ replace!(flag, replacement)
+ end
+
+ def revoke!
+ say_status :deinject, config[:verbose]
+ replace!(replacement, flag)
+ end
+
+ protected
+
+ # Adds the content to the file.
+ #
+ def replace!(regexp, string)
+ unless base.options[:pretend]
+ content = File.read(destination)
+ content.gsub!(regexp, string)
+ File.open(destination, 'wb') { |file| file.write(content) }
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/base.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/base.rb
new file mode 100644
index 0000000000..0bdcc1f4d5
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/base.rb
@@ -0,0 +1,516 @@
+require 'thor/core_ext/hash_with_indifferent_access'
+require 'thor/core_ext/ordered_hash'
+require 'thor/error'
+require 'thor/shell'
+require 'thor/invocation'
+require 'thor/parser'
+require 'thor/task'
+require 'thor/util'
+
+class Thor
+ HELP_MAPPINGS = %w(-h -? --help -D)
+ THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
+ action add_file create_file in_root inside run run_ruby_script)
+
+ module Base
+ attr_accessor :options
+
+ # It receives arguments in an Array and two hashes, one for options and
+ # other for configuration.
+ #
+ # Notice that it does not check if all required arguments were supplied.
+ # It should be done by the parser.
+ #
+ # ==== Parameters
+ # args<Array[Object]>:: An array of objects. The objects are applied to their
+ # respective accessors declared with <tt>argument</tt>.
+ #
+ # options<Hash>:: An options hash that will be available as self.options.
+ # The hash given is converted to a hash with indifferent
+ # access, magic predicates (options.skip?) and then frozen.
+ #
+ # config<Hash>:: Configuration for this Thor class.
+ #
+ def initialize(args=[], options={}, config={})
+ Thor::Arguments.parse(self.class.arguments, args).each do |key, value|
+ send("#{key}=", value)
+ end
+
+ parse_options = self.class.class_options
+
+ if options.is_a?(Array)
+ task_options = config.delete(:task_options) # hook for start
+ parse_options = parse_options.merge(task_options) if task_options
+ array_options, hash_options = options, {}
+ else
+ array_options, hash_options = [], options
+ end
+
+ options = Thor::Options.parse(parse_options, array_options)
+ self.options = Thor::CoreExt::HashWithIndifferentAccess.new(options).merge!(hash_options)
+ self.options.freeze
+ end
+
+ class << self
+ def included(base) #:nodoc:
+ base.send :extend, ClassMethods
+ base.send :include, Invocation
+ base.send :include, Shell
+ end
+
+ # Returns the classes that inherits from Thor or Thor::Group.
+ #
+ # ==== Returns
+ # Array[Class]
+ #
+ def subclasses
+ @subclasses ||= []
+ end
+
+ # Returns the files where the subclasses are kept.
+ #
+ # ==== Returns
+ # Hash[path<String> => Class]
+ #
+ def subclass_files
+ @subclass_files ||= Hash.new{ |h,k| h[k] = [] }
+ end
+
+ # Whenever a class inherits from Thor or Thor::Group, we should track the
+ # class and the file on Thor::Base. This is the method responsable for it.
+ # Also adds the source root to the source paths if the klass respond to it.
+ #
+ def register_klass_file(klass) #:nodoc:
+ file = caller[1].match(/(.*):\d+/)[1]
+ Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass)
+
+ file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
+ file_subclasses << klass unless file_subclasses.include?(klass)
+ end
+ end
+
+ module ClassMethods
+ # Adds an argument to the class and creates an attr_accessor for it.
+ #
+ # Arguments are different from options in several aspects. The first one
+ # is how they are parsed from the command line, arguments are retrieved
+ # from position:
+ #
+ # thor task NAME
+ #
+ # Instead of:
+ #
+ # thor task --name=NAME
+ #
+ # Besides, arguments are used inside your code as an accessor (self.argument),
+ # while options are all kept in a hash (self.options).
+ #
+ # Finally, arguments cannot have type :default or :boolean but can be
+ # optional (supplying :optional => :true or :required => false), although
+ # you cannot have a required argument after a non-required argument. If you
+ # try it, an error is raised.
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc - Description for the argument.
+ # :required - If the argument is required or not.
+ # :optional - If the argument is optional or not.
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric.
+ # :default - Default value for this argument. It cannot be required and have default values.
+ # :banner - String to show on usage notes.
+ #
+ # ==== Errors
+ # ArgumentError:: Raised if you supply a required argument after a non required one.
+ #
+ def argument(name, options={})
+ is_thor_reserved_word?(name, :argument)
+ no_tasks { attr_accessor name }
+
+ required = if options.key?(:optional)
+ !options[:optional]
+ elsif options.key?(:required)
+ options[:required]
+ else
+ options[:default].nil?
+ end
+
+ remove_argument name
+
+ arguments.each do |argument|
+ next if argument.required?
+ raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
+ "the non-required argument #{argument.human_name.inspect}."
+ end if required
+
+ arguments << Thor::Argument.new(name, options[:desc], required, options[:type],
+ options[:default], options[:banner])
+ end
+
+ # Returns this class arguments, looking up in the ancestors chain.
+ #
+ # ==== Returns
+ # Array[Thor::Argument]
+ #
+ def arguments
+ @arguments ||= from_superclass(:arguments, [])
+ end
+
+ # Adds a bunch of options to the set of class options.
+ #
+ # class_options :foo => false, :bar => :required, :baz => :string
+ #
+ # If you prefer more detailed declaration, check class_option.
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]
+ #
+ def class_options(options=nil)
+ @class_options ||= from_superclass(:class_options, {})
+ build_options(options, @class_options) if options
+ @class_options
+ end
+
+ # Adds an option to the set of class options
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described below.
+ #
+ # ==== Options
+ # :desc - Description for the argument.
+ # :required - If the argument is required or not.
+ # :default - Default value for this argument.
+ # :group - The group for this options. Use by class options to output options in different levels.
+ # :aliases - Aliases for this option.
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
+ # :banner - String to show on usage notes.
+ #
+ def class_option(name, options={})
+ build_option(name, options, class_options)
+ end
+
+ # Removes a previous defined argument. If :undefine is given, undefine
+ # accessors as well.
+ #
+ # ==== Paremeters
+ # names<Array>:: Arguments to be removed
+ #
+ # ==== Examples
+ #
+ # remove_argument :foo
+ # remove_argument :foo, :bar, :baz, :undefine => true
+ #
+ def remove_argument(*names)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+
+ names.each do |name|
+ arguments.delete_if { |a| a.name == name.to_s }
+ undef_method name, "#{name}=" if options[:undefine]
+ end
+ end
+
+ # Removes a previous defined class option.
+ #
+ # ==== Paremeters
+ # names<Array>:: Class options to be removed
+ #
+ # ==== Examples
+ #
+ # remove_class_option :foo
+ # remove_class_option :foo, :bar, :baz
+ #
+ def remove_class_option(*names)
+ names.each do |name|
+ class_options.delete(name)
+ end
+ end
+
+ # Defines the group. This is used when thor list is invoked so you can specify
+ # that only tasks from a pre-defined group will be shown. Defaults to standard.
+ #
+ # ==== Parameters
+ # name<String|Symbol>
+ #
+ def group(name=nil)
+ case name
+ when nil
+ @group ||= from_superclass(:group, 'standard')
+ else
+ @group = name.to_s
+ end
+ end
+
+ # Returns the tasks for this Thor class.
+ #
+ # ==== Returns
+ # OrderedHash:: An ordered hash with this class tasks.
+ #
+ def tasks
+ @tasks ||= Thor::CoreExt::OrderedHash.new
+ end
+
+ # Returns the tasks for this Thor class and all subclasses.
+ #
+ # ==== Returns
+ # OrderedHash
+ #
+ def all_tasks
+ @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new)
+ @all_tasks.merge(tasks)
+ end
+
+ # Removes a given task from this Thor class. This is usually done if you
+ # are inheriting from another class and don't want it to be available
+ # anymore.
+ #
+ # By default it only remove the mapping to the task. But you can supply
+ # :undefine => true to undefine the method from the class as well.
+ #
+ # ==== Parameters
+ # name<Symbol|String>:: The name of the task to be removed
+ # options<Hash>:: You can give :undefine => true if you want tasks the method
+ # to be undefined from the class as well.
+ #
+ def remove_task(*names)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+
+ names.each do |name|
+ tasks.delete(name.to_s)
+ all_tasks.delete(name.to_s)
+ undef_method name if options[:undefine]
+ end
+ end
+
+ # All methods defined inside the given block are not added as tasks.
+ #
+ # So you can do:
+ #
+ # class MyScript < Thor
+ # no_tasks do
+ # def this_is_not_a_task
+ # end
+ # end
+ # end
+ #
+ # You can also add the method and remove it from the task list:
+ #
+ # class MyScript < Thor
+ # def this_is_not_a_task
+ # end
+ # remove_task :this_is_not_a_task
+ # end
+ #
+ def no_tasks
+ @no_tasks = true
+ yield
+ @no_tasks = false
+ end
+
+ # Sets the namespace for the Thor or Thor::Group class. By default the
+ # namespace is retrieved from the class name. If your Thor class is named
+ # Scripts::MyScript, the help method, for example, will be called as:
+ #
+ # thor scripts:my_script -h
+ #
+ # If you change the namespace:
+ #
+ # namespace :my_scripts
+ #
+ # You change how your tasks are invoked:
+ #
+ # thor my_scripts -h
+ #
+ # Finally, if you change your namespace to default:
+ #
+ # namespace :default
+ #
+ # Your tasks can be invoked with a shortcut. Instead of:
+ #
+ # thor :my_task
+ #
+ def namespace(name=nil)
+ case name
+ when nil
+ @namespace ||= Thor::Util.constant_to_namespace(self, false)
+ else
+ @namespace = name.to_s
+ end
+ end
+
+ # Default way to start generators from the command line.
+ #
+ def start(given_args=ARGV, config={}) #:nodoc:
+ config[:shell] ||= Thor::Base.shell.new
+ yield
+ rescue Thor::Error => e
+ if given_args.include?("--debug")
+ raise e
+ else
+ config[:shell].error e.message
+ end
+ end
+
+ protected
+
+ # Prints the class options per group. If an option does not belong to
+ # any group, it uses the ungrouped name value. This method provide to
+ # hooks to add extra options, one of them if the third argument called
+ # extra_group that should be a hash in the format :group => Array[Options].
+ #
+ # The second is by returning a lamda used to print values. The lambda
+ # requires two options: the group name and the array of options.
+ #
+ def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc:
+ groups = {}
+
+ class_options.each do |_, value|
+ groups[value.group] ||= []
+ groups[value.group] << value
+ end
+
+ printer = proc do |group_name, options|
+ list = []
+ padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
+
+ options.each do |option|
+ item = [ option.usage(padding) ]
+
+ item << if option.description
+ "# #{option.description}"
+ else
+ ""
+ end
+
+ list << item
+ list << [ "", "# Default: #{option.default}" ] if option.show_default?
+ end
+
+ unless list.empty?
+ if group_name
+ shell.say "#{group_name} options:"
+ else
+ shell.say "Options:"
+ end
+
+ shell.print_table(list, :ident => 2)
+ shell.say ""
+ end
+ end
+
+ # Deal with default group
+ global_options = groups.delete(nil) || []
+ printer.call(ungrouped_name, global_options) if global_options
+
+ # Print all others
+ groups = extra_group.merge(groups) if extra_group
+ groups.each(&printer)
+ printer
+ end
+
+ # Raises an error if the word given is a Thor reserved word.
+ #
+ def is_thor_reserved_word?(word, type)
+ return false unless THOR_RESERVED_WORDS.include?(word.to_s)
+ raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
+ end
+
+ # Build an option and adds it to the given scope.
+ #
+ # ==== Parameters
+ # name<Symbol>:: The name of the argument.
+ # options<Hash>:: Described in both class_option and method_option.
+ #
+ def build_option(name, options, scope)
+ scope[name] = Thor::Option.new(name, options[:desc], options[:required],
+ options[:type], options[:default], options[:banner],
+ options[:group], options[:aliases])
+ end
+
+ # Receives a hash of options, parse them and add to the scope. This is a
+ # fast way to set a bunch of options:
+ #
+ # build_options :foo => true, :bar => :required, :baz => :string
+ #
+ # ==== Parameters
+ # Hash[Symbol => Object]
+ #
+ def build_options(options, scope)
+ options.each do |key, value|
+ scope[key] = Thor::Option.parse(key, value)
+ end
+ end
+
+ # Finds a task with the given name. If the task belongs to the current
+ # class, just return it, otherwise dup it and add the fresh copy to the
+ # current task hash.
+ #
+ def find_and_refresh_task(name)
+ task = if task = tasks[name.to_s]
+ task
+ elsif task = all_tasks[name.to_s]
+ tasks[name.to_s] = task.clone
+ else
+ raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found."
+ end
+ end
+
+ # Everytime someone inherits from a Thor class, register the klass
+ # and file into baseclass.
+ #
+ def inherited(klass)
+ Thor::Base.register_klass_file(klass)
+ end
+
+ # Fire this callback whenever a method is added. Added methods are
+ # tracked as tasks if the requirements set by valid_task? are valid.
+ #
+ def method_added(meth)
+ meth = meth.to_s
+
+ if meth == "initialize"
+ initialize_added
+ return
+ end
+
+ # Return if it's not a public instance method
+ return unless public_instance_methods.include?(meth) ||
+ public_instance_methods.include?(meth.to_sym)
+
+ return if @no_tasks || !create_task(meth)
+
+ is_thor_reserved_word?(meth, :task)
+ Thor::Base.register_klass_file(self)
+ end
+
+ # Retrieves a value from superclass. If it reaches the baseclass,
+ # returns nil.
+ #
+ def from_superclass(method, default=nil)
+ if self == baseclass || !superclass.respond_to?(method, true)
+ default
+ else
+ value = superclass.send(method)
+ value.dup if value
+ end
+ end
+
+ # SIGNATURE: Sets the baseclass. This is where the superclass lookup
+ # finishes.
+ def baseclass #:nodoc:
+ end
+
+ # SIGNATURE: Creates a new task if valid_task? is true. This method is
+ # called when a new method is added to the class.
+ def create_task(meth) #:nodoc:
+ end
+
+ # SIGNATURE: Defines behavior when the initialize method is added to the
+ # class.
+ def initialize_added #:nodoc:
+ end
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb
new file mode 100644
index 0000000000..3213961fe4
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -0,0 +1,75 @@
+class Thor
+ module CoreExt
+
+ # A hash with indifferent access and magic predicates.
+ #
+ # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
+ #
+ # hash[:foo] #=> 'bar'
+ # hash['foo'] #=> 'bar'
+ # hash.foo? #=> true
+ #
+ class HashWithIndifferentAccess < ::Hash
+
+ def initialize(hash={})
+ super()
+ hash.each do |key, value|
+ self[convert_key(key)] = value
+ end
+ end
+
+ def [](key)
+ super(convert_key(key))
+ end
+
+ def []=(key, value)
+ super(convert_key(key), value)
+ end
+
+ def delete(key)
+ super(convert_key(key))
+ end
+
+ def values_at(*indices)
+ indices.collect { |key| self[convert_key(key)] }
+ end
+
+ def merge(other)
+ dup.merge!(other)
+ end
+
+ def merge!(other)
+ other.each do |key, value|
+ self[convert_key(key)] = value
+ end
+ self
+ end
+
+ protected
+
+ def convert_key(key)
+ key.is_a?(Symbol) ? key.to_s : key
+ end
+
+ # Magic predicates. For instance:
+ #
+ # options.force? # => !!options['force']
+ # options.shebang # => "/usr/lib/local/ruby"
+ # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
+ #
+ def method_missing(method, *args, &block)
+ method = method.to_s
+ if method =~ /^(\w+)\?$/
+ if args.empty?
+ !!self[$1]
+ else
+ self[$1] == args.first
+ end
+ else
+ self[method]
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb
new file mode 100644
index 0000000000..5e4ad5609f
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/core_ext/ordered_hash.rb
@@ -0,0 +1,102 @@
+require 'forwardable'
+
+class Thor #:nodoc:
+ module CoreExt #:nodoc:
+
+ if RUBY_VERSION >= '1.9'
+ class OrderedHash < ::Hash
+ end
+ else
+ # This class is based on the Ruby 1.9 ordered hashes.
+ #
+ # It keeps the semantics and most of the efficiency of normal hashes
+ # while also keeping track of the order in which elements were set.
+ #
+ class OrderedHash #:nodoc:
+ include Enumerable
+
+ Node = Struct.new(:key, :value, :next, :prev)
+
+ def initialize
+ @hash = {}
+ end
+
+ def [](key)
+ @hash[key] && @hash[key].value
+ end
+
+ def []=(key, value)
+ if node = @hash[key]
+ node.value = value
+ else
+ node = Node.new(key, value)
+
+ if @first.nil?
+ @first = @last = node
+ else
+ node.prev = @last
+ @last.next = node
+ @last = node
+ end
+ end
+
+ @hash[key] = node
+ value
+ end
+
+ def delete(key)
+ if node = @hash[key]
+ prev_node = node.prev
+ next_node = node.next
+
+ next_node.prev = prev_node if next_node
+ prev_node.next = next_node if prev_node
+
+ @first = next_node if @first == node
+ @last = prev_node if @last == node
+
+ value = node.value
+ end
+
+ @hash.delete(key)
+ value
+ end
+
+ def keys
+ self.map { |k, v| k }
+ end
+
+ def values
+ self.map { |k, v| v }
+ end
+
+ def each
+ return unless @first
+ yield [@first.key, @first.value]
+ node = @first
+ yield [node.key, node.value] while node = node.next
+ self
+ end
+
+ def merge(other)
+ hash = self.class.new
+
+ self.each do |key, value|
+ hash[key] = value
+ end
+
+ other.each do |key, value|
+ hash[key] = value
+ end
+
+ hash
+ end
+
+ def empty?
+ @hash.empty?
+ end
+ end
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb
new file mode 100644
index 0000000000..c846e9ce74
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/error.rb
@@ -0,0 +1,27 @@
+class Thor
+ # Thor::Error is raised when it's caused by the user invoking the task and
+ # only errors that inherit from it are rescued.
+ #
+ # So, for example, if the developer declares a required argument after an
+ # option, it should raise an ::ArgumentError and not ::Thor::ArgumentError,
+ # because it was caused by the developer and not the "final user".
+ #
+ class Error < StandardError #:nodoc:
+ end
+
+ # Raised when a task was not found.
+ #
+ class UndefinedTaskError < Error #:nodoc:
+ end
+
+ # Raised when a task was found, but not invoked properly.
+ #
+ class InvocationError < Error #:nodoc:
+ end
+
+ class RequiredArgumentMissingError < InvocationError #:nodoc:
+ end
+
+ class MalformattedArgumentError < InvocationError #:nodoc:
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/group.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/group.rb
new file mode 100644
index 0000000000..1be1c35ba5
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/group.rb
@@ -0,0 +1,263 @@
+# Thor has a special class called Thor::Group. The main difference to Thor class
+# is that it invokes all tasks at once. It also include some methods that allows
+# invocations to be done at the class method, which are not available to Thor
+# tasks.
+#
+class Thor::Group
+ class << self
+ # The descrition for this Thor::Group. If none is provided, but a source root
+ # exists, tries to find the USAGE one folder above it, otherwise searches
+ # in the superclass.
+ #
+ # ==== Parameters
+ # description<String>:: The description for this Thor::Group.
+ #
+ def desc(description=nil)
+ case description
+ when nil
+ @desc ||= from_superclass(:desc, nil)
+ else
+ @desc = description
+ end
+ end
+
+ # Start works differently in Thor::Group, it simply invokes all tasks
+ # inside the class.
+ #
+ def start(given_args=ARGV, config={})
+ super do
+ if Thor::HELP_MAPPINGS.include?(given_args.first)
+ help(config[:shell])
+ return
+ end
+
+ args, opts = Thor::Options.split(given_args)
+ new(args, opts, config).invoke
+ end
+ end
+
+ # Prints help information.
+ #
+ # ==== Options
+ # short:: When true, shows only usage.
+ #
+ def help(shell, options={})
+ if options[:short]
+ shell.say banner
+ else
+ shell.say "Usage:"
+ shell.say " #{banner}"
+ shell.say
+ class_options_help(shell)
+ shell.say self.desc if self.desc
+ end
+ end
+
+ # Stores invocations for this class merging with superclass values.
+ #
+ def invocations #:nodoc:
+ @invocations ||= from_superclass(:invocations, {})
+ end
+
+ # Stores invocation blocks used on invoke_from_option.
+ #
+ def invocation_blocks #:nodoc:
+ @invocation_blocks ||= from_superclass(:invocation_blocks, {})
+ end
+
+ # Invoke the given namespace or class given. It adds an instance
+ # method that will invoke the klass and task. You can give a block to
+ # configure how it will be invoked.
+ #
+ # The namespace/class given will have its options showed on the help
+ # usage. Check invoke_from_option for more information.
+ #
+ def invoke(*names, &block)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ verbose = options.fetch(:verbose, :white)
+
+ names.each do |name|
+ invocations[name] = false
+ invocation_blocks[name] = block if block_given?
+
+ class_eval <<-METHOD, __FILE__, __LINE__
+ def _invoke_#{name.to_s.gsub(/\W/, '_')}
+ klass, task = self.class.prepare_for_invocation(nil, #{name.inspect})
+
+ if klass
+ say_status :invoke, #{name.inspect}, #{verbose.inspect}
+ block = self.class.invocation_blocks[#{name.inspect}]
+ _invoke_for_class_method klass, task, &block
+ else
+ say_status :error, %(#{name.inspect} [not found]), :red
+ end
+ end
+ METHOD
+ end
+ end
+
+ # Invoke a thor class based on the value supplied by the user to the
+ # given option named "name". A class option must be created before this
+ # method is invoked for each name given.
+ #
+ # ==== Examples
+ #
+ # class GemGenerator < Thor::Group
+ # class_option :test_framework, :type => :string
+ # invoke_from_option :test_framework
+ # end
+ #
+ # ==== Boolean options
+ #
+ # In some cases, you want to invoke a thor class if some option is true or
+ # false. This is automatically handled by invoke_from_option. Then the
+ # option name is used to invoke the generator.
+ #
+ # ==== Preparing for invocation
+ #
+ # In some cases you want to customize how a specified hook is going to be
+ # invoked. You can do that by overwriting the class method
+ # prepare_for_invocation. The class method must necessarily return a klass
+ # and an optional task.
+ #
+ # ==== Custom invocations
+ #
+ # You can also supply a block to customize how the option is giong to be
+ # invoked. The block receives two parameters, an instance of the current
+ # class and the klass to be invoked.
+ #
+ def invoke_from_option(*names, &block)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ verbose = options.fetch(:verbose, :white)
+
+ names.each do |name|
+ unless class_options.key?(name)
+ raise ArgumentError, "You have to define the option #{name.inspect} " <<
+ "before setting invoke_from_option."
+ end
+
+ invocations[name] = true
+ invocation_blocks[name] = block if block_given?
+
+ class_eval <<-METHOD, __FILE__, __LINE__
+ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
+ return unless options[#{name.inspect}]
+
+ value = options[#{name.inspect}]
+ value = #{name.inspect} if TrueClass === value
+ klass, task = self.class.prepare_for_invocation(#{name.inspect}, value)
+
+ if klass
+ say_status :invoke, value, #{verbose.inspect}
+ block = self.class.invocation_blocks[#{name.inspect}]
+ _invoke_for_class_method klass, task, &block
+ else
+ say_status :error, %(\#{value} [not found]), :red
+ end
+ end
+ METHOD
+ end
+ end
+
+ # Remove a previously added invocation.
+ #
+ # ==== Examples
+ #
+ # remove_invocation :test_framework
+ #
+ def remove_invocation(*names)
+ names.each do |name|
+ remove_task(name)
+ remove_class_option(name)
+ invocations.delete(name)
+ invocation_blocks.delete(name)
+ end
+ end
+
+ # Overwrite class options help to allow invoked generators options to be
+ # shown recursively when invoking a generator.
+ #
+ def class_options_help(shell, ungrouped_name=nil, extra_group=nil) #:nodoc:
+ group_options = {}
+
+ get_options_from_invocations(group_options, class_options) do |klass|
+ klass.send(:get_options_from_invocations, group_options, class_options)
+ end
+
+ group_options.merge!(extra_group) if extra_group
+ super(shell, ungrouped_name, group_options)
+ end
+
+ # Get invocations array and merge options from invocations. Those
+ # options are added to group_options hash. Options that already exists
+ # in base_options are not added twice.
+ #
+ def get_options_from_invocations(group_options, base_options) #:nodoc:
+ invocations.each do |name, from_option|
+ value = if from_option
+ option = class_options[name]
+ option.type == :boolean ? name : option.default
+ else
+ name
+ end
+ next unless value
+
+ klass, task = prepare_for_invocation(name, value)
+ next unless klass && klass.respond_to?(:class_options)
+
+ value = value.to_s
+ human_name = value.respond_to?(:classify) ? value.classify : value
+
+ group_options[human_name] ||= []
+ group_options[human_name] += klass.class_options.values.select do |option|
+ base_options[option.name.to_sym].nil? && option.group.nil? &&
+ !group_options.values.flatten.any? { |i| i.name == option.name }
+ end
+
+ yield klass if block_given?
+ end
+ end
+
+ protected
+
+ # The banner for this class. You can customize it if you are invoking the
+ # thor class by another means which is not the Thor::Runner.
+ #
+ def banner #:nodoc:
+ "#{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
+ end
+
+ def baseclass #:nodoc:
+ Thor::Group
+ end
+
+ def create_task(meth) #:nodoc:
+ tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil)
+ true
+ end
+ end
+
+ include Thor::Base
+
+ protected
+
+ # Shortcut to invoke with padding and block handling. Use internally by
+ # invoke and invoke_from_option class methods.
+ #
+ def _invoke_for_class_method(klass, task=nil, *args, &block)
+ shell.padding += 1
+
+ result = if block_given?
+ if block.arity == 2
+ block.call(self, klass)
+ else
+ block.call(self, klass, task)
+ end
+ else
+ invoke klass, task, *args
+ end
+
+ shell.padding -= 1
+ result
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb
new file mode 100644
index 0000000000..34e7a4b911
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/invocation.rb
@@ -0,0 +1,172 @@
+class Thor
+ module Invocation
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # Prepare for class methods invocations. This method must return a klass to
+ # have the invoked class options showed in help messages in generators.
+ #
+ def prepare_for_invocation(key, name) #:nodoc:
+ case name
+ when Symbol, String
+ Thor::Util.namespace_to_thor_class(name.to_s, false)
+ else
+ name
+ end
+ end
+ end
+
+ # Make initializer aware of invocations and the initializer proc.
+ #
+ def initialize(args=[], options={}, config={}, &block) #:nodoc:
+ @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] }
+ @_initializer = [ args, options, config ]
+ super
+ end
+
+ # Receives a name and invokes it. The name can be a string (either "task" or
+ # "namespace:task"), a Thor::Task, a Class or a Thor instance. If the task
+ # cannot be guessed by name, it can also be supplied as second argument.
+ #
+ # You can also supply the arguments, options and configuration values for
+ # the task to be invoked, if none is given, the same values used to
+ # initialize the invoker are used to initialize the invoked.
+ #
+ # ==== Examples
+ #
+ # class A < Thor
+ # def foo
+ # invoke :bar
+ # invoke "b:hello", ["José"]
+ # end
+ #
+ # def bar
+ # invoke "b:hello", ["José"]
+ # end
+ # end
+ #
+ # class B < Thor
+ # def hello(name)
+ # puts "hello #{name}"
+ # end
+ # end
+ #
+ # You can notice that the method "foo" above invokes two tasks: "bar",
+ # which belongs to the same class and "hello" which belongs to the class B.
+ #
+ # By using an invocation system you ensure that a task is invoked only once.
+ # In the example above, invoking "foo" will invoke "b:hello" just once, even
+ # if it's invoked later by "bar" method.
+ #
+ # When class A invokes class B, all arguments used on A initialization are
+ # supplied to B. This allows lazy parse of options. Let's suppose you have
+ # some rspec tasks:
+ #
+ # class Rspec < Thor::Group
+ # class_option :mock_framework, :type => :string, :default => :rr
+ #
+ # def invoke_mock_framework
+ # invoke "rspec:#{options[:mock_framework]}"
+ # end
+ # end
+ #
+ # As you noticed, it invokes the given mock framework, which might have its
+ # own options:
+ #
+ # class Rspec::RR < Thor::Group
+ # class_option :style, :type => :string, :default => :mock
+ # end
+ #
+ # Since it's not rspec concern to parse mock framework options, when RR
+ # is invoked all options are parsed again, so RR can extract only the options
+ # that it's going to use.
+ #
+ # If you want Rspec::RR to be initialized with its own set of options, you
+ # have to do that explicitely:
+ #
+ # invoke "rspec:rr", [], :style => :foo
+ #
+ # Besides giving an instance, you can also give a class to invoke:
+ #
+ # invoke Rspec::RR, [], :style => :foo
+ #
+ def invoke(name=nil, task=nil, args=nil, opts=nil, config=nil)
+ task, args, opts, config = nil, task, args, opts if task.nil? || task.is_a?(Array)
+ args, opts, config = nil, args, opts if args.is_a?(Hash)
+
+ object, task = _prepare_for_invocation(name, task)
+ if object.is_a?(Class)
+ klass = object
+
+ stored_args, stored_opts, stored_config = @_initializer
+ args ||= stored_args.dup
+ opts ||= stored_opts.dup
+
+ config ||= {}
+ config = stored_config.merge(_shared_configuration).merge!(config)
+ instance = klass.new(args, opts, config)
+ else
+ klass, instance = object.class, object
+ end
+
+ method_args = []
+ current = @_invocations[klass]
+
+ iterator = proc do |_, task|
+ unless current.include?(task.name)
+ current << task.name
+ task.run(instance, method_args)
+ end
+ end
+
+ if task
+ args ||= []
+ method_args = args[Range.new(klass.arguments.size, -1)] || []
+ iterator.call(nil, task)
+ else
+ klass.all_tasks.map(&iterator)
+ end
+ end
+
+ protected
+
+ # Configuration values that are shared between invocations.
+ #
+ def _shared_configuration
+ { :invocations => @_invocations }
+ end
+
+ # Prepare for invocation in the instance level. In this case, we have to
+ # take into account that a just a task name from the current class was
+ # given or even a Thor::Task object.
+ #
+ def _prepare_for_invocation(name, sent_task=nil) #:nodoc:
+ if name.is_a?(Thor::Task)
+ task = name
+ elsif task = self.class.all_tasks[name.to_s]
+ object = self
+ else
+ object, task = self.class.prepare_for_invocation(nil, name)
+ task ||= sent_task
+ end
+
+ # If the object was not set, use self and use the name as task.
+ object, task = self, name unless object
+ return object, _validate_klass_and_task(object, task)
+ end
+
+ # Check if the object given is a Thor class object and get a task object
+ # for it.
+ #
+ def _validate_klass_and_task(object, task) #:nodoc:
+ klass = object.is_a?(Class) ? object : object.class
+ raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
+
+ task ||= klass.default_task if klass <= Thor
+ task = klass.all_tasks[task.to_s] || Task.dynamic(task) if task && !task.is_a?(Thor::Task)
+ task
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb
new file mode 100644
index 0000000000..57a3f6e1a5
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/parser.rb
@@ -0,0 +1,4 @@
+require 'thor/parser/argument'
+require 'thor/parser/arguments'
+require 'thor/parser/option'
+require 'thor/parser/options'
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb
new file mode 100644
index 0000000000..2d7f4dbafb
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/argument.rb
@@ -0,0 +1,67 @@
+class Thor
+ class Argument
+ VALID_TYPES = [ :numeric, :hash, :array, :string ]
+
+ attr_reader :name, :description, :required, :type, :default, :banner
+ alias :human_name :name
+
+ def initialize(name, description=nil, required=true, type=:string, default=nil, banner=nil)
+ class_name = self.class.name.split("::").last
+
+ raise ArgumentError, "#{class_name} name can't be nil." if name.nil?
+ raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
+
+ @name = name.to_s
+ @description = description
+ @required = required || false
+ @type = (type || :string).to_sym
+ @default = default
+ @banner = banner || default_banner
+
+ validate! # Trigger specific validations
+ end
+
+ def usage
+ required? ? banner : "[#{banner}]"
+ end
+
+ def required?
+ required
+ end
+
+ def show_default?
+ case default
+ when Array, String, Hash
+ !default.empty?
+ else
+ default
+ end
+ end
+
+ protected
+
+ def validate!
+ raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
+ end
+
+ def valid_type?(type)
+ VALID_TYPES.include?(type.to_sym)
+ end
+
+ def default_banner
+ case type
+ when :boolean
+ nil
+ when :string, :default
+ human_name.upcase
+ when :numeric
+ "N"
+ when :hash
+ "key:value"
+ when :array
+ "one two three"
+ end
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb
new file mode 100644
index 0000000000..9a2262d6f7
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/arguments.rb
@@ -0,0 +1,145 @@
+class Thor
+ class Arguments
+ NUMERIC = /(\d*\.\d+|\d+)/
+
+ # Receives an array of args and returns two arrays, one with arguments
+ # and one with switches.
+ #
+ def self.split(args)
+ arguments = []
+
+ args.each do |item|
+ break if item =~ /^-/
+ arguments << item
+ end
+
+ return arguments, args[Range.new(arguments.size, -1)]
+ end
+
+ def self.parse(base, args)
+ new(base).parse(args)
+ end
+
+ # Takes an array of Thor::Argument objects.
+ #
+ def initialize(arguments=[])
+ @assigns, @non_assigned_required = {}, []
+ @switches = arguments
+
+ arguments.each do |argument|
+ if argument.default
+ @assigns[argument.human_name] = argument.default
+ elsif argument.required?
+ @non_assigned_required << argument
+ end
+ end
+ end
+
+ def parse(args)
+ @pile = args.dup
+
+ @switches.each do |argument|
+ break unless peek
+ @non_assigned_required.delete(argument)
+ @assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name)
+ end
+
+ check_requirement!
+ @assigns
+ end
+
+ private
+
+ def peek
+ @pile.first
+ end
+
+ def shift
+ @pile.shift
+ end
+
+ def unshift(arg)
+ unless arg.kind_of?(Array)
+ @pile.unshift(arg)
+ else
+ @pile = arg + @pile
+ end
+ end
+
+ def current_is_value?
+ peek && peek.to_s !~ /^-/
+ end
+
+ # Runs through the argument array getting strings that contains ":" and
+ # mark it as a hash:
+ #
+ # [ "name:string", "age:integer" ]
+ #
+ # Becomes:
+ #
+ # { "name" => "string", "age" => "integer" }
+ #
+ def parse_hash(name)
+ return shift if peek.is_a?(Hash)
+ hash = {}
+
+ while current_is_value? && peek.include?(?:)
+ key, value = shift.split(':')
+ hash[key] = value
+ end
+ hash
+ end
+
+ # Runs through the argument array getting all strings until no string is
+ # found or a switch is found.
+ #
+ # ["a", "b", "c"]
+ #
+ # And returns it as an array:
+ #
+ # ["a", "b", "c"]
+ #
+ def parse_array(name)
+ return shift if peek.is_a?(Array)
+ array = []
+
+ while current_is_value?
+ array << shift
+ end
+ array
+ end
+
+ # Check if the peel is numeric ofrmat and return a Float or Integer.
+ # Otherwise raises an error.
+ #
+ def parse_numeric(name)
+ return shift if peek.is_a?(Numeric)
+
+ unless peek =~ NUMERIC && $& == peek
+ raise MalformattedArgumentError, "expected numeric value for '#{name}'; got #{peek.inspect}"
+ end
+
+ $&.index('.') ? shift.to_f : shift.to_i
+ end
+
+ # Parse string, i.e., just return the current value in the pile.
+ #
+ def parse_string(name)
+ shift
+ end
+
+ # Raises an error if @non_assigned_required array is not empty.
+ #
+ def check_requirement!
+ unless @non_assigned_required.empty?
+ names = @non_assigned_required.map do |o|
+ o.respond_to?(:switch_name) ? o.switch_name : o.human_name
+ end.join("', '")
+
+ class_name = self.class.name.split('::').last.downcase
+ raise RequiredArgumentMissingError, "no value provided for required #{class_name} '#{names}'"
+ end
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb
new file mode 100644
index 0000000000..5c43f6b18f
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/option.rb
@@ -0,0 +1,132 @@
+class Thor
+ class Option < Argument
+ attr_reader :aliases, :group
+
+ VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
+
+ def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil)
+ super(name, description, required, type, default, banner)
+ @aliases = [*aliases].compact
+ @group = group.to_s.capitalize if group
+ end
+
+ # This parse quick options given as method_options. It makes several
+ # assumptions, but you can be more specific using the option method.
+ #
+ # parse :foo => "bar"
+ # #=> Option foo with default value bar
+ #
+ # parse [:foo, :baz] => "bar"
+ # #=> Option foo with default value bar and alias :baz
+ #
+ # parse :foo => :required
+ # #=> Required option foo without default value
+ #
+ # parse :foo => 2
+ # #=> Option foo with default value 2 and type numeric
+ #
+ # parse :foo => :numeric
+ # #=> Option foo without default value and type numeric
+ #
+ # parse :foo => true
+ # #=> Option foo with default value true and type boolean
+ #
+ # The valid types are :boolean, :numeric, :hash, :array and :string. If none
+ # is given a default type is assumed. This default type accepts arguments as
+ # string (--foo=value) or booleans (just --foo).
+ #
+ # By default all options are optional, unless :required is given.
+ #
+ def self.parse(key, value)
+ if key.is_a?(Array)
+ name, *aliases = key
+ else
+ name, aliases = key, []
+ end
+
+ name = name.to_s
+ default = value
+
+ type = case value
+ when Symbol
+ default = nil
+
+ if VALID_TYPES.include?(value)
+ value
+ elsif required = (value == :required)
+ :string
+ elsif value == :optional
+ # TODO Remove this warning in the future.
+ warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean."
+ :boolean
+ end
+ when TrueClass, FalseClass
+ :boolean
+ when Numeric
+ :numeric
+ when Hash, Array, String
+ value.class.name.downcase.to_sym
+ end
+
+ self.new(name.to_s, nil, required, type, default, nil, nil, aliases)
+ end
+
+ def switch_name
+ @switch_name ||= dasherized? ? name : dasherize(name)
+ end
+
+ def human_name
+ @human_name ||= dasherized? ? undasherize(name) : name
+ end
+
+ def usage(padding=0)
+ sample = if banner && !banner.to_s.empty?
+ "#{switch_name}=#{banner}"
+ else
+ switch_name
+ end
+
+ sample = "[#{sample}]" unless required?
+
+ if aliases.empty?
+ (" " * padding) << sample
+ else
+ "#{aliases.join(', ')}, #{sample}"
+ end
+ end
+
+ # Allow some type predicates as: boolean?, string? and etc.
+ #
+ def method_missing(method, *args, &block)
+ given = method.to_s.sub(/\?$/, '').to_sym
+ if valid_type?(given)
+ self.type == given
+ else
+ super
+ end
+ end
+
+ protected
+
+ def validate!
+ raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
+ end
+
+ def valid_type?(type)
+ VALID_TYPES.include?(type.to_sym)
+ end
+
+ def dasherized?
+ name.index('-') == 0
+ end
+
+ def undasherize(str)
+ str.sub(/^-{1,2}/, '')
+ end
+
+ def dasherize(str)
+ (str.length > 1 ? "--" : "-") + str.gsub('_', '-')
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb
new file mode 100644
index 0000000000..01c86b7b27
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/parser/options.rb
@@ -0,0 +1,142 @@
+class Thor
+ # This is a modified version of Daniel Berger's Getopt::Long class, licensed
+ # under Ruby's license.
+ #
+ class Options < Arguments
+ LONG_RE = /^(--\w+[-\w+]*)$/
+ SHORT_RE = /^(-[a-z])$/i
+ EQ_RE = /^(--\w+[-\w+]*|-[a-z])=(.*)$/i
+ SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
+ SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
+
+ # Receives a hash and makes it switches.
+ #
+ def self.to_switches(options)
+ options.map do |key, value|
+ case value
+ when true
+ "--#{key}"
+ when Array
+ "--#{key} #{value.map{ |v| v.inspect }.join(' ')}"
+ when Hash
+ "--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}"
+ when nil, false
+ ""
+ else
+ "--#{key} #{value.inspect}"
+ end
+ end.join(" ")
+ end
+
+ # Takes a hash of Thor::Option objects.
+ #
+ def initialize(options={})
+ options = options.values
+ super(options)
+ @shorts, @switches = {}, {}
+
+ options.each do |option|
+ @switches[option.switch_name] = option
+
+ option.aliases.each do |short|
+ @shorts[short.to_s] ||= option.switch_name
+ end
+ end
+ end
+
+ def parse(args)
+ @pile = args.dup
+
+ while peek
+ if current_is_switch?
+ case shift
+ when SHORT_SQ_RE
+ unshift($1.split('').map { |f| "-#{f}" })
+ next
+ when EQ_RE, SHORT_NUM
+ unshift($2)
+ switch = $1
+ when LONG_RE, SHORT_RE
+ switch = $1
+ end
+
+ switch = normalize_switch(switch)
+ next unless option = switch_option(switch)
+
+ @assigns[option.human_name] = parse_peek(switch, option)
+ else
+ shift
+ end
+ end
+
+ check_requirement!
+ @assigns
+ end
+
+ protected
+
+ # Returns true if the current value in peek is a registered switch.
+ #
+ def current_is_switch?
+ case peek
+ when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
+ switch?($1)
+ when SHORT_SQ_RE
+ $1.split('').any? { |f| switch?("-#{f}") }
+ end
+ end
+
+ def switch?(arg)
+ switch_option(arg) || @shorts.key?(arg)
+ end
+
+ def switch_option(arg)
+ if match = no_or_skip?(arg)
+ @switches[arg] || @switches["--#{match}"]
+ else
+ @switches[arg]
+ end
+ end
+
+ def no_or_skip?(arg)
+ arg =~ /^--(no|skip)-([-\w]+)$/
+ $2
+ end
+
+ # Check if the given argument is actually a shortcut.
+ #
+ def normalize_switch(arg)
+ @shorts.key?(arg) ? @shorts[arg] : arg
+ end
+
+ # Parse boolean values which can be given as --foo=true, --foo or --no-foo.
+ #
+ def parse_boolean(switch)
+ if current_is_value?
+ ["true", "TRUE", "t", "T", true].include?(shift)
+ else
+ @switches.key?(switch) || !no_or_skip?(switch)
+ end
+ end
+
+ # Parse the value at the peek analyzing if it requires an input or not.
+ #
+ def parse_peek(switch, option)
+ unless current_is_value?
+ if option.boolean?
+ # No problem for boolean types
+ elsif no_or_skip?(switch)
+ return nil # User set value to nil
+ elsif option.string? && !option.required?
+ return option.human_name # Return the option name
+ else
+ raise MalformattedArgumentError, "no value provided for option '#{switch}'"
+ end
+ end
+
+ @non_assigned_required.delete(option)
+ send(:"parse_#{option.type}", switch)
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb
new file mode 100644
index 0000000000..6782c61dec
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/runner.rb
@@ -0,0 +1,291 @@
+require 'fileutils'
+require 'open-uri'
+require 'yaml'
+require 'digest/md5'
+require 'pathname'
+
+class Thor::Runner < Thor
+ map "-T" => :list, "-i" => :install, "-u" => :update
+
+ # Override Thor#help so it can give information about any class and any method.
+ #
+ def help(meth=nil)
+ if meth && !self.respond_to?(meth)
+ initialize_thorfiles(meth)
+ klass, task = Thor::Util.namespace_to_thor_class(meth)
+ klass.start(["-h", task].compact, :shell => self.shell) # send mapping -h because it works with Thor::Group too
+ else
+ super
+ end
+ end
+
+ # If a task is not found on Thor::Runner, method missing is invoked and
+ # Thor::Runner is then responsable for finding the task in all classes.
+ #
+ def method_missing(meth, *args)
+ meth = meth.to_s
+ initialize_thorfiles(meth)
+ klass, task = Thor::Util.namespace_to_thor_class(meth)
+ args.unshift(task) if task
+ klass.start(args, :shell => shell)
+ end
+
+ desc "install NAME", "Install a Thor file into your system tasks, optionally named for future updates"
+ method_options :as => :string, :relative => :boolean
+ def install(name)
+ initialize_thorfiles
+
+ # If a directory name is provided as the argument, look for a 'main.thor'
+ # task in said directory.
+ begin
+ if File.directory?(File.expand_path(name))
+ base, package = File.join(name, "main.thor"), :directory
+ contents = open(base).read
+ else
+ base, package = name, :file
+ contents = open(name).read
+ end
+ rescue OpenURI::HTTPError
+ raise Error, "Error opening URI '#{name}'"
+ rescue Errno::ENOENT
+ raise Error, "Error opening file '#{name}'"
+ end
+
+ say "Your Thorfile contains:"
+ say contents
+
+ return false if no?("Do you wish to continue [y/N]?")
+
+ as = options["as"] || begin
+ first_line = contents.split("\n")[0]
+ (match = first_line.match(/\s*#\s*module:\s*([^\n]*)/)) ? match[1].strip : nil
+ end
+
+ unless as
+ basename = File.basename(name)
+ as = ask("Please specify a name for #{name} in the system repository [#{basename}]:")
+ as = basename if as.empty?
+ end
+
+ location = if options[:relative] || name =~ /^http:\/\//
+ name
+ else
+ File.expand_path(name)
+ end
+
+ thor_yaml[as] = {
+ :filename => Digest::MD5.hexdigest(name + as),
+ :location => location,
+ :namespaces => Thor::Util.namespaces_in_contents(contents, base)
+ }
+
+ save_yaml(thor_yaml)
+ say "Storing thor file in your system repository"
+ destination = File.join(thor_root, thor_yaml[as][:filename])
+
+ if package == :file
+ File.open(destination, "w") { |f| f.puts contents }
+ else
+ FileUtils.cp_r(name, destination)
+ end
+
+ thor_yaml[as][:filename] # Indicate success
+ end
+
+ desc "uninstall NAME", "Uninstall a named Thor module"
+ def uninstall(name)
+ raise Error, "Can't find module '#{name}'" unless thor_yaml[name]
+ say "Uninstalling #{name}."
+ FileUtils.rm_rf(File.join(thor_root, "#{thor_yaml[name][:filename]}"))
+
+ thor_yaml.delete(name)
+ save_yaml(thor_yaml)
+
+ puts "Done."
+ end
+
+ desc "update NAME", "Update a Thor file from its original location"
+ def update(name)
+ raise Error, "Can't find module '#{name}'" if !thor_yaml[name] || !thor_yaml[name][:location]
+
+ say "Updating '#{name}' from #{thor_yaml[name][:location]}"
+
+ old_filename = thor_yaml[name][:filename]
+ self.options = self.options.merge("as" => name)
+ filename = install(thor_yaml[name][:location])
+
+ unless filename == old_filename
+ File.delete(File.join(thor_root, old_filename))
+ end
+ end
+
+ desc "installed", "List the installed Thor modules and tasks"
+ method_options :internal => :boolean
+ def installed
+ initialize_thorfiles(nil, true)
+
+ klasses = Thor::Base.subclasses
+ klasses -= [Thor, Thor::Runner] unless options["internal"]
+
+ display_klasses(true, klasses)
+ end
+
+ desc "list [SEARCH]",
+ "List the available thor tasks (--substring means SEARCH anywhere in the namespace)"
+ method_options :substring => :boolean, :group => :string, :all => :boolean
+ def list(search="")
+ initialize_thorfiles
+
+ search = ".*#{search}" if options["substring"]
+ search = /^#{search}.*/i
+ group = options[:group] || "standard"
+
+ klasses = Thor::Base.subclasses.select do |k|
+ (options[:all] || k.group == group) && k.namespace =~ search
+ end
+
+ display_klasses(false, klasses)
+ end
+
+ private
+
+ def thor_root
+ Thor::Util.thor_root
+ end
+
+ def thor_yaml
+ @thor_yaml ||= begin
+ yaml_file = File.join(thor_root, "thor.yml")
+ yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
+ yaml || {}
+ end
+ end
+
+ # Save the yaml file. If none exists in thor root, creates one.
+ #
+ def save_yaml(yaml)
+ yaml_file = File.join(thor_root, "thor.yml")
+
+ unless File.exists?(yaml_file)
+ FileUtils.mkdir_p(thor_root)
+ yaml_file = File.join(thor_root, "thor.yml")
+ FileUtils.touch(yaml_file)
+ end
+
+ File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
+ end
+
+ # Load the thorfiles. If relevant_to is supplied, looks for specific files
+ # in the thor_root instead of loading them all.
+ #
+ # By default, it also traverses the current path until find Thor files, as
+ # described in thorfiles. This look up can be skipped by suppliying
+ # skip_lookup true.
+ #
+ def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
+ thorfiles(relevant_to, skip_lookup).each do |f|
+ Thor::Util.load_thorfile(f) unless Thor::Base.subclass_files.keys.include?(File.expand_path(f))
+ end
+ end
+
+ # Finds Thorfiles by traversing from your current directory down to the root
+ # directory of your system. If at any time we find a Thor file, we stop.
+ #
+ # We also ensure that system-wide Thorfiles are loaded first, so local
+ # Thorfiles can override them.
+ #
+ # ==== Example
+ #
+ # If we start at /Users/wycats/dev/thor ...
+ #
+ # 1. /Users/wycats/dev/thor
+ # 2. /Users/wycats/dev
+ # 3. /Users/wycats <-- we find a Thorfile here, so we stop
+ #
+ # Suppose we start at c:\Documents and Settings\james\dev\thor ...
+ #
+ # 1. c:\Documents and Settings\james\dev\thor
+ # 2. c:\Documents and Settings\james\dev
+ # 3. c:\Documents and Settings\james
+ # 4. c:\Documents and Settings
+ # 5. c:\ <-- no Thorfiles found!
+ #
+ def thorfiles(relevant_to=nil, skip_lookup=false)
+ # Deal with deprecated thor when :namespaces: is available as constants
+ save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml)
+
+ thorfiles = []
+
+ unless skip_lookup
+ Pathname.pwd.ascend do |path|
+ thorfiles = Thor::Util.globs_for(path).map { |g| Dir[g] }.flatten
+ break unless thorfiles.empty?
+ end
+ end
+
+ files = (relevant_to ? thorfiles_relevant_to(relevant_to) : Thor::Util.thor_root_glob)
+ files += thorfiles
+ files -= ["#{thor_root}/thor.yml"]
+
+ files.map! do |file|
+ File.directory?(file) ? File.join(file, "main.thor") : file
+ end
+ end
+
+ # Load thorfiles relevant to the given method. If you provide "foo:bar" it
+ # will load all thor files in the thor.yaml that has "foo" e "foo:bar"
+ # namespaces registered.
+ #
+ def thorfiles_relevant_to(meth)
+ lookup = [ meth, meth.split(":")[0...-1].join(":") ]
+
+ files = thor_yaml.select do |k, v|
+ v[:namespaces] && !(v[:namespaces] & lookup).empty?
+ end
+
+ files.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
+ end
+
+ # Display information about the given klasses. If with_module is given,
+ # it shows a table with information extracted from the yaml file.
+ #
+ def display_klasses(with_modules=false, klasses=Thor.subclasses)
+ klasses -= [Thor, Thor::Runner] unless with_modules
+ raise Error, "No Thor tasks available" if klasses.empty?
+
+ if with_modules && !thor_yaml.empty?
+ info = []
+ labels = ["Modules", "Namespaces"]
+
+ info << labels
+ info << [ "-" * labels[0].size, "-" * labels[1].size ]
+
+ thor_yaml.each do |name, hash|
+ info << [ name, hash[:namespaces].join(", ") ]
+ end
+
+ print_table info
+ say ""
+ end
+
+ unless klasses.empty?
+ klasses.each { |k| display_tasks(k) }
+ else
+ say "\033[1;34mNo Thor tasks available\033[0m"
+ end
+ end
+
+ # Display tasks from the given Thor class.
+ #
+ def display_tasks(klass)
+ unless klass.tasks.empty?
+ base = klass.namespace
+
+ color = base == "default" ? :magenta : :blue
+ say shell.set_color(base, color, true)
+ say "-" * base.length
+
+ klass.help(shell, :short => true, :namespace => true)
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb
new file mode 100644
index 0000000000..7ed4a24bfb
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/shell.rb
@@ -0,0 +1,72 @@
+require 'thor/shell/color'
+
+class Thor
+ module Base
+ # Returns the shell used in all Thor classes. Default to color one.
+ #
+ def self.shell
+ @shell ||= Thor::Shell::Color
+ end
+
+ # Sets the shell used in all Thor classes.
+ #
+ def self.shell=(klass)
+ @shell = klass
+ end
+ end
+
+ module Shell
+ SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_list, :print_table]
+
+ # Add shell to initialize config values.
+ #
+ # ==== Configuration
+ # shell<Object>:: An instance of the shell to be used.
+ #
+ # ==== Examples
+ #
+ # class MyScript < Thor
+ # argument :first, :type => :numeric
+ # end
+ #
+ # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new
+ #
+ def initialize(args=[], options={}, config={})
+ super
+ self.shell = config[:shell]
+ self.shell.base ||= self if self.shell.respond_to?(:base)
+ end
+
+ # Holds the shell for the given Thor instance. If no shell is given,
+ # it gets a default shell from Thor::Base.shell.
+ #
+ def shell
+ @shell ||= Thor::Base.shell.new
+ end
+
+ # Sets the shell for this thor class.
+ #
+ def shell=(shell)
+ @shell = shell
+ end
+
+ # Common methods that are delegated to the shell.
+ #
+ SHELL_DELEGATED_METHODS.each do |method|
+ module_eval <<-METHOD, __FILE__, __LINE__
+ def #{method}(*args)
+ shell.#{method}(*args)
+ end
+ METHOD
+ end
+
+ protected
+
+ # Allow shell to be shared between invocations.
+ #
+ def _shared_configuration
+ super.merge!(:shell => self.shell)
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb
new file mode 100644
index 0000000000..e294c87567
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/shell/basic.rb
@@ -0,0 +1,216 @@
+require 'tempfile'
+
+class Thor
+ module Shell
+ class Basic
+ attr_accessor :base, :padding
+
+ # Initialize base and padding to nil.
+ #
+ def initialize #:nodoc:
+ @base, @padding = nil, 0
+ end
+
+ # Do not allow padding to be less than zero.
+ #
+ def padding=(value) #:nodoc:
+ @padding = [0, value].max
+ end
+
+ # Ask something to the user and receives a response.
+ #
+ # ==== Example
+ # ask("What is your name?")
+ #
+ def ask(statement, color=nil)
+ say("#{statement} ", color)
+ $stdin.gets.strip
+ end
+
+ # Say (print) something to the user. If the sentence ends with a whitespace
+ # or tab character, a new line is not appended (print + flush). Otherwise
+ # are passed straight to puts (behavior got from Highline).
+ #
+ # ==== Example
+ # say("I know you knew that.")
+ #
+ def say(message="", color=nil, force_new_line=false)
+ message = message.to_s
+ new_line = force_new_line || !(message[-1, 1] == " " || message[-1, 1] == "\t")
+ message = set_color(message, color) if color
+
+ if new_line
+ $stdout.puts(message)
+ else
+ $stdout.print(message)
+ $stdout.flush
+ end
+ end
+
+ # Say a status with the given color and appends the message. Since this
+ # method is used frequently by actions, it allows nil or false to be given
+ # in log_status, avoiding the message from being shown. If a Symbol is
+ # given in log_status, it's used as the color.
+ #
+ def say_status(status, message, log_status=true) #:nodoc:
+ return if quiet? || log_status == false
+ spaces = " " * (padding + 1)
+ color = log_status.is_a?(Symbol) ? log_status : :green
+
+ status = status.to_s.rjust(12)
+ status = set_color status, color, true if color
+ say "#{status}#{spaces}#{message}", nil, true
+ end
+
+ # Make a question the to user and returns true if the user replies "y" or
+ # "yes".
+ #
+ def yes?(statement, color=nil)
+ ask(statement, color) =~ is?(:yes)
+ end
+
+ # Make a question the to user and returns true if the user replies "n" or
+ # "no".
+ #
+ def no?(statement, color=nil)
+ !yes?(statement, color)
+ end
+
+ # Prints a list of items.
+ #
+ # ==== Parameters
+ # list<Array[String, String, ...]>
+ # mode<Symbol>:: Can be :rows or :inline. Defaults to :rows.
+ #
+ def print_list(list, mode=:rows)
+ return if list.empty?
+
+ content = case mode
+ when :inline
+ last = list.pop
+ "#{list.join(", ")}, and #{last}"
+ else # rows
+ list.join("\n")
+ end
+
+ $stdout.puts content
+ end
+
+ # Prints a table.
+ #
+ # ==== Parameters
+ # Array[Array[String, String, ...]]
+ #
+ # ==== Options
+ # ident<Integer>:: Ident the first column by ident value.
+ # emphasize_last<Boolean>:: When true, add a different behavior to the last column.
+ #
+ def print_table(table, options={})
+ return if table.empty?
+
+ formats = []
+ 0.upto(table.first.length - 2) do |i|
+ maxima = table.max{ |a,b| a[i].size <=> b[i].size }[i].size
+ formats << "%-#{maxima + 2}s"
+ end
+
+ formats[0] = formats[0].insert(0, " " * options[:ident]) if options[:ident]
+ formats << "%s"
+
+ table.each do |row|
+ row.each_with_index do |column, i|
+ $stdout.print formats[i] % column.to_s
+ end
+ $stdout.puts
+ end
+ end
+
+ # Deals with file collision and returns true if the file should be
+ # overwriten and false otherwise. If a block is given, it uses the block
+ # response as the content for the diff.
+ #
+ # ==== Parameters
+ # destination<String>:: the destination file to solve conflicts
+ # block<Proc>:: an optional proc that returns the value to be used in diff
+ #
+ def file_collision(destination)
+ return true if @always_force
+ options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
+
+ while true
+ answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
+
+ case answer
+ when is?(:yes), is?(:force)
+ return true
+ when is?(:no), is?(:skip)
+ return false
+ when is?(:always)
+ return @always_force = true
+ when is?(:quit)
+ say 'Aborting...'
+ raise SystemExit
+ when is?(:diff)
+ show_diff(destination, yield) if block_given?
+ say 'Retrying...'
+ else
+ say file_collision_help
+ end
+ end
+ end
+
+ # Called if something goes wrong during the execution. This is used by Thor
+ # internally and should not be used inside your scripts. If someone went
+ # wrong, you can always raise an exception. If you raise a Thor::Error, it
+ # will be rescued and wrapped in the method below.
+ #
+ def error(statement) #:nodoc:
+ $stderr.puts statement
+ end
+
+ # Apply color to the given string with optional bold.
+ #
+ def set_color(string, color, bold=false)
+ string
+ end
+
+ protected
+
+ def is?(value)
+ value = value.to_s
+
+ if value.size == 1
+ /\A#{value}\z/i
+ else
+ /\A(#{value}|#{value[0,1]})\z/i
+ end
+ end
+
+ def file_collision_help
+<<HELP
+Y - yes, overwrite
+n - no, do not overwrite
+a - all, overwrite this and all others
+q - quit, abort
+d - diff, show the differences between the old and the new
+h - help, show this help
+HELP
+ end
+
+ def show_diff(destination, content)
+ diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u'
+
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
+ temp.write content
+ temp.rewind
+ say `#{diff_cmd} "#{destination}" "#{temp.path}"`
+ end
+ end
+
+ def quiet?
+ base && base.options[:quiet]
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb
new file mode 100644
index 0000000000..be7995146a
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/shell/color.rb
@@ -0,0 +1,106 @@
+require 'thor/shell/basic'
+
+class Thor
+ module Shell
+ # Set color in the output. Got color values from HighLine.
+ #
+ class Color < Basic
+ # Embed in a String to clear all previous ANSI sequences.
+ CLEAR = "\e[0m"
+ # The start of an ANSI bold sequence.
+ BOLD = "\e[1m"
+
+ # Set the terminal's foreground ANSI color to black.
+ BLACK = "\e[30m"
+ # Set the terminal's foreground ANSI color to red.
+ RED = "\e[31m"
+ # Set the terminal's foreground ANSI color to green.
+ GREEN = "\e[32m"
+ # Set the terminal's foreground ANSI color to yellow.
+ YELLOW = "\e[33m"
+ # Set the terminal's foreground ANSI color to blue.
+ BLUE = "\e[34m"
+ # Set the terminal's foreground ANSI color to magenta.
+ MAGENTA = "\e[35m"
+ # Set the terminal's foreground ANSI color to cyan.
+ CYAN = "\e[36m"
+ # Set the terminal's foreground ANSI color to white.
+ WHITE = "\e[37m"
+
+ # Set the terminal's background ANSI color to black.
+ ON_BLACK = "\e[40m"
+ # Set the terminal's background ANSI color to red.
+ ON_RED = "\e[41m"
+ # Set the terminal's background ANSI color to green.
+ ON_GREEN = "\e[42m"
+ # Set the terminal's background ANSI color to yellow.
+ ON_YELLOW = "\e[43m"
+ # Set the terminal's background ANSI color to blue.
+ ON_BLUE = "\e[44m"
+ # Set the terminal's background ANSI color to magenta.
+ ON_MAGENTA = "\e[45m"
+ # Set the terminal's background ANSI color to cyan.
+ ON_CYAN = "\e[46m"
+ # Set the terminal's background ANSI color to white.
+ ON_WHITE = "\e[47m"
+
+ # Set color by using a string or one of the defined constants. Based
+ # on Highline implementation. CLEAR is automatically be embedded to
+ # the end of the returned String.
+ #
+ def set_color(string, color, bold=false)
+ color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
+ bold = bold ? BOLD : ""
+ "#{bold}#{color}#{string}#{CLEAR}"
+ end
+
+ protected
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content)
+ if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
+ actual = File.read(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff)
+ case diff.action
+ when '-'
+ say "- #{diff.old_element.chomp}", :red, true
+ when '+'
+ say "+ #{diff.new_element.chomp}", :green, true
+ when '!'
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded?
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require 'diff/lcs'
+ true
+ rescue LoadError
+ false
+ end
+ end
+
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/task.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/task.rb
new file mode 100644
index 0000000000..92c0776c04
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/task.rb
@@ -0,0 +1,108 @@
+class Thor
+ class Task < Struct.new(:name, :description, :usage, :options)
+
+ # Creates a dynamic task. Dynamic tasks are created on demand to allow method
+ # missing calls (since a method missing does not have a task object for it).
+ #
+ def self.dynamic(name)
+ new(name, "A dynamically-generated task", name.to_s)
+ end
+
+ def initialize(name, description, usage, options=nil)
+ super(name.to_s, description, usage, options || {})
+ end
+
+ def initialize_copy(other)
+ super(other)
+ self.options = other.options.dup if other.options
+ end
+
+ def short_description
+ description.split("\n").first if description
+ end
+
+ # By default, a task invokes a method in the thor class. You can change this
+ # implementation to create custom tasks.
+ #
+ def run(instance, args=[])
+ raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance)
+ instance.send(name, *args)
+ rescue ArgumentError => e
+ parse_argument_error(instance, e, caller)
+ rescue NoMethodError => e
+ parse_no_method_error(instance, e)
+ end
+
+ # Returns the formatted usage. If a class is given, the class arguments are
+ # injected in the usage.
+ #
+ def formatted_usage(klass=nil, namespace=false)
+ formatted = ''
+ formatted << "#{klass.namespace.gsub(/^default/,'')}:" if klass && namespace
+ formatted << formatted_arguments(klass)
+ formatted << " #{formatted_options}"
+ formatted.strip!
+ formatted
+ end
+
+ # Injects the class arguments into the task usage.
+ #
+ def formatted_arguments(klass)
+ if klass && !klass.arguments.empty?
+ usage.to_s.gsub(/^#{name}/) do |match|
+ match << " " << klass.arguments.map{ |a| a.usage }.join(' ')
+ end
+ else
+ usage.to_s
+ end
+ end
+
+ # Returns the options usage for this task.
+ #
+ def formatted_options
+ @formatted_options ||= options.map{ |_, o| o.usage }.sort.join(" ")
+ end
+
+ protected
+
+ # Given a target, checks if this class name is not a private/protected method.
+ #
+ def public_method?(instance)
+ collection = instance.private_methods + instance.protected_methods
+ !(collection).include?(name.to_s) && !(collection).include?(name.to_sym) # For Ruby 1.9
+ end
+
+ # Clean everything that comes from the Thor gempath and remove the caller.
+ #
+ def sans_backtrace(backtrace, caller)
+ dirname = /^#{Regexp.escape(File.dirname(__FILE__))}/
+ saned = backtrace.reject { |frame| frame =~ dirname }
+ saned -= caller
+ end
+
+ def parse_argument_error(instance, e, caller)
+ backtrace = sans_backtrace(e.backtrace, caller)
+
+ if backtrace.empty? && e.message =~ /wrong number of arguments/
+ if instance.is_a?(Thor::Group)
+ raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?"
+ else
+ raise InvocationError, "'#{name}' was called incorrectly. Call as " <<
+ "'#{formatted_usage(instance.class, true)}'"
+ end
+ else
+ raise e
+ end
+ end
+
+ def parse_no_method_error(instance, e)
+ if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
+ raise UndefinedTaskError, "The #{instance.class.namespace} namespace " <<
+ "doesn't have a '#{name}' task"
+ else
+ raise e
+ end
+ end
+
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb
new file mode 100644
index 0000000000..d1a7b1c673
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks.rb
@@ -0,0 +1,4 @@
+# This only loads all tasks inside tasks.
+Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task|
+ require task
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb
new file mode 100644
index 0000000000..6b20ff1634
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/install.rb
@@ -0,0 +1,35 @@
+class Thor
+ # Creates an install task.
+ #
+ # ==== Parameters
+ # spec<Gem::Specification>
+ #
+ # ==== Options
+ # :dir - The directory where the package is hold before installation. Defaults to ./pkg.
+ #
+ def self.install_task(spec, options={})
+ package_task(spec, options)
+ tasks['install'] = Thor::InstallTask.new(spec, options)
+ end
+
+ class InstallTask < Task
+ attr_accessor :spec, :config
+
+ def initialize(gemspec, config={})
+ super(:install, "Install the gem", "install", {})
+ @spec = gemspec
+ @config = { :dir => File.join(Dir.pwd, "pkg") }.merge(config)
+ end
+
+ def run(instance, args=[])
+ null, sudo, gem = RUBY_PLATFORM =~ /mswin|mingw/ ? ['NUL', '', 'gem.bat'] :
+ ['/dev/null', 'sudo', 'gem']
+
+ old_stderr, $stderr = $stderr.dup, File.open(null, "w")
+ instance.invoke(:package)
+ $stderr = old_stderr
+
+ system %{#{sudo} #{Gem.ruby} -S #{gem} install #{config[:dir]}/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources}
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb
new file mode 100644
index 0000000000..603d61b4ab
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/package.rb
@@ -0,0 +1,31 @@
+require "fileutils"
+
+class Thor
+ # Creates a package task.
+ #
+ # ==== Parameters
+ # spec<Gem::Specification>
+ #
+ # ==== Options
+ # :dir - The package directory. Defaults to ./pkg.
+ #
+ def self.package_task(spec, options={})
+ tasks['package'] = Thor::PackageTask.new(spec, options)
+ end
+
+ class PackageTask < Task
+ attr_accessor :spec, :config
+
+ def initialize(gemspec, config={})
+ super(:package, "Build a gem package", "package", {})
+ @spec = gemspec
+ @config = {:dir => File.join(Dir.pwd, "pkg")}.merge(config)
+ end
+
+ def run(instance, args=[])
+ FileUtils.mkdir_p(config[:dir])
+ Gem::Builder.new(spec).build
+ FileUtils.mv(spec.file_name, File.join(config[:dir], spec.file_name))
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb
new file mode 100644
index 0000000000..c7d00968e8
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/tasks/spec.rb
@@ -0,0 +1,70 @@
+require "fileutils"
+
+class Thor
+ # Creates a spec task.
+ #
+ # ==== Parameters
+ # files<Array> - Array of files to spec
+ #
+ # ==== Options
+ # :name - The name of the task. It can be rcov or spec. Spec is the default.
+ # :rcov - A hash with rcov specific options.
+ # :rcov_dir - Where rcov reports should be printed.
+ # :verbose - Sets the default value for verbose, although it can be specified
+ # also through the command line.
+ #
+ # All other options are added to rspec.
+ #
+ def self.spec_task(files, options={})
+ name = (options.delete(:name) || 'spec').to_s
+ tasks[name] = Thor::SpecTask.new(name, files, options)
+ end
+
+ class SpecTask < Task
+ attr_accessor :name, :files, :rcov_dir, :rcov_config, :spec_config
+
+ def initialize(name, files, config={})
+ options = { :verbose => Thor::Option.parse(:verbose, config.delete(:verbose) || false) }
+ super(name, "#{name.capitalize} task", name, options)
+
+ @name = name
+ @files = files.map{ |f| %["#{f}"] }.join(" ")
+ @rcov_dir = config.delete(:rdoc_dir) || File.join(Dir.pwd, 'coverage')
+ @rcov_config = config.delete(:rcov) || {}
+ @spec_config = { :format => 'specdoc', :color => true }.merge(config)
+ end
+
+ def run(instance, args=[])
+ rcov_opts = Thor::Options.to_switches(rcov_config)
+ spec_opts = Thor::Options.to_switches(spec_config)
+
+ require 'rbconfig'
+ cmd = RbConfig::CONFIG['ruby_install_name'] << " "
+
+ if rcov?
+ FileUtils.rm_rf(rcov_dir)
+ cmd << "-S #{where('rcov')} -o #{rcov_dir} #{rcov_opts} "
+ end
+
+ cmd << [where('spec'), rcov? ? " -- " : nil, files, spec_opts].join(" ")
+
+ puts cmd if instance.options.verbose?
+ system(cmd)
+ exit($?.exitstatus)
+ end
+
+ private
+
+ def rcov?
+ name == "rcov"
+ end
+
+ def where(file)
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
+ file_with_path = File.join(path, file)
+ next unless File.exist?(file_with_path) && File.executable?(file_with_path)
+ return File.expand_path(file_with_path)
+ end
+ end
+ end
+end
diff --git a/railties/lib/vendor/thor-0.11.3/lib/thor/util.rb b/railties/lib/vendor/thor-0.11.3/lib/thor/util.rb
new file mode 100644
index 0000000000..26db24aadb
--- /dev/null
+++ b/railties/lib/vendor/thor-0.11.3/lib/thor/util.rb
@@ -0,0 +1,229 @@
+require 'rbconfig'
+
+class Thor
+ module Sandbox; end
+
+ # This module holds several utilities:
+ #
+ # 1) Methods to convert thor namespaces to constants and vice-versa.
+ #
+ # Thor::Utils.constant_to_namespace(Foo::Bar::Baz) #=> "foo:bar:baz"
+ # Thor::Utils.namespace_to_constant("foo:bar:baz") #=> Foo::Bar::Baz
+ #
+ # 2) Loading thor files and sandboxing:
+ #
+ # Thor::Utils.load_thorfile("~/.thor/foo")
+ #
+ module Util
+
+ # Receives a namespace and search for it in the Thor::Base subclasses.
+ #
+ # ==== Parameters
+ # namespace<String>:: The namespace to search for.
+ #
+ def self.find_by_namespace(namespace)
+ namespace = 'default' if namespace.empty?
+
+ Thor::Base.subclasses.find do |klass|
+ klass.namespace == namespace
+ end
+ end
+
+ # Receives a constant and converts it to a Thor namespace. Since Thor tasks
+ # can be added to a sandbox, this method is also responsable for removing
+ # the sandbox namespace.
+ #
+ # This method should not be used in general because it's used to deal with
+ # older versions of Thor. On current versions, if you need to get the
+ # namespace from a class, just call namespace on it.
+ #
+ # ==== Parameters
+ # constant<Object>:: The constant to be converted to the thor path.
+ #
+ # ==== Returns
+ # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
+ #
+ def self.constant_to_namespace(constant, remove_default=true)
+ constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
+ constant = snake_case(constant).squeeze(":")
+ constant.gsub!(/^default/, '') if remove_default
+ constant
+ end
+
+ # Given the contents, evaluate it inside the sandbox and returns the thor
+ # classes defined in the sandbox.
+ #
+ # ==== Parameters
+ # contents<String>
+ #
+ # ==== Returns
+ # Array[Object]
+ #
+ def self.namespaces_in_contents(contents, file=__FILE__)
+ old_constants = Thor::Base.subclasses.dup
+ Thor::Base.subclasses.clear
+
+ load_thorfile(file, contents)
+
+ new_constants = Thor::Base.subclasses.dup
+ Thor::Base.subclasses.replace(old_constants)
+
+ new_constants.map!{ |c| c.namespace }
+ new_constants.compact!
+ new_constants
+ end
+
+ # Receives a string and convert it to snake case. SnakeCase returns snake_case.
+ #
+ # ==== Parameters
+ # String
+ #
+ # ==== Returns
+ # String
+ #
+ def self.snake_case(str)
+ return str.downcase if str =~ /^[A-Z_]+$/
+ str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/
+ return $+.downcase
+ end
+
+ # Receives a namespace and tries to retrieve a Thor or Thor::Group class
+ # from it. It first searches for a class using the all the given namespace,
+ # if it's not found, removes the highest entry and searches for the class
+ # again. If found, returns the highest entry as the class name.
+ #
+ # ==== Examples
+ #
+ # class Foo::Bar < Thor
+ # def baz
+ # end
+ # end
+ #
+ # class Baz::Foo < Thor::Group
+ # end
+ #
+ # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task
+ # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
+ # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
+ #
+ # ==== Parameters
+ # namespace<String>
+ #
+ # ==== Errors
+ # Thor::Error:: raised if the namespace cannot be found.
+ #
+ # Thor::Error:: raised if the namespace evals to a class which does not
+ # inherit from Thor or Thor::Group.
+ #
+ def self.namespace_to_thor_class(namespace, raise_if_nil=true)
+ klass, task_name = Thor::Util.find_by_namespace(namespace), nil
+
+ if klass.nil? && namespace.include?(?:)
+ namespace = namespace.split(":")
+ task_name = namespace.pop
+ klass = Thor::Util.find_by_namespace(namespace.join(":"))
+ end
+
+ raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil?
+
+ return klass, task_name
+ end
+
+ # Receives a path and load the thor file in the path. The file is evaluated
+ # inside the sandbox to avoid namespacing conflicts.
+ #
+ def self.load_thorfile(path, content=nil)
+ content ||= File.read(path)
+
+ begin
+ Thor::Sandbox.class_eval(content, path)
+ rescue Exception => e
+ $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}"
+ end
+ end
+
+ # Receives a yaml (hash) and updates all constants entries to namespace.
+ # This was added to deal with deprecated versions of Thor.
+ #
+ # TODO Deprecate this method in the future.
+ #
+ # ==== Returns
+ # TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
+ #
+ def self.convert_constants_to_namespaces(yaml)
+ yaml_changed = false
+
+ yaml.each do |k, v|
+ next unless v[:constants] && v[:namespaces].nil?
+ yaml_changed = true
+ yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.constant_to_namespace(c)}
+ end
+
+ yaml_changed
+ end
+
+ def self.user_home
+ @@user_home ||= if ENV["HOME"]
+ ENV["HOME"]
+ elsif ENV["USERPROFILE"]
+ ENV["USERPROFILE"]
+ elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
+ File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
+ elsif ENV["APPDATA"]
+ ENV["APPDATA"]
+ else
+ begin
+ File.expand_path("~")
+ rescue
+ if File::ALT_SEPARATOR
+ "C:/"
+ else
+ "/"
+ end
+ end
+ end
+ end
+
+ # Returns the root where thor files are located, dependending on the OS.
+ #
+ def self.thor_root
+ File.join(user_home, ".thor")
+ end
+
+ # Returns the files in the thor root. On Windows thor_root will be something
+ # like this:
+ #
+ # C:\Documents and Settings\james\.thor
+ #
+ # If we don't #gsub the \ character, Dir.glob will fail.
+ #
+ def self.thor_root_glob
+ files = Dir["#{thor_root.gsub(/\\/, '/')}/*"]
+
+ files.map! do |file|
+ File.directory?(file) ? File.join(file, "main.thor") : file
+ end
+ end
+
+ # Where to look for Thor files.
+ #
+ def self.globs_for(path)
+ ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
+ end
+
+ # Return the path to the ruby interpreter taking into account multiple
+ # installations and windows extensions.
+ #
+ def self.ruby_command #:nodoc:
+ @ruby_command ||= begin
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
+ ruby << Config::CONFIG['EXEEXT']
+
+ # escape string in case path to ruby executable contain spaces.
+ ruby.sub!(/.*\s.*/m, '"\&"')
+ ruby
+ end
+ end
+
+ end
+end
diff --git a/railties/test/boot_test.rb b/railties/test/boot_test.rb
index 2dd68857c3..7bf420d4f2 100644
--- a/railties/test/boot_test.rb
+++ b/railties/test/boot_test.rb
@@ -1,6 +1,6 @@
require 'abstract_unit'
require 'initializer'
-require "#{File.dirname(__FILE__)}/../environments/boot"
+require "#{File.dirname(__FILE__)}/../lib/generators/rails/app/templates/config/boot"
require 'rails/gem_dependency'
class BootTest < Test::Unit::TestCase
diff --git a/railties/test/fixtures/lib/generators/active_record/fixjour/fixjour_generator.rb b/railties/test/fixtures/lib/generators/active_record/fixjour/fixjour_generator.rb
new file mode 100644
index 0000000000..7a4edb8bcb
--- /dev/null
+++ b/railties/test/fixtures/lib/generators/active_record/fixjour/fixjour_generator.rb
@@ -0,0 +1,8 @@
+require 'generators/active_record'
+
+module ActiveRecord
+ module Generators
+ class FixjourGenerator < Base
+ end
+ end
+end
diff --git a/railties/test/fixtures/lib/generators/fixjour_generator.rb b/railties/test/fixtures/lib/generators/fixjour_generator.rb
new file mode 100644
index 0000000000..ef3e9edbed
--- /dev/null
+++ b/railties/test/fixtures/lib/generators/fixjour_generator.rb
@@ -0,0 +1,2 @@
+class FixjourGenerator < Rails::Generators::NamedBase
+end
diff --git a/railties/test/fixtures/lib/generators/rails/javascripts_generator.rb b/railties/test/fixtures/lib/generators/rails/javascripts_generator.rb
new file mode 100644
index 0000000000..cad5e96784
--- /dev/null
+++ b/railties/test/fixtures/lib/generators/rails/javascripts_generator.rb
@@ -0,0 +1,4 @@
+module Rails::Generators
+ class JavascriptsGenerator < Rails::Generators::NamedBase
+ end
+end
diff --git a/railties/test/fixtures/lib/generators/working/working_generator.rb b/railties/test/fixtures/lib/generators/working/working_generator.rb
deleted file mode 100644
index 465b34319a..0000000000
--- a/railties/test/fixtures/lib/generators/working/working_generator.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class WorkingGenerator < Rails::Generator::NamedBase
-end
diff --git a/railties/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb b/railties/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb
deleted file mode 100644
index 8fda8197d1..0000000000
--- a/railties/test/fixtures/plugins/default/stubby/generators/stubby_generator/stubby_generator.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class StubbyGenerator < Rails::Generator::Base
- def manifest
- end
-end
diff --git a/railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb b/railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb
new file mode 100644
index 0000000000..191bdbf2fc
--- /dev/null
+++ b/railties/test/fixtures/vendor/gems/mspec/lib/generators/mspec_generator.rb
@@ -0,0 +1,2 @@
+class MspecGenerator < Rails::Generators::NamedBase
+end
diff --git a/railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb b/railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb
new file mode 100644
index 0000000000..6aa7cb052e
--- /dev/null
+++ b/railties/test/fixtures/vendor/gems/wrong/lib/generators/wrong_generator.rb
@@ -0,0 +1,3 @@
+# Old generator version
+class WrongGenerator < Rails::Generator::NamedBase
+end
diff --git a/railties/test/generator_lookup_test.rb b/railties/test/generator_lookup_test.rb
deleted file mode 100644
index b67087e5ea..0000000000
--- a/railties/test/generator_lookup_test.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'plugin_test_helper'
-
-class GeneratorLookupTest < Test::Unit::TestCase
- def setup
- @fixture_dirs = %w{alternate default}
- @configuration = Rails.configuration = Rails::Configuration.new
- # We need to add our testing plugin directory to the plugin paths so
- # the locator knows where to look for our plugins
- @configuration.plugin_paths += @fixture_dirs.map{|fd| plugin_fixture_path(fd)}
- @initializer = Rails::Initializer.default
- @initializer.config = @configuration
- @initializer.run(:add_plugin_load_paths)
- @initializer.run(:load_plugins)
- @initializer.run(:set_root_path)
- load 'rails_generator.rb'
- require 'rails_generator/scripts'
- end
-
- def test_should_load_from_all_plugin_paths
- assert Rails::Generator::Base.lookup('a_generator')
- assert Rails::Generator::Base.lookup('stubby_generator')
- end
-
- def test_should_create_generator_source_for_each_directory_in_plugin_paths
- sources = Rails::Generator::Base.sources
- @fixture_dirs.each do |gen_dir|
- expected_label = "plugins (fixtures/plugins/#{gen_dir})".to_sym
- assert sources.any? {|source| source.label == expected_label }
- end
- end
-
- def test_should_preserve_order_in_usage_message
- msg = Rails::Generator::Scripts::Base.new.send(:usage_message)
- positions = @fixture_dirs.map do |gen_dir|
- pos = msg.index("Plugins (fixtures/plugins/#{gen_dir})")
- assert_not_nil pos
- pos
- end
- assert_equal positions.sort, positions
- end
-
-end
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
new file mode 100644
index 0000000000..0cda49702b
--- /dev/null
+++ b/railties/test/generators/actions_test.rb
@@ -0,0 +1,177 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/app/app_generator'
+
+class ActionsTest < GeneratorsTestCase
+ def setup
+ super
+ @git_plugin_uri = 'git://github.com/technoweenie/restful-authentication.git'
+ @svn_plugin_uri = 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
+ end
+
+ def test_create_file_should_write_data_to_file_path
+ action :create_file, 'lib/test_file.rb', 'heres test data'
+ assert_file 'lib/test_file.rb', 'heres test data'
+ end
+
+ def test_create_file_should_write_block_contents_to_file_path
+ action(:create_file, 'lib/test_file.rb'){ 'heres block data' }
+ assert_file 'lib/test_file.rb', 'heres block data'
+ end
+
+ def test_plugin_with_git_option_should_run_plugin_install
+ generator.expects(:run_ruby_script).once.with("script/plugin install #{@git_plugin_uri}", :verbose => false)
+ action :plugin, 'restful-authentication', :git => @git_plugin_uri
+ end
+
+ def test_plugin_with_svn_option_should_run_plugin_install
+ generator.expects(:run_ruby_script).once.with("script/plugin install #{@svn_plugin_uri}", :verbose => false)
+ action :plugin, 'restful-authentication', :svn => @svn_plugin_uri
+ end
+
+ def test_plugin_with_git_option_and_submodule_should_use_git_scm
+ generator.expects(:run).with("git submodule add #{@git_plugin_uri} vendor/plugins/rest_auth", :verbose => false)
+ action :plugin, 'rest_auth', :git => @git_plugin_uri, :submodule => true
+ end
+
+ def test_plugin_with_no_options_should_skip_method
+ generator.expects(:run).never
+ action :plugin, 'rest_auth', {}
+ end
+
+ def test_gem_should_put_gem_dependency_in_enviroment
+ run_generator
+ action :gem, 'will-paginate'
+ assert_file 'config/environment.rb', /config\.gem 'will\-paginate'/
+ end
+
+ def test_gem_with_options_should_include_options_in_gem_dependency_in_environment
+ run_generator
+ action :gem, 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com'
+
+ regexp = /#{Regexp.escape("config.gem 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com'")}/
+ assert_file 'config/environment.rb', regexp
+ end
+
+ def test_gem_with_env_string_should_put_gem_dependency_in_specified_environment
+ run_generator
+ action :gem, 'rspec', :env => 'test'
+ assert_file 'config/environments/test.rb', /config\.gem 'rspec'/
+ end
+
+ def test_gem_with_env_array_should_put_gem_dependency_in_specified_environments
+ run_generator
+ action :gem, 'quietbacktrace', :env => %w[ development test ]
+ assert_file 'config/environments/development.rb', /config\.gem 'quietbacktrace'/
+ assert_file 'config/environments/test.rb', /config\.gem 'quietbacktrace'/
+ end
+
+ def test_gem_with_lib_option_set_to_false_should_put_gem_dependency_in_enviroment_correctly
+ run_generator
+ action :gem, 'mislav-will-paginate', :lib => false
+ assert_file 'config/environment.rb', /config\.gem 'mislav\-will\-paginate'\, :lib => false/
+ end
+
+ def test_environment_should_include_data_in_environment_initializer_block
+ run_generator
+ load_paths = 'config.load_paths += %w["#{RAILS_ROOT}/app/extras"]'
+ action :environment, load_paths
+ assert_file 'config/environment.rb', /#{Regexp.escape(load_paths)}/
+ end
+
+ def test_environment_with_block_should_include_block_contents_in_environment_initializer_block
+ run_generator
+
+ action :environment do
+ '# This wont be added'
+ '# This will be added'
+ end
+
+ assert_file 'config/environment.rb' do |content|
+ assert_match /# This will be added/, content
+ assert_no_match /# This wont be added/, content
+ end
+ end
+
+ def test_git_with_symbol_should_run_command_using_git_scm
+ generator.expects(:run).once.with('git init')
+ action :git, :init
+ end
+
+ def test_git_with_hash_should_run_each_command_using_git_scm
+ generator.expects(:run).times(2)
+ action :git, :rm => 'README', :add => '.'
+ end
+
+ def test_vendor_should_write_data_to_file_in_vendor
+ action :vendor, 'vendor_file.rb', '# vendor data'
+ assert_file 'vendor/vendor_file.rb', '# vendor data'
+ end
+
+ def test_lib_should_write_data_to_file_in_lib
+ action :lib, 'my_library.rb', 'class MyLibrary'
+ assert_file 'lib/my_library.rb', 'class MyLibrary'
+ end
+
+ def test_rakefile_should_write_date_to_file_in_lib_tasks
+ action :rakefile, 'myapp.rake', 'task :run => [:environment]'
+ assert_file 'lib/tasks/myapp.rake', 'task :run => [:environment]'
+ end
+
+ def test_initializer_should_write_date_to_file_in_config_initializers
+ action :initializer, 'constants.rb', 'MY_CONSTANT = 42'
+ assert_file 'config/initializers/constants.rb', 'MY_CONSTANT = 42'
+ end
+
+ def test_generate_should_run_script_generate_with_argument_and_options
+ generator.expects(:run_ruby_script).once.with('script/generate model MyModel', :verbose => false)
+ action :generate, 'model', 'MyModel'
+ end
+
+ def test_rake_should_run_rake_command_with_development_env
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=development', :verbose => false)
+ action :rake, 'log:clear'
+ end
+
+ def test_rake_with_env_option_should_run_rake_command_in_env
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ action :rake, 'log:clear', :env => 'production'
+ end
+
+ def test_rake_with_sudo_option_should_run_rake_command_with_sudo
+ generator.expects(:run).once.with('sudo rake log:clear RAILS_ENV=development', :verbose => false)
+ action :rake, 'log:clear', :sudo => true
+ end
+
+ def test_capify_should_run_the_capify_command
+ generator.expects(:run).once.with('capify .', :verbose => false)
+ action :capify!
+ end
+
+ def test_freeze_should_freeze_rails_edge
+ generator.expects(:run).once.with('rake rails:freeze:edge', :verbose => false)
+ action :freeze!
+ end
+
+ def test_route_should_add_data_to_the_routes_block_in_config_routes
+ run_generator
+ route_command = "map.route '/login', :controller => 'sessions', :action => 'new'"
+ action :route, route_command
+ assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/
+ end
+
+ protected
+
+ def run_generator
+ silence(:stdout) { Rails::Generators::AppGenerator.start [destination_root] }
+ end
+
+ def generator(config={})
+ @generator ||= Rails::Generators::Base.new([], {}, { :destination_root => destination_root }.merge!(config))
+ end
+
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
+ end
+
+end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
new file mode 100644
index 0000000000..c794a2ade6
--- /dev/null
+++ b/railties/test/generators/app_generator_test.rb
@@ -0,0 +1,182 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/app/app_generator'
+
+class AppGeneratorTest < GeneratorsTestCase
+
+ def setup
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ end
+
+ def teardown
+ super
+ Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ end
+
+ def test_application_skeleton_is_created
+ run_generator
+
+ %w(
+ app/controllers
+ app/helpers
+ app/models
+ app/views/layouts
+ config/environments
+ config/initializers
+ config/locales
+ db
+ doc
+ lib
+ lib/tasks
+ log
+ public/images
+ public/javascripts
+ public/stylesheets
+ script/performance
+ test/fixtures
+ test/functional
+ test/integration
+ test/performance
+ test/unit
+ vendor
+ vendor/plugins
+ tmp/sessions
+ tmp/sockets
+ tmp/cache
+ tmp/pids
+ ).each{ |path| assert_file path }
+ end
+
+ def test_invalid_database_option_raises_an_error
+ content = capture(:stderr){ run_generator(["-d", "unknown"]) }
+ assert_match /Invalid value for \-\-database option/, content
+ end
+
+ def test_dispatchers_are_not_added_by_default
+ run_generator
+ assert_no_file "config.ru"
+ assert_no_file "public/dispatch.cgi"
+ assert_no_file "public/dispatch.fcgi"
+ end
+
+ def test_dispatchers_are_added_if_required
+ run_generator ["--with-dispatchers"]
+ assert_file "config.ru"
+ assert_file "public/dispatch.cgi"
+ assert_file "public/dispatch.fcgi"
+ end
+
+ def test_config_database_is_added_by_default
+ run_generator
+ assert_file "config/database.yml", /sqlite3/
+ end
+
+ def test_config_database_is_not_added_if_skip_activerecord_is_given
+ run_generator ["--skip-activerecord"]
+ assert_no_file "config/database.yml"
+ end
+
+ def test_activerecord_is_removed_from_frameworks_if_skip_activerecord_is_given
+ run_generator ["--skip-activerecord"]
+ assert_file "config/environment.rb", /config\.frameworks \-= \[ :active_record \]/
+ end
+
+ def test_prototype_and_test_unit_are_added_by_default
+ run_generator
+ assert_file "public/javascripts/prototype.js"
+ assert_file "test"
+ end
+
+ def test_prototype_and_test_unit_are_skipped_if_required
+ run_generator ["--skip-prototype", "--skip-testunit"]
+ assert_no_file "public/javascripts/prototype.js"
+ assert_no_file "test"
+ end
+
+ def test_shebang_is_added_to_files
+ run_generator ["--ruby", "foo/bar/baz"]
+
+ %w(
+ about
+ console
+ dbconsole
+ destroy
+ generate
+ plugin
+ runner
+ server
+ ).each { |path| assert_file "script/#{path}", /#!foo\/bar\/baz/ }
+ end
+
+ def test_shebang_when_is_the_same_as_default_use_env
+ run_generator ["--ruby", Thor::Util.ruby_command]
+
+ %w(
+ about
+ console
+ dbconsole
+ destroy
+ generate
+ plugin
+ runner
+ server
+ ).each { |path| assert_file "script/#{path}", /#!\/usr\/bin\/env/ }
+ end
+
+ def test_rails_is_frozen
+ generator(:freeze => true, :database => "sqlite3").expects(:run).
+ with("rake rails:freeze:edge", :verbose => false)
+ silence(:stdout){ generator.invoke }
+ assert_file 'config/environment.rb', /# RAILS_GEM_VERSION/
+ end
+
+ def test_template_raises_an_error_with_invalid_path
+ content = capture(:stderr){ run_generator(["-m", "non/existant/path"]) }
+ assert_match /The template \[.*\] could not be loaded/, content
+ assert_match /non\/existant\/path/, content
+ end
+
+ def test_template_is_executed_when_supplied
+ path = "http://gist.github.com/103208.txt"
+ template = %{ say "It works!" }
+ template.instance_eval "def read; self; end" # Make the string respond to read
+
+ generator(:template => path, :database => "sqlite3").expects(:open).with(path).returns(template)
+ assert_match /It works!/, silence(:stdout){ generator.invoke }
+ end
+
+ def test_usage_read_from_file
+ File.expects(:read).returns("USAGE FROM FILE")
+ assert_equal "USAGE FROM FILE", Rails::Generators::AppGenerator.desc
+ end
+
+ def test_default_usage
+ File.expects(:exist?).returns(false)
+ assert_match /Create rails files for app generator/, Rails::Generators::AppGenerator.desc
+ end
+
+ def test_default_namespace
+ assert_match "rails:generators:app", Rails::Generators::AppGenerator.namespace
+ end
+
+ def test_file_is_added_for_backwards_compatibility
+ action :file, 'lib/test_file.rb', 'heres test data'
+ assert_file 'lib/test_file.rb', 'heres test data'
+ end
+
+ protected
+
+ def run_generator(args=[])
+ silence(:stdout) { Rails::Generators::AppGenerator.start [destination_root].concat(args) }
+ end
+
+ def generator(options={})
+ @generator ||= Rails::Generators::AppGenerator.new([destination_root], options, :destination_root => destination_root)
+ end
+
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
+ end
+
+end
diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb
new file mode 100644
index 0000000000..850b9e632d
--- /dev/null
+++ b/railties/test/generators/controller_generator_test.rb
@@ -0,0 +1,80 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/controller/controller_generator'
+
+class ControllerGeneratorTest < GeneratorsTestCase
+
+ def test_help_does_not_show_invoked_generators_options_if_they_already_exist
+ content = run_generator ["--help"]
+ assert_no_match /Helper options:/, content
+ end
+
+ def test_controller_skeleton_is_created
+ run_generator
+ assert_file "app/controllers/account_controller.rb", /class AccountController < ApplicationController/
+ end
+
+ def test_check_class_collision
+ Object.send :const_set, :ObjectController, Class.new
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'ObjectController' is either already used in your application or reserved/, content
+ ensure
+ Object.send :remove_const, :ObjectController
+ end
+
+ # No need to spec content since it's already spec'ed on helper generator.
+ #
+ def test_invokes_helper
+ run_generator
+ assert_file "app/helpers/account_helper.rb"
+ assert_file "test/unit/helpers/account_helper_test.rb"
+ end
+
+ def test_does_not_invoke_helper_if_required
+ run_generator ["account", "--skip-helper"]
+ assert_no_file "app/helpers/account_helper.rb"
+ assert_no_file "test/unit/helpers/account_helper_test.rb"
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "test/functional/account_controller_test.rb"
+ end
+
+ def test_does_not_invoke_test_framework_if_required
+ run_generator ["account", "--no-test-framework"]
+ assert_no_file "test/functional/account_controller_test.rb"
+ end
+
+ def test_invokes_default_template_engine
+ run_generator
+ assert_file "app/views/account/foo.html.erb", /app\/views\/account\/foo/
+ assert_file "app/views/account/bar.html.erb", /app\/views\/account\/bar/
+ end
+
+ def test_invokes_default_template_engine_even_with_no_action
+ run_generator ["account"]
+ assert_file "app/views/account"
+ end
+
+ def test_template_engine_with_class_path
+ run_generator ["admin/account"]
+ assert_file "app/views/admin/account"
+ end
+
+ def test_actions_are_turned_into_methods
+ run_generator
+
+ assert_file "app/controllers/account_controller.rb" do |controller|
+ assert_instance_method controller, :foo
+ assert_instance_method controller, :bar
+ end
+ end
+
+ protected
+
+ def run_generator(args=["Account", "foo", "bar"])
+ silence(:stdout) { Rails::Generators::ControllerGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/generator_generator_test.rb b/railties/test/generators/generator_generator_test.rb
new file mode 100644
index 0000000000..b1ebe5f1b5
--- /dev/null
+++ b/railties/test/generators/generator_generator_test.rb
@@ -0,0 +1,26 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/generator/generator_generator'
+
+class GeneratorGeneratorTest < GeneratorsTestCase
+
+ def test_generator_skeleton_is_created
+ run_generator
+
+ %w(
+ lib/generators/awesome
+ lib/generators/awesome/USAGE
+ lib/generators/awesome/templates
+ ).each{ |path| assert_file path }
+
+ assert_file "lib/generators/awesome/awesome_generator.rb",
+ /class AwesomeGenerator < Rails::Generators::NamedBase/
+ end
+
+ protected
+
+ def run_generator(args=["awesome"], config={})
+ silence(:stdout) { Rails::Generators::GeneratorGenerator.start args, config.merge(:destination_root => destination_root) }
+ end
+
+end
diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb
deleted file mode 100644
index 01bf1c90bd..0000000000
--- a/railties/test/generators/generator_test_helper.rb
+++ /dev/null
@@ -1,303 +0,0 @@
-require 'test/unit'
-require 'fileutils'
-
-# Mock out what we need from AR::Base
-module ActiveRecord
- class Base
- class << self
- attr_accessor :pluralize_table_names, :timestamped_migrations
- end
- self.pluralize_table_names = true
- self.timestamped_migrations = true
- end
-
- module ConnectionAdapters
- class Column
- attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
-
- def initialize(name, default, sql_type = nil)
- @name = name
- @default = default
- @type = @sql_type = sql_type
- end
-
- def human_name
- @name.humanize
- end
- end
- end
-end
-
-# Mock up necessities from ActionView
-module ActionView
- module Helpers
- module ActionRecordHelper; end
- class InstanceTag; end
- end
-end
-
-# Set RAILS_ROOT appropriately fixture generation
-tmp_dir = "#{File.dirname(__FILE__)}/../fixtures/tmp"
-
-if defined? RAILS_ROOT
- RAILS_ROOT.replace tmp_dir
-else
- RAILS_ROOT = tmp_dir
-end
-FileUtils.mkdir_p RAILS_ROOT
-
-$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
-require 'initializer'
-
-# Mocks out the configuration
-module Rails
- def self.configuration
- Rails::Configuration.new
- end
-end
-
-require 'rails_generator'
-
-class GeneratorTestCase < Test::Unit::TestCase
- include FileUtils
-
- def setup
- ActiveRecord::Base.pluralize_table_names = true
-
- mkdir_p "#{RAILS_ROOT}/app/views/layouts"
- mkdir_p "#{RAILS_ROOT}/config"
- mkdir_p "#{RAILS_ROOT}/db"
- mkdir_p "#{RAILS_ROOT}/test/fixtures"
- mkdir_p "#{RAILS_ROOT}/public/stylesheets"
-
- File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
- f << "ActionController::Routing::Routes.draw do |map|\n\nend"
- end
- end
-
- def teardown
- rm_rf "#{RAILS_ROOT}/app"
- rm_rf "#{RAILS_ROOT}/test"
- rm_rf "#{RAILS_ROOT}/config"
- rm_rf "#{RAILS_ROOT}/db"
- rm_rf "#{RAILS_ROOT}/public"
- end
-
- def test_truth
- # don't complain, test/unit
- end
-
- # Instantiates the Generator.
- def build_generator(name, params)
- Rails::Generator::Base.instance(name, params)
- end
-
- # Runs the +create+ command (like the command line does).
- def run_generator(name, params)
- silence_generator do
- build_generator(name, params).command(:create).invoke!
- end
- end
-
- # Silences the logger temporarily and returns the output as a String.
- def silence_generator
- logger_original = Rails::Generator::Base.logger
- myout = StringIO.new
- Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(myout)
- yield if block_given?
- Rails::Generator::Base.logger = logger_original
- myout.string
- end
-
- # Asserts that the given controller was generated.
- # It takes a name or symbol without the <tt>_controller</tt> part and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_controller_for(name, parent = "ApplicationController")
- assert_generated_class "app/controllers/#{name.to_s.underscore}_controller", parent do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given model was generated.
- # It takes a name or symbol and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_model_for(name, parent = "ActiveRecord::Base")
- assert_generated_class "app/models/#{name.to_s.underscore}", parent do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given helper was generated.
- # It takes a name or symbol without the <tt>_helper</tt> part.
- # The contents of the module source file is passed to a block.
- def assert_generated_helper_for(name)
- assert_generated_module "app/helpers/#{name.to_s.underscore}_helper" do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given functional test was generated.
- # It takes a name or symbol without the <tt>_controller_test</tt> part and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_functional_test_for(name, parent = "ActionController::TestCase")
- assert_generated_class "test/functional/#{name.to_s.underscore}_controller_test",parent do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given helper test test was generated.
- # It takes a name or symbol without the <tt>_helper_test</tt> part and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_helper_test_for(name, parent = "ActionView::TestCase")
- path = "test/unit/helpers/#{name.to_s.underscore}_helper_test"
- # Have to pass the path without the "test/" part so that class_name_from_path will return a correct result
- class_name = class_name_from_path(path.gsub(/^test\//, ''))
-
- assert_generated_class path,parent,class_name do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given unit test was generated.
- # It takes a name or symbol without the <tt>_test</tt> part and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_unit_test_for(name, parent = "ActiveSupport::TestCase")
- assert_generated_class "test/unit/#{name.to_s.underscore}_test", parent do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given file was generated.
- # The contents of the file is passed to a block.
- def assert_generated_file(path)
- assert_file_exists(path)
- File.open("#{RAILS_ROOT}/#{path}") do |f|
- yield f.read if block_given?
- end
- end
-
- # asserts that the given file exists
- def assert_file_exists(path)
- assert File.exist?("#{RAILS_ROOT}/#{path}"),
- "The file '#{RAILS_ROOT}/#{path}' should exist"
- end
-
- # Asserts that the given class source file was generated.
- # It takes a path without the <tt>.rb</tt> part and an optional super class.
- # The contents of the class source file is passed to a block.
- def assert_generated_class(path, parent = nil, class_name = class_name_from_path(path))
- assert_generated_file("#{path}.rb") do |body|
- assert_match /class #{class_name}#{parent.nil? ? '':" < #{parent}"}/, body, "the file '#{path}.rb' should be a class"
- yield body if block_given?
- end
- end
-
- def class_name_from_path(path)
- # FIXME: Sucky way to detect namespaced classes
- if path.split('/').size > 3
- path =~ /\/?(\d+_)?(\w+)\/(\w+)$/
- "#{$2.camelize}::#{$3.camelize}"
- else
- path =~ /\/?(\d+_)?(\w+)$/
- $2.camelize
- end
- end
-
- # Asserts that the given module source file was generated.
- # It takes a path without the <tt>.rb</tt> part.
- # The contents of the class source file is passed to a block.
- def assert_generated_module(path)
- # FIXME: Sucky way to detect namespaced modules
- if path.split('/').size > 3
- path =~ /\/?(\w+)\/(\w+)$/
- module_name = "#{$1.camelize}::#{$2.camelize}"
- else
- path =~ /\/?(\w+)$/
- module_name = $1.camelize
- end
-
- assert_generated_file("#{path}.rb") do |body|
- assert_match /module #{module_name}/, body, "the file '#{path}.rb' should be a module"
- yield body if block_given?
- end
- end
-
- # Asserts that the given CSS stylesheet file was generated.
- # It takes a path without the <tt>.css</tt> part.
- # The contents of the stylesheet source file is passed to a block.
- def assert_generated_stylesheet(path)
- assert_generated_file("public/stylesheets/#{path}.css") do |body|
- yield body if block_given?
- end
- end
-
- # Asserts that the given YAML file was generated.
- # It takes a path without the <tt>.yml</tt> part.
- # The parsed YAML tree is passed to a block.
- def assert_generated_yaml(path)
- assert_generated_file("#{path}.yml") do |body|
- yaml = YAML.load(body)
- assert yaml, 'YAML data missing'
- yield yaml if block_given?
- end
- end
-
- # Asserts that the given fixtures YAML file was generated.
- # It takes a fixture name without the <tt>.yml</tt> part.
- # The parsed YAML tree is passed to a block.
- def assert_generated_fixtures_for(name)
- assert_generated_yaml "test/fixtures/#{name.to_s.underscore}" do |yaml|
- yield yaml if block_given?
- end
- end
-
- # Asserts that the given views were generated.
- # It takes a controller name and a list of views (including extensions).
- # The body of each view is passed to a block.
- def assert_generated_views_for(name, *actions)
- actions.each do |action|
- assert_generated_file("app/views/#{name.to_s.underscore}/#{action}") do |body|
- yield body if block_given?
- end
- end
- end
-
- def assert_generated_migration(name, parent = "ActiveRecord::Migration")
- file = Dir.glob("#{RAILS_ROOT}/db/migrate/*_#{name.to_s.underscore}.rb").first
- file = file.match(/db\/migrate\/[0-9]+_\w+/).to_s
- assert_generated_class file, parent do |body|
- assert_match /timestamps/, body, "should have timestamps defined"
- yield body if block_given?
- end
- end
-
- # Asserts that the given migration file was not generated.
- # It takes the name of the migration as a parameter.
- def assert_skipped_migration(name)
- migration_file = "#{RAILS_ROOT}/db/migrate/001_#{name.to_s.underscore}.rb"
- assert !File.exist?(migration_file), "should not create migration #{migration_file}"
- end
-
- # Asserts that the given resource was added to the routes.
- def assert_added_route_for(name)
- assert_generated_file("config/routes.rb") do |body|
- assert_match /map.resources :#{name.to_s.underscore}/, body,
- "should add route for :#{name.to_s.underscore}"
- end
- end
-
- # Asserts that the given methods are defined in the body.
- # This does assume standard rails code conventions with regards to the source code.
- # The body of each individual method is passed to a block.
- def assert_has_method(body, *methods)
- methods.each do |name|
- assert body =~ /^ def #{name}(\(.+\))?\n((\n| .*\n)*) end/, "should have method #{name}"
- yield(name, $2) if block_given?
- end
- end
-
- # Asserts that the given column is defined in the migration.
- def assert_generated_column(body, name, type)
- assert_match /t\.#{type.to_s} :#{name.to_s}/, body, "should have column #{name.to_s} defined"
- end
-end
diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb
new file mode 100644
index 0000000000..011bd518f8
--- /dev/null
+++ b/railties/test/generators/generators_test_helper.rb
@@ -0,0 +1,101 @@
+require 'test/unit'
+require 'fileutils'
+
+fixtures = File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures'))
+if defined?(RAILS_ROOT)
+ RAILS_ROOT.replace fixtures
+else
+ RAILS_ROOT = fixtures
+end
+
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../activerecord/lib"
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../lib"
+require 'generators'
+
+CURRENT_PATH = File.expand_path(Dir.pwd)
+Rails::Generators.no_color!
+
+class GeneratorsTestCase < Test::Unit::TestCase
+ include FileUtils
+
+ def destination_root
+ @destination_root ||= File.expand_path(File.join(File.dirname(__FILE__),
+ '..', '..', 'fixtures', 'tmp'))
+ end
+
+ def setup
+ cd CURRENT_PATH
+ rm_rf(destination_root)
+ mkdir_p(destination_root)
+ end
+
+ def test_truth
+ # don't complain, test/unit
+ end
+
+ def capture(stream)
+ begin
+ stream = stream.to_s
+ eval "$#{stream} = StringIO.new"
+ yield
+ result = eval("$#{stream}").string
+ ensure
+ eval("$#{stream} = #{stream.upcase}")
+ end
+
+ result
+ end
+ alias :silence :capture
+
+ def assert_file(relative, *contents)
+ absolute = File.join(destination_root, relative)
+ assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not"
+
+ read = File.read(absolute) if block_given? || !contents.empty?
+ yield read if block_given?
+
+ contents.each do |content|
+ case content
+ when String
+ assert_equal content, read
+ when Regexp
+ assert_match content, read
+ end
+ end
+ end
+
+ def assert_no_file(relative)
+ absolute = File.join(destination_root, relative)
+ assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does"
+ end
+
+ def assert_migration(relative, *contents, &block)
+ file_name = migration_file_name(relative)
+ assert file_name, "Expected migration #{relative} to exist, but was not found"
+ assert_file File.join(File.dirname(relative), file_name), *contents, &block
+ end
+
+ def assert_no_migration(relative)
+ file_name = migration_file_name(relative)
+ assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
+ end
+
+ def assert_class_method(content, method, &block)
+ assert_instance_method content, "self.#{method}", &block
+ end
+
+ def assert_instance_method(content, method)
+ assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}"
+ yield $2.strip if block_given?
+ end
+
+ protected
+
+ def migration_file_name(relative)
+ absolute = File.join(destination_root, relative)
+ dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '')
+
+ migration = Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
+ File.basename(migration) if migration
+ end
+end
diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb
new file mode 100644
index 0000000000..3d655016f1
--- /dev/null
+++ b/railties/test/generators/helper_generator_test.rb
@@ -0,0 +1,60 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/helper/helper_generator'
+
+ObjectHelper = Class.new
+AnotherObjectHelperTest = Class.new
+
+class HelperGeneratorTest < GeneratorsTestCase
+
+ def test_helper_skeleton_is_created
+ run_generator
+ assert_file "app/helpers/admin_helper.rb", /module AdminHelper/
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "test/unit/helpers/admin_helper_test.rb", /class AdminHelperTest < ActionView::TestCase/
+ end
+
+ def test_logs_if_the_test_framework_cannot_be_found
+ content = run_generator ["admin", "--test-framework=rspec"]
+ assert_match /rspec \[not found\]/, content
+ end
+
+ def test_check_class_collision
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'ObjectHelper' is either already used in your application or reserved/, content
+ end
+
+ def test_check_class_collision_on_tests
+ content = capture(:stderr){ run_generator ["another_object"] }
+ assert_match /The name 'AnotherObjectHelperTest' is either already used in your application or reserved/, content
+ end
+
+ def test_namespaced_and_not_namespaced_helpers
+ run_generator ["products"]
+
+ # We have to require the generated helper to show the problem because
+ # the test helpers just check for generated files and contents but
+ # do not actually load them. But they have to be loaded (as in a real environment)
+ # to make the second generator run fail
+ require "#{destination_root}/app/helpers/products_helper"
+
+ assert_nothing_raised do
+ begin
+ run_generator ["admin::products"]
+ ensure
+ # cleanup
+ Object.send(:remove_const, :ProductsHelper)
+ end
+ end
+ end
+
+ protected
+
+ def run_generator(args=["admin"])
+ silence(:stdout) { Rails::Generators::HelperGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/integration_test_generator_test.rb b/railties/test/generators/integration_test_generator_test.rb
new file mode 100644
index 0000000000..190b28012c
--- /dev/null
+++ b/railties/test/generators/integration_test_generator_test.rb
@@ -0,0 +1,18 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/integration_test/integration_test_generator'
+
+class IntegrationTestGeneratorTest < GeneratorsTestCase
+
+ def test_integration_test_skeleton_is_created
+ run_generator
+ assert_file "test/integration/integration_test.rb", /class IntegrationTest < ActionController::IntegrationTest/
+ end
+
+ protected
+
+ def run_generator(args=["integration"])
+ silence(:stdout) { Rails::Generators::IntegrationTestGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
new file mode 100644
index 0000000000..9e74859c3a
--- /dev/null
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -0,0 +1,52 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/mailer/mailer_generator'
+
+class MailerGeneratorTest < GeneratorsTestCase
+
+ def test_mailer_skeleton_is_created
+ run_generator
+ assert_file "app/models/notifier.rb", /class Notifier < ActionMailer::Base/
+ end
+
+ def test_check_class_collision
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'Object' is either already used in your application or reserved/, content
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "test/unit/notifier_test.rb", /class NotifierTest < ActionMailer::TestCase/
+ assert_file "test/fixtures/notifier/foo", /app\/views\/notifier\/foo/
+ assert_file "test/fixtures/notifier/bar", /app\/views\/notifier\/bar/
+ end
+
+ def test_invokes_default_template_engine
+ run_generator
+ assert_file "app/views/notifier/foo.erb", /app\/views\/notifier\/foo/
+ assert_file "app/views/notifier/bar.erb", /app\/views\/notifier\/bar/
+ end
+
+ def test_invokes_default_template_engine_even_with_no_action
+ run_generator ["notifier"]
+ assert_file "app/views/notifier"
+ end
+
+ def test_logs_if_the_template_engine_cannot_be_found
+ content = run_generator ["notifier", "foo", "bar", "--template-engine=haml"]
+ assert_match /haml \[not found\]/, content
+ end
+
+ def test_actions_are_turned_into_methods
+ run_generator
+ assert_file "app/models/notifier.rb", /def foo/
+ assert_file "app/models/notifier.rb", /def bar/
+ end
+
+ protected
+
+ def run_generator(args=["notifier", "foo", "bar"])
+ silence(:stdout) { Rails::Generators::MailerGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/metal_generator_test.rb b/railties/test/generators/metal_generator_test.rb
new file mode 100644
index 0000000000..97e892cefb
--- /dev/null
+++ b/railties/test/generators/metal_generator_test.rb
@@ -0,0 +1,23 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/metal/metal_generator'
+
+class MetalGeneratorTest < GeneratorsTestCase
+
+ def test_metal_skeleton_is_created
+ run_generator
+ assert_file "app/metal/foo.rb", /class Foo/
+ end
+
+ def test_check_class_collision
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'Object' is either already used in your application or reserved/, content
+ end
+
+ protected
+
+ def run_generator(args=["foo"])
+ silence(:stdout) { Rails::Generators::MetalGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
new file mode 100644
index 0000000000..a4335068e6
--- /dev/null
+++ b/railties/test/generators/migration_generator_test.rb
@@ -0,0 +1,59 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/migration/migration_generator'
+
+class MigrationGeneratorTest < GeneratorsTestCase
+
+ def test_migration
+ @migration = "change_title_body_from_posts"
+ run_generator
+ assert_migration "db/migrate/#{@migration}.rb", /class ChangeTitleBodyFromPosts < ActiveRecord::Migration/
+ end
+
+ def test_migration_with_class_name
+ @migration = "ChangeTitleBodyFromPosts"
+ run_generator
+ assert_migration "db/migrate/change_title_body_from_posts.rb", /class #{@migration} < ActiveRecord::Migration/
+ end
+
+ def test_add_migration_with_attributes
+ @migration = "add_title_body_to_posts"
+ run_generator [@migration, "title:string", "body:text"]
+
+ assert_migration "db/migrate/#{@migration}.rb" do |content|
+ assert_class_method content, :up do |up|
+ assert_match /add_column :posts, :title, :string/, up
+ assert_match /add_column :posts, :body, :text/, up
+ end
+
+ assert_class_method content, :down do |down|
+ assert_match /remove_column :posts, :title/, down
+ assert_match /remove_column :posts, :body/, down
+ end
+ end
+ end
+
+ def test_remove_migration_with_attributes
+ @migration = "remove_title_body_from_posts"
+ run_generator [@migration, "title:string", "body:text"]
+
+ assert_migration "db/migrate/#{@migration}.rb" do |content|
+ assert_class_method content, :up do |up|
+ assert_match /remove_column :posts, :title/, up
+ assert_match /remove_column :posts, :body/, up
+ end
+
+ assert_class_method content, :down do |down|
+ assert_match /add_column :posts, :title, :string/, down
+ assert_match /add_column :posts, :body, :text/, down
+ end
+ end
+ end
+
+ protected
+
+ def run_generator(args=[@migration])
+ silence(:stdout) { Rails::Generators::MigrationGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
new file mode 100644
index 0000000000..a9b772d67b
--- /dev/null
+++ b/railties/test/generators/model_generator_test.rb
@@ -0,0 +1,137 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/model/model_generator'
+
+class ModelGeneratorTest < GeneratorsTestCase
+
+ def test_help_shows_invoked_generators_options
+ content = run_generator ["--help"]
+ assert_match /ActiveRecord options:/, content
+ assert_match /TestUnit options:/, content
+ end
+
+ def test_invokes_default_orm
+ run_generator
+ assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/
+ end
+
+ def test_model_with_parent_option
+ run_generator ["account", "--parent", "Admin::Account"]
+ assert_file "app/models/account.rb", /class Account < Admin::Account/
+ assert_no_migration "db/migrate/create_accounts.rb"
+ end
+
+ def test_model_with_underscored_parent_option
+ run_generator ["account", "--parent", "admin/account"]
+ assert_file "app/models/account.rb", /class Account < Admin::Account/
+ end
+
+ def test_migration
+ run_generator
+ assert_migration "db/migrate/create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration/
+ end
+
+ def test_migration_is_skipped
+ run_generator ["account", "--no-migration"]
+ assert_no_migration "db/migrate/create_accounts.rb"
+ end
+
+ def test_migration_with_attributes
+ run_generator ["product", "name:string", "supplier_id:integer"]
+
+ assert_migration "db/migrate/create_products.rb" do |m|
+ assert_class_method m, :up do |up|
+ assert_match /create_table :products/, up
+ assert_match /t\.string :name/, up
+ assert_match /t\.integer :supplier_id/, up
+ end
+
+ assert_class_method m, :down do |down|
+ assert_match /drop_table :products/, down
+ end
+ end
+ end
+
+ def test_migration_without_timestamps
+ ActiveRecord::Base.timestamped_migrations = false
+ run_generator ["account"]
+ assert_file "db/migrate/001_create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration/
+
+ run_generator ["project"]
+ assert_file "db/migrate/002_create_projects.rb", /class CreateProjects < ActiveRecord::Migration/
+ ensure
+ ActiveRecord::Base.timestamped_migrations = true
+ end
+
+ def test_model_with_references_attribute_generates_belongs_to_associations
+ run_generator ["product", "name:string", "supplier_id:references"]
+ assert_file "app/models/product.rb", /belongs_to :supplier/
+ end
+
+ def test_model_with_belongs_to_attribute_generates_belongs_to_associations
+ run_generator ["product", "name:string", "supplier_id:belongs_to"]
+ assert_file "app/models/product.rb", /belongs_to :supplier/
+ end
+
+ def test_migration_with_timestamps
+ run_generator
+ assert_migration "db/migrate/create_accounts.rb", /t.timestamps/
+ end
+
+ def test_migration_timestamps_are_skipped
+ run_generator ["account", "--no-timestamps"]
+
+ assert_migration "db/migrate/create_accounts.rb" do |m|
+ assert_class_method m, :up do |up|
+ assert_no_match /t.timestamps/, up
+ end
+ end
+ end
+
+ def test_migration_already_exists_error_message
+ run_generator
+ error = capture(:stderr){ run_generator ["Account"], :behavior => :skip }
+ assert_match /Another migration is already named create_accounts/, error
+ end
+
+ def test_migration_error_is_not_shown_on_revoke
+ run_generator
+ error = capture(:stderr){ run_generator ["Account"], :behavior => :revoke }
+ assert_no_match /Another migration is already named create_accounts/, error
+ end
+
+ def test_migration_is_removed_on_revoke
+ run_generator
+ run_generator ["Account"], :behavior => :revoke
+ assert_no_migration "db/migrate/create_accounts.rb"
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "test/unit/account_test.rb", /class AccountTest < ActiveSupport::TestCase/
+ assert_file "test/fixtures/accounts.yml", /name: MyString/, /age: 1/
+ end
+
+ def test_fixture_is_skipped
+ run_generator ["account", "--skip-fixture"]
+ assert_no_file "test/fixtures/accounts.yml"
+ end
+
+ def test_fixture_is_skipped_if_fixture_replacement_is_given
+ content = run_generator ["account", "-r", "factory_girl"]
+ assert_match /factory_girl \[not found\]/, content
+ assert_no_file "test/fixtures/accounts.yml"
+ end
+
+ def test_check_class_collision
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'Object' is either already used in your application or reserved/, content
+ end
+
+ protected
+
+ def run_generator(args=["Account", "name:string", "age:integer"], config={})
+ silence(:stdout) { Rails::Generators::ModelGenerator.start args, config.merge(:destination_root => destination_root) }
+ end
+
+end
diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb
new file mode 100644
index 0000000000..3a5c58ab32
--- /dev/null
+++ b/railties/test/generators/named_base_test.rb
@@ -0,0 +1,42 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/scaffold_controller/scaffold_controller_generator'
+
+# Mock out what we need from AR::Base.
+module ActiveRecord
+ class Base
+ class << self
+ attr_accessor :pluralize_table_names
+ end
+ self.pluralize_table_names = true
+ end
+end
+
+class NamedBaseTest < GeneratorsTestCase
+
+ def test_named_generator_attributes
+ g = Rails::Generators::ScaffoldControllerGenerator.new ["admin/foo"]
+ assert_equal 'admin/foo', g.name
+ assert_equal %w(admin), g.class_path
+ assert_equal 1, g.class_nesting_depth
+ assert_equal 'Admin::Foo', g.class_name
+ assert_equal 'foo', g.singular_name
+ assert_equal 'foos', g.plural_name
+ assert_equal g.singular_name, g.file_name
+ assert_equal "admin_#{g.plural_name}", g.table_name
+ end
+
+ def test_named_generator_attributes_without_pluralized
+ ActiveRecord::Base.pluralize_table_names = false
+ g = Rails::Generators::ScaffoldControllerGenerator.new ["admin/foo"]
+ assert_equal "admin_#{g.singular_name}", g.table_name
+ end
+
+ def test_scaffold_plural_names
+ g = Rails::Generators::ScaffoldControllerGenerator.new ["ProductLine"]
+ assert_equal "ProductLines", g.controller_name
+ assert_equal "ProductLines", g.controller_class_name
+ assert_equal "product_lines", g.controller_file_name
+ end
+
+end
diff --git a/railties/test/generators/observer_generator_test.rb b/railties/test/generators/observer_generator_test.rb
new file mode 100644
index 0000000000..a556731e16
--- /dev/null
+++ b/railties/test/generators/observer_generator_test.rb
@@ -0,0 +1,33 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/observer/observer_generator'
+
+class ObserverGeneratorTest < GeneratorsTestCase
+
+ def test_invokes_default_orm
+ run_generator
+ assert_file "app/models/account_observer.rb", /class AccountObserver < ActiveRecord::Observer/
+ end
+
+ def test_invokes_default_orm_with_class_path
+ run_generator ["admin/account"]
+ assert_file "app/models/admin/account_observer.rb", /class Admin::AccountObserver < ActiveRecord::Observer/
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "test/unit/account_observer_test.rb", /class AccountObserverTest < ActiveSupport::TestCase/
+ end
+
+ def test_logs_if_the_test_framework_cannot_be_found
+ content = run_generator ["account", "--test-framework=rspec"]
+ assert_match /rspec \[not found\]/, content
+ end
+
+ protected
+
+ def run_generator(args=["account"])
+ silence(:stdout) { Rails::Generators::ObserverGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/performance_test_generator_test.rb b/railties/test/generators/performance_test_generator_test.rb
new file mode 100644
index 0000000000..74c9c20c4c
--- /dev/null
+++ b/railties/test/generators/performance_test_generator_test.rb
@@ -0,0 +1,18 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/performance_test/performance_test_generator'
+
+class PerformanceTestGeneratorTest < GeneratorsTestCase
+
+ def test_performance_test_skeleton_is_created
+ run_generator
+ assert_file "test/performance/performance_test.rb", /class PerformanceTest < ActionController::PerformanceTest/
+ end
+
+ protected
+
+ def run_generator(args=["performance"])
+ silence(:stdout) { Rails::Generators::PerformanceTestGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
new file mode 100644
index 0000000000..3982586bc3
--- /dev/null
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -0,0 +1,56 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/plugin/plugin_generator'
+
+class PluginGeneratorTest < GeneratorsTestCase
+
+ def test_plugin_skeleton_is_created
+ run_generator
+
+ %w(
+ vendor/plugins
+ vendor/plugins/plugin_fu
+ vendor/plugins/plugin_fu/lib
+ ).each{ |path| assert_file path }
+ end
+
+ def test_check_class_collision
+ content = capture(:stderr){ run_generator ["object"] }
+ assert_match /The name 'Object' is either already used in your application or reserved/, content
+ end
+
+ def test_invokes_default_test_framework
+ run_generator
+ assert_file "vendor/plugins/plugin_fu/test/plugin_fu_test.rb", /class PluginFuTest < ActiveSupport::TestCase/
+ assert_file "vendor/plugins/plugin_fu/test/test_helper.rb"
+ end
+
+ def test_logs_if_the_test_framework_cannot_be_found
+ content = run_generator ["plugin_fu", "--test-framework=rspec"]
+ assert_match /rspec \[not found\]/, content
+ end
+
+ def test_creates_tasks_if_required
+ run_generator ["plugin_fu", "--tasks"]
+ assert_file "vendor/plugins/plugin_fu/tasks/plugin_fu_tasks.rake"
+ end
+
+ def test_creates_generator_if_required
+ run_generator ["plugin_fu", "--generator"]
+ assert_file "vendor/plugins/plugin_fu/lib/generators/templates"
+ assert_file "vendor/plugins/plugin_fu/lib/generators/plugin_fu_generator.rb",
+ /class PluginFuGenerator < Rails::Generators::NamedBase/
+ end
+
+ def test_plugin_generator_on_revoke
+ run_generator
+ run_generator ["plugin_fu"], :behavior => :revoke
+ end
+
+ protected
+
+ def run_generator(args=["plugin_fu"], config={})
+ silence(:stdout) { Rails::Generators::PluginGenerator.start args, config.merge(:destination_root => destination_root) }
+ end
+
+end
diff --git a/railties/test/generators/rails_controller_generator_test.rb b/railties/test/generators/rails_controller_generator_test.rb
deleted file mode 100644
index 43fbe972e2..0000000000
--- a/railties/test/generators/rails_controller_generator_test.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require 'generators/generator_test_helper'
-
-module Admin
-end
-
-class RailsControllerGeneratorTest < GeneratorTestCase
-
- def test_controller_generates_controller
- run_generator('controller', %w(products))
-
- assert_generated_controller_for :products
- assert_generated_functional_test_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- end
-
- def test_controller_generates_namespaced_controller
- run_generator('controller', %w(admin::products))
-
- assert_generated_controller_for "admin::products"
- assert_generated_functional_test_for "admin::products"
- assert_generated_helper_for "admin::products"
- assert_generated_helper_test_for "admin::products"
- end
-
- def test_controller_generates_namespaced_and_not_namespaced_controllers
- run_generator('controller', %w(products))
-
- # We have to require the generated helper to show the problem because
- # the test helpers just check for generated files and contents but
- # do not actually load them. But they have to be loaded (as in a real environment)
- # to make the second generator run fail
- require "#{RAILS_ROOT}/app/helpers/products_helper"
-
- assert_nothing_raised do
- begin
- run_generator('controller', %w(admin::products))
- ensure
- # cleanup
- Object.send(:remove_const, :ProductsHelper)
- end
- end
- end
-end
diff --git a/railties/test/generators/rails_helper_generator_test.rb b/railties/test/generators/rails_helper_generator_test.rb
deleted file mode 100644
index 8d05f555e6..0000000000
--- a/railties/test/generators/rails_helper_generator_test.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require File.dirname(__FILE__) + '/generator_test_helper'
-
-class RailsHelperGeneratorTest < GeneratorTestCase
- def test_helper_generates_helper
- run_generator('helper', %w(products))
-
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- end
-
- def test_helper_generates_namespaced_helper
- run_generator('helper', %w(admin::products))
-
- assert_generated_helper_for "admin::products"
- assert_generated_helper_test_for "admin::products"
- end
-
- def test_helper_generates_namespaced_and_not_namespaced_helpers
- run_generator('helper', %w(products))
-
- # We have to require the generated helper to show the problem because
- # the test helpers just check for generated files and contents but
- # do not actually load them. But they have to be loaded (as in a real environment)
- # to make the second generator run fail
- require "#{RAILS_ROOT}/app/helpers/products_helper"
-
- assert_nothing_raised do
- begin
- run_generator('helper', %w(admin::products))
- ensure
- # cleanup
- Object.send(:remove_const, :ProductsHelper)
- end
- end
- end
-end
diff --git a/railties/test/generators/rails_mailer_generator_test.rb b/railties/test/generators/rails_mailer_generator_test.rb
deleted file mode 100644
index de61e6736d..0000000000
--- a/railties/test/generators/rails_mailer_generator_test.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'generators/generator_test_helper'
-
-class RailsMailerGeneratorTest < GeneratorTestCase
-
- def test_generates_mailer
- run_generator('mailer', %w(Notifier reset_password))
-
- assert_generated_model_for :notifier, 'ActionMailer::Base' do |model|
- assert_has_method model, :reset_password do |name, body|
- assert_equal [
- "subject 'Notifier#reset_password'",
- "recipients ''",
- "from ''",
- "sent_on sent_at",
- "",
- "body :greeting => 'Hi,'"
- ],
- body.split("\n").map{|line| line.sub(' '*4, '') }
- end
-
- assert_no_match /(self.default_url_options =|default_url_options\[.*\] =)/, model,
- 'individual mailer models should not set default_url_options because the options are shared by all mailers'
- end
-
- assert_generated_views_for :notifier, 'reset_password.erb'
- assert_generated_unit_test_for :notifier, 'ActionMailer::TestCase'
- assert_generated_file "test/fixtures/notifier/reset_password"
- end
-end
diff --git a/railties/test/generators/rails_model_generator_test.rb b/railties/test/generators/rails_model_generator_test.rb
deleted file mode 100644
index aea2abafba..0000000000
--- a/railties/test/generators/rails_model_generator_test.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require 'generators/generator_test_helper'
-
-class RailsModelGeneratorTest < GeneratorTestCase
-
- def test_model_generates_resources
- run_generator('model', %w(Product name:string))
-
- assert_generated_model_for :product
- assert_generated_fixtures_for :products
- assert_generated_migration :create_products
- end
-
- def test_model_skip_migration_skips_migration
- run_generator('model', %w(Product name:string --skip-migration))
-
- assert_generated_model_for :product
- assert_generated_fixtures_for :products
- assert_skipped_migration :create_products
- end
-
- def test_model_with_attributes_generates_resources_with_attributes
- run_generator('model', %w(Product name:string supplier_id:integer created_at:timestamp))
-
- assert_generated_model_for :product
- assert_generated_fixtures_for :products
- assert_generated_migration :create_products do |t|
- assert_generated_column t, :name, :string
- assert_generated_column t, :supplier_id, :integer
- assert_generated_column t, :created_at, :timestamp
- end
- end
-
- def test_model_with_reference_attributes_generates_belongs_to_associations
- run_generator('model', %w(Product name:string supplier:references))
-
- assert_generated_model_for :product do |body|
- assert body =~ /^\s+belongs_to :supplier/, "#{body.inspect} should contain 'belongs_to :supplier'"
- end
- end
-
- def test_model_with_belongs_to_attributes_generates_belongs_to_associations
- run_generator('model', %w(Product name:string supplier:belongs_to))
-
- assert_generated_model_for :product do |body|
- assert body =~ /^\s+belongs_to :supplier/, "#{body.inspect} should contain 'belongs_to :supplier'"
- end
- end
-end
diff --git a/railties/test/generators/rails_model_subclass_generator_test.rb b/railties/test/generators/rails_model_subclass_generator_test.rb
deleted file mode 100644
index 30066b5a3c..0000000000
--- a/railties/test/generators/rails_model_subclass_generator_test.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'generators/generator_test_helper'
-
-class RailsModelSubclassGeneratorTest < GeneratorTestCase
-
- def test_model_subclass_generates_resources
- run_generator('model_subclass', %w(Car Product))
-
- assert_generated_model_for :car, "Product"
- assert_generated_unit_test_for :car
- end
-
- def test_model_subclass_must_have_a_parent_class_name
- assert_raise(Rails::Generator::UsageError) { run_generator('model_subclass', %w(Car)) }
- end
-end \ No newline at end of file
diff --git a/railties/test/generators/rails_resource_generator_test.rb b/railties/test/generators/rails_resource_generator_test.rb
deleted file mode 100644
index 1f5bd0ef1e..0000000000
--- a/railties/test/generators/rails_resource_generator_test.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'generators/generator_test_helper'
-
-class RailsResourceGeneratorTest < GeneratorTestCase
- def test_resource_generates_resources
- run_generator('resource', %w(Product name:string))
-
- assert_generated_controller_for :products
- assert_generated_model_for :product
- assert_generated_fixtures_for :products
- assert_generated_functional_test_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_migration :create_products
- assert_added_route_for :products
- end
-
- def test_resource_skip_migration_skips_migration
- run_generator('resource', %w(Product name:string --skip-migration))
-
- assert_generated_controller_for :products
- assert_generated_model_for :product
- assert_generated_fixtures_for :products
- assert_generated_functional_test_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_skipped_migration :create_products
- assert_added_route_for :products
- end
-end
diff --git a/railties/test/generators/rails_scaffold_generator_test.rb b/railties/test/generators/rails_scaffold_generator_test.rb
deleted file mode 100644
index 70829a77fd..0000000000
--- a/railties/test/generators/rails_scaffold_generator_test.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-require 'generators/generator_test_helper'
-require 'abstract_unit'
-
-class RailsScaffoldGeneratorTest < GeneratorTestCase
- def test_scaffolded_names
- g = Rails::Generator::Base.instance('scaffold', %w(ProductLine))
- assert_equal "ProductLines", g.controller_name
- assert_equal "ProductLines", g.controller_class_name
- assert_equal "ProductLine", g.controller_singular_name
- assert_equal "product_lines", g.controller_plural_name
- assert_equal "product_lines", g.controller_file_name
- assert_equal "product_lines", g.controller_table_name
- end
-
- def test_scaffold_generates_resources
-
- run_generator('scaffold', %w(Product name:string))
-
- assert_generated_controller_for :products do |f|
-
- assert_has_method f, :index do |name, m|
- assert_match /@products = Product\.all/, m, "#{name} should query products table"
- end
-
- assert_has_method f, :show, :edit, :update, :destroy do |name, m|
- assert_match /@product = Product\.find\(params\[:id\]\)/, m, "#{name.to_s} should query products table"
- end
-
- assert_has_method f, :new do |name, m|
- assert_match /@product = Product\.new/, m, "#{name.to_s} should instantiate a product"
- end
-
- assert_has_method f, :create do |name, m|
- assert_match /@product = Product\.new\(params\[:product\]\)/, m, "#{name.to_s} should instantiate a product"
- assert_match /format.xml \{ render :xml => @product.errors, :status => :unprocessable_entity \}/, m, "#{name.to_s} should set status to :unprocessable_entity code for xml"
- end
-
- end
-
- assert_generated_model_for :product
- assert_generated_functional_test_for :products
- assert_generated_unit_test_for :product
- assert_generated_fixtures_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_stylesheet :scaffold
- assert_generated_views_for :products, "index.html.erb", "new.html.erb", "edit.html.erb", "show.html.erb"
-
- assert_generated_migration :create_products
- assert_added_route_for :products
- end
-
- def test_scaffold_skip_migration_skips_migration
- run_generator('scaffold', %w(Product name:string --skip-migration))
-
- assert_generated_model_for :product
- assert_generated_functional_test_for :products
- assert_generated_unit_test_for :product
- assert_generated_fixtures_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_stylesheet :scaffold
- assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
- assert_skipped_migration :create_products
- assert_added_route_for :products
- end
-
- def test_scaffold_generates_resources_with_attributes
- run_generator('scaffold', %w(Product name:string supplier_id:integer created_at:timestamp))
-
- assert_generated_controller_for :products do |f|
-
- assert_has_method f, :index do |name, m|
- assert_match /@products = Product\.all/, m, "#{name} should query products table"
- end
-
- assert_has_method f, :show, :edit, :update, :destroy do |name, m|
- assert_match /@product = Product\.find\(params\[:id\]\)/, m, "#{name.to_s} should query products table"
- end
-
- assert_has_method f, :new do |name, m|
- assert_match /@product = Product\.new/, m, "#{name.to_s} should instantiate a product"
- end
-
- assert_has_method f, :create do |name, m|
- assert_match /@product = Product\.new\(params\[:product\]\)/, m, "#{name.to_s} should instantiate a product"
- assert_match /format.xml \{ render :xml => @product.errors, :status => :unprocessable_entity \}/, m, "#{name.to_s} should set status to :unprocessable_entity code for xml"
- end
-
- end
-
- assert_generated_model_for :product
- assert_generated_functional_test_for :products
- assert_generated_unit_test_for :product
- assert_generated_fixtures_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_stylesheet :scaffold
- assert_generated_views_for :products, "index.html.erb", "new.html.erb", "edit.html.erb", "show.html.erb"
-
- assert_generated_migration :create_products do |t|
- assert_generated_column t, :name, :string
- assert_generated_column t, :supplier_id, :integer
- assert_generated_column t, :created_at, :timestamp
- end
-
- assert_added_route_for :products
- end
-
- def test_scaffolded_plural_names
- Rails::Generator::Base.logger.expects(:warning)
- g = Rails::Generator::Base.instance('scaffold', %w(ProductLines))
- assert_equal "ProductLines", g.controller_name
- assert_equal "ProductLines", g.controller_class_name
- assert_equal "ProductLine", g.controller_singular_name
- assert_equal "product_lines", g.controller_plural_name
- assert_equal "product_lines", g.controller_file_name
- assert_equal "product_lines", g.controller_table_name
- end
-
- def test_scaffold_plural_model_name_without_force_plural_generates_singular_model
- run_generator('scaffold', %w(Products name:string))
-
- assert_generated_model_for :product
- assert_generated_functional_test_for :products
- assert_generated_unit_test_for :product
- assert_generated_fixtures_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_stylesheet :scaffold
- assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
- assert_skipped_migration :create_products
- assert_added_route_for :products
- end
-
- def test_scaffold_plural_model_name_with_force_plural_forces_plural_model
- run_generator('scaffold', %w(Products name:string --force-plural))
-
- assert_generated_model_for :products
- assert_generated_functional_test_for :products
- assert_generated_unit_test_for :products
- assert_generated_fixtures_for :products
- assert_generated_helper_for :products
- assert_generated_helper_test_for :products
- assert_generated_stylesheet :scaffold
- assert_generated_views_for :products, "index.html.erb","new.html.erb","edit.html.erb","show.html.erb"
- assert_skipped_migration :create_products
- assert_added_route_for :products
- end
-end
diff --git a/railties/test/generators/rails_template_runner_test.rb b/railties/test/generators/rails_template_runner_test.rb
deleted file mode 100644
index 2da6bd59b5..0000000000
--- a/railties/test/generators/rails_template_runner_test.rb
+++ /dev/null
@@ -1,216 +0,0 @@
-require 'abstract_unit'
-require 'generators/generator_test_helper'
-
-class RailsTemplateRunnerTest < GeneratorTestCase
- def setup
- Rails::Generator::Base.use_application_sources!
- run_generator('app', [RAILS_ROOT])
- # generate empty template
- @template_path = File.join(RAILS_ROOT, 'template.rb')
- File.open(File.join(@template_path), 'w') {|f| f << '' }
-
- @git_plugin_uri = 'git://github.com/technoweenie/restful-authentication.git'
- @svn_plugin_uri = 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
- end
-
- def teardown
- super
- rm_rf "#{RAILS_ROOT}/README"
- rm_rf "#{RAILS_ROOT}/Rakefile"
- rm_rf "#{RAILS_ROOT}/doc"
- rm_rf "#{RAILS_ROOT}/lib"
- rm_rf "#{RAILS_ROOT}/log"
- rm_rf "#{RAILS_ROOT}/script"
- rm_rf "#{RAILS_ROOT}/vendor"
- rm_rf "#{RAILS_ROOT}/tmp"
- rm_rf "#{RAILS_ROOT}/Capfile"
- rm_rf @template_path
- end
-
- def test_initialize_should_load_template
- Rails::TemplateRunner.any_instance.expects(:load_template).with(@template_path)
- silence_generator do
- Rails::TemplateRunner.new(@template_path, RAILS_ROOT)
- end
- end
-
- def test_initialize_should_raise_error_on_missing_template_file
- assert_raise(RuntimeError) do
- silence_generator do
- Rails::TemplateRunner.new('non/existent/path/to/template.rb', RAILS_ROOT)
- end
- end
- end
-
- def test_file_should_write_data_to_file_path
- run_template_method(:file, 'lib/test_file.rb', 'heres test data')
- assert_generated_file_with_data 'lib/test_file.rb', 'heres test data'
- end
-
- def test_file_should_write_block_contents_to_file_path
- run_template_method(:file, 'lib/test_file.rb') { 'heres block data' }
- assert_generated_file_with_data 'lib/test_file.rb', 'heres block data'
- end
-
- def test_plugin_with_git_option_should_run_plugin_install
- expects_run_ruby_script_with_command("script/plugin install #{@git_plugin_uri}")
- run_template_method(:plugin, 'restful-authentication', :git => @git_plugin_uri)
- end
-
- def test_plugin_with_svn_option_should_run_plugin_install
- expects_run_ruby_script_with_command("script/plugin install #{@svn_plugin_uri}")
- run_template_method(:plugin, 'restful-authentication', :svn => @svn_plugin_uri)
- end
-
- def test_plugin_with_git_option_and_submodule_should_use_git_scm
- Rails::Git.expects(:run).with("submodule add #{@git_plugin_uri} vendor/plugins/rest_auth")
- run_template_method(:plugin, 'rest_auth', :git => @git_plugin_uri, :submodule => true)
- end
-
- def test_plugin_with_no_options_should_skip_method
- Rails::TemplateRunner.any_instance.expects(:run).never
- run_template_method(:plugin, 'rest_auth', {})
- end
-
- def test_gem_should_put_gem_dependency_in_enviroment
- run_template_method(:gem, 'will-paginate')
- assert_rails_initializer_includes("config.gem 'will-paginate'")
- end
-
- def test_gem_with_options_should_include_options_in_gem_dependency_in_environment
- run_template_method(:gem, 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com')
- assert_rails_initializer_includes("config.gem 'mislav-will-paginate', :lib => 'will-paginate', :source => 'http://gems.github.com'")
- end
-
- def test_gem_with_env_string_should_put_gem_dependency_in_specified_environment
- run_template_method(:gem, 'rspec', :env => 'test')
- assert_generated_file_with_data('config/environments/test.rb', "config.gem 'rspec'", 'test')
- end
-
- def test_gem_with_env_array_should_put_gem_dependency_in_specified_environments
- run_template_method(:gem, 'quietbacktrace', :env => %w[ development test ])
- assert_generated_file_with_data('config/environments/development.rb', "config.gem 'quietbacktrace'")
- assert_generated_file_with_data('config/environments/test.rb', "config.gem 'quietbacktrace'")
- end
-
- def test_gem_with_lib_option_set_to_false_should_put_gem_dependency_in_enviroment_correctly
- run_template_method(:gem, 'mislav-will-paginate', :lib => false, :source => 'http://gems.github.com')
- assert_rails_initializer_includes("config.gem 'mislav-will-paginate', :lib => false, :source => 'http://gems.github.com'")
- end
-
- def test_environment_should_include_data_in_environment_initializer_block
- load_paths = 'config.load_paths += %w["#{RAILS_ROOT}/app/extras"]'
- run_template_method(:environment, load_paths)
- assert_rails_initializer_includes(load_paths)
- end
-
- def test_environment_with_block_should_include_block_contents_in_environment_initializer_block
- run_template_method(:environment) do
- '# This wont be added'
- '# This will be added'
- end
- assert_rails_initializer_includes('# This will be added')
- end
-
- def test_git_with_symbol_should_run_command_using_git_scm
- Rails::Git.expects(:run).once.with('init')
- run_template_method(:git, :init)
- end
-
- def test_git_with_hash_should_run_each_command_using_git_scm
- Rails::Git.expects(:run).times(2)
- run_template_method(:git, {:init => '', :add => '.'})
- end
-
- def test_vendor_should_write_data_to_file_in_vendor
- run_template_method(:vendor, 'vendor_file.rb', '# vendor data')
- assert_generated_file_with_data('vendor/vendor_file.rb', '# vendor data')
- end
-
- def test_lib_should_write_data_to_file_in_lib
- run_template_method(:lib, 'my_library.rb', 'class MyLibrary')
- assert_generated_file_with_data('lib/my_library.rb', 'class MyLibrary')
- end
-
- def test_rakefile_should_write_date_to_file_in_lib_tasks
- run_template_method(:rakefile, 'myapp.rake', 'task :run => [:environment]')
- assert_generated_file_with_data('lib/tasks/myapp.rake', 'task :run => [:environment]')
- end
-
- def test_initializer_should_write_date_to_file_in_config_initializers
- run_template_method(:initializer, 'constants.rb', 'MY_CONSTANT = 42')
- assert_generated_file_with_data('config/initializers/constants.rb', 'MY_CONSTANT = 42')
- end
-
- def test_generate_should_run_script_generate_with_argument_and_options
- expects_run_ruby_script_with_command('script/generate model MyModel')
- run_template_method(:generate, 'model', 'MyModel')
- end
-
- def test_rake_should_run_rake_command_with_development_env
- expects_run_with_command('rake log:clear RAILS_ENV=development')
- run_template_method(:rake, 'log:clear')
- end
-
- def test_rake_with_env_option_should_run_rake_command_in_env
- expects_run_with_command('rake log:clear RAILS_ENV=production')
- run_template_method(:rake, 'log:clear', :env => 'production')
- end
-
- def test_rake_with_sudo_option_should_run_rake_command_with_sudo
- expects_run_with_command('sudo rake log:clear RAILS_ENV=development')
- run_template_method(:rake, 'log:clear', :sudo => true)
- end
-
- def test_capify_should_run_the_capify_command
- expects_run_with_command('capify .')
- run_template_method(:capify!)
- end
-
- def test_freeze_should_freeze_rails_edge
- expects_run_with_command('rake rails:freeze:edge')
- run_template_method(:freeze!)
- end
-
- def test_route_should_add_data_to_the_routes_block_in_config_routes
- route_command = "map.route '/login', :controller => 'sessions', :action => 'new'"
- run_template_method(:route, route_command)
- assert_generated_file_with_data 'config/routes.rb', route_command
- end
-
- def test_run_ruby_script_should_add_ruby_to_command_in_win32_environment
- ruby_command = RUBY_PLATFORM =~ /win32/ ? 'ruby ' : ''
- expects_run_with_command("#{ruby_command}script/generate model MyModel")
- run_template_method(:generate, 'model', 'MyModel')
- end
-
- protected
- def run_template_method(method_name, *args, &block)
- silence_generator do
- @template_runner = Rails::TemplateRunner.new(@template_path, RAILS_ROOT)
- @template_runner.send(method_name, *args, &block)
- end
- end
-
- def expects_run_with_command(command)
- Rails::TemplateRunner.any_instance.stubs(:run).once.with(command, false)
- end
-
- def expects_run_ruby_script_with_command(command)
- Rails::TemplateRunner.any_instance.stubs(:run_ruby_script).once.with(command,false)
- end
-
- def assert_rails_initializer_includes(data, message = nil)
- message ||= "Rails::Initializer should include #{data}"
- assert_generated_file 'config/environment.rb' do |body|
- assert_match(/#{Regexp.escape("Rails::Initializer.run do |config|")}.+#{Regexp.escape(data)}.+end/m, body, message)
- end
- end
-
- def assert_generated_file_with_data(file, data, message = nil)
- message ||= "#{file} should include '#{data}'"
- assert_generated_file(file) do |file|
- assert_match(/#{Regexp.escape(data)}/,file, message)
- end
- end
-end \ No newline at end of file
diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb
new file mode 100644
index 0000000000..876ddbf84e
--- /dev/null
+++ b/railties/test/generators/resource_generator_test.rb
@@ -0,0 +1,106 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/resource/resource_generator'
+
+class ResourceGeneratorTest < GeneratorsTestCase
+
+ def setup
+ super
+ routes = Rails::Generators::ResourceGenerator.source_root
+ routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb")
+ destination = File.join(destination_root, "config")
+
+ FileUtils.mkdir_p(destination)
+ FileUtils.cp File.expand_path(routes), destination
+ end
+
+ def test_help_with_inherited_options
+ content = run_generator ["--help"]
+ assert_match /ActiveRecord options:/, content
+ assert_match /TestUnit options:/, content
+ end
+
+ def test_files_from_inherited_invocation
+ run_generator
+
+ %w(
+ app/models/account.rb
+ test/unit/account_test.rb
+ test/fixtures/accounts.yml
+ ).each { |path| assert_file path }
+
+ assert_migration "db/migrate/create_accounts.rb"
+ end
+
+ def test_inherited_invocations_with_attributes
+ run_generator ["account", "name:string"]
+ assert_migration "db/migrate/create_accounts.rb", /t.string :name/
+ end
+
+ def test_resource_controller_with_pluralized_class_name
+ run_generator
+ assert_file "app/controllers/accounts_controller.rb", /class AccountsController < ApplicationController/
+ assert_file "test/functional/accounts_controller_test.rb", /class AccountsControllerTest < ActionController::TestCase/
+
+ assert_file "app/helpers/accounts_helper.rb", /module AccountsHelper/
+ assert_file "test/unit/helpers/accounts_helper_test.rb", /class AccountsHelperTest < ActionView::TestCase/
+ end
+
+ def test_resource_controller_with_actions
+ run_generator ["account", "--actions", "index", "new"]
+
+ assert_file "app/controllers/accounts_controller.rb" do |controller|
+ assert_instance_method controller, :index
+ assert_instance_method controller, :new
+ end
+
+ assert_file "app/views/accounts/index.html.erb"
+ assert_file "app/views/accounts/new.html.erb"
+ end
+
+ def test_resource_routes_are_added
+ run_generator
+
+ assert_file "config/routes.rb" do |route|
+ assert_match /map\.resources :accounts$/, route
+ end
+ end
+
+ def test_singleton_resource
+ run_generator ["account", "--singleton"]
+
+ assert_file "config/routes.rb" do |route|
+ assert_match /map\.resource :account$/, route
+ end
+ end
+
+ def test_plural_names_are_singularized
+ content = run_generator ["accounts"]
+ assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/
+ assert_file "test/unit/account_test.rb", /class AccountTest/
+ assert_match /Plural version of the model detected, using singularized version. Override with --force-plural./, content
+ end
+
+ def test_plural_names_can_be_forced
+ content = run_generator ["accounts", "--force-plural"]
+ assert_file "app/models/accounts.rb", /class Accounts < ActiveRecord::Base/
+ assert_file "test/unit/accounts_test.rb", /class AccountsTest/
+ assert_no_match /Plural version of the model detected/, content
+ end
+
+ def test_route_is_removed_on_revoke
+ run_generator
+ run_generator ["account"], :behavior => :revoke
+
+ assert_file "config/routes.rb" do |route|
+ assert_no_match /map\.resources :accounts$/, route
+ end
+ end
+
+ protected
+
+ def run_generator(args=["account"], config={})
+ silence(:stdout) { Rails::Generators::ResourceGenerator.start args, config.merge(:destination_root => destination_root) }
+ end
+
+end
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
new file mode 100644
index 0000000000..024ea439ef
--- /dev/null
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -0,0 +1,112 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/scaffold_controller/scaffold_controller_generator'
+
+class ScaffoldControllerGeneratorTest < GeneratorsTestCase
+
+ def test_controller_skeleton_is_created
+ run_generator
+
+ assert_file "app/controllers/users_controller.rb" do |content|
+ assert_match /class UsersController < ApplicationController/, content
+
+ assert_instance_method content, :index do |m|
+ assert_match /@users = User\.all/, m
+ end
+
+ assert_instance_method content, :show do |m|
+ assert_match /@user = User\.find\(params\[:id\]\)/, m
+ end
+
+ assert_instance_method content, :new do |m|
+ assert_match /@user = User\.new/, m
+ end
+
+ assert_instance_method content, :edit do |m|
+ assert_match /@user = User\.find\(params\[:id\]\)/, m
+ end
+
+ assert_instance_method content, :create do |m|
+ assert_match /@user = User\.new\(params\[:user\]\)/, m
+ assert_match /@user\.save/, m
+ assert_match /@user\.errors/, m
+ end
+
+ assert_instance_method content, :update do |m|
+ assert_match /@user = User\.find\(params\[:id\]\)/, m
+ assert_match /@user\.update_attributes\(params\[:user\]\)/, m
+ assert_match /@user\.errors/, m
+ end
+
+ assert_instance_method content, :destroy do |m|
+ assert_match /@user = User\.find\(params\[:id\]\)/, m
+ assert_match /@user\.destroy/, m
+ end
+ end
+ end
+
+ def test_helper_are_invoked_with_a_pluralized_name
+ run_generator
+ assert_file "app/helpers/users_helper.rb", /module UsersHelper/
+ assert_file "test/unit/helpers/users_helper_test.rb", /class UsersHelperTest < ActionView::TestCase/
+ end
+
+ def test_views_are_generated
+ run_generator
+
+ %w(
+ index
+ edit
+ new
+ show
+ ).each { |view| assert_file "app/views/users/#{view}.html.erb" }
+ assert_file "app/views/layouts/users.html.erb"
+ end
+
+ def test_functional_tests
+ run_generator
+
+ assert_file "test/functional/users_controller_test.rb" do |content|
+ assert_match /class UsersControllerTest < ActionController::TestCase/, content
+ assert_match /test "should get index"/, content
+ end
+ end
+
+ def test_generates_singleton_controller
+ run_generator ["User", "name:string", "age:integer", "--singleton"]
+
+ assert_file "app/controllers/users_controller.rb" do |content|
+ assert_no_match /def index/, content
+ end
+
+ assert_file "test/functional/users_controller_test.rb" do |content|
+ assert_no_match /test "should get index"/, content
+ end
+
+ assert_no_file "app/views/users/index.html.erb"
+ end
+
+ def test_skip_helper_if_required
+ run_generator ["User", "name:string", "age:integer", "--no-helper"]
+ assert_no_file "app/helpers/users_helper.rb"
+ assert_no_file "test/unit/helpers/users_helper_test.rb"
+ end
+
+ def test_skip_layout_if_required
+ run_generator ["User", "name:string", "age:integer", "--no-layout"]
+ assert_no_file "app/views/layouts/users.html.erb"
+ end
+
+ def test_error_is_shown_if_orm_does_not_provide_interface
+ error = capture(:stderr){ run_generator ["User", "--orm=unknown"] }
+ assert_equal "Could not load Unknown::Generators::ActionORM, skipping controller. " <<
+ "Error: no such file to load -- generators/unknown.\n", error
+ end
+
+ protected
+
+ def run_generator(args=["User", "name:string", "age:integer"])
+ silence(:stdout) { Rails::Generators::ScaffoldControllerGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
new file mode 100644
index 0000000000..05eadd3460
--- /dev/null
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -0,0 +1,129 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/scaffold/scaffold_generator'
+
+class ScaffoldGeneratorTest < GeneratorsTestCase
+
+ def setup
+ super
+ routes = Rails::Generators::ResourceGenerator.source_root
+ routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb")
+ destination = File.join(destination_root, "config")
+
+ FileUtils.mkdir_p(destination)
+ FileUtils.cp File.expand_path(routes), destination
+ end
+
+ def test_scaffold_on_invoke
+ run_generator
+
+ # Model
+ assert_file "app/models/product_line.rb", /class ProductLine < ActiveRecord::Base/
+ assert_file "test/unit/product_line_test.rb", /class ProductLineTest < ActiveSupport::TestCase/
+ assert_file "test/fixtures/product_lines.yml"
+ assert_migration "db/migrate/create_product_lines.rb"
+
+ # Route
+ assert_file "config/routes.rb" do |route|
+ assert_match /map\.resources :product_lines$/, route
+ end
+
+ # Controller
+ assert_file "app/controllers/product_lines_controller.rb" do |content|
+ assert_match /class ProductLinesController < ApplicationController/, content
+
+ assert_instance_method content, :index do |m|
+ assert_match /@product_lines = ProductLine\.all/, m
+ end
+
+ assert_instance_method content, :show do |m|
+ assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
+ end
+
+ assert_instance_method content, :new do |m|
+ assert_match /@product_line = ProductLine\.new/, m
+ end
+
+ assert_instance_method content, :edit do |m|
+ assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
+ end
+
+ assert_instance_method content, :create do |m|
+ assert_match /@product_line = ProductLine\.new\(params\[:product_line\]\)/, m
+ assert_match /@product_line\.save/, m
+ assert_match /@product_line\.errors/, m
+ end
+
+ assert_instance_method content, :update do |m|
+ assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
+ assert_match /@product_line\.update_attributes\(params\[:product_line\]\)/, m
+ assert_match /@product_line\.errors/, m
+ end
+
+ assert_instance_method content, :destroy do |m|
+ assert_match /@product_line = ProductLine\.find\(params\[:id\]\)/, m
+ assert_match /@product_line\.destroy/, m
+ end
+ end
+
+ assert_file "test/functional/product_lines_controller_test.rb",
+ /class ProductLinesControllerTest < ActionController::TestCase/
+
+ # Views
+ %w(
+ index
+ edit
+ new
+ show
+ ).each { |view| assert_file "app/views/product_lines/#{view}.html.erb" }
+ assert_file "app/views/layouts/product_lines.html.erb"
+
+ # Helpers
+ assert_file "app/helpers/product_lines_helper.rb"
+ assert_file "test/unit/helpers/product_lines_helper_test.rb"
+
+ # Stylesheets
+ assert_file "public/stylesheets/scaffold.css"
+ end
+
+ def test_scaffold_on_revoke
+ run_generator
+ run_generator :behavior => :revoke
+
+ # Model
+ assert_no_file "app/models/product_line.rb"
+ assert_no_file "test/unit/product_line_test.rb"
+ assert_no_file "test/fixtures/product_lines.yml"
+ assert_no_migration "db/migrate/create_product_lines.rb"
+
+ # Route
+ assert_file "config/routes.rb" do |route|
+ assert_no_match /map\.resources :product_lines$/, route
+ end
+
+ # Controller
+ assert_no_file "app/controllers/product_lines_controller.rb"
+ assert_no_file "test/functional/product_lines_controller_test.rb"
+
+ # Views
+ assert_no_file "app/views/product_lines"
+ assert_no_file "app/views/layouts/product_lines.html.erb"
+
+ # Helpers
+ assert_no_file "app/helpers/product_lines_helper.rb"
+ assert_no_file "test/unit/helpers/product_lines_helper_test.rb"
+
+ # Stylesheets (should not be removed)
+ assert_file "public/stylesheets/scaffold.css"
+ end
+
+ protected
+
+ def run_generator(config={})
+ silence(:stdout) do
+ Rails::Generators::ScaffoldGenerator.start ["product_line", "title:string", "price:integer"],
+ config.merge(:destination_root => destination_root)
+ end
+ end
+
+end
diff --git a/railties/test/generators/session_migration_generator_test.rb b/railties/test/generators/session_migration_generator_test.rb
new file mode 100644
index 0000000000..f83109800b
--- /dev/null
+++ b/railties/test/generators/session_migration_generator_test.rb
@@ -0,0 +1,23 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/session_migration/session_migration_generator'
+
+class SessionMigrationGeneratorTest < GeneratorsTestCase
+
+ def test_session_migration_with_default_name
+ run_generator
+ assert_migration "db/migrate/add_sessions_table.rb", /class AddSessionsTable < ActiveRecord::Migration/
+ end
+
+ def test_session_migration_with_given_name
+ run_generator ["create_session_table"]
+ assert_migration "db/migrate/create_session_table.rb", /class CreateSessionTable < ActiveRecord::Migration/
+ end
+
+ protected
+
+ def run_generator(args=[])
+ silence(:stdout) { Rails::Generators::SessionMigrationGenerator.start args, :destination_root => destination_root }
+ end
+
+end
diff --git a/railties/test/generators/stylesheets_generator_test.rb b/railties/test/generators/stylesheets_generator_test.rb
new file mode 100644
index 0000000000..02082d5cc8
--- /dev/null
+++ b/railties/test/generators/stylesheets_generator_test.rb
@@ -0,0 +1,24 @@
+require 'abstract_unit'
+require 'generators/generators_test_helper'
+require 'generators/rails/stylesheets/stylesheets_generator'
+
+class StylesheetsGeneratorTest < GeneratorsTestCase
+
+ def test_copy_stylesheets
+ run_generator
+ assert_file "public/stylesheets/scaffold.css"
+ end
+
+ def test_stylesheets_are_not_deleted_on_revoke
+ run_generator
+ run_generator :behavior => :revoke
+ assert_file "public/stylesheets/scaffold.css"
+ end
+
+ protected
+
+ def run_generator(config={})
+ silence(:stdout) { Rails::Generators::StylesheetsGenerator.start [], config.merge(:destination_root => destination_root) }
+ end
+
+end
diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb
new file mode 100644
index 0000000000..89d52dd170
--- /dev/null
+++ b/railties/test/generators_test.rb
@@ -0,0 +1,156 @@
+require File.join(File.dirname(__FILE__), 'generators', 'generators_test_helper')
+require 'generators/rails/model/model_generator'
+require 'generators/test_unit/model/model_generator'
+require 'mocha'
+
+class GeneratorsTest < GeneratorsTestCase
+ def test_invoke_when_generator_is_not_found
+ output = capture(:stdout){ Rails::Generators.invoke :unknown }
+ assert_equal "Could not find generator unknown.\n", output
+ end
+
+ def test_help_when_a_generator_with_required_arguments_is_invoked_without_arguments
+ output = capture(:stdout){ Rails::Generators.invoke :model, [] }
+ assert_match /Description:/, output
+ end
+
+ def test_invoke_with_default_values
+ Rails::Generators::ModelGenerator.expects(:start).with(["Account"], {})
+ Rails::Generators.invoke :model, ["Account"]
+ end
+
+ def test_invoke_with_config_values
+ Rails::Generators::ModelGenerator.expects(:start).with(["Account"], :behavior => :skip)
+ Rails::Generators.invoke :model, ["Account"], :behavior => :skip
+ end
+
+ def test_find_by_namespace_without_base_or_context
+ assert_nil Rails::Generators.find_by_namespace(:model)
+ end
+
+ def test_find_by_namespace_with_base
+ klass = Rails::Generators.find_by_namespace(:model, :rails)
+ assert klass
+ assert_equal "rails:generators:model", klass.namespace
+ end
+
+ def test_find_by_namespace_with_context
+ klass = Rails::Generators.find_by_namespace(:test_unit, nil, :model)
+ assert klass
+ assert_equal "test_unit:generators:model", klass.namespace
+ end
+
+ def test_find_by_namespace_add_generators_to_raw_lookups
+ klass = Rails::Generators.find_by_namespace("test_unit:model")
+ assert klass
+ assert_equal "test_unit:generators:model", klass.namespace
+ end
+
+ def test_find_by_namespace_lookup_to_the_rails_root_folder
+ klass = Rails::Generators.find_by_namespace(:fixjour)
+ assert klass
+ assert_equal "fixjour", klass.namespace
+ end
+
+ def test_find_by_namespace_lookup_to_deep_rails_root_folders
+ klass = Rails::Generators.find_by_namespace(:fixjour, :active_record)
+ assert klass
+ assert_equal "active_record:generators:fixjour", klass.namespace
+ end
+
+ def test_find_by_namespace_lookup_traverse_folders
+ klass = Rails::Generators.find_by_namespace(:javascripts, :rails)
+ assert klass
+ assert_equal "rails:generators:javascripts", klass.namespace
+ end
+
+ def test_find_by_namespace_lookup_to_vendor_folders
+ klass = Rails::Generators.find_by_namespace(:mspec)
+ assert klass
+ assert_equal "mspec", klass.namespace
+ end
+
+ def test_builtin_generators
+ assert Rails::Generators.builtin.include? %w(rails model)
+ end
+
+ def test_rails_generators_help_with_builtin_information
+ output = capture(:stdout){ Rails::Generators.help }
+ assert_match /model/, output
+ assert_match /scaffold_controller/, output
+ end
+
+ def test_rails_generators_with_others_information
+ output = capture(:stdout){ Rails::Generators.help }.split("\n").last
+ assert_equal "Others: active_record:fixjour, fixjour, mspec, rails:javascripts, wrong.", output
+ end
+
+ def test_warning_is_shown_if_generator_cant_be_loaded
+ output = capture(:stderr){ Rails::Generators.find_by_namespace(:wrong) }
+ assert_match /\[WARNING\] Could not load generator at/, output
+ assert_match /Error: uninitialized constant Rails::Generator/, output
+ end
+
+ def test_no_color_sets_proper_shell
+ Rails::Generators.no_color!
+ assert_equal Thor::Shell::Basic, Thor::Base.shell
+ ensure
+ Thor::Base.shell = Thor::Shell::Color
+ end
+
+ def test_rails_root_templates
+ template = File.join(RAILS_ROOT, "lib", "templates", "active_record", "model", "model.rb")
+
+ # Create template
+ mkdir_p(File.dirname(template))
+ File.open(template, 'w'){ |f| f.write "empty" }
+
+ output = capture(:stdout) do
+ Rails::Generators.invoke :model, ["user"], :destination_root => destination_root
+ end
+
+ assert_file "app/models/user.rb" do |content|
+ assert_equal "empty", content
+ end
+ ensure
+ rm_rf File.dirname(template)
+ end
+
+ def test_fallbacks_for_generators_on_find_by_namespace
+ Rails::Generators.fallbacks[:remarkable] = :test_unit
+ klass = Rails::Generators.find_by_namespace(:plugin, :remarkable)
+ assert klass
+ assert_equal "test_unit:generators:plugin", klass.namespace
+ end
+
+ def test_fallbacks_for_generators_on_invoke
+ Rails::Generators.fallbacks[:shoulda] = :test_unit
+ TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {})
+ Rails::Generators.invoke "shoulda:model", ["Account"]
+ end
+
+ def test_nested_fallbacks_for_generators
+ Rails::Generators.fallbacks[:super_shoulda] = :shoulda
+ TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {})
+ Rails::Generators.invoke "super_shoulda:model", ["Account"]
+ end
+
+ def test_developer_options_are_overwriten_by_user_options
+ Rails::Generators.options[:new_generator] = { :generate => false }
+
+ klass = Class.new(Rails::Generators::Base) do
+ def self.name
+ "NewGenerator"
+ end
+
+ class_option :generate, :default => true
+ end
+
+ assert_equal false, klass.class_options[:generate].default
+ end
+
+ def test_source_paths_for_not_namespaced_generators
+ mspec = Rails::Generators.find_by_namespace :mspec
+ assert mspec.source_paths.include?(File.join(RAILS_ROOT, "lib", "templates", "mspec"))
+ end
+end
diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb
index 550cb7de76..1fecd62995 100644
--- a/railties/test/initializer_test.rb
+++ b/railties/test/initializer_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'initializer'
+require 'generators'
require 'action_view'
require 'action_mailer'
@@ -10,8 +11,19 @@ module Rails
def self.configuration
Rails::Configuration.new
end
+
+ module Generators
+ def self.clear_aliases!
+ @aliases = nil
+ end
+
+ def self.clear_options!
+ @@options = nil
+ end
+ end
end
+
class ConfigurationMock < Rails::Configuration
attr_reader :environment_path
@@ -278,6 +290,87 @@ class InitializerPluginLoadingTests < Test::Unit::TestCase
end
end
+class InitializerGeneratorsTests < Test::Unit::TestCase
+
+ def setup
+ @configuration = Rails::Configuration.new
+ @initializer = Rails::Initializer.default
+ @initializer.config = @configuration
+ end
+
+ def test_generators_default_values
+ assert_equal(true, @configuration.generators.colorize_logging)
+ assert_equal({}, @configuration.generators.aliases)
+ assert_equal({}, @configuration.generators.options)
+ end
+
+ def test_generators_set_rails_options
+ @configuration.generators.orm = :datamapper
+ @configuration.generators.test_framework = :rspec
+ expected = { :rails => { :orm => :datamapper, :test_framework => :rspec } }
+ assert_equal expected, @configuration.generators.options
+ end
+
+ def test_generators_set_rails_aliases
+ @configuration.generators.aliases = { :rails => { :test_framework => "-w" } }
+ expected = { :rails => { :test_framework => "-w" } }
+ assert_equal expected, @configuration.generators.aliases
+ end
+
+ def test_generators_aliases_and_options_on_initialization
+ @configuration.generators.rails :aliases => { :test_framework => "-w" }
+ @configuration.generators.orm :datamapper
+ @configuration.generators.test_framework :rspec
+
+ @initializer.run(:initialize_generators)
+
+ assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
+ assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework]
+ end
+
+ def test_generators_no_color_on_initialization
+ @configuration.generators.colorize_logging = false
+ @initializer.run(:initialize_generators)
+ assert_equal Thor::Base.shell, Thor::Shell::Basic
+ end
+
+ def test_generators_with_hashes_for_options_and_aliases
+ @configuration.generators do |g|
+ g.orm :datamapper, :migration => false
+ g.plugin :aliases => { :generator => "-g" },
+ :generator => true
+ end
+
+ expected = {
+ :rails => { :orm => :datamapper },
+ :plugin => { :generator => true },
+ :datamapper => { :migration => false }
+ }
+
+ assert_equal expected, @configuration.generators.options
+ assert_equal({ :plugin => { :generator => "-g" } }, @configuration.generators.aliases)
+ end
+
+ def test_generators_with_hashes_are_deep_merged
+ @configuration.generators do |g|
+ g.orm :datamapper, :migration => false
+ g.plugin :aliases => { :generator => "-g" },
+ :generator => true
+ end
+ @initializer.run(:initialize_generators)
+
+ assert Rails::Generators.aliases.size >= 1
+ assert Rails::Generators.options.size >= 1
+ end
+
+ protected
+
+ def teardown
+ Rails::Generators.clear_aliases!
+ Rails::Generators.clear_options!
+ end
+end
+
class InitializerSetupI18nTests < Test::Unit::TestCase
def test_no_config_locales_dir_present_should_return_empty_load_path
File.stubs(:exist?).returns(false)
diff --git a/railties/test/rails_generator_test.rb b/railties/test/rails_generator_test.rb
deleted file mode 100644
index 38bd90dcc1..0000000000
--- a/railties/test/rails_generator_test.rb
+++ /dev/null
@@ -1,148 +0,0 @@
-require 'test/unit'
-
-# Optionally load RubyGems.
-begin
- require 'rubygems'
-rescue LoadError
-end
-
-# Mock out what we need from AR::Base.
-module ActiveRecord
- class Base
- class << self
- attr_accessor :pluralize_table_names
- end
- self.pluralize_table_names = true
- end
-end
-
-# And what we need from ActionView
-module ActionView
- module Helpers
- module ActiveRecordHelper; end
- class InstanceTag; end
- end
-end
-
-
-# Must set before requiring generator libs.
-if defined?(RAILS_ROOT)
- RAILS_ROOT.replace "#{File.dirname(__FILE__)}/fixtures"
-else
- RAILS_ROOT = "#{File.dirname(__FILE__)}/fixtures"
-end
-
-$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
-require 'initializer'
-
-# Mocks out the configuration
-module Rails
- def self.configuration
- Rails::Configuration.new
- end
-end
-
-require 'rails_generator'
-
-class RailsGeneratorTest < Test::Unit::TestCase
- BUILTINS = %w(controller integration_test mailer migration model observer plugin resource scaffold session_migration)
- CAPITALIZED_BUILTINS = BUILTINS.map { |b| b.capitalize }
-
- def setup
- ActiveRecord::Base.pluralize_table_names = true
- @initializer = Rails::Initializer.default
- @initializer.config = Rails.configuration
- @initializer.run(:set_root_path)
- end
-
- def test_sources
- expected = [:lib, :vendor,
- "plugins (vendor/plugins)".to_sym, # <plugin>/generators and <plugin>/rails_generators
- :user,
- :RubyGems, :RubyGems, # gems named <x>_generator, gems containing /rails_generator/ folder
- :builtin]
- expected.delete(:RubyGems) unless Object.const_defined?(:Gem)
- assert_equal expected, Rails::Generator::Base.sources.map { |s| s.label }
- end
-
- def test_lookup_builtins
- (BUILTINS + CAPITALIZED_BUILTINS).each do |name|
- assert_nothing_raised do
- spec = Rails::Generator::Base.lookup(name)
- assert_not_nil spec
- assert_kind_of Rails::Generator::Spec, spec
-
- klass = spec.klass
- assert klass < Rails::Generator::Base
- assert_equal spec, klass.spec
- end
- end
- end
-
- def test_autolookup
- assert_nothing_raised { ControllerGenerator }
- assert_nothing_raised { ModelGenerator }
- end
-
- def test_lookup_missing_generator
- assert_raise Rails::Generator::GeneratorError do
- Rails::Generator::Base.lookup('missing').klass
- end
- end
-
- def test_lookup_missing_class
- spec = nil
- assert_nothing_raised { spec = Rails::Generator::Base.lookup('missing_class') }
- assert_not_nil spec
- assert_kind_of Rails::Generator::Spec, spec
- assert_raise(NameError) { spec.klass }
- end
-
- def test_generator_usage
- (BUILTINS - ["session_migration"]).each do |name|
- assert_raise(Rails::Generator::UsageError, "Generator '#{name}' should raise an error without arguments") {
- Rails::Generator::Base.instance(name)
- }
- end
- end
-
- def test_generator_spec
- spec = Rails::Generator::Base.lookup('working')
- assert_equal 'working', spec.name
- assert_match(/#{spec.path}$/, "#{RAILS_ROOT}/lib/generators/working")
- assert_equal :lib, spec.source
- assert_nothing_raised { assert_match(/WorkingGenerator$/, spec.klass.name) }
- end
-
- def test_named_generator_attributes
- g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz))
- assert_equal 'admin/foo', g.name
- assert_equal %w(admin), g.class_path
- assert_equal 'Admin', g.class_nesting
- assert_equal 'Admin::Foo', g.class_name
- assert_equal 'foo', g.singular_name
- assert_equal 'foos', g.plural_name
- assert_equal g.singular_name, g.file_name
- assert_equal "admin_#{g.plural_name}", g.table_name
- assert_equal %w(bar baz), g.args
- end
-
- def test_named_generator_attributes_without_pluralized
- ActiveRecord::Base.pluralize_table_names = false
- g = Rails::Generator::Base.instance('working', %w(admin/foo bar baz))
- assert_equal "admin_#{g.singular_name}", g.table_name
- end
-
- def test_session_migration_generator_with_pluralization
- g = Rails::Generator::Base.instance('session_migration')
- assert_equal 'session'.pluralize, g.send(:default_session_table_name)
- ActiveRecord::Base.pluralize_table_names = false
- assert_equal 'session', g.send(:default_session_table_name)
- end
-
- def test_scaffold_controller_name
- # Default behaviour is use the model name
- g = Rails::Generator::Base.instance('scaffold', %w(Product))
- assert_equal "Products", g.controller_name
- end
-end
diff --git a/railties/test/secret_key_generation_test.rb b/railties/test/secret_key_generation_test.rb
deleted file mode 100644
index 2c7c3d5dfe..0000000000
--- a/railties/test/secret_key_generation_test.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'abstract_unit'
-
-# Must set before requiring generator libs.
-if defined?(RAILS_ROOT)
- RAILS_ROOT.replace "#{File.dirname(__FILE__)}/fixtures"
-else
- RAILS_ROOT = "#{File.dirname(__FILE__)}/fixtures"
-end
-
-$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
-
-require 'initializer'
-
-# Mocks out the configuration
-module Rails
- def self.configuration
- Rails::Configuration.new
- end
-end
-
-require 'rails_generator'
-require 'rails_generator/secret_key_generator'
-require 'rails_generator/generators/applications/app/app_generator'
-
-class SecretKeyGenerationTest < ActiveSupport::TestCase
- SECRET_KEY_MIN_LENGTH = 128
- APP_NAME = "foo"
-
- def setup
- @generator = Rails::SecretKeyGenerator.new(APP_NAME)
- end
-
- def test_secret_key_generation
- assert_deprecated /ActiveSupport::SecureRandom\.hex\(64\)/ do
- assert @generator.generate_secret.length >= SECRET_KEY_MIN_LENGTH
- end
- end
-end