diff options
Diffstat (limited to 'railties')
252 files changed, 5897 insertions, 3540 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index ba9b24c6c6..8963f6e604 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,114 +1,142 @@ -## Rails 4.0.0 (unreleased) ## +* Removal of all javascript stuff (gems and files) when generating a new + application using the `--skip-javascript` option. -* Add `.rake` to list of file extensions included by `rake notes` and `rake notes:custom`. *Brent J. Nordquist* + *Robin Dupret* -* New test locations `test/models`, `test/helpers`, `test/controllers`, and - `test/mailers`. Corresponding rake tasks added as well. *Mike Moore* +* Make the application name snake cased when it contains spaces -* Set a different cache per environment for assets pipeline - through `config.assets.cache`. + The application name is used to fill the `database.yml` and + `session_store.rb` files ; previously, if the provided name + contained whitespaces, it led to unexpected names in these files. - *Guillermo Iguaran* + *Robin Dupret* -* `Rails.public_path` now returns a Pathname object. *Prem Sichanugrist* +* Added `--model-name` option to `ScaffoldControllerGenerator`. -* Remove highly uncommon `config.assets.manifest` option for moving the manifest path. - This option is now unsupported in sprockets-rails. + *yalab* - *Guillermo Iguaran & Dmitry Vorotilin* +* Expose MiddlewareStack#unshift to environment configuration. -* Add `config.action_controller.permit_all_parameters` to disable - StrongParameters protection, it's false by default. + *Ben Pickles* - *Guillermo Iguaran* +* Include `web-console` into newly generated applications' Gemfile. -* Remove `config.active_record.whitelist_attributes` and - `config.active_record.mass_assignment_sanitizer` from new applications since - MassAssignmentSecurity has been extracted from Rails. + *Genadi Samokovarov* - *Guillermo Iguaran* +* `rails server` will only extend the logger to output to STDOUT + in development environment. -* Change `rails new` and `rails plugin new` generators to name the `.gitkeep` files - as `.keep` in a more SCM-agnostic way. + *Richard Schneeman* - Change `--skip-git` option to only skip the `.gitignore` file and still generate - the `.keep` files. +* Don't require passing path to app before options in `rails new` + and `rails plugin new` - Add `--skip-keeps` option to skip the `.keep` files. + *Piotr Sarnacki* - *Derek Prior & Francesco Rodriguez* +* rake notes now searches *.less files -* Fixed support for DATABASE_URL environment variable for rake db tasks. *Grace Liu* + *Josh Crowder* -* rails dbconsole now can use SSL for MySQL. The database.yml options sslca, sslcert, sslcapath, sslcipher, - and sslkey now affect rails dbconsole. *Jim Kingdon and Lars Petrus* +* Generate nested route for namespaced controller generated using + `rails g controller`. + Fixes #11532. -* Correctly handle SCRIPT_NAME when generating routes to engine in application - that's mounted at a sub-uri. With this behavior, you *should not* use - default_url_options[:script_name] to set proper application's mount point by - yourself. *Piotr Sarnacki* + Example: -* `config.threadsafe!` is deprecated in favor of `config.eager_load` which provides a more fine grained control on what is eager loaded *José Valim* + rails g controller admin/dashboard index -* The migration generator will now produce AddXXXToYYY/RemoveXXXFromYYY migrations with references statements, for instance + # Before: + get "dashboard/index" - rails g migration AddReferencesToProducts user:references supplier:references{polymorphic} + # After: + namespace :admin do + get "dashboard/index" + end - will generate the migration with: + *Prathamesh Sonpatki* - add_reference :products, :user, index: true - add_reference :products, :supplier, polymorphic: true, index: true +* Fix the event name of action_dispatch requests. - *Aleksey Magusev* + *Rafael Mendonça França* -* Allow scaffold/model/migration generators to accept a `polymorphic` modifier - for `references`/`belongs_to`, for instance +* Make `config.log_level` work with custom loggers. - rails g model Product supplier:references{polymorphic} + *Max Shytikov* - will generate the model with `belongs_to :supplier, polymorphic: true` - association and appropriate migration. +* Changed stylesheet load order in the stylesheet manifest generator. + Fixes #11639. - *Aleksey Magusev* + *Pawel Janiak* -* Set `config.active_record.migration_error` to `:page_load` for development *Richard Schneeman* +* Added generated unit test for generator generator using new + `test:generators` rake task. -* Add runner to Rails::Railtie as a hook called just after runner starts. *José Valim & kennyj* + *Josef Šimánek* -* Add `/rails/info/routes` path, displays same information as `rake routes` *Richard Schneeman & Andrew White* +* Removed `update:application_controller` rake task. -* Improved `rake routes` output for redirects *Łukasz Strzałkowski & Andrew White* + *Josef Šimánek* -* Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki* +* Fix `rake environment` to do not eager load modules -* Add `config.queue_consumer` to change the job queue consumer from the default `ActiveSupport::ThreadedQueueConsumer`. *Carlos Antonio da Silva* + *Paul Nikitochkin* -* Add `Rails.queue` for processing jobs in the background. *Yehuda Katz* +* Fix `rake notes` to look into `*.sass` files -* Remove Rack::SSL in favour of ActionDispatch::SSL. *Rafael Mendonça França* + *Yuri Artemev* -* Remove Active Resource from Rails framework. *Prem Sichangrist* +* Removed deprecated `Rails.application.railties.engines`. -* Allow to set class that will be used to run as a console, other than IRB, with `Rails.application.config.console=`. It's best to add it to `console` block. *Piotr Sarnacki* + *Arun Agrawal* - Example: +* Removed deprecated threadsafe! from Rails Config. - # it can be added to config/application.rb - console do - # this block is called only when running console, - # so we can safely require pry here - require "pry" - config.console = Pry - end + *Paul Nikitochkin* + +* Remove deprecated `ActiveRecord::Generators::ActiveModel#update_attributes` in + favor of `ActiveRecord::Generators::ActiveModel#update` + + *Vipul A M* + +* Remove deprecated `config.whiny_nils` option + + *Vipul A M* + +* Rename `commands/plugin_new.rb` to `commands/plugin.rb` and fix references + + *Richard Schneeman* + +* Fix `rails plugin --help` command. + + *Richard Schneeman* + +* Omit turbolinks configuration completely on skip_javascript generator option. + + *Nikita Fedyashev* + +* Removed deprecated rake tasks for running tests: `rake test:uncommitted` and + `rake test:recent`. + + *John Wang* + +* Clearing autoloaded constants triggers routes reloading. + Fixes #10685. + + *Xavier Noria* + +* Fixes bug with scaffold generator with `--assets=false --resource-route=false`. + Fixes #9525. + + *Arun Agrawal* -* Add convenience `hide!` method to Rails generators to hide current generator - namespace from showing when running `rails generate`. *Carlos Antonio da Silva* +* Rails::Railtie no longer forces the Rails::Configurable module on everything + that subclasses it. Instead, the methods from Rails::Configurable have been + moved to class methods in Railtie and the Railtie has been made abstract. -* Scaffold now uses `content_tag_for` in index.html.erb *José Valim* + *John Wang* -* Rails::Plugin has gone. Instead of adding plugins to vendor/plugins use gems or bundler with path or git dependencies. *Santiago Pastorino* +* Changes repetitive th tags to use colspan attribute in `index.html.erb` template. -* Set config.action_mailer.async = true to turn on asynchronous - message delivery *Brian Cardarella* + *Sıtkı Bağdat* -Please check [3-2-stable](https://github.com/rails/rails/blob/3-2-stable/railties/CHANGELOG.md) for previous changes. +Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/railties/CHANGELOG.md) for previous changes. diff --git a/railties/MIT-LICENSE b/railties/MIT-LICENSE index 03bde18130..0d7fb865e2 100644 --- a/railties/MIT-LICENSE +++ b/railties/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2012 David Heinemeier Hansson +Copyright (c) 2004-2013 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/railties/RDOC_MAIN.rdoc b/railties/RDOC_MAIN.rdoc new file mode 100644 index 0000000000..eccdee7b07 --- /dev/null +++ b/railties/RDOC_MAIN.rdoc @@ -0,0 +1,73 @@ +== Welcome to \Rails + +\Rails is a web-application framework that includes everything needed to create +database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller] pattern. + +Understanding the MVC pattern is key to understanding \Rails. MVC divides your application +into three layers, each with a specific responsibility. + +The View layer is composed of "templates" that are responsible for providing +appropriate representations of your application's resources. Templates +can come in a variety of formats, but most view templates are \HTML with embedded Ruby +code (.erb files). + +The Model layer represents your domain model (such as Account, Product, Person, Post) +and encapsulates the business logic that is specific to your application. In \Rails, +database-backed model classes are derived from ActiveRecord::Base. Active Record allows +you to present the data from database rows as objects and embellish these data objects +with business logic methods. Although most \Rails models are backed by a database, models +can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as +provided by the ActiveModel module. You can read more about Active Record in its +{README}[link:files/activerecord/README_rdoc.html]. + +The Controller layer is responsible for handling incoming HTTP requests and providing a +suitable response. Usually this means returning \HTML, but \Rails controllers can also +generate XML, JSON, PDFs, mobile-specific views, and more. Controllers manipulate models +and render view templates in order to generate the appropriate HTTP response. + +In \Rails, the Controller and View layers are handled together by Action Pack. +These two layers are bundled in a single package due to their heavy interdependence. +This is unlike the relationship between Active Record and Action Pack, which are +independent. Each of these packages can be used independently outside of \Rails. You +can read more about Action Pack in its {README}[link:files/actionpack/README_rdoc.html]. + +== Getting Started + +1. Install \Rails at the command prompt if you haven't yet: + + gem install rails + +2. At the command prompt, create a new \Rails application: + + rails new myapp + + where "myapp" is the application name. + +3. Change directory to +myapp+ and start the web server: + + cd myapp; rails server + + Run with <tt>--help</tt> or <tt>-h</tt> for options. + +4. Go to http://localhost:3000 and you'll see: + + "Welcome aboard: You're riding Ruby on Rails!" + +5. Follow the guidelines to start developing your application. You may find the following resources handy: + +* The \README file created within your application. +* {Getting Started with \Rails}[http://guides.rubyonrails.org/getting_started.html]. +* {Ruby on \Rails Tutorial}[http://ruby.railstutorial.org/ruby-on-rails-tutorial-book]. +* {Ruby on \Rails Guides}[http://guides.rubyonrails.org]. +* {The API Documentation}[http://api.rubyonrails.org]. + +== Contributing + +We encourage you to contribute to Ruby on \Rails! Please check out the {Contributing to Rails +guide}[http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html] for guidelines about how +to proceed. {Join us}[http://contributors.rubyonrails.org]! + + +== License + +Ruby on \Rails is released under the {MIT License}[http://www.opensource.org/licenses/MIT]. diff --git a/railties/Rakefile b/railties/Rakefile index 8576275aea..a899d069b5 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -1,17 +1,16 @@ require 'rake/testtask' require 'rubygems/package_task' -require 'date' -require 'rbconfig' - - task :default => :test + +desc "Run all unit tests" task :test => 'test:isolated' namespace :test do task :isolated do - dir = ENV["TEST_DIR"] || "**" - Dir["test/#{dir}/*_test.rb"].each do |file| + dirs = (ENV["TEST_DIR"] || ENV["TEST_DIRS"] || "**").split(",") + test_files = dirs.map { |dir| "test/#{dir}/*_test.rb" } + Dir[*test_files].each do |file| next true if file.include?("fixtures") dash_i = [ 'test', @@ -20,7 +19,7 @@ namespace :test do "#{File.dirname(__FILE__)}/../actionpack/lib", "#{File.dirname(__FILE__)}/../activemodel/lib" ] - ruby "-I#{dash_i.join ':'}", file + ruby "-w", "-I#{dash_i.join ':'}", file end end end @@ -32,15 +31,6 @@ Rake::TestTask.new('test:regular') do |t| t.verbose = true end -# Update spinoffs ------------------------------------------------------------------- - -desc "Updates application README to the latest version Railties README" -task :update_readme do - readme = "lib/rails/generators/rails/app/templates/README" - rm readme - cp "./README.rdoc", readme -end - # Generate GEM ---------------------------------------------------------------------------- spec = eval(File.read('railties.gemspec')) @@ -51,7 +41,7 @@ end # Publishing ------------------------------------------------------- -desc "Release to gemcutter" +desc "Release to rubygems" task :release => :package do require 'rake/gemcutter' Rake::Gemcutter::Tasks.new(spec).define diff --git a/railties/bin/rails b/railties/bin/rails index a1c4faaa73..c11d65a08e 100755 --- a/railties/bin/rails +++ b/railties/bin/rails @@ -1,6 +1,8 @@ #!/usr/bin/env ruby -if File.exists?(File.join(File.expand_path('../../..', __FILE__), '.git')) +git_path = File.join(File.expand_path('../../..', __FILE__), '.git') + +if File.exist?(git_path) railties_path = File.expand_path('../../lib', __FILE__) $:.unshift(railties_path) end diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index dd51a6fb01..ea82327365 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -3,12 +3,13 @@ require 'rails/ruby_version_check' require 'pathname' require 'active_support' +require 'active_support/dependencies/autoload' require 'active_support/core_ext/kernel/reporting' +require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/array/extract_options' require 'rails/application' require 'rails/version' -require 'rails/deprecation' require 'active_support/railtie' require 'action_dispatch/railtie' @@ -20,58 +21,22 @@ silence_warnings do end module Rails - autoload :Info, 'rails/info' - autoload :InfoController, 'rails/info_controller' + extend ActiveSupport::Autoload + + autoload :Info + autoload :InfoController + autoload :WelcomeController class << self - def application - @application ||= nil - end + attr_accessor :application, :cache, :logger - def application=(application) - @application = application - end + delegate :initialize!, :initialized?, to: :application # The Configuration instance used to configure the Rails environment def configuration application.config end - # Rails.queue is the application's queue. You can push a job onto - # the queue by: - # - # Rails.queue.push job - # - # A job is an object that responds to +run+. Queue consumers will - # pop jobs off of the queue and invoke the queue's +run+ method. - # - # Note that depending on your queue implementation, jobs may not - # be executed in the same process as they were created in, and - # are never executed in the same thread as they were created in. - # - # If necessary, a queue implementation may need to serialize your - # job for distribution to another process. The documentation of - # your queue will specify the requirements for that serialization. - def queue - application.queue - end - - def initialize! - application.initialize! - end - - def initialized? - application.initialized? - end - - def logger - @logger ||= nil - end - - def logger=(logger) - @logger = logger - end - def backtrace_cleaner @backtrace_cleaner ||= begin # Relies on Active Support, so we have to lazy load to postpone definition until AS has been loaded @@ -92,14 +57,6 @@ module Rails @_env = ActiveSupport::StringInquirer.new(environment) end - def cache - @cache ||= nil - end - - def cache=(cache) - @cache = cache - end - # Returns all rails groups for loading based on: # # * The Rails environment; @@ -116,7 +73,7 @@ module Rails env = Rails.env groups.unshift(:default, env) groups.concat ENV["RAILS_GROUPS"].to_s.split(",") - groups.concat hash.map { |k,v| k if v.map(&:to_s).include?(env) } + groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) } groups.compact! groups.uniq! groups diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb index eabe566829..2e83c0fe14 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -3,9 +3,10 @@ require "rails" %w( active_record action_controller + action_view action_mailer rails/test_unit - sprockets/rails + sprockets ).each do |framework| begin require "#{framework}/railtie" diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb new file mode 100644 index 0000000000..3e32576040 --- /dev/null +++ b/railties/lib/rails/api/task.rb @@ -0,0 +1,163 @@ +require 'rdoc/task' + +module Rails + module API + class Task < RDoc::Task + RDOC_FILES = { + 'activesupport' => { + :include => %w( + README.rdoc + lib/active_support/**/*.rb + ), + :exclude => 'lib/active_support/vendor/*' + }, + + 'activerecord' => { + :include => %w( + README.rdoc + lib/active_record/**/*.rb + ) + }, + + 'activemodel' => { + :include => %w( + README.rdoc + lib/active_model/**/*.rb + ) + }, + + 'actionpack' => { + :include => %w( + README.rdoc + lib/abstract_controller/**/*.rb + lib/action_controller/**/*.rb + lib/action_dispatch/**/*.rb + ) + }, + + 'actionview' => { + :include => %w( + README.rdoc + lib/action_view/**/*.rb + ), + :exclude => 'lib/action_view/vendor/*' + }, + + 'actionmailer' => { + :include => %w( + README.rdoc + lib/action_mailer/**/*.rb + ) + }, + + 'railties' => { + :include => %w( + README.rdoc + lib/**/*.rb + ), + :exclude => 'lib/rails/generators/rails/**/templates/**/*.rb' + } + } + + def initialize(name) + super + + # Every time rake runs this task is instantiated as all the rest. + # Be lazy computing stuff to have as light impact as possible to + # the rest of tasks. + before_running_rdoc do + load_and_configure_sdoc + configure_rdoc_files + setup_horo_variables + end + end + + # Hack, ignore the desc calls performed by the original initializer. + def desc(description) + # no-op + end + + def load_and_configure_sdoc + require 'sdoc' + + self.title = 'Ruby on Rails API' + self.rdoc_dir = api_dir + + options << '-m' << api_main + options << '-e' << 'UTF-8' + + options << '-f' << 'sdoc' + options << '-T' << 'rails' + rescue LoadError + $stderr.puts %(Unable to load SDoc, please add\n\n gem 'sdoc', require: false\n\nto the Gemfile.) + exit 1 + end + + def configure_rdoc_files + rdoc_files.include(api_main) + + RDOC_FILES.each do |component, cfg| + cdr = component_root_dir(component) + + Array(cfg[:include]).each do |pattern| + rdoc_files.include("#{cdr}/#{pattern}") + end + + Array(cfg[:exclude]).each do |pattern| + rdoc_files.exclude("#{cdr}/#{pattern}") + end + end + end + + def setup_horo_variables + ENV['HORO_PROJECT_NAME'] = 'Ruby on Rails' + ENV['HORO_PROJECT_VERSION'] = rails_version + end + + def api_main + component_root_dir('railties') + '/RDOC_MAIN.rdoc' + end + end + + class RepoTask < Task + def load_and_configure_sdoc + super + options << '-g' # link to GitHub, SDoc flag + end + + def component_root_dir(component) + component + end + + def api_dir + 'doc/rdoc' + end + end + + class EdgeTask < RepoTask + def rails_version + "master@#{`git rev-parse HEAD`[0, 7]}" + end + end + + class StableTask < RepoTask + def rails_version + File.read('RAILS_VERSION').strip + end + end + + class AppTask < Task + def component_root_dir(gem_name) + $:.grep(%r{#{gem_name}[\w.-]*/lib\z}).first[0..-5] + end + + def api_dir + 'doc/api' + end + + def rails_version + Rails::VERSION::STRING + end + end + end +end diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb new file mode 100644 index 0000000000..1610751844 --- /dev/null +++ b/railties/lib/rails/app_rails_loader.rb @@ -0,0 +1,61 @@ +require 'pathname' + +module Rails + module AppRailsLoader + RUBY = Gem.ruby + EXECUTABLES = ['bin/rails', 'script/rails'] + BUNDLER_WARNING = <<EOS +Looks like your app's ./bin/rails is a stub that was generated by Bundler. + +In Rails 4, your app's bin/ directory contains executables that are versioned +like any other source code, rather than stubs that are generated on demand. + +Here's how to upgrade: + + bundle config --delete bin # Turn off Bundler's stub generator + rake rails:update:bin # Use the new Rails 4 executables + git add bin # Add bin/ to source control + +You may need to remove bin/ from your .gitignore as well. + +When you install a gem whose executable you want to use in your app, +generate it and add it to source control: + + bundle binstubs some-gem-name + git add bin/new-executable + +EOS + + def self.exec_app_rails + original_cwd = Dir.pwd + + loop do + if exe = find_executable + contents = File.read(exe) + + if contents =~ /(APP|ENGINE)_PATH/ + exec RUBY, exe, *ARGV + break # non reachable, hack to be able to stub exec in the test suite + elsif exe.end_with?('bin/rails') && contents.include?('This file was generated by Bundler') + $stderr.puts(BUNDLER_WARNING) + Object.const_set(:APP_PATH, File.expand_path('config/application', Dir.pwd)) + require File.expand_path('../boot', APP_PATH) + require 'rails/commands' + break + end + end + + # If we exhaust the search there is no executable, this could be a + # call to generate a new application, so restore the original cwd. + Dir.chdir(original_cwd) and return if Pathname.new(Dir.pwd).root? + + # Otherwise keep moving upwards in search of an executable. + Dir.chdir('..') + end + end + + def self.find_executable + EXECUTABLES.find { |exe| File.exist?(exe) } + end + end +end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index eff5bbbdd6..d1e88cfafd 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,5 +1,6 @@ require 'fileutils' -require 'active_support/queueing' +require 'active_support/core_ext/object/blank' +require 'active_support/key_generator' require 'rails/engine' module Rails @@ -45,43 +46,84 @@ module Rails # 6) Run config.before_initialize callbacks # 7) Run Railtie#initializer defined by railties, engines and application. # One by one, each engine sets up its load paths, routes and runs its config/initializers/* files. - # 9) Custom Railtie#initializers added by railties, engines and applications are executed - # 10) Build the middleware stack and run to_prepare callbacks - # 11) Run config.before_eager_load and eager_load! if eager_load is true - # 12) Run config.after_initialize callbacks + # 8) Custom Railtie#initializers added by railties, engines and applications are executed + # 9) Build the middleware stack and run to_prepare callbacks + # 10) Run config.before_eager_load and eager_load! if eager_load is true + # 11) Run config.after_initialize callbacks # + # == Multiple Applications + # + # If you decide to define multiple applications, then the first application + # that is initialized will be set to +Rails.application+, unless you override + # it with a different application. + # + # To create a new application, you can instantiate a new instance of a class + # that has already been created: + # + # class Application < Rails::Application + # end + # + # first_application = Application.new + # second_application = Application.new(config: first_application.config) + # + # In the above example, the configuration from the first application was used + # to initialize the second application. You can also use the +initialize_copy+ + # on one of the applications to create a copy of the application which shares + # the configuration. + # + # If you decide to define rake tasks, runners, or initializers in an + # application other than +Rails.application+, then you must run those + # these manually. class Application < Engine - autoload :Bootstrap, 'rails/application/bootstrap' - autoload :Configuration, 'rails/application/configuration' - autoload :Finisher, 'rails/application/finisher' - autoload :RoutesReloader, 'rails/application/routes_reloader' + autoload :Bootstrap, 'rails/application/bootstrap' + autoload :Configuration, 'rails/application/configuration' + autoload :DefaultMiddlewareStack, 'rails/application/default_middleware_stack' + autoload :Finisher, 'rails/application/finisher' + autoload :Railties, 'rails/engine/railties' + autoload :RoutesReloader, 'rails/application/routes_reloader' class << self def inherited(base) - raise "You cannot have more than one Rails::Application" if Rails.application super - Rails.application = base.instance - Rails.application.add_lib_to_load_path! - ActiveSupport.run_load_hooks(:before_configuration, base.instance) + Rails.application ||= base.instance end + + # Makes the +new+ method public. + # + # Note that Rails::Application inherits from Rails::Engine, which + # inherits from Rails::Railtie and the +new+ method on Rails::Railtie is + # private + public :new end - attr_accessor :assets, :sandbox, :queue_consumer + attr_accessor :assets, :sandbox alias_method :sandbox?, :sandbox attr_reader :reloaders - attr_writer :queue delegate :default_url_options, :default_url_options=, to: :routes - def initialize - super + INITIAL_VARIABLES = [:config, :railties, :routes_reloader, :reloaders, + :routes, :helpers, :app_env_config] # :nodoc: + + def initialize(initial_variable_values = {}, &block) + super() @initialized = false @reloaders = [] @routes_reloader = nil - @env_config = nil + @app_env_config = nil @ordered_railties = nil @railties = nil - @queue = nil + + add_lib_to_load_path! + ActiveSupport.run_load_hooks(:before_configuration, self) + + initial_variable_values.each do |variable_name, value| + if INITIAL_VARIABLES.include?(variable_name) + instance_variable_set("@#{variable_name}", value) + end + end + + instance_eval(&block) if block_given? end # Returns true if the application is initialized. @@ -93,6 +135,7 @@ module Rails # dispatches the request to the underlying middleware stack. def call(env) env["ORIGINAL_FULLPATH"] = build_original_fullpath(env) + env["ORIGINAL_SCRIPT_NAME"] = env["SCRIPT_NAME"] super(env) end @@ -101,37 +144,66 @@ module Rails routes_reloader.reload! end - # Return the application's KeyGenerator def key_generator # number of iterations selected based on consultation with the google security # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 - @key_generator ||= ActiveSupport::KeyGenerator.new(config.secret_token, iterations: 1000) + @caching_key_generator ||= begin + if config.secret_key_base + key_generator = ActiveSupport::KeyGenerator.new(config.secret_key_base, iterations: 1000) + ActiveSupport::CachingKeyGenerator.new(key_generator) + else + ActiveSupport::LegacyKeyGenerator.new(config.secret_token) + end + end end # Stores some of the Rails initial environment parameters which # will be used by middlewares and engines to configure themselves. - # Currently stores: - # - # * "action_dispatch.parameter_filter" => config.filter_parameters, - # * "action_dispatch.secret_token" => config.secret_token, - # * "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, - # * "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, - # * "action_dispatch.logger" => Rails.logger, - # * "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner - # - # These parameters will be used by middlewares and engines to configure themselves - # def env_config - @env_config ||= super.merge({ - "action_dispatch.parameter_filter" => config.filter_parameters, - "action_dispatch.secret_token" => config.secret_token, - "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, - "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, - "action_dispatch.logger" => Rails.logger, - "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner, - "action_dispatch.key_generator" => key_generator - }) + @app_env_config ||= begin + validate_secret_key_config! + + super.merge({ + "action_dispatch.parameter_filter" => config.filter_parameters, + "action_dispatch.redirect_filter" => config.filter_redirect, + "action_dispatch.secret_token" => config.secret_token, + "action_dispatch.secret_key_base" => config.secret_key_base, + "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, + "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, + "action_dispatch.logger" => Rails.logger, + "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner, + "action_dispatch.key_generator" => key_generator, + "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt, + "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, + "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, + "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt + }) + end + end + + # If you try to define a set of rake tasks on the instance, these will get + # passed up to the rake tasks defined on the application's class. + def rake_tasks(&block) + self.class.rake_tasks(&block) + end + + # Sends the initializers to the +initializer+ method defined in the + # Rails::Initializable module. Each Rails::Application class has its own + # set of initializers, as defined by the Initializable module. + def initializer(name, opts={}, &block) + self.class.initializer(name, opts, &block) + end + + # Sends any runner called in the instance of a new application up + # to the +runner+ method defined in Rails::Railtie. + def runner(&blk) + self.class.runner(&blk) + end + + # Sends the +isolate_namespace+ method up to the class method. + def isolate_namespace(mod) + self.class.isolate_namespace(mod) end ## Rails internal API @@ -151,7 +223,9 @@ module Rails # you need to load files in lib/ during the application configuration as well. def add_lib_to_load_path! #:nodoc: path = File.join config.root, 'lib' - $LOAD_PATH.unshift(path) if File.exists?(path) + if File.exist?(path) && !$LOAD_PATH.include?(path) + $LOAD_PATH.unshift(path) + end end def require_environment! #:nodoc: @@ -177,9 +251,7 @@ module Rails end # Initialize the application passing the given group. By default, the - # group is :default but sprockets precompilation passes group equals - # to assets if initialize_on_precompile is false to avoid booting the - # whole app. + # group is :default def initialize!(group=:default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @@ -197,8 +269,8 @@ module Rails @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) end - def queue #:nodoc: - @queue ||= config.queue || ActiveSupport::Queue.new + def config=(configuration) #:nodoc: + @config = configuration end def to_app #:nodoc: @@ -209,11 +281,6 @@ module Rails config.helpers_paths end - def railties #:nodoc: - @railties ||= Rails::Railtie.subclasses.map(&:instance) + - Rails::Engine.subclasses.map(&:instance) - end - protected alias :build_middleware_stack :app @@ -222,9 +289,9 @@ module Rails railties.each { |r| r.run_tasks_blocks(app) } super require "rails/tasks" - config = self.config task :environment do - config.eager_load = false + ActiveSupport.on_load(:before_initialize) { config.eager_load = false } + require_environment! end end @@ -279,78 +346,9 @@ module Rails initializers end - def reload_dependencies? #:nodoc: - config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any? - end - def default_middleware_stack #:nodoc: - ActionDispatch::MiddlewareStack.new.tap do |middleware| - app = self - if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache - begin - require 'rack/cache' - rescue LoadError => error - error.message << ' Be sure to add rack-cache to your Gemfile' - raise - end - - if rack_cache == true - rack_cache = { - metastore: "rails:/", - entitystore: "rails:/", - verbose: false - } - end - - require "action_dispatch/http/rack_cache" - middleware.use ::Rack::Cache, rack_cache - end - - if config.force_ssl - middleware.use ::ActionDispatch::SSL, config.ssl_options - end - - if config.action_dispatch.x_sendfile_header.present? - middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header - end - - if config.serve_static_assets - middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control - end - - middleware.use ::Rack::Lock unless config.cache_classes - middleware.use ::Rack::Runtime - middleware.use ::Rack::MethodOverride - middleware.use ::ActionDispatch::RequestId - middleware.use ::Rails::Rack::Logger, config.log_tags # must come after Rack::MethodOverride to properly log overridden methods - middleware.use ::ActionDispatch::ShowExceptions, config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) - middleware.use ::ActionDispatch::DebugExceptions, app - middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - - unless config.cache_classes - middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? } - end - - middleware.use ::ActionDispatch::Callbacks - middleware.use ::ActionDispatch::Cookies - - if config.session_store - if config.force_ssl && !config.session_options.key?(:secure) - config.session_options[:secure] = true - end - middleware.use config.session_store, config.session_options - middleware.use ::ActionDispatch::Flash - end - - middleware.use ::ActionDispatch::ParamsParser - middleware.use ::Rack::Head - middleware.use ::Rack::ConditionalGet - middleware.use ::Rack::ETag, "no-cache" - - if config.action_dispatch.best_standards_support - middleware.use ::ActionDispatch::BestStandardsSupport, config.action_dispatch.best_standards_support - end - end + default_stack = DefaultMiddlewareStack.new(self, config, paths) + default_stack.build_stack end def build_original_fullpath(env) #:nodoc: @@ -364,5 +362,11 @@ module Rails "#{script_name}#{path_info}" end end + + def validate_secret_key_config! #:nodoc: + if config.secret_key_base.blank? && config.secret_token.blank? + raise "You must set config.secret_key_base in your app's config." + end + end end end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 62d57c0cc6..a26d41c0cf 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -42,7 +42,6 @@ INFO logger = ActiveSupport::Logger.new f logger.formatter = config.log_formatter logger = ActiveSupport::TaggedLogging.new(logger) - logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase) logger rescue StandardError logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR)) @@ -53,6 +52,8 @@ INFO ) logger end + + Rails.logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase) end # Initialize cache early in the stack so railties can make use of it. diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index c3e75a643b..dd0b9c6d70 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,19 +1,18 @@ require 'active_support/core_ext/kernel/reporting' require 'active_support/file_update_checker' -require 'active_support/queueing' require 'rails/engine/configuration' module Rails class Application class Configuration < ::Rails::Engine::Configuration - attr_accessor :asset_host, :asset_path, :assets, :autoflush_log, + attr_accessor :allow_concurrency, :asset_host, :assets, :autoflush_log, :cache_classes, :cache_store, :consider_all_requests_local, :console, :eager_load, :exceptions_app, :file_watcher, :filter_parameters, :force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags, - :railties_order, :relative_url_root, :secret_token, + :railties_order, :relative_url_root, :secret_key_base, :secret_token, :serve_static_assets, :ssl_options, :static_cache_control, :session_options, :time_zone, :reload_classes_only_on_change, - :queue, :queue_consumer, :beginning_of_week + :beginning_of_week, :filter_redirect attr_writer :log_level attr_reader :encoding @@ -21,8 +20,10 @@ module Rails def initialize(*) super self.encoding = "utf-8" + @allow_concurrency = nil @consider_all_requests_local = false @filter_parameters = [] + @filter_redirect = [] @helpers_paths = [] @serve_static_assets = true @static_cache_control = nil @@ -43,31 +44,26 @@ module Rails @exceptions_app = nil @autoflush_log = true @log_formatter = ActiveSupport::Logger::SimpleFormatter.new - @queue = ActiveSupport::SynchronousQueue.new - @queue_consumer = nil @eager_load = nil + @secret_token = nil + @secret_key_base = nil @assets = ActiveSupport::OrderedOptions.new - @assets.enabled = false + @assets.enabled = true @assets.paths = [] - @assets.precompile = [ Proc.new { |path| !%w(.js .css).include?(File.extname(path)) }, + @assets.precompile = [ Proc.new { |path, fn| fn =~ /app\/assets/ && !%w(.js .css).include?(File.extname(path)) }, /(?:\/|\\|\A)application\.(css|js)$/ ] @assets.prefix = "/assets" - @assets.version = '' + @assets.version = '1.0' @assets.debug = false @assets.compile = true @assets.digest = false @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/#{Rails.env}/" ] @assets.js_compressor = nil @assets.css_compressor = nil - @assets.initialize_on_precompile = true @assets.logger = nil end - def compiled_asset_path - "/" - end - def encoding=(value) @encoding = value silence_warnings do @@ -91,21 +87,21 @@ module Rails end end - def threadsafe! - ActiveSupport::Deprecation.warn "config.threadsafe! is deprecated. Rails applications " \ - "behave by default as thread safe in production as long as config.cache_classes and " \ - "config.eager_load are set to true" - @cache_classes = true - @eager_load = true - self - end - - # Loads and returns the contents of the #database_configuration_file. The - # contents of the file are processed via ERB before being sent through - # YAML::load. + # Loads and returns the configuration of the database. def database_configuration - require 'erb' - YAML.load ERB.new(IO.read(paths["config/database"].first)).result + yaml = paths["config/database"].first + if File.exist?(yaml) + require "erb" + YAML.load ERB.new(IO.read(yaml)).result + elsif ENV['DATABASE_URL'] + nil + else + raise "Could not load database configuration. No such file - #{yaml}" + end + rescue Psych::SyntaxError => e + raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \ + "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ + "Error: #{e.message}" end def log_level @@ -144,10 +140,6 @@ module Rails end end - def whiny_nils=(*) - ActiveSupport::Deprecation.warn "config.whiny_nils option " \ - "is deprecated and no longer works", caller - end end end end diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb new file mode 100644 index 0000000000..570ff02c83 --- /dev/null +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -0,0 +1,99 @@ +module Rails + class Application + class DefaultMiddlewareStack + attr_reader :config, :paths, :app + + def initialize(app, config, paths) + @app = app + @config = config + @paths = paths + end + + def build_stack + ActionDispatch::MiddlewareStack.new.tap do |middleware| + if rack_cache = load_rack_cache + require "action_dispatch/http/rack_cache" + middleware.use ::Rack::Cache, rack_cache + end + + if config.force_ssl + middleware.use ::ActionDispatch::SSL, config.ssl_options + end + + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + + if config.serve_static_assets + middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control + end + + middleware.use ::Rack::Lock unless allow_concurrency? + middleware.use ::Rack::Runtime + middleware.use ::Rack::MethodOverride + middleware.use ::ActionDispatch::RequestId + + # Must come after Rack::MethodOverride to properly log overridden methods + middleware.use ::Rails::Rack::Logger, config.log_tags + middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app + middleware.use ::ActionDispatch::DebugExceptions, app + middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies + + unless config.cache_classes + middleware.use ::ActionDispatch::Reloader, lambda { reload_dependencies? } + end + + middleware.use ::ActionDispatch::Callbacks + middleware.use ::ActionDispatch::Cookies + + if config.session_store + if config.force_ssl && !config.session_options.key?(:secure) + config.session_options[:secure] = true + end + middleware.use config.session_store, config.session_options + middleware.use ::ActionDispatch::Flash + end + + middleware.use ::ActionDispatch::ParamsParser + middleware.use ::Rack::Head + middleware.use ::Rack::ConditionalGet + middleware.use ::Rack::ETag, "no-cache" + end + end + + private + + def reload_dependencies? + config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any? + end + + def allow_concurrency? + config.allow_concurrency.nil? ? config.cache_classes : config.allow_concurrency + end + + def load_rack_cache + rack_cache = config.action_dispatch.rack_cache + return unless rack_cache + + begin + require 'rack/cache' + rescue LoadError => error + error.message << ' Be sure to add rack-cache to your Gemfile' + raise + end + + if rack_cache == true + { + metastore: "rails:/", + entitystore: "rails:/", + verbose: false + } + else + rack_cache + end + end + + def show_exceptions_app + config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) + end + end + end +end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index c520f7af9d..7a1bb1e25c 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -25,6 +25,7 @@ module Rails get '/rails/info/properties' => "rails/info#properties" get '/rails/info/routes' => "rails/info#routes" get '/rails/info' => "rails/info#index" + get '/' => "rails/welcome#index" end end end @@ -61,17 +62,28 @@ module Rails ActiveSupport.run_load_hooks(:after_initialize, self) end - # Set app reload just after the finisher hook to ensure - # routes added in the hook are still loaded. + # Set routes reload after the finisher hook to ensure routes added in + # the hook are taken into account. initializer :set_routes_reloader_hook do reloader = routes_reloader reloader.execute_if_updated self.reloaders << reloader - ActionDispatch::Reloader.to_prepare { reloader.execute_if_updated } + ActionDispatch::Reloader.to_prepare do + # We configure #execute rather than #execute_if_updated because if + # autoloaded constants are cleared we need to reload routes also in + # case any was used there, as in + # + # mount MailPreview => 'mail_view' + # + # This means routes are also reloaded if i18n is updated, which + # might not be necessary, but in order to be more precise we need + # some sort of reloaders dependency support, to be added. + reloader.execute + end end - # Set app reload just after the finisher hook to ensure - # paths added in the hook are still loaded. + # Set clearing dependencies after the finisher hook to ensure paths + # added in the hook are taken into account. initializer :set_clear_dependencies_hook, group: :all do callback = lambda do ActiveSupport::DescendantsTracker.clear @@ -81,28 +93,21 @@ module Rails if config.reload_classes_only_on_change reloader = config.file_watcher.new(*watchable_args, &callback) self.reloaders << reloader - # We need to set a to_prepare callback regardless of the reloader result, i.e. - # models should be reloaded if any of the reloaders (i18n, routes) were updated. - ActionDispatch::Reloader.to_prepare(prepend: true){ reloader.execute } + + # Prepend this callback to have autoloaded constants cleared before + # any other possible reloading, in case they need to autoload fresh + # constants. + ActionDispatch::Reloader.to_prepare(prepend: true) do + # In addition to changes detected by the file watcher, if routes + # or i18n have been updated we also need to clear constants, + # that's why we run #execute rather than #execute_if_updated, this + # callback has to clear autoloaded constants after any update. + reloader.execute + end else ActionDispatch::Reloader.to_cleanup(&callback) end end - - # Disable dependency loading during request cycle - initializer :disable_dependency_loading do - if config.eager_load && config.cache_classes - ActiveSupport::Dependencies.unhook! - end - end - - initializer :activate_queue_consumer do |app| - if config.queue.class == ActiveSupport::Queue - app.queue_consumer = config.queue_consumer || config.queue.consumer - app.queue_consumer.start - at_exit { app.queue_consumer.shutdown } - end - end end end end diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index 443d6f47ad..dd70c272c6 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -1,16 +1,15 @@ -require 'rbconfig' -require 'rails/script_rails_loader' +require 'rails/app_rails_loader' # If we are inside a Rails application this method performs an exec and thus # the rest of this script is not run. -Rails::ScriptRailsLoader.exec_script_rails! +Rails::AppRailsLoader.exec_app_rails require 'rails/ruby_version_check' Signal.trap("INT") { puts; exit(1) } if ARGV.first == 'plugin' ARGV.shift - require 'rails/commands/plugin_new' + require 'rails/commands/plugin' else require 'rails/commands/application' end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index 1aed2796c1..0ae6d2a455 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -1,6 +1,14 @@ +require 'rails/code_statistics_calculator' + class CodeStatistics #:nodoc: - TEST_TYPES = %w(Units Functionals Unit\ tests Functional\ tests Integration\ tests) + TEST_TYPES = ['Controller tests', + 'Helper tests', + 'Model tests', + 'Mailer tests', + 'Integration tests', + 'Functional tests (old)', + 'Unit tests (old)'] def initialize(*pairs) @pairs = pairs @@ -27,64 +35,38 @@ class CodeStatistics #:nodoc: end def calculate_directory_statistics(directory, pattern = /.*\.(rb|js|coffee)$/) - stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 } + stats = CodeStatisticsCalculator.new Dir.foreach(directory) do |file_name| - if File.directory?(directory + "/" + file_name) and (/^\./ !~ file_name) - newstats = calculate_directory_statistics(directory + "/" + file_name, pattern) - stats.each { |k, v| stats[k] += newstats[k] } + path = "#{directory}/#{file_name}" + + if File.directory?(path) && (/^\./ !~ file_name) + stats.add(calculate_directory_statistics(path, pattern)) end next unless file_name =~ pattern - comment_started = false - - case file_name - when /.*\.js$/ - comment_pattern = /^\s*\/\// - else - comment_pattern = /^\s*#/ - end - - File.open(directory + "/" + file_name) do |f| - while line = f.gets - stats["lines"] += 1 - if(comment_started) - if line =~ /^=end/ - comment_started = false - end - next - else - if line =~ /^=begin/ - comment_started = true - next - end - end - stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/ - stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/ - stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ comment_pattern - end - end + stats.add_by_file_path(path) end stats end def calculate_total - total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 } - @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } } - total + @statistics.each_with_object(CodeStatisticsCalculator.new) do |pair, total| + total.add(pair.last) + end end def calculate_code code_loc = 0 - @statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k } + @statistics.each { |k, v| code_loc += v.code_lines unless TEST_TYPES.include? k } code_loc end def calculate_tests test_loc = 0 - @statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k } + @statistics.each { |k, v| test_loc += v.code_lines if TEST_TYPES.include? k } test_loc end @@ -99,15 +81,15 @@ class CodeStatistics #:nodoc: end def print_line(name, statistics) - m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0 - loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0 - - puts "| #{name.ljust(20)} " + - "| #{statistics["lines"].to_s.rjust(5)} " + - "| #{statistics["codelines"].to_s.rjust(5)} " + - "| #{statistics["classes"].to_s.rjust(7)} " + - "| #{statistics["methods"].to_s.rjust(7)} " + - "| #{m_over_c.to_s.rjust(3)} " + + m_over_c = (statistics.methods / statistics.classes) rescue m_over_c = 0 + loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue loc_over_m = 0 + + puts "| #{name.ljust(20)} " \ + "| #{statistics.lines.to_s.rjust(5)} " \ + "| #{statistics.code_lines.to_s.rjust(5)} " \ + "| #{statistics.classes.to_s.rjust(7)} " \ + "| #{statistics.methods.to_s.rjust(7)} " \ + "| #{m_over_c.to_s.rjust(3)} " \ "| #{loc_over_m.to_s.rjust(5)} |" end diff --git a/railties/lib/rails/code_statistics_calculator.rb b/railties/lib/rails/code_statistics_calculator.rb new file mode 100644 index 0000000000..60e4aef9b7 --- /dev/null +++ b/railties/lib/rails/code_statistics_calculator.rb @@ -0,0 +1,79 @@ +class CodeStatisticsCalculator #:nodoc: + attr_reader :lines, :code_lines, :classes, :methods + + PATTERNS = { + rb: { + line_comment: /^\s*#/, + begin_block_comment: /^=begin/, + end_block_comment: /^=end/, + class: /^\s*class\s+[_A-Z]/, + method: /^\s*def\s+[_a-z]/, + }, + js: { + line_comment: %r{^\s*//}, + begin_block_comment: %r{^\s*/\*}, + end_block_comment: %r{\*/}, + method: /function(\s+[_a-zA-Z][\da-zA-Z]*)?\s*\(/, + }, + coffee: { + line_comment: /^\s*#/, + begin_block_comment: /^\s*###/, + end_block_comment: /^\s*###/, + class: /^\s*class\s+[_A-Z]/, + method: /[-=]>/, + } + } + + def initialize(lines = 0, code_lines = 0, classes = 0, methods = 0) + @lines = lines + @code_lines = code_lines + @classes = classes + @methods = methods + end + + def add(code_statistics_calculator) + @lines += code_statistics_calculator.lines + @code_lines += code_statistics_calculator.code_lines + @classes += code_statistics_calculator.classes + @methods += code_statistics_calculator.methods + end + + def add_by_file_path(file_path) + File.open(file_path) do |f| + self.add_by_io(f, file_type(file_path)) + end + end + + def add_by_io(io, file_type) + patterns = PATTERNS[file_type] || {} + + comment_started = false + + while line = io.gets + @lines += 1 + + if comment_started + if patterns[:end_block_comment] && line =~ patterns[:end_block_comment] + comment_started = false + end + next + else + if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment] + comment_started = true + next + end + end + + @classes += 1 if patterns[:class] && line =~ patterns[:class] + @methods += 1 if patterns[:method] && line =~ patterns[:method] + if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment]) + @code_lines += 1 + end + end + end + + private + def file_type(file_path) + File.extname(file_path).sub(/\A\./, '').downcase.to_sym + end +end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index b0fae13192..f32bf772a5 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -9,110 +9,9 @@ aliases = { "r" => "runner" } -help_message = <<-EOT -Usage: rails COMMAND [ARGS] - -The most common rails commands are: - generate Generate new code (short-cut alias: "g") - console Start the Rails console (short-cut alias: "c") - server Start the Rails server (short-cut alias: "s") - dbconsole Start a console for the database specified in config/database.yml - (short-cut alias: "db") - new Create a new Rails application. "rails new my_app" creates a - new application called MyApp in "./my_app" - -In addition to those, there are: - application Generate the Rails application code - destroy Undo code generated with "generate" (short-cut alias: "d") - benchmarker See how fast a piece of code runs - profiler Get profile information from a piece of code - plugin new Generates skeleton for developing a Rails plugin - runner Run a piece of code in the application environment (short-cut alias: "r") - -All commands can be run with -h (or --help) for more information. -EOT - - command = ARGV.shift command = aliases[command] || command -case command -when 'generate', 'destroy', 'plugin' - require 'rails/generators' - - if command == 'plugin' && ARGV.first == 'new' - require "rails/commands/plugin_new" - else - require APP_PATH - Rails.application.require_environment! - - Rails.application.load_generators - - require "rails/commands/#{command}" - end - -when 'benchmarker', 'profiler' - require APP_PATH - Rails.application.require_environment! - require "rails/commands/#{command}" - -when 'console' - require 'rails/commands/console' - options = Rails::Console.parse_arguments(ARGV) - - # RAILS_ENV needs to be set before config/application is required - ENV['RAILS_ENV'] = options[:environment] if options[:environment] - - # shift ARGV so IRB doesn't freak - ARGV.shift if ARGV.first && ARGV.first[0] != '-' - - require APP_PATH - Rails.application.require_environment! - Rails::Console.start(Rails.application, options) - -when 'server' - # Change to the application's path if there is no config.ru file in current dir. - # This allows us to run script/rails server from other directories, but still get - # the main config.ru and properly set the tmp directory. - Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru")) - - require 'rails/commands/server' - Rails::Server.new.tap { |server| - # We need to require application after the server sets environment, - # otherwise the --environment option given to the server won't propagate. - require APP_PATH - Dir.chdir(Rails.application.root) - server.start - } - -when 'dbconsole' - require 'rails/commands/dbconsole' - Rails::DBConsole.start - -when 'application', 'runner' - require "rails/commands/#{command}" - -when 'new' - if %w(-h --help).include?(ARGV.first) - require 'rails/commands/application' - else - puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" - puts "Type 'rails' for help." - exit(1) - end - -when '--version', '-v' - ARGV.unshift '--version' - require 'rails/commands/application' - -when '-h', '--help' - puts help_message +require 'rails/commands/commands_tasks' -else - puts "Error: Command '#{command}' not recognized" - if %x{rake #{command} --dry-run 2>&1 } && $?.success? - puts "Did you mean: `$ rake #{command}` ?\n\n" - end - puts help_message - exit(1) -end +Rails::CommandsTasks.new(ARGV).run_command!(command) diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index ff0eda3413..c998e6b6a8 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -1,24 +1,3 @@ -require 'rails/version' - -if ['--version', '-v'].include?(ARGV.first) - puts "Rails #{Rails::VERSION::STRING}" - exit(0) -end - -if ARGV.first != "new" - ARGV[0] = "--help" -else - ARGV.shift - railsrc = File.join(File.expand_path("~"), ".railsrc") - if File.exist?(railsrc) - extra_args_string = File.open(railsrc).read - extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten - puts "Using #{extra_args.join(" ")} from #{railsrc}" - ARGV << extra_args - ARGV.flatten! - end -end - require 'rails/generators' require 'rails/generators/rails/app/app_generator' @@ -34,4 +13,5 @@ module Rails end end -Rails::Generators::AppGenerator.start +args = Rails::Generators::ARGVScrubber.new(ARGV).prepare! +Rails::Generators::AppGenerator.start args diff --git a/railties/lib/rails/commands/benchmarker.rb b/railties/lib/rails/commands/benchmarker.rb deleted file mode 100644 index b745b45e17..0000000000 --- a/railties/lib/rails/commands/benchmarker.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'optparse' -require 'rails/test_help' -require 'rails/performance_test_help' - -ARGV.push('--benchmark') # HAX -require 'active_support/testing/performance' -ARGV.pop - -def options - options = {} - defaults = ActiveSupport::Testing::Performance::DEFAULTS - - OptionParser.new do |opt| - opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]" - opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r } - opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o } - opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) } - opt.parse!(ARGV) - end - - options -end - -class BenchmarkerTest < ActionDispatch::PerformanceTest #:nodoc: - self.profile_options = options - - ARGV.each do |expression| - eval <<-RUBY - def test_#{expression.parameterize('_')} - #{expression} - end - RUBY - end -end diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb new file mode 100644 index 0000000000..de60423784 --- /dev/null +++ b/railties/lib/rails/commands/commands_tasks.rb @@ -0,0 +1,174 @@ +module Rails + # This is a class which takes in a rails command and initiates the appropriate + # initiation sequence. + # + # Warning: This class mutates ARGV because some commands require manipulating + # it before they are run. + class CommandsTasks # :nodoc: + attr_reader :argv + + HELP_MESSAGE = <<-EOT +Usage: rails COMMAND [ARGS] + +The most common rails commands are: + generate Generate new code (short-cut alias: "g") + console Start the Rails console (short-cut alias: "c") + server Start the Rails server (short-cut alias: "s") + dbconsole Start a console for the database specified in config/database.yml + (short-cut alias: "db") + new Create a new Rails application. "rails new my_app" creates a + new application called MyApp in "./my_app" + +In addition to those, there are: + application Generate the Rails application code + destroy Undo code generated with "generate" (short-cut alias: "d") + plugin new Generates skeleton for developing a Rails plugin + runner Run a piece of code in the application environment (short-cut alias: "r") + +All commands can be run with -h (or --help) for more information. +EOT + + COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help) + + def initialize(argv) + @argv = argv + end + + def run_command!(command) + command = parse_command(command) + if COMMAND_WHITELIST.include?(command) + send(command) + else + write_error_message(command) + end + end + + def plugin + require_command!("plugin") + end + + def generate + generate_or_destroy(:generate) + end + + def destroy + generate_or_destroy(:destroy) + end + + def console + require_command!("console") + options = Rails::Console.parse_arguments(argv) + + # RAILS_ENV needs to be set before config/application is required + ENV['RAILS_ENV'] = options[:environment] if options[:environment] + + # shift ARGV so IRB doesn't freak + shift_argv! + + require_application_and_environment! + Rails::Console.start(Rails.application, options) + end + + def server + set_application_directory! + require_command!("server") + + Rails::Server.new.tap do |server| + # We need to require application after the server sets environment, + # otherwise the --environment option given to the server won't propagate. + require APP_PATH + Dir.chdir(Rails.application.root) + server.start + end + end + + def dbconsole + require_command!("dbconsole") + Rails::DBConsole.start + end + + def application + require_command!("application") + end + + def runner + require_command!("runner") + end + + def new + if %w(-h --help).include?(argv.first) + require_command!("application") + else + exit_with_initialization_warning! + end + end + + def version + argv.unshift '--version' + require_command!("application") + end + + def help + write_help_message + end + + private + + def exit_with_initialization_warning! + puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" + puts "Type 'rails' for help." + exit(1) + end + + def shift_argv! + argv.shift if argv.first && argv.first[0] != '-' + end + + def require_command!(command) + require "rails/commands/#{command}" + end + + def generate_or_destroy(command) + require 'rails/generators' + require_application_and_environment! + Rails.application.load_generators + require "rails/commands/#{command}" + end + + # Change to the application's path if there is no config.ru file in current directory. + # This allows us to run `rails server` from other directories, but still get + # the main config.ru and properly set the tmp directory. + def set_application_directory! + Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru")) + end + + def require_application_and_environment! + require APP_PATH + Rails.application.require_environment! + end + + def write_help_message + puts HELP_MESSAGE + end + + def write_error_message(command) + puts "Error: Command '#{command}' not recognized" + if %x{rake #{command} --dry-run 2>&1 } && $?.success? + puts "Did you mean: `$ rake #{command}` ?\n\n" + end + write_help_message + exit(1) + end + + def parse_command(command) + case command + when '--version', '-v' + 'version' + when '--help', '-h' + 'help' + else + command + end + end + end +end diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index 92cee6b638..f6bdf129d6 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -24,11 +24,21 @@ module Rails if arguments.first && arguments.first[0] != '-' env = arguments.first - options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + if available_environments.include? env + options[:environment] = env + else + options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + end end options end + + private + + def available_environments + Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') } + end end attr_reader :options, :app, :console @@ -36,7 +46,10 @@ module Rails def initialize(app, options={}) @app = app @options = options + + app.sandbox = sandbox? app.load_console + @console = app.config.console || IRB end @@ -45,7 +58,7 @@ module Rails end def environment - options[:environment] ||= ENV['RAILS_ENV'] || 'development' + options[:environment] ||= ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development' end def environment? @@ -61,7 +74,6 @@ module Rails end def start - app.sandbox = sandbox? require_debugger if debugger? set_environment! if environment? @@ -79,13 +91,11 @@ module Rails end def require_debugger - begin - require 'debugger' - puts "=> Debugger enabled" - rescue Exception - puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again." - exit - end + require 'debugger' + puts "=> Debugger enabled" + rescue LoadError + puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again." + exit(1) end end end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index c84fa832f5..3e4cc787c4 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -5,8 +5,8 @@ require 'rbconfig' module Rails class DBConsole - attr_reader :config, :arguments - + attr_reader :arguments + def self.start new.start end @@ -44,7 +44,7 @@ module Rails find_cmd_and_exec(['mysql', 'mysql5'], *args) - when "postgresql", "postgres" + when "postgresql", "postgres", "postgis" ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] @@ -59,7 +59,7 @@ module Rails args << "-#{options['mode']}" if options['mode'] args << "-header" if options['header'] - args << File.expand_path(config['database'], Rails.root) + args << File.expand_path(config['database'], Rails.respond_to?(:root) ? Rails.root : nil) find_cmd_and_exec('sqlite3', *args) @@ -82,17 +82,13 @@ module Rails def config @config ||= begin cfg = begin - cfg = YAML.load(ERB.new(IO.read("config/database.yml")).result) + YAML.load(ERB.new(IO.read("config/database.yml")).result) rescue SyntaxError, StandardError require APP_PATH Rails.application.config.database_configuration end - unless cfg[environment] - abort "No database is configured for the environment '#{environment}'" - end - - cfg[environment] + cfg[environment] || abort("No database is configured for the environment '#{environment}'") end end @@ -108,7 +104,7 @@ module Rails def parse_arguments(arguments) options = {} - + OptionParser.new do |opt| opt.banner = "Usage: rails dbconsole [environment] [options]" opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v| @@ -123,7 +119,7 @@ module Rails opt.on("--header") do |h| options['header'] = h end - + opt.on("-h", "--help", "Show this help message.") do puts opt exit @@ -140,12 +136,20 @@ module Rails if arguments.first && arguments.first[0] != '-' env = arguments.first - options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + if available_environments.include? env + options[:environment] = env + else + options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env + end end - + options end + def available_environments + Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') } + end + def find_cmd_and_exec(commands, *args) commands = Array(commands) @@ -154,7 +158,7 @@ module Rails full_path_command = nil found = commands.detect do |cmd| - dir = dirs_on_path.detect do |path| + dirs_on_path.detect do |path| full_path_command = File.join(path, cmd) File.executable? full_path_command end diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb new file mode 100644 index 0000000000..837fe0ec10 --- /dev/null +++ b/railties/lib/rails/commands/plugin.rb @@ -0,0 +1,9 @@ +if ARGV.first != "new" + ARGV[0] = "--help" +else + ARGV.shift +end + +require 'rails/generators' +require 'rails/generators/rails/plugin/plugin_generator' +Rails::Generators::PluginGenerator.start diff --git a/railties/lib/rails/commands/plugin_new.rb b/railties/lib/rails/commands/plugin_new.rb deleted file mode 100644 index 4d7bf3c9f3..0000000000 --- a/railties/lib/rails/commands/plugin_new.rb +++ /dev/null @@ -1,9 +0,0 @@ -if ARGV.first != "new" - ARGV[0] = "--help" -else - ARGV.shift -end - -require 'rails/generators' -require 'rails/generators/rails/plugin_new/plugin_new_generator' -Rails::Generators::PluginNewGenerator.start
\ No newline at end of file diff --git a/railties/lib/rails/commands/profiler.rb b/railties/lib/rails/commands/profiler.rb deleted file mode 100644 index 3f6966b4f0..0000000000 --- a/railties/lib/rails/commands/profiler.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'optparse' -require 'rails/test_help' -require 'rails/performance_test_help' -require 'active_support/testing/performance' - -def options - options = {} - defaults = ActiveSupport::Testing::Performance::DEFAULTS - - OptionParser.new do |opt| - opt.banner = "Usage: rails benchmarker 'Ruby.code' 'Ruby.more_code' ... [OPTS]" - opt.on('-r', '--runs N', Numeric, 'Number of runs.', "Default: #{defaults[:runs]}") { |r| options[:runs] = r } - opt.on('-o', '--output PATH', String, 'Directory to use when writing the results.', "Default: #{defaults[:output]}") { |o| options[:output] = o } - opt.on('-m', '--metrics a,b,c', Array, 'Metrics to use.', "Default: #{defaults[:metrics].join(",")}") { |m| options[:metrics] = m.map(&:to_sym) } - opt.on('-f', '--formats x,y,z', Array, 'Formats to output to.', "Default: #{defaults[:formats].join(",")}") { |m| options[:formats] = m.map(&:to_sym) } - opt.parse!(ARGV) - end - - options -end - -class ProfilerTest < ActionDispatch::PerformanceTest #:nodoc: - self.profile_options = options - - ARGV.each do |expression| - eval <<-RUBY - def test_#{expression.parameterize('_')} - #{expression} - end - RUBY - end -end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index 0cc672e01c..2b77d5d387 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -1,7 +1,7 @@ require 'optparse' require 'rbconfig' -options = { environment: (ENV['RAILS_ENV'] || "development").dup } +options = { environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup } code_or_file = nil if ARGV.first.nil? @@ -24,7 +24,7 @@ ARGV.clone.options do |opts| if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ opts.separator "" - opts.separator "You can also use runner as a shebang line for your scripts like this:" + opts.separator "You can also use runner as a shebang line for your executables:" opts.separator "-------------------------------------------------------------" opts.separator "#!/usr/bin/env #{File.expand_path($0)} runner" opts.separator "" @@ -41,14 +41,14 @@ ENV["RAILS_ENV"] = options[:environment] require APP_PATH Rails.application.require_environment! - Rails.application.load_runner +Rails.application.load_runner if code_or_file.nil? $stderr.puts "Run '#{$0} -h' for help." exit 1 elsif File.exist?(code_or_file) $0 = code_or_file - eval(File.read(code_or_file), nil, code_or_file) + Kernel.load code_or_file else eval(code_or_file) end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 80fdc06cd2..4201dac42f 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -1,6 +1,7 @@ require 'fileutils' require 'optparse' require 'action_dispatch' +require 'rails' module Rails class Server < ::Rack::Server @@ -32,7 +33,8 @@ module Rails opt_parser.parse! args - options[:server] = args.shift + options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development" + options[:server] = args.shift options end end @@ -42,8 +44,12 @@ module Rails set_environment end + # TODO: this is no longer required but we keep it for the moment to support older config.ru files. def app - @app ||= super.respond_to?(:to_app) ? super.to_app : super + @app ||= begin + app = super + app.respond_to?(:to_app) ? app.to_app : app + end end def opt_parser @@ -58,7 +64,10 @@ module Rails url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" - puts "=> Call with -d to detach" unless options[:daemonize] + puts "=> Run `rails server -h` for more startup options" + if options[:Host].to_s.match(/0\.0\.0\.0/) + puts "=> Notice: server is listening on all interfaces (#{options[:Host]}). Consider using 127.0.0.1 (--binding option)" + end trap(:INT) { exit } puts "=> Ctrl-C to shutdown server" unless options[:daemonize] @@ -67,11 +76,12 @@ module Rails FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make)) end - unless options[:daemonize] + if options[:log_stdout] wrapped_app # touch the app so the logger is set up console = ActiveSupport::Logger.new($stdout) console.formatter = Rails.logger.formatter + console.level = Rails.logger.level Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end @@ -107,7 +117,7 @@ module Rails super.merge({ Port: 3000, DoNotReverseLookup: true, - environment: (ENV['RAILS_ENV'] || "development").dup, + environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup, daemonize: false, debugger: false, pid: File.expand_path("tmp/pids/server.pid"), diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 5fa7f043c6..f5d7dede66 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,4 +1,3 @@ -require 'active_support/deprecation' require 'active_support/ordered_options' require 'active_support/core_ext/object' require 'rails/paths' @@ -27,11 +26,11 @@ module Rails # # Middlewares can also be completely swapped out and replaced with others: # - # config.middleware.swap ActionDispatch::BestStandardsSupport, Magical::Unicorns + # config.middleware.swap ActionDispatch::Flash, Magical::Unicorns # # And finally they can also be removed from the stack completely: # - # config.middleware.delete ActionDispatch::BestStandardsSupport + # config.middleware.delete ActionDispatch::Flash # class MiddlewareStackProxy def initialize @@ -60,6 +59,10 @@ module Rails @operations << [__method__, args, block] end + def unshift(*args, &block) + @operations << [__method__, args, block] + end + def merge_into(other) #:nodoc: @operations.each do |operation, args, block| other.send(operation, *args, &block) diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb index 230d3d9d04..b775f1ff8d 100644 --- a/railties/lib/rails/console/helpers.rb +++ b/railties/lib/rails/console/helpers.rb @@ -1,9 +1,15 @@ module Rails module ConsoleMethods + # Gets the helper methods available to the controller. + # + # This method assumes an +ApplicationController+ exists, and it extends +ActionController::Base+ def helper @helper ||= ApplicationController.helpers end + # Gets a new instance of a controller object. + # + # This method assumes an +ApplicationController+ exists, and it extends +ActionController::Base+ def controller @controller ||= ApplicationController.new end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 2c2bb1c714..e8adef2fd3 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -1,4 +1,5 @@ require 'rails/railtie' +require 'rails/engine/railties' require 'active_support/core_ext/module/delegation' require 'pathname' require 'rbconfig' @@ -101,12 +102,12 @@ module Rails # paths["config"] # => ["config"] # paths["config/initializers"] # => ["config/initializers"] # paths["config/locales"] # => ["config/locales"] - # paths["config/routes"] # => ["config/routes.rb"] + # paths["config/routes.rb"] # => ["config/routes.rb"] # end # # The <tt>Application</tt> class adds a couple more paths to this set. And as in your # <tt>Application</tt>, all folders under +app+ are automatically added to the load path. - # If you have an <tt>app/observers</tt> folder for example, it will be added by default. + # If you have an <tt>app/services</tt> folder for example, it will be added by default. # # == Endpoint # @@ -123,7 +124,7 @@ module Rails # # Now you can mount your engine in application's routes just like that: # - # MyRailsApp::Application.routes.draw do + # Rails.application.routes.draw do # mount MyEngine::Engine => "/engine" # end # @@ -153,7 +154,7 @@ module Rails # Note that now there can be more than one router in your application, and it's better to avoid # passing requests through many routers. Consider this situation: # - # MyRailsApp::Application.routes.draw do + # Rails.application.routes.draw do # mount MyEngine::Engine => "/blog" # get "/blog/omg" => "main#omg" # end @@ -163,7 +164,7 @@ module Rails # and if there is no such route in +Engine+'s routes, it will be dispatched to <tt>main#omg</tt>. # It's much better to swap that: # - # MyRailsApp::Application.routes.draw do + # Rails.application.routes.draw do # get "/blog/omg" => "main#omg" # mount MyEngine::Engine => "/blog" # end @@ -175,7 +176,7 @@ module Rails # There are some places where an Engine's name is used: # # * routes: when you mount an Engine with <tt>mount(MyEngine::Engine => '/my_engine')</tt>, - # it's used as default :as option + # it's used as default <tt>:as</tt> option # * rake task for installing migrations <tt>my_engine:install:migrations</tt> # # Engine name is set by default based on class name. For <tt>MyEngine::Engine</tt> it will be @@ -250,7 +251,7 @@ module Rails # created to allow you to do that. Consider such a scenario: # # # config/routes.rb - # MyApplication::Application.routes.draw do + # Rails.application.routes.draw do # mount MyEngine::Engine => "/my_engine", as: "my_engine" # get "/foo" => "foo#index" # end @@ -350,8 +351,13 @@ module Rails Rails::Railtie::Configuration.eager_load_namespaces << base base.called_from = begin - # Remove the line number from backtraces making sure we don't leave anything behind - call_stack = caller.map { |p| p.sub(/:\d+.*/, '') } + call_stack = if Kernel.respond_to?(:caller_locations) + caller_locations.map(&:path) + else + # Remove the line number from backtraces making sure we don't leave anything behind + caller.map { |p| p.sub(/:\d+.*/, '') } + end + File.dirname(call_stack.detect { |p| p !~ %r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack] }) end end @@ -408,7 +414,7 @@ module Rails end delegate :middleware, :root, :paths, to: :config - delegate :engine_name, :isolated?, to: "self.class" + delegate :engine_name, :isolated?, to: :class def initialize @_all_autoload_paths = nil @@ -446,7 +452,7 @@ module Rails self end - # Load rails generators and invoke the registered hooks. + # Load Rails generators and invoke the registered hooks. # Check <tt>Rails::Railtie.generators</tt> for more info. def load_generators(app=self) require "rails/generators" @@ -466,6 +472,10 @@ module Rails end end + def railties + @railties ||= Railties.new + end + # Returns a module with all the helpers defined for the engine. def helpers @helpers ||= begin @@ -548,7 +558,7 @@ module Rails # # This needs to be an initializer, since it needs to run once # per engine and get the engine as a block parameter - initializer :set_autoload_paths, before: :bootstrap_hook do |app| + initializer :set_autoload_paths, before: :bootstrap_hook do ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths) ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths) @@ -629,6 +639,10 @@ module Rails end end + def routes? #:nodoc: + @routes + end + protected def run_tasks_blocks(*) #:nodoc: @@ -636,10 +650,6 @@ module Rails paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end - def routes? #:nodoc: - @routes - end - def has_migrations? #:nodoc: paths["db/migrate"].existent.any? end diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index 072d16291b..f39f926109 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -27,7 +27,7 @@ else puts <<-EOT Usage: rails COMMAND [ARGS] -The common rails commands available for engines are: +The common Rails commands available for engines are: generate Generate new code (short-cut alias: "g") destroy Undo code generated with "generate" (short-cut alias: "d") diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 22e885a3a6..10d1821709 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -38,6 +38,7 @@ module Rails def paths @paths ||= begin paths = Rails::Paths::Root.new(@root) + paths.add "app", eager_load: true, glob: "*" paths.add "app/assets", glob: "*" paths.add "app/controllers", eager_load: true @@ -45,19 +46,27 @@ module Rails paths.add "app/models", eager_load: true paths.add "app/mailers", eager_load: true paths.add "app/views" + + paths.add "app/controllers/concerns", eager_load: true + paths.add "app/models/concerns", eager_load: true + paths.add "lib", load_path: true paths.add "lib/assets", glob: "*" paths.add "lib/tasks", glob: "**/*.rake" + paths.add "config" paths.add "config/environments", glob: "#{Rails.env}.rb" paths.add "config/initializers", glob: "**/*.rb" paths.add "config/locales", glob: "*.{rb,yml}" paths.add "config/routes.rb" + paths.add "db" paths.add "db/migrate" paths.add "db/seeds.rb" + paths.add "vendor", load_path: true paths.add "vendor/assets", glob: "*" + paths end end diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb new file mode 100644 index 0000000000..9969a1475d --- /dev/null +++ b/railties/lib/rails/engine/railties.rb @@ -0,0 +1,21 @@ +module Rails + class Engine < Railtie + class Railties + include Enumerable + attr_reader :_all + + def initialize + @_all ||= ::Rails::Railtie.subclasses.map(&:instance) + + ::Rails::Engine.subclasses.map(&:instance) + end + + def each(*args, &block) + _all.each(*args, &block) + end + + def -(others) + _all - others + end + end + end +end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 367f9288b8..1c0952cc55 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -1,6 +1,8 @@ activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__) $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) +require 'thor/group' + require 'active_support' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/kernel/singleton_class' @@ -9,8 +11,6 @@ require 'active_support/core_ext/hash/deep_merge' require 'active_support/core_ext/module/attribute_accessors' require 'active_support/core_ext/string/inflections' -require 'rails/generators/base' - module Rails module Generators autoload :Actions, 'rails/generators/actions' @@ -50,7 +50,6 @@ module Rails javascripts: true, javascript_engine: :js, orm: false, - performance_tool: nil, resource_controller: :controller, resource_route: true, scaffold_controller: :scaffold_controller, @@ -172,16 +171,13 @@ module Rails "resource_route", "#{orm}:migration", "#{orm}:model", - "#{orm}:observer", "#{test}:controller", "#{test}:helper", "#{test}:integration", "#{test}:mailer", "#{test}:model", - "#{test}:observer", "#{test}:scaffold", "#{test}:view", - "#{test}:performance", "#{template}:controller", "#{template}:scaffold", "#{template}:mailer", @@ -229,7 +225,7 @@ module Rails rails = groups.delete("rails") rails.map! { |n| n.sub(/^rails:/, '') } rails.delete("app") - rails.delete("plugin_new") + rails.delete("plugin") print_list("rails", rails) hidden_namespaces.each { |n| groups.delete(n.to_s) } diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 5c4e81431c..366c72ebaa 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -4,6 +4,10 @@ require 'rbconfig' module Rails module Generators module Actions + def initialize(*) # :nodoc: + super + @in_group = nil + end # Adds an entry into Gemfile for the supplied gem. # @@ -78,11 +82,11 @@ module Rails # end # # environment(nil, env: "development") do - # "config.active_record.observers = :cacher" + # "config.autoload_paths += %W(#{config.root}/extras)" # end def environment(data=nil, options={}, &block) sentinel = /class [a-z_:]+ < Rails::Application/i - env_file_sentinel = /::Application\.configure do/ + env_file_sentinel = /Rails\.application\.configure do/ data = block.call if !data && block_given? in_root do @@ -186,7 +190,7 @@ module Rails log :generate, what argument = args.map {|arg| arg.to_s }.flatten.join(" ") - in_root { run_ruby_script("script/rails generate #{what} #{argument}", verbose: false) } + in_root { run_ruby_script("bin/rails generate #{what} #{argument}", verbose: false) } end # Runs the supplied rake task @@ -211,7 +215,7 @@ module Rails # Make an entry in Rails routing file config/routes.rb # - # route "root :to => 'welcome#index'" + # route "root 'welcome#index'" def route(routing_code) log :route, routing_code sentinel = /\.routes\.draw do\s*$/ diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 0e51b9c568..6183944bb0 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -59,8 +59,8 @@ module Rails end # PATCH/PUT update - def update_attributes(params=nil) - "#{name}.update_attributes(#{params})" + def update(params=nil) + "#{name}.update(#{params})" end # POST create diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index e761e26b04..1a270a6c8c 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -5,6 +5,8 @@ require 'rails/version' unless defined?(Rails::VERSION) require 'rbconfig' require 'open-uri' require 'uri' +require 'rails/generators/base' +require 'active_support/core_ext/array/extract_options' module Rails module Generators @@ -18,17 +20,18 @@ module Rails argument :app_path, type: :string - def self.add_shared_options_for(name) - class_option :builder, type: :string, aliases: '-b', - desc: "Path to a #{name} builder (can be a filesystem path or URL)" + def self.strict_args_position + false + end + def self.add_shared_options_for(name) class_option :template, type: :string, aliases: '-m', - desc: "Path to an #{name} template (can be a filesystem path or URL)" + desc: "Path to some #{name} template (can be a filesystem path or URL)" class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" - class_option :skip_bundle, type: :boolean, default: false, + class_option :skip_bundle, type: :boolean, aliases: '-B', default: false, desc: "Don't run bundle install" class_option :skip_git, type: :boolean, aliases: '-G', default: false, @@ -40,6 +43,9 @@ module Rails class_option :skip_active_record, type: :boolean, aliases: '-O', default: false, desc: 'Skip Active Record files' + class_option :skip_action_view, type: :boolean, aliases: '-V', default: false, + desc: 'Skip Action View files' + class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, desc: 'Skip Sprockets files' @@ -52,9 +58,6 @@ module Rails class_option :skip_javascript, type: :boolean, aliases: '-J', default: false, desc: 'Skip JavaScript files' - class_option :skip_index_html, type: :boolean, aliases: '-I', default: false, - desc: 'Skip public/index.html and app/assets/images/rails.png files' - class_option :dev, type: :boolean, default: false, desc: "Setup the #{name} with Gemfile pointing to your Rails checkout" @@ -64,31 +67,61 @@ module Rails class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false, desc: 'Skip Test::Unit files' + class_option :rc, type: :string, default: false, + desc: "Path to file containing extra configuration options for rails command" + + class_option :no_rc, type: :boolean, default: false, + desc: 'Skip loading of extra configuration options from .railsrc file' + class_option :help, type: :boolean, aliases: '-h', group: :rails, desc: 'Show this help message and quit' end def initialize(*args) - @original_wd = Dir.pwd + @original_wd = Dir.pwd + @gem_filter = lambda { |gem| true } + @extra_entries = [] super convert_database_option_for_jruby end protected + def gemfile_entry(name, *args) + options = args.extract_options! + version = args.first + github = options[:github] + path = options[:path] + + if github + @extra_entries << GemfileEntry.github(name, github) + elsif path + @extra_entries << GemfileEntry.path(name, path) + else + @extra_entries << GemfileEntry.version(name, version) + end + self + end + + def gemfile_entries + [ rails_gemfile_entry, + database_gemfile_entry, + assets_gemfile_entry, + javascript_gemfile_entry, + jbuilder_gemfile_entry, + webconsole_gemfile_entry, + sdoc_gemfile_entry, + @extra_entries].flatten.find_all(&@gem_filter) + end + + def add_gem_entry_filter + @gem_filter = lambda { |next_filter,entry| + yield(entry) && next_filter.call(entry) + }.curry[@gem_filter] + end + def builder @builder ||= begin - if path = options[:builder] - if URI(path).is_a?(URI::HTTP) - contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } - else - contents = open(File.expand_path(path, @original_wd)) {|io| io.read } - end - - prok = eval("proc { #{contents} }", TOPLEVEL_BINDING, path, 1) - instance_eval(&prok) - end - builder_class = get_builder_class builder_class.send(:include, ActionMethods) builder_class.new(self) @@ -100,11 +133,9 @@ module Rails end def create_root - self.destination_root = File.expand_path(app_path, destination_root) valid_const? empty_directory '.' - set_default_accessors! FileUtils.cd(destination_root) unless options[:pretend] end @@ -115,6 +146,7 @@ module Rails end def set_default_accessors! + self.destination_root = File.expand_path(app_path, destination_root) self.rails_template = case options[:template] when /^https?:\/\// options[:template] @@ -126,37 +158,52 @@ module Rails end def database_gemfile_entry - options[:skip_active_record] ? "" : "gem '#{gem_for_database}'" + return [] if options[:skip_active_record] + GemfileEntry.version gem_for_database, nil, + "Use #{options[:database]} as the database for Active Record" end def include_all_railties? - !options[:skip_active_record] && !options[:skip_test_unit] && !options[:skip_sprockets] + !options[:skip_active_record] && !options[:skip_action_view] && !options[:skip_test_unit] && !options[:skip_sprockets] end def comment_if(value) options[value] ? '# ' : '' end + class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out) + def initialize(name, version, comment, options = {}, commented_out = false) + super + end + + def self.github(name, github, comment = nil) + new(name, nil, comment, github: github) + end + + def self.version(name, version, comment = nil) + new(name, version, comment) + end + + def self.path(name, path, comment = nil) + new(name, nil, comment, path: path) + end + + def padding(max_width) + ' ' * (max_width - name.length + 2) + end + end + def rails_gemfile_entry if options.dev? - <<-GEMFILE.strip_heredoc - gem 'rails', path: '#{Rails::Generators::RAILS_DEV_PATH}' - gem 'journey', github: 'rails/journey' - gem 'arel', github: 'rails/arel' - gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' - GEMFILE + [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), + GemfileEntry.github('arel', 'rails/arel')] elsif options.edge? - <<-GEMFILE.strip_heredoc - gem 'rails', github: 'rails/rails' - gem 'journey', github: 'rails/journey' - gem 'arel', github: 'rails/arel' - gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' - GEMFILE + [GemfileEntry.github('rails', 'rails/rails'), + GemfileEntry.github('arel', 'rails/arel')] else - <<-GEMFILE.strip_heredoc - # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' - gem 'rails', '#{Rails::VERSION::STRING}' - GEMFILE + [GemfileEntry.version('rails', + Rails::VERSION::STRING, + "Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")] end end @@ -188,57 +235,71 @@ module Rails end def assets_gemfile_entry - return if options[:skip_sprockets] - - gemfile = if options.dev? || options.edge? - <<-GEMFILE - # Gems used only for assets and not required - # in production environments by default. - group :assets do - gem 'sprockets-rails', github: 'rails/sprockets-rails' - gem 'sass-rails', github: 'rails/sass-rails' - gem 'coffee-rails', github: 'rails/coffee-rails' - - # See https://github.com/sstephenson/execjs#readme for more supported runtimes - #{javascript_runtime_gemfile_entry} - gem 'uglifier', '>= 1.0.3' - end - GEMFILE + return [] if options[:skip_sprockets] + + gems = [] + if options.dev? || options.edge? + gems << GemfileEntry.github('sprockets-rails', 'rails/sprockets-rails', + 'Use edge version of sprockets-rails') + gems << GemfileEntry.github('sass-rails', 'rails/sass-rails', + 'Use SCSS for stylesheets') else - <<-GEMFILE - # Gems used only for assets and not required - # in production environments by default. - group :assets do - gem 'sprockets-rails', github: 'rails/sprockets-rails' - gem 'sass-rails', '~> 4.0.0.beta' - gem 'coffee-rails', '~> 4.0.0.beta' - - # See https://github.com/sstephenson/execjs#readme for more supported runtimes - #{javascript_runtime_gemfile_entry} - gem 'uglifier', '>= 1.0.3' - end - GEMFILE + gems << GemfileEntry.version('sass-rails', + '~> 4.0.0.rc1', + 'Use SCSS for stylesheets') end - gemfile.strip_heredoc.gsub(/^[ \t]*$/, '') + gems << GemfileEntry.version('uglifier', + '>= 1.3.0', + 'Use Uglifier as compressor for JavaScript assets') + + gems + end + + def jbuilder_gemfile_entry + comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder' + GemfileEntry.version('jbuilder', '~> 1.2', comment) + end + + def webconsole_gemfile_entry + comment = 'Run `rails console` in the browser. Read more: https://github.com/rails/web-console' + GemfileEntry.new('web-console', nil, comment, group: :development) + end + + def sdoc_gemfile_entry + comment = 'bundle exec rake doc:rails generates the API under doc/api.' + GemfileEntry.new('sdoc', nil, comment, { group: :doc, require: false }) + end + + def coffee_gemfile_entry + comment = 'Use CoffeeScript for .js.coffee assets and views' + if options.dev? || options.edge? + GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', comment + else + GemfileEntry.version 'coffee-rails', '~> 4.0.0', comment + end end def javascript_gemfile_entry - unless options[:skip_javascript] - <<-GEMFILE.strip_heredoc - gem '#{options[:javascript]}-rails' + if options[:skip_javascript] + [] + else + gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry] + gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, + "Use #{options[:javascript]} as the JavaScript library") - # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks - gem 'turbolinks' - GEMFILE + gems << GemfileEntry.version("turbolinks", nil, + "Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks") + gems end end def javascript_runtime_gemfile_entry + comment = 'See https://github.com/sstephenson/execjs#readme for more supported runtimes' if defined?(JRUBY_VERSION) - "gem 'therubyrhino'\n" + GemfileEntry.version 'therubyrhino', nil, comment else - "# gem 'therubyracer', platforms: :ruby\n" + GemfileEntry.new 'therubyracer', nil, comment, { platforms: :ruby }, true end end diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 7e938fab47..dc1d4fa181 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -7,7 +7,7 @@ rescue LoadError exit end -require 'rails/generators/actions' +require 'rails/generators' module Rails module Generators @@ -168,15 +168,15 @@ module Rails 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) + 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 + class_option(name, defaults.merge!(options)) end @@ -211,7 +211,7 @@ module Rails return unless base_name && generator_name return unless default_generator_root path = File.join(default_generator_root, 'templates') - path if File.exists?(path) + path if File.exist?(path) end # Returns the base root for a common set of generators. This is used to dynamically @@ -255,12 +255,7 @@ module Rails # Split the class from its module nesting nesting = class_name.split('::') last_name = nesting.pop - - # Extract the last Module in the nesting - last = nesting.inject(Object) do |last_module, nest| - break unless last_module.const_defined?(nest, false) - last_module.const_get(nest) - end + last = extract_last_module(nesting) if last && last.const_defined?(last_name.camelize, false) raise Error, "The name '#{class_name}' is either already used in your application " << @@ -270,6 +265,14 @@ module Rails end end + # Takes in an array of nested modules and extracts the last module + def extract_last_module(nesting) + nesting.inject(Object) do |last_module, nest| + break unless last_module.const_defined?(nest, false) + last_module.const_get(nest) + end + end + # Use Rails default banner. def self.banner "rails generate #{namespace.sub(/^rails:/,'')} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]".gsub(/\s+/, ' ') @@ -365,12 +368,12 @@ module Rails source_root && File.expand_path("../USAGE", source_root), default_generator_root && File.join(default_generator_root, "USAGE") ] - paths.compact.detect { |path| File.exists? path } + paths.compact.detect { |path| File.exist? path } end def self.default_generator_root path = File.expand_path(File.join(base_name, generator_name), base_root) - path if File.exists?(path) + path if File.exist?(path) end end diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 32546936e3..69c10efa47 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -13,8 +13,22 @@ <% attributes.each do |attribute| -%> <div class="field"> - <%%= f.label :<%= attribute.name %> %><br /> +<% if attribute.password_digest? -%> + <%%= f.label :password %><br> + <%%= f.password_field :password %> + </div> + <div> + <%%= f.label :password_confirmation %><br> + <%%= f.password_field :password_confirmation %> +<% else -%> + <%- if attribute.reference? -%> + <%%= f.label :<%= attribute.column_name %> %><br> + <%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %> + <%- else -%> + <%%= f.label :<%= attribute.name %> %><br> <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> + <%- end -%> +<% end -%> </div> <% end -%> <div class="actions"> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index f5182bcc50..814d6fdb0e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -3,27 +3,27 @@ <table> <thead> <tr> - <% attributes.each do |attribute| -%> +<% attributes.reject(&:password_digest?).each do |attribute| -%> <th><%= attribute.human_name %></th> - <% end -%> - <th></th> - <th></th> - <th></th> +<% end -%> + <th colspan="3"></th> </tr> </thead> <tbody> - <%%= content_tag_for(:tr, @<%= plural_table_name %>) do |<%= singular_table_name %>| %> - <% attributes.each do |attribute| -%> - <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td> - <% end -%> - <td><%%= link_to 'Show', <%= singular_table_name %> %></td> - <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td> - <td><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td> + <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %> + <tr> +<% attributes.reject(&:password_digest?).each do |attribute| -%> + <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td> +<% end -%> + <td><%%= link_to 'Show', <%= singular_table_name %> %></td> + <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td> + <td><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td> + </tr> <%% end %> </tbody> </table> -<br /> +<br> <%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index e15c963971..5e634153be 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -1,12 +1,11 @@ <p id="notice"><%%= notice %></p> -<% attributes.each do |attribute| -%> +<% attributes.reject(&:password_digest?).each do |attribute| -%> <p> <strong><%= attribute.human_name %>:</strong> <%%= @<%= singular_table_name %>.<%= attribute.name %> %> </p> <% end -%> - <%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> | <%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index d8a4f15b4b..5e2784c4b0 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -99,13 +99,17 @@ module Rails end def index_name - @index_name ||= if reference? - polymorphic? ? %w(id type).map { |t| "#{name}_#{t}" } : "#{name}_id" + @index_name ||= if polymorphic? + %w(id type).map { |t| "#{name}_#{t}" } else - name + column_name end end + def column_name + @column_name ||= reference? ? "#{name}_id" : name + end + def foreign_key? !!(name =~ /_id$/) end @@ -126,6 +130,10 @@ module Rails @has_uniq_index end + def password_digest? + name == 'password' && type == :digest + end + def inject_options "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } end diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 5bf98bb6e0..3566f96f5e 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -1,15 +1,14 @@ +require 'active_support/concern' + 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 version method. module Migration + extend ActiveSupport::Concern attr_reader :migration_number, :migration_file_name, :migration_class_name - def self.included(base) #:nodoc: - base.extend ClassMethods - end - module ClassMethods def migration_lookup_at(dirname) #:nodoc: Dir.glob("#{dirname}/[0-9]*_*.rb") @@ -52,7 +51,7 @@ module Rails if destination && options.force? remove_file(destination) elsif destination - raise Error, "Another migration is already named #{@migration_file_name}: #{destination}" + raise Error, "Another migration is already named #{@migration_file_name}: #{destination}. Use --force to remove the old migration file and replace it." end destination = File.join(migration_dir, "#{@migration_number}_#{@migration_file_name}.rb") end diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 84f8f76838..e712c747b0 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -18,6 +18,8 @@ module Rails parse_attributes! if respond_to?(:attributes) end + # Defines the template that would be used for the migration file. + # The arguments include the source template file, the migration filename etc. no_tasks do def template(source, *args, &block) inside_template do @@ -40,7 +42,7 @@ module Rails def indent(content, multiplier = 2) spaces = " " * multiplier - content = content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join + content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join end def wrap_with_namespace(content) @@ -160,6 +162,14 @@ module Rails end end + def attributes_names + @attributes_names ||= attributes.each_with_object([]) do |a, names| + names << a.column_name + names << 'password_confirmation' if a.password_digest? + names << "#{a.name}_type" if a.polymorphic? + end + end + def pluralize_table_names? !defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names end @@ -169,10 +179,10 @@ module Rails # # ==== Examples # - # check_class_collision suffix: "Observer" + # check_class_collision suffix: "Decorator" # # If the generator is invoked with class name Admin, it will check for - # the presence of "AdminObserver". + # the presence of "AdminDecorator". # def self.check_class_collision(options={}) define_method :check_class_collision do diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 18637451ac..3c62e7a4d2 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -38,7 +38,7 @@ module Rails end def readme - copy_file "README", "README.rdoc" + copy_file "README.rdoc", "README.rdoc" end def gemfile @@ -55,8 +55,20 @@ module Rails def app directory 'app' + + keep_file 'app/assets/images' keep_file 'app/mailers' keep_file 'app/models' + + keep_file 'app/controllers/concerns' + keep_file 'app/models/concerns' + end + + def bin + directory "bin" do |content| + "#{shebang}\n" + content + end + chmod "bin", 0755 & ~File.umask, verbose: false end def config @@ -81,10 +93,6 @@ module Rails directory "db" end - def doc - directory "doc" - end - def lib empty_directory 'lib' empty_directory_with_keep_file 'lib/tasks' @@ -97,18 +105,6 @@ module Rails def public_directory directory "public", "public", recursive: false - if options[:skip_index_html] - remove_file "public/index.html" - remove_file 'app/assets/images/rails.png' - keep_file 'app/assets/images' - end - end - - def script - directory "script" do |content| - "#{shebang}\n" + content - end - chmod "script", 0755, verbose: false end def test @@ -119,7 +115,6 @@ module Rails empty_directory_with_keep_file 'test/helpers' empty_directory_with_keep_file 'test/integration' - template 'test/performance/browsing_test.rb' template 'test/test_helper.rb' end @@ -134,7 +129,9 @@ module Rails end def vendor_javascripts - empty_directory_with_keep_file 'vendor/assets/javascripts' + unless options[:skip_javascript] + empty_directory_with_keep_file 'vendor/assets/javascripts' + end end def vendor_stylesheets @@ -146,7 +143,7 @@ module Rails # We need to store the RAILS_DEV_PATH in a constant, otherwise the path # can change in Ruby 1.8.7 when we FileUtils.cd. RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) - RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test] + RESERVED_NAMES = %w[application destroy plugin runner test] class AppGenerator < AppBase # :nodoc: add_shared_options_for "application" @@ -156,15 +153,18 @@ module Rails desc: "Show Rails version number and quit" def initialize(*args) - raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank? - super + unless app_path + raise Error, "Application name should be provided in arguments. For details run: rails --help" + end + if !options[:skip_active_record] && !DATABASES.include?(options[:database]) raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}." end end + public_task :set_default_accessors! public_task :create_root def create_root_files @@ -179,6 +179,10 @@ module Rails build(:app) end + def create_bin_files + build(:bin) + end + def create_config_files build(:config) end @@ -196,10 +200,6 @@ module Rails build(:db) end - def create_doc_files - build(:doc) - end - def create_lib_files build(:lib) end @@ -212,10 +212,6 @@ module Rails build(:public_directory) end - def create_script_files - build(:script) - end - def create_test_files build(:test) unless options[:skip_test_unit] end @@ -232,6 +228,12 @@ module Rails build(:leftovers) end + def delete_js_folder_skipping_javascript + if options[:skip_javascript] + remove_dir 'app/assets/javascripts' + end + end + public_task :apply_rails_template, :run_bundle protected @@ -246,7 +248,7 @@ module Rails end def app_name - @app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root) + @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', '').tr(". ", "_") end def defined_app_name @@ -301,5 +303,76 @@ module Rails defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder end end + + # This class handles preparation of the arguments before the AppGenerator is + # called. The class provides version or help information if they were + # requested, and also constructs the railsrc file (used for extra configuration + # options). + # + # This class should be called before the AppGenerator is required and started + # since it configures and mutates ARGV correctly. + class ARGVScrubber # :nodoc + def initialize(argv = ARGV) + @argv = argv + end + + def prepare! + handle_version_request!(@argv.first) + handle_invalid_command!(@argv.first, @argv) do + handle_rails_rc!(@argv.drop(1)) + end + end + + def self.default_rc_file + File.join(File.expand_path('~'), '.railsrc') + end + + private + + def handle_version_request!(argument) + if ['--version', '-v'].include?(argument) + require 'rails/version' + puts "Rails #{Rails::VERSION::STRING}" + exit(0) + end + end + + def handle_invalid_command!(argument, argv) + if argument == "new" + yield + else + ['--help'] + argv.drop(1) + end + end + + def handle_rails_rc!(argv) + if argv.find { |arg| arg == '--no-rc' } + argv.reject { |arg| arg == '--no-rc' } + else + railsrc(argv) { |rc_argv, rc| insert_railsrc_into_argv!(rc_argv, rc) } + end + end + + def railsrc(argv) + if (customrc = argv.index{ |x| x.include?("--rc=") }) + fname = File.expand_path(argv[customrc].gsub(/--rc=/, "")) + yield(argv.take(customrc) + argv.drop(customrc + 1), fname) + else + yield argv, self.class.default_rc_file + end + end + + def read_rc_file(railsrc) + extra_args = File.readlines(railsrc).flat_map(&:split) + puts "Using #{extra_args.join(" ")} from #{railsrc}" + extra_args + end + + def insert_railsrc_into_argv!(argv, railsrc) + return argv unless File.exist?(railsrc) + extra_args = read_rc_file railsrc + argv.take(1) + extra_args + argv.drop(1) + end + end end end diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 30f8a5f75e..21dcba7947 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,25 +1,30 @@ source 'https://rubygems.org' -<%= rails_gemfile_entry -%> - -<%= database_gemfile_entry -%> - -<%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%> - -<%= assets_gemfile_entry %> -<%= javascript_gemfile_entry %> - -# To use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.0.0' - -# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -# gem 'jbuilder' +<% max_width = gemfile_entries.map { |g| g.name.length }.max -%> +<% gemfile_entries.each do |gem| -%> +<% if gem.comment -%> + +# <%= gem.comment %> +<% end -%> +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> +, '<%= gem.version %>' +<% elsif gem.options.any? -%> +,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| + "#{k}: #{v.inspect}" }.join(', ') %> +<% else %> +<% end -%> +<% end -%> + +# Use ActiveModel has_secure_password +# gem 'bcrypt-ruby', '~> 3.1.2' # Use unicorn as the app server # gem 'unicorn' -# Deploy with Capistrano -# gem 'capistrano', group: :development +# Use Capistrano for deployment +# gem 'capistrano-rails', group: :development -# To use debugger -# gem 'debugger' +<% unless defined?(JRUBY_VERSION) -%> +# Use debugger +# gem 'debugger', group: [:development, :test] +<% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README deleted file mode 100644 index b5d7b6436b..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/README +++ /dev/null @@ -1,259 +0,0 @@ -== 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, create a new Rails application: - <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name) - -2. Change directory to <tt>myapp</tt> and start the web server: - <tt>cd myapp; rails server</tt> (run with --help for options) - -3. Go to http://localhost:3000/ and you'll see: - "Welcome aboard: You're riding Ruby on Rails!" - -4. Follow the guidelines to start developing your application. You can find -the following resources handy: - -* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html -* Ruby on Rails Tutorial Book: http://www.railstutorial.org/ - - -== 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/. There are -several books available online as well: - -* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) -* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) - -These two 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 the 'debugger' gem to run the server in debugging -mode. Add gem 'debugger' to your Gemfile and run <tt>bundle</tt> to install it. Example: - - class WeblogController < ActionController::Base - def index - @posts = Post.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", "body"=>"Only ten..", "id"=>"2"}>]" - >> @posts.first.title = "hello from a debugger" - => "hello from a debugger" - -...and even better, 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 can enter "cont". - - -== Console - -The console is a Ruby shell, which allows you to interact with your -application's domain model. 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. - -To start the console, run <tt>rails console</tt> from the application -directory. - -Options: - -* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications - made to the database. -* Passing an environment name as an argument will load the corresponding - environment. Example: <tt>rails console production</tt>. - -To reload your controllers and models after launching the console run -<tt>reload!</tt> - -More information about irb can be found at: -link:http://www.rubycentral.org/pickaxe/irb.html - - -== dbconsole - -You can go to the command line of your database directly through <tt>rails -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>rails dbconsole production</tt>. Currently works for MySQL, -PostgreSQL and SQLite 3. - -== Description of Contents - -The default directory structure of a generated Ruby on Rails application: - - |-- app - | |-- assets - | |-- images - | |-- javascripts - | `-- stylesheets - | |-- controllers - | |-- helpers - | |-- mailers - | |-- models - | `-- views - | `-- layouts - |-- config - | |-- environments - | |-- initializers - | `-- locales - |-- db - |-- doc - |-- lib - | `-- tasks - |-- log - |-- public - |-- script - |-- test - | |-- fixtures - | |-- functional - | |-- integration - | |-- performance - | `-- unit - |-- tmp - | |-- cache - | |-- pids - | |-- sessions - | `-- sockets - `-- vendor - |-- assets - `-- stylesheets - -app - Holds all the code that's specific to this particular application. - -app/assets - Contains subdirectories for images, stylesheets, and JavaScript files. - -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. Models descend from - ActiveRecord::Base by default. - -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 by default. - -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 generators 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. 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 rails generate - command, template test files will be generated for you and placed in this - directory. - -vendor - External libraries that the application depends on. 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/lib/rails/generators/rails/app/templates/README.rdoc b/railties/lib/rails/generators/rails/app/templates/README.rdoc new file mode 100644 index 0000000000..dd4e97e22e --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/README.rdoc @@ -0,0 +1,28 @@ +== README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... + + +Please feel free to use a different markup language if you do not plan to run +<tt>rake doc:app</tt>. diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile index 6eb23f68a3..ba6b733dd2 100644 --- a/railties/lib/rails/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile @@ -3,4 +3,4 @@ require File.expand_path('../config/application', __FILE__) -<%= app_const %>.load_tasks +Rails.application.load_tasks diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/images/rails.png b/railties/lib/rails/generators/rails/app/templates/app/assets/images/rails.png Binary files differdeleted file mode 100644 index d5edc04e65..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/images/rails.png +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt index 7342bffd9d..8b91313e51 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt @@ -7,8 +7,8 @@ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // -// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD -// GO AFTER THE REQUIRES BELOW. +// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details +// about supported directives. // <% unless options[:skip_javascript] -%> //= require <%= options[:javascript] %> diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css index 3192ec897b..a443db3401 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css @@ -5,9 +5,11 @@ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. * - * You're free to add application-wide styles to this file and they'll appear at the top of the - * compiled file, but it's generally better to create a new file per style scope. + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any styles + * defined in the other CSS/SCSS files in this directory. It is generally better to create a new + * file per style scope. * - *= require_self *= require_tree . + *= require_self */ diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index e0539aa8bb..4cf47bd0a0 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -2,8 +2,12 @@ <html> <head> <title><%= camelized %></title> + <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag "application", media: "all" %> - <%%= javascript_include_tag "application" %> + <%- else -%> + <%%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> + <%%= javascript_include_tag "application", "data-turbolinks-track" => true %> + <%- end -%> <%%= csrf_meta_tags %> </head> <body> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/bundle b/railties/lib/rails/generators/rails/app/templates/bin/bundle new file mode 100644 index 0000000000..1123dcf501 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/bundle @@ -0,0 +1,2 @@ +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails new file mode 100644 index 0000000000..6a128b95e5 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/rails @@ -0,0 +1,3 @@ +APP_PATH = File.expand_path('../../config/application', __FILE__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rake b/railties/lib/rails/generators/rails/app/templates/bin/rake new file mode 100644 index 0000000000..d14fc8395b --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/rake @@ -0,0 +1,3 @@ +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru index fcfbc6b07a..5bc2a619e8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config.ru +++ b/railties/lib/rails/generators/rails/app/templates/config.ru @@ -1,4 +1,4 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -run <%= app_const %> +run Rails.application diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index fb43c90e21..ac41a0cadb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -4,15 +4,18 @@ require File.expand_path('../boot', __FILE__) require 'rails/all' <% else -%> # Pick the frameworks you want: +require "active_model/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie" +<%= comment_if :skip_action_view %>require "action_view/railtie" +<%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> -# Assets should be precompiled for production (so we don't need the gems loaded then) -Bundler.require(*Rails.groups(assets: %w(development test))) +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) module <%= app_const_base %> class Application < Rails::Application @@ -20,23 +23,17 @@ module <%= app_const_base %> # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. - # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) + # 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. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' - # Configure sensitive parameters which will be filtered from the log file. - config.filter_parameters += [:password] + # 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}').to_s] + # config.i18n.default_locale = :de +<% if options.skip_sprockets? -%> - # Use SQL instead of Active Record's schema dumper when creating the database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types. - # config.active_record.schema_format = :sql - -<% unless options.skip_sprockets? -%> - # Enable the asset pipeline. - config.assets.enabled = true - - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # Disable the asset pipeline. + config.assets.enabled = false <% end -%> end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 3596736667..5e5f0c1fac 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb @@ -1,4 +1,4 @@ # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index 22c9194fad..0194dce6f3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml @@ -26,7 +26,7 @@ development: # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. #host: localhost - + # The TCP port the server listens on. Defaults to 5432. # If your server runs on a different port number, change accordingly. #port: 5432 @@ -55,6 +55,8 @@ production: adapter: postgresql encoding: unicode database: <%= app_name %>_production + # For details on connection pooling, see rails configration guide + # http://guides.rubyonrails.org/configuring.html#database-pooling pool: 5 username: <%= app_name %> password: diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml new file mode 100644 index 0000000000..7ef89d6608 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml @@ -0,0 +1,57 @@ +# SQL Server (2005 or higher recommended) +# +# Install the adapters and driver +# gem install tiny_tds +# gem install activerecord-sqlserver-adapter +# +# Ensure the activerecord adapter and db driver gems are defined in your Gemfile +# gem 'tiny_tds' +# gem 'activerecord-sqlserver-adapter' +# +# You should make sure freetds is configured correctly first. +# freetds.conf contains host/port/protocol_versions settings. +# http://freetds.schemamania.org/userguide/freetdsconf.htm +# +# A typical Microsoft server +# [mssql] +# host = mssqlserver.yourdomain.com +# port = 1433 +# tds version = 7.1 + +# If you can connect with "tsql -S servername", your basic FreeTDS installation is working. +# 'man tsql' for more info +# Set timeout to a larger number if valid queries against a live db fail + +development: + adapter: sqlserver + encoding: utf8 + reconnect: false + database: <%= app_name %>_development + username: <%= app_name %> + password: + timeout: 25 + dataserver: from_freetds.conf + + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlserver + encoding: utf8 + reconnect: false + database: <%= app_name %>_test + username: <%= app_name %> + password: + timeout: 25 + dataserver: from_freetds.conf + +production: + adapter: sqlserver + encoding: utf8 + reconnect: false + database: <%= app_name %>_production + username: <%= app_name %> + password: + timeout: 25 + dataserver: from_freetds.conf diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb index e080ebd74e..ee8d90dc65 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb @@ -1,5 +1,5 @@ -# Load the rails application. +# Load the Rails application. require File.expand_path('../application', __FILE__) -# Initialize the rails application. -<%= app_const %>.initialize! +# Initialize the Rails application. +Rails.application.initialize! diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 6b5b3a0b1f..cff570a631 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -1,4 +1,4 @@ -<%= app_const %>.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on @@ -19,23 +19,15 @@ # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Only use best-standards-support built into browsers. - config.action_dispatch.best_standards_support = :builtin - <%- unless options.skip_active_record? -%> - # Log the query plan for queries taking more than this (works - # with SQLite, MySQL, and PostgreSQL). - config.active_record.auto_explain_threshold_in_seconds = 0.5 - - # Raise an error on page load if there are pending migrations + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load <%- end -%> <%- unless options.skip_sprockets? -%> - # Do not compress assets. - config.assets.compress = false - # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. config.assets.debug = true <%- end -%> end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 8aaaba628c..1dfc9f136b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -1,4 +1,4 @@ -<%= app_const %>.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. @@ -24,13 +24,17 @@ <%- unless options.skip_sprockets? -%> # Compress JavaScripts and CSS. - config.assets.compress = true + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass - # Don't fallback to assets pipeline if a precompiled asset is missed. + # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Generate digests for assets URLs. config.assets.digest = true + + # Version of your assets, change this if you want to expire all your assets. + config.assets.version = '1.0' <%- end -%> # Specifies the header that your server uses for sending files. @@ -56,17 +60,15 @@ # config.action_controller.asset_host = "http://assets.example.com" <%- unless options.skip_sprockets? -%> - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added). + # Precompile additional assets. + # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # config.assets.precompile += %w( search.js ) <%- end -%> # Ignore bad email addresses and do not raise email delivery errors. - # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false - # Enable threaded mode. - # config.threadsafe! - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found). config.i18n.fallbacks = true @@ -74,19 +76,9 @@ # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - <%- unless options.skip_active_record? -%> - # Log the query plan for queries taking more than this (works - # with SQLite, MySQL, and PostgreSQL). - # config.active_record.auto_explain_threshold_in_seconds = 0.5 - <%- end -%> - # Disable automatic flushing of the log to improve performance. # config.autoflush_log = false # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new - - # Default the production mode queue to an synchronous queue. You will probably - # want to replace this with an out-of-process queueing solution. - # config.queue = ActiveSupport::SynchronousQueue.new end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index a5ef0cd9cd..ba0742f97f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -1,4 +1,4 @@ -<%= app_const %>.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's @@ -13,7 +13,7 @@ config.eager_load = false # Configure static asset server for tests with Cache-Control for performance. - config.serve_static_assets = true + config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" # Show full error reports and disable caching. @@ -33,7 +33,4 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - - # Use the synchronous queue to run jobs immediately. - config.queue = ActiveSupport::SynchronousQueue.new end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000..4a994e1e7b --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb index 9262c3379f..ac033bf9dc 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb @@ -9,7 +9,7 @@ # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end -# + # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/locale.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/locale.rb deleted file mode 100644 index a8285f88ca..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/locale.rb +++ /dev/null @@ -1,7 +0,0 @@ -# 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. Default is UTC. -# Rails.application.config.time_zone = 'Central Time (US & Canada)' - -# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. -# Rails.application.config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] -# Rails.application.config.i18n.default_locale = :de diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt index 3c5611ca59..f3cc6098a3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt @@ -1,12 +1,12 @@ # Be sure to restart your server when you modify this file. -# Your secret key for verifying the integrity of signed cookies. +# Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. -# Make sure your secret_token is kept private +# Make sure your secret_key_base is kept private # if you're sharing your code publicly. -<%= app_const %>.config.secret_token = '<%= app_secret %>' +Rails.application.config.secret_key_base = '<%= app_secret %>' diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt index 4a099a4ce2..2bb9b82c61 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt @@ -1,3 +1,3 @@ # Be sure to restart your server when you modify this file. -<%= app_const %>.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> +Rails.application.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index 280f777cc0..f2110c2c70 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -1,5 +1,5 @@ # Be sure to restart your server when you modify this file. -# + # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. @@ -7,8 +7,8 @@ ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] if respond_to?(:wrap_parameters) end - <%- unless options.skip_active_record? -%> + # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index 631543c705..3f66539d54 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,9 +1,9 @@ -<%= app_const %>.routes.draw do +Rails.application.routes.draw do # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". - # You can have the root of your site routed with "root" just remember to delete public/index.html. - # root to: 'welcome#index' + # You can have the root of your site routed with "root" + # root 'welcome#index' # Example of regular route: # get 'products/:id' => 'catalog#view' @@ -40,6 +40,13 @@ # end # end + # Example resource route with concerns: + # concern :toggleable do + # post 'toggle' + # end + # resources :posts, concerns: :toggleable + # resources :photos, concerns: :toggleable + # Example resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController diff --git a/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP b/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP deleted file mode 100644 index fe41f5cc24..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP +++ /dev/null @@ -1,2 +0,0 @@ -Use this README file to introduce your application and point to useful places in the API for learning more. -Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 8910bf5a06..6a502e997f 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -1,10 +1,10 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# See https://help.github.com/articles/ignoring-files for more about ignoring files. # # If you find yourself ignoring temporary files generated by your text editor # or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile ~/.gitignore_global +# git config --global core.excludesfile '~/.gitignore_global' -# Ignore bundler config +# Ignore bundler config. /.bundle # Ignore the default SQLite database. diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index 3d875c342e..a0daa0c156 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -3,16 +3,47 @@ <head> <title>The page you were looking for doesn't exist (404)</title> <style> - body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } - div.dialog { - width: 25em; - padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; - } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + } + + div.dialog { + width: 25em; + margin: 4em auto 0 auto; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 4em 0 4em; + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + body > p { + width: 33em; + margin: 0 auto 1em; + padding: 1em 0; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + } </style> </head> diff --git a/railties/lib/rails/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index 3f1bfb3417..fbb4b84d72 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html @@ -3,16 +3,47 @@ <head> <title>The change you wanted was rejected (422)</title> <style> - body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } - div.dialog { - width: 25em; - padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; - } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + } + + div.dialog { + width: 25em; + margin: 4em auto 0 auto; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 4em 0 4em; + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + body > p { + width: 33em; + margin: 0 auto 1em; + padding: 1em 0; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + } </style> </head> @@ -22,5 +53,6 @@ <h1>The change you wanted was rejected.</h1> <p>Maybe you tried to change something you didn't have access to.</p> </div> + <p>If you are the application owner check the logs for more information.</p> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index 012977d3d2..e9052d35bf 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -3,16 +3,47 @@ <head> <title>We're sorry, but something went wrong (500)</title> <style> - body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } - div.dialog { - width: 25em; - padding: 0 4em; - margin: 4em auto 0 auto; - border: 1px solid #ccc; - border-right-color: #999; - border-bottom-color: #999; - } - h1 { font-size: 100%; color: #f00; line-height: 1.5em; } + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + } + + div.dialog { + width: 25em; + margin: 4em auto 0 auto; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 4em 0 4em; + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + body > p { + width: 33em; + margin: 0 auto 1em; + padding: 1em 0; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow:0 3px 8px rgba(50, 50, 50, 0.17); + } </style> </head> diff --git a/railties/lib/rails/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html deleted file mode 100644 index dd09a96de9..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/public/index.html +++ /dev/null @@ -1,241 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Ruby on Rails: Welcome aboard</title> - <style media="screen"> - body { - margin: 0; - margin-bottom: 25px; - padding: 0; - background-color: #f0f0f0; - font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana"; - font-size: 13px; - color: #333; - } - - h1 { - font-size: 28px; - color: #000; - } - - a {color: #03c} - a:hover { - background-color: #03c; - color: white; - text-decoration: none; - } - - - #page { - background-color: #f0f0f0; - width: 750px; - margin: 0; - margin-left: auto; - margin-right: auto; - } - - #content { - float: left; - background-color: white; - border: 3px solid #aaa; - border-top: none; - padding: 25px; - width: 500px; - } - - #sidebar { - float: right; - width: 175px; - } - - #footer { - clear: both; - } - - #header, #about, #getting-started { - padding-left: 75px; - padding-right: 30px; - } - - - #header { - background-image: url("assets/rails.png"); - background-repeat: no-repeat; - background-position: top left; - height: 64px; - } - #header h1, #header h2 {margin: 0} - #header h2 { - color: #888; - font-weight: normal; - font-size: 16px; - } - - - #about h3 { - margin: 0; - margin-bottom: 10px; - font-size: 14px; - } - - #about-content { - background-color: #ffd; - border: 1px solid #fc0; - margin-left: -55px; - margin-right: -10px; - } - #about-content table { - margin-top: 10px; - margin-bottom: 10px; - font-size: 11px; - border-collapse: collapse; - } - #about-content td { - padding: 10px; - padding-top: 3px; - padding-bottom: 3px; - } - #about-content td.name {color: #555} - #about-content td.value {color: #000} - - #about-content ul { - padding: 0; - list-style-type: none; - } - - #about-content.failure { - background-color: #fcc; - border: 1px solid #f00; - } - #about-content.failure p { - margin: 0; - padding: 10px; - } - - - #getting-started { - border-top: 1px solid #ccc; - margin-top: 25px; - padding-top: 15px; - } - #getting-started h1 { - margin: 0; - font-size: 20px; - } - #getting-started h2 { - margin: 0; - font-size: 14px; - font-weight: normal; - color: #333; - margin-bottom: 25px; - } - #getting-started ol { - margin-left: 0; - padding-left: 0; - } - #getting-started li { - font-size: 18px; - color: #888; - margin-bottom: 25px; - } - #getting-started li h2 { - margin: 0; - font-weight: normal; - font-size: 18px; - color: #333; - } - #getting-started li p { - color: #555; - font-size: 13px; - } - - - #sidebar ul { - margin-left: 0; - padding-left: 0; - } - #sidebar ul h3 { - margin-top: 25px; - font-size: 16px; - padding-bottom: 10px; - border-bottom: 1px solid #ccc; - } - #sidebar li { - list-style-type: none; - } - #sidebar ul.links li { - margin-bottom: 5px; - } - - .filename { - font-style: italic; - } - </style> - <script> - function about() { - info = document.getElementById('about-content'); - if (window.XMLHttpRequest) - { xhr = new XMLHttpRequest(); } - else - { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } - xhr.open("GET","rails/info/properties",false); - xhr.send(""); - info.innerHTML = xhr.responseText; - info.style.display = 'block' - } - </script> - </head> - <body> - <div id="page"> - <div id="sidebar"> - <ul id="sidebar-items"> - <li> - <h3>Browse the documentation</h3> - <ul class="links"> - <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li> - <li><a href="http://api.rubyonrails.org/">Rails API</a></li> - <li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li> - <li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li> - </ul> - </li> - </ul> - </div> - - <div id="content"> - <div id="header"> - <h1>Welcome aboard</h1> - <h2>You’re riding Ruby on Rails!</h2> - </div> - - <div id="about"> - <h3><a href="rails/info/properties" onclick="about(); return false">About your application’s environment</a></h3> - <div id="about-content" style="display: none"></div> - </div> - - <div id="getting-started"> - <h1>Getting started</h1> - <h2>Here’s how to get rolling:</h2> - - <ol> - <li> - <h2>Use <code>rails generate</code> to create your models and controllers</h2> - <p>To see all available options, run it without parameters.</p> - </li> - - <li> - <h2>Set up a default route and remove <span class="filename">public/index.html</span></h2> - <p>Routes are set up in <span class="filename">config/routes.rb</span>.</p> - </li> - - <li> - <h2>Create your database</h2> - <p>Run <code>rake db:create</code> to create your database. If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p> - </li> - </ol> - </div> - </div> - - <div id="footer"> </div> - </div> - </body> -</html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/script/rails b/railties/lib/rails/generators/rails/app/templates/script/rails deleted file mode 100644 index 11bc1edde9..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/script/rails +++ /dev/null @@ -1,5 +0,0 @@ -# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. - -APP_PATH = File.expand_path('../../config/application', __FILE__) -require File.expand_path('../../config/boot', __FILE__) -require 'rails/commands' diff --git a/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb deleted file mode 100644 index d09ce5ad34..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'test_helper' -require 'rails/performance_test_help' - -class BrowsingTest < ActionDispatch::PerformanceTest - # Refer to the documentation for all available options - # self.profile_options = { runs: 5, metrics: [:wall_time, :memory], - # output: 'tmp/performance', formats: [:flat] } - - test "homepage" do - get '/' - end -end diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 9afda2d0df..4fd060341e 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -1,4 +1,4 @@ -ENV["RAILS_ENV"] = "test" +ENV["RAILS_ENV"] ||= "test" require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' diff --git a/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/controller/USAGE b/railties/lib/rails/generators/rails/controller/USAGE index 9def4af65c..de33900e0a 100644 --- a/railties/lib/rails/generators/rails/controller/USAGE +++ b/railties/lib/rails/generators/rails/controller/USAGE @@ -6,7 +6,7 @@ Description: path like 'parent_module/controller_name'. This generates a controller class in app/controllers and invokes helper, - template engine and test framework generators. + template engine, assets, and test framework generators. Example: `rails generate controller CreditCards open debit credit close` @@ -16,3 +16,4 @@ Example: Test: test/controllers/credit_cards_controller_test.rb Views: app/views/credit_cards/debit.html.erb [...] Helper: app/helpers/credit_cards_helper.rb + Test: test/helpers/credit_cards_helper_test.rb diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index bae54623c6..ef84447df9 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -10,11 +10,45 @@ module Rails def add_routes actions.reverse.each do |action| - route %{get "#{file_name}/#{action}"} + route generate_routing_code(action) end end hook_for :template_engine, :test_framework, :helper, :assets + + private + + # This method creates nested route entry for namespaced resources. + # For eg. rails g controller foo/bar/baz index + # Will generate - + # namespace :foo do + # namespace :bar do + # get "baz/index" + # end + # end + def generate_routing_code(action) + depth = class_path.length + # Create 'namespace' ladder + # namespace :foo do + # namespace :bar do + namespace_ladder = class_path.each_with_index.map do |ns, i| + indent("namespace :#{ns} do\n", i * 2) + end.join + + # Create route + # get "baz/index" + route = indent(%{get "#{file_name}/#{action}"\n}, depth * 2) + + # Create `end` ladder + # end + # end + end_ladder = (1..depth).reverse_each.map do |i| + indent("end\n", i * 2) + end.join + + # Combine the 3 parts to generate complete route entry + namespace_ladder + route + end_ladder + end end end end diff --git a/railties/lib/rails/generators/rails/generator/USAGE b/railties/lib/rails/generators/rails/generator/USAGE index d28eb3d7d8..799383050c 100644 --- a/railties/lib/rails/generators/rails/generator/USAGE +++ b/railties/lib/rails/generators/rails/generator/USAGE @@ -10,3 +10,4 @@ Example: lib/generators/awesome/awesome_generator.rb lib/generators/awesome/USAGE lib/generators/awesome/templates/ + test/lib/generators/awesome_generator_test.rb diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 9a7a516b5b..15d88f06ac 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -10,6 +10,8 @@ module Rails directory '.', generator_dir end + hook_for :test_framework + protected def generator_dir diff --git a/railties/lib/rails/generators/rails/migration/USAGE b/railties/lib/rails/generators/rails/migration/USAGE index af74963b01..baf3d9894f 100644 --- a/railties/lib/rails/generators/rails/migration/USAGE +++ b/railties/lib/rails/generators/rails/migration/USAGE @@ -15,15 +15,21 @@ Example: `rails 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: + This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Change migration: add_column :posts, :title, :string add_column :posts, :body, :text add_column :posts, :published, :boolean - And this in the Down migration: +Migration names containing JoinTable will generate join tables for use with +has_and_belongs_to_many associations. - remove_column :posts, :published - remove_column :posts, :body - remove_column :posts, :title +Example: + `rails g migration CreateMediaJoinTable artists musics:uniq` + + will create the migration + + create_join_table :artists, :musics do |t| + # t.index [:artist_id, :music_id] + t.index [:music_id, :artist_id], unique: true + end diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index e29e19490e..833b7beb7f 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -21,12 +21,12 @@ Description: Available field types: - Just after the field name you can specify a type like text or boolean. + Just after the field name you can specify a type like text or boolean. It will generate the column with the associated SQL type. For instance: `rails generate model post title:string body:text` - will generate a title column with a varchar type and a body column with a text + will generate a title column with a varchar type and a body column with a text type. You can use the following types: integer @@ -46,27 +46,33 @@ Available field types: `rails generate model photo title:string album:references` - It will generate an album_id column. You should generate this kind of fields when - you will use a `belongs_to` association for instance. `references` also support - the polymorphism, you could enable the polymorphism like this: + It will generate an `album_id` column. You should generate these kinds of fields when + you will use a `belongs_to` association, for instance. `references` also supports + polymorphism, you can enable polymorphism like this: `rails generate model product supplier:references{polymorphic}` - You can also specify some options just after the field type. You can use the - following options: + For integer, string, text and binary fields, an integer in curly braces will + be set as the limit: - limit Set the maximum size of the field giving a number between curly braces - default Set a default value for the field - precision Defines the precision for the decimal fields - scale Defines the scale for the decimal fields - uniq Defines the field values as unique - index Will add an index on the field + `rails generate model user pseudo:string{30}` - Examples: + For decimal, two integers separated by a comma in curly braces will be used + for precision and scale: + + `rails generate model product 'price:decimal{10,2}'` + + You can add a `:uniq` or `:index` suffix for unique or standard indexes + respectively: - `rails generate model user pseudo:string{30}` `rails generate model user pseudo:string:uniq` - + `rails generate model user pseudo:string:index` + + You can combine any single curly brace option with the index options: + + `rails generate model user username:string{30}:uniq` + `rails generate model product supplier:references{polymorphic}:index` + Examples: `rails generate model account` @@ -76,7 +82,7 @@ Examples: Model: app/models/account.rb Test: test/models/account_test.rb Fixtures: test/fixtures/accounts.yml - Migration: db/migrate/XXX_add_accounts.rb + Migration: db/migrate/XXX_create_accounts.rb `rails generate model post title:string body:text published:boolean` @@ -90,5 +96,5 @@ Examples: Model: app/models/admin/account.rb Test: test/models/admin/account_test.rb Fixtures: test/fixtures/admin/accounts.yml - Migration: db/migrate/XXX_add_admin_accounts.rb + Migration: db/migrate/XXX_create_admin_accounts.rb diff --git a/railties/lib/rails/generators/rails/observer/USAGE b/railties/lib/rails/generators/rails/observer/USAGE deleted file mode 100644 index 177ff49e4a..0000000000 --- a/railties/lib/rails/generators/rails/observer/USAGE +++ /dev/null @@ -1,12 +0,0 @@ -Description: - Stubs out a new observer. Pass the observer name, either CamelCased or - under_scored, as an argument. - - This generator only invokes your ORM and test framework generators. - -Example: - `rails generate observer Account` - - For ActiveRecord and TestUnit it creates: - Observer: app/models/account_observer.rb - TestUnit: test/models/account_observer_test.rb diff --git a/railties/lib/rails/generators/rails/observer/observer_generator.rb b/railties/lib/rails/generators/rails/observer/observer_generator.rb deleted file mode 100644 index 7a4d701ac6..0000000000 --- a/railties/lib/rails/generators/rails/observer/observer_generator.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Rails - module Generators - class ObserverGenerator < NamedBase # :nodoc: - hook_for :orm, required: true - end - end -end diff --git a/railties/lib/rails/generators/rails/performance_test/USAGE b/railties/lib/rails/generators/rails/performance_test/USAGE deleted file mode 100644 index 9dc799559c..0000000000 --- a/railties/lib/rails/generators/rails/performance_test/USAGE +++ /dev/null @@ -1,10 +0,0 @@ -Description: - Stubs out a new performance test. Pass the name of the test, either - CamelCased or under_scored, as an argument. - - This generator invokes the current performance tool, which defaults to - TestUnit. - -Example: - `rails generate performance_test GeneralStories` creates a GeneralStories - performance test in test/performance/general_stories_test.rb diff --git a/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb deleted file mode 100644 index 56cd562f3d..0000000000 --- a/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Rails - module Generators - class PerformanceTestGenerator < NamedBase # :nodoc: - hook_for :performance_tool, as: :performance - end - end -end diff --git a/railties/lib/rails/generators/rails/plugin_new/USAGE b/railties/lib/rails/generators/rails/plugin/USAGE index 9a7bf9f396..9a7bf9f396 100644 --- a/railties/lib/rails/generators/rails/plugin_new/USAGE +++ b/railties/lib/rails/generators/rails/plugin/USAGE diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 4a0bcc35a4..f6f529b80a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -53,13 +53,11 @@ module Rails template "lib/%name%.rb" template "lib/tasks/%name%_tasks.rake" template "lib/%name%/version.rb" - if full? - template "lib/%name%/engine.rb" - end + template "lib/%name%/engine.rb" if engine? end def config - template "config/routes.rb" if full? + template "config/routes.rb" if engine? end def test @@ -70,7 +68,7 @@ module Rails task default: :test EOF - if full? + if engine? template "test/integration/navigation_test.rb" end end @@ -96,6 +94,11 @@ task default: :test end end + def test_dummy_assets + template "rails/javascripts.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true + template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true + end + def test_dummy_clean inside dummy_path do remove_file ".gitignore" @@ -103,8 +106,6 @@ task default: :test remove_file "doc" remove_file "Gemfile" remove_file "lib/tasks" - remove_file "app/assets/images/rails.png" - remove_file "public/index.html" remove_file "public/robots.txt" remove_file "README" remove_file "test" @@ -114,7 +115,7 @@ task default: :test def stylesheets if mountable? - copy_file "#{app_templates_dir}/app/assets/stylesheets/application.css", + copy_file "rails/stylesheets.css", "app/assets/stylesheets/#{name}/application.css" elsif full? empty_directory_with_keep_file "app/assets/stylesheets/#{name}" @@ -125,20 +126,20 @@ task default: :test return if options.skip_javascript? if mountable? - template "#{app_templates_dir}/app/assets/javascripts/application.js.tt", - "app/assets/javascripts/#{name}/application.js" + template "rails/javascripts.js", + "app/assets/javascripts/#{name}/application.js" elsif full? empty_directory_with_keep_file "app/assets/javascripts/#{name}" end end - def script(force = false) - return unless full? + def bin(force = false) + return unless engine? - directory "script", force: force do |content| + directory "bin", force: force do |content| "#{shebang}\n" + content end - chmod "script", 0755, verbose: false + chmod "bin", 0755, verbose: false end def gemfile_entry @@ -153,7 +154,7 @@ task default: :test end module Generators - class PluginNewGenerator < AppBase # :nodoc: + class PluginGenerator < AppBase # :nodoc: add_shared_options_for "plugin" alias_method :plugin_path, :app_path @@ -175,12 +176,15 @@ task default: :test "skip adding entry to Gemfile" def initialize(*args) - raise Error, "Options should be given after the plugin name. For details run: rails plugin --help" if args[0].blank? - @dummy_path = nil super + + unless plugin_path + raise Error, "Plugin name should be provided in arguments. For details run: rails plugin new --help" + end end + public_task :set_default_accessors! public_task :create_root def create_root_files @@ -216,8 +220,8 @@ task default: :test build(:images) end - def create_script_files - build(:script) + def create_bin_files + build(:bin) end def create_test_files @@ -225,7 +229,7 @@ task default: :test end def create_test_dummy_files - return if options[:skip_test_unit] && options[:dummy_path] == 'test/dummy' + return unless with_dummy_app? create_dummy_app end @@ -265,20 +269,29 @@ task default: :test build(:generate_test_dummy) store_application_definition! build(:test_dummy_config) + build(:test_dummy_assets) build(:test_dummy_clean) - # ensure that script/rails has proper dummy_path - build(:script, true) + # ensure that bin/rails has proper dummy_path + build(:bin, true) end end + def engine? + full? || mountable? + end + def full? - options[:full] || options[:mountable] + options[:full] end def mountable? options[:mountable] end + def with_dummy_app? + options[:skip_test_unit].blank? || options[:dummy_path] != 'test/dummy' + end + def self.banner "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" end @@ -307,7 +320,7 @@ task default: :test @application_definition ||= begin dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root) - unless options[:pretend] || !File.exists?(dummy_application_path) + unless options[:pretend] || !File.exist?(dummy_application_path) contents = File.read(dummy_application_path) contents[(contents.index(/module ([\w]+)\n(.*)class Application/m))..-1] end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec index 568ed653b7..5fdf0e1554 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.homepage = "TODO" s.summary = "TODO: Summary of <%= camelized %>." s.description = "TODO: Description of <%= camelized %>." + s.license = "MIT" s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] <% unless options.skip_test_unit? -%> @@ -19,9 +20,6 @@ Gem::Specification.new do |s| <% end -%> <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", "~> <%= Rails::VERSION::STRING %>" -<% if full? && !options[:skip_javascript] -%> - # s.add_dependency "<%= "#{options[:javascript]}-rails" %>" -<% end -%> <% unless options[:skip_active_record] -%> s.add_development_dependency "<%= gem_for_database %>" diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin/templates/Gemfile index 7448b386c5..d576784415 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin/templates/Gemfile @@ -1,10 +1,7 @@ -source "http://rubygems.org" +source "https://rubygems.org" <% if options[:skip_gemspec] -%> <%= '# ' if options.dev? || options.edge? -%>gem "rails", "~> <%= Rails::VERSION::STRING %>" -<% if full? && !options[:skip_javascript] -%> -# gem "<%= "#{options[:javascript]}-rails" %>" -<% end -%> <% else -%> # Declare your gem's dependencies in <%= name %>.gemspec. # Bundler will treat runtime dependencies like base dependencies, and @@ -12,11 +9,6 @@ source "http://rubygems.org" gemspec <% end -%> -<% unless options[:javascript] == 'jquery' -%> -# jquery-rails is used by the dummy application -gem "jquery-rails" - -<% end -%> <% if options[:skip_gemspec] -%> group :development do gem "<%= gem_for_database %>" @@ -31,7 +23,20 @@ end <% if options.dev? || options.edge? -%> # Your gem is dependent on dev or edge Rails. Once you can lock this # dependency down to a specific version, move it to your gemspec. -<%= rails_gemfile_entry -%> +<% max_width = gemfile_entries.map { |g| g.name.length }.max -%> +<% gemfile_entries.each do |gem| -%> +<% if gem.comment -%> + +# <%= gem.comment %> +<% end -%> +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> +, '<%= gem.version %>' +<% elsif gem.options.any? -%> +,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| + "#{k}: #{v.inspect}" }.join(', ') %> +<% else %> +<% end -%> +<% end -%> <% end -%> # To use debugger diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE index d7a9109894..d7a9109894 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE +++ b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc index 301d647731..301d647731 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/README.rdoc +++ b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile index 1369140537..0ba899176c 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile @@ -14,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('lib/**/*.rb') end -<% if full? && !options[:skip_active_record] && !options[:skip_test_unit] -%> +<% if engine? && !options[:skip_active_record] && with_dummy_app? -%> APP_RAKEFILE = File.expand_path("../<%= dummy_path -%>/Rakefile", __FILE__) load 'rails/tasks/engine.rake' <% end %> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt index 448ad7f989..448ad7f989 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt index 40ae9f52c2..40ae9f52c2 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +++ b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/.empty_directory diff --git a/railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory b/railties/lib/rails/generators/rails/plugin/templates/app/models/.empty_directory index e69de29bb2..e69de29bb2 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory +++ b/railties/lib/rails/generators/rails/plugin/templates/app/models/.empty_directory diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt index 1d380420b4..1d380420b4 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt index aa87d1b50c..c8de9f3e0f 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt @@ -1,4 +1,4 @@ -# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. +# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application. ENGINE_ROOT = File.expand_path('../..', __FILE__) ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb index 8e158d5831..8e158d5831 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore index 086d87818a..086d87818a 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/gitignore +++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb index 2d3bdc510c..40c074cced 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb @@ -1,4 +1,4 @@ -<% if full? -%> +<% if engine? -%> require "<%= name %>/engine" <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb index 967668fe66..967668fe66 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb index ef07ef2e19..ef07ef2e19 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake index 7121f5ae23..7121f5ae23 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index 2f9b7fc962..5508829f6b 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -7,11 +7,12 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie" +<%= comment_if :skip_action_view %>require "action_view/railtie" +<%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> -Bundler.require +Bundler.require(*Rails.groups) require "<%= name %>" <%= application_definition %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb new file mode 100644 index 0000000000..6266cfc509 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb @@ -0,0 +1,5 @@ +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js new file mode 100644 index 0000000000..5bc2e1c8b5 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js @@ -0,0 +1,13 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. +// +// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require_tree . diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb index 730ee31c3d..730ee31c3d 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css b/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css new file mode 100644 index 0000000000..a443db3401 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any styles + * defined in the other CSS/SCSS files in this directory. It is generally better to create a new + * file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb index 0a8bbd4aaf..0a8bbd4aaf 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb index 824caecb24..824caecb24 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index 1e26a313cd..1e26a313cd 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory b/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory b/railties/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +++ /dev/null diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb deleted file mode 100644 index c78bfb7f63..0000000000 --- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +++ /dev/null @@ -1,9 +0,0 @@ -gemfile = File.expand_path('../../../../Gemfile', __FILE__) - -if File.exist?(gemfile) - ENV['BUNDLE_GEMFILE'] = gemfile - require 'bundler' - Bundler.setup -end - -$:.unshift File.expand_path('../../../../lib', __FILE__)
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb index 121205b254..a0e5553e44 100644 --- a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb +++ b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb @@ -32,7 +32,7 @@ module Rails # route prepends two spaces onto the front of the string that is passed, this corrects that route route_string[2..-1] end - + private def route_string @route_string ||= "" diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index b4f466fbd8..e89789e72b 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -2,12 +2,19 @@ require 'rails/generators/rails/resource/resource_generator' module Rails module Generators - class ScaffoldGenerator < ResourceGenerator # :nodoc: + class ScaffoldGenerator < ResourceGenerator # :nodoc: remove_hook_for :resource_controller remove_class_option :actions class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" class_option :stylesheet_engine, desc: "Engine for Stylesheets" + class_option :assets, type: :boolean + class_option :resource_route, type: :boolean + + def handle_skip + @options = @options.merge(stylesheets: false) unless options[:assets] + @options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] + end hook_for :scaffold_controller, required: true @@ -16,7 +23,9 @@ module Rails end hook_for :stylesheet_engine do |stylesheet_engine| - invoke stylesheet_engine, [controller_name] if options[:stylesheets] && behavior == :invoke + if behavior == :invoke + invoke stylesheet_engine, [controller_name] + end end end end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index 4f36b612ae..6bf0a33a5f 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -13,7 +13,7 @@ module Rails argument :attributes, type: :array, default: [], banner: "field:type field:type" def create_controller_files - template "controller.rb", File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb") + template "controller.rb", File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") end hook_for :template_engine, :test_framework, as: :scaffold diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index d6bce40b0c..0e69aa101f 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -4,97 +4,64 @@ require_dependency "<%= namespaced_file_path %>/application_controller" <% end -%> <% module_namespacing do -%> class <%= controller_class_name %>Controller < ApplicationController + before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy] + # GET <%= route_url %> - # GET <%= route_url %>.json def index @<%= plural_table_name %> = <%= orm_class.all(class_name) %> - - respond_to do |format| - format.html # index.html.erb - format.json { render json: <%= "@#{plural_table_name}" %> } - end end # GET <%= route_url %>/1 - # GET <%= route_url %>/1.json def show - @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> - - respond_to do |format| - format.html # show.html.erb - format.json { render json: <%= "@#{singular_table_name}" %> } - end end # GET <%= route_url %>/new - # GET <%= route_url %>/new.json def new @<%= singular_table_name %> = <%= orm_class.build(class_name) %> - - respond_to do |format| - format.html # new.html.erb - format.json { render json: <%= "@#{singular_table_name}" %> } - end end # GET <%= route_url %>/1/edit def edit - @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> end # POST <%= route_url %> - # POST <%= route_url %>.json def create @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %> - respond_to do |format| - if @<%= orm_instance.save %> - format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> } - format.json { render json: <%= "@#{singular_table_name}" %>, status: :created, location: <%= "@#{singular_table_name}" %> } - else - format.html { render action: "new" } - format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity } - end + if @<%= orm_instance.save %> + redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> + else + render action: 'new' end end # PATCH/PUT <%= route_url %>/1 - # PATCH/PUT <%= route_url %>/1.json def update - @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> - - respond_to do |format| - if @<%= orm_instance.update_attributes("#{singular_table_name}_params") %> - format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> } - format.json { head :no_content } - else - format.html { render action: "edit" } - format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity } - end + if @<%= orm_instance.update("#{singular_table_name}_params") %> + redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> + else + render action: 'edit' end end # DELETE <%= route_url %>/1 - # DELETE <%= route_url %>/1.json def destroy - @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> @<%= orm_instance.destroy %> - - respond_to do |format| - format.html { redirect_to <%= index_helper %>_url } - format.json { head :no_content } - end + redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %> end private + # Use callbacks to share common setup or constraints between actions. + def set_<%= singular_table_name %> + @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %> + end - # Use this method to whitelist the permissible parameters. Example: params.require(:person).permit(:name, :age) - # Also, you can specialize this method with per-user checking of permissible attributes. + # Only allow a trusted parameter "white list" through. def <%= "#{singular_table_name}_params" %> - <%- if attributes.empty? -%> - params[<%= ":#{singular_table_name}" %>] + <%- if attributes_names.empty? -%> + params[:<%= singular_table_name %>] <%- else -%> - params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes.map {|a| ":#{a.name}" }.join(', ') %>) + params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>) <%- end -%> end end diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 7fd5c00768..a01eb57651 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -9,11 +9,19 @@ module Rails def self.included(base) #:nodoc: base.class_option :force_plural, type: :boolean, desc: "Forces the use of a plural ModelName" + base.class_option :model_name, type: :string, desc: "ModelName to be used" end # Set controller variables on initialization. def initialize(*args) #:nodoc: super + if options[:model_name] + controller_name = name + self.name = options[:model_name] + assign_names!(self.name) + else + controller_name = name + end if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] unless ResourceHelpers.skip_warn @@ -24,19 +32,26 @@ module Rails assign_names!(name) end - @controller_name = name.pluralize + assign_controller_names!(controller_name.pluralize) end protected - attr_reader :controller_name + attr_reader :controller_name, :controller_file_name def controller_class_path - class_path + if options[:model_name] + @controller_class_path + else + class_path + end end - def controller_file_name - @controller_file_name ||= file_name.pluralize + def assign_controller_names!(name) + @controller_name = name + @controller_class_path = name.include?('/') ? name.split('/') : name.split('::') + @controller_class_path.map! { |m| m.underscore } + @controller_file_name = @controller_class_path.pop end def controller_file_path diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 24308dcf6c..58592b4f8e 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -1,8 +1,7 @@ -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/kernel/reporting' require 'rails/generators' +require 'rails/generators/testing/behaviour' +require 'rails/generators/testing/setup_and_teardown' +require 'rails/generators/testing/assertions' require 'fileutils' module Rails @@ -27,215 +26,11 @@ module Rails # setup :prepare_destination # end class TestCase < ActiveSupport::TestCase + include Rails::Generators::Testing::Behaviour + include Rails::Generators::Testing::SetupAndTeardown + include Rails::Generators::Testing::Assertions include FileUtils - class_attribute :destination_root, :current_path, :generator_class, :default_arguments - - # Generators frequently change the current path using +FileUtils.cd+. - # So we need to store the path at file load and revert back to it after each test. - self.current_path = File.expand_path(Dir.pwd) - self.default_arguments = [] - - def setup # :nodoc: - destination_root_is_set? - ensure_current_path - super - end - - def teardown # :nodoc: - ensure_current_path - super - end - - # Sets which generator should be tested: - # - # tests AppGenerator - def self.tests(klass) - self.generator_class = klass - end - - # Sets default arguments on generator invocation. This can be overwritten when - # invoking it. - # - # arguments %w(app_name --skip-active-record) - def self.arguments(array) - self.default_arguments = array - end - - # Sets the destination of generator files: - # - # destination File.expand_path("../tmp", File.dirname(__FILE__)) - def self.destination(path) - self.destination_root = path - end - - # Asserts a given file exists. You need to supply an absolute path or a path relative - # to the configured destination: - # - # assert_file "config/environment.rb" - # - # You can also give extra arguments. If the argument is a regexp, it will check if the - # regular expression matches the given file content. If it's a string, it compares the - # file with the given string: - # - # assert_file "config/environment.rb", /initialize/ - # - # Finally, when a block is given, it yields the file content: - # - # assert_file "app/controllers/products_controller.rb" do |controller| - # assert_instance_method :index, controller do |index| - # assert_match(/Product\.all/, index) - # end - # end - def assert_file(relative, *contents) - absolute = File.expand_path(relative, destination_root) - 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 - alias :assert_directory :assert_file - - # Asserts a given file does not exist. You need to supply an absolute path or a - # path relative to the configured destination: - # - # assert_no_file "config/random.rb" - def assert_no_file(relative) - absolute = File.expand_path(relative, destination_root) - assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does" - end - alias :assert_no_directory :assert_no_file - - # Asserts a given migration exists. You need to supply an absolute path or a - # path relative to the configured destination: - # - # assert_migration "db/migrate/create_products.rb" - # - # This method manipulates the given path and tries to find any migration which - # matches the migration name. For example, the call above is converted to: - # - # assert_file "db/migrate/003_create_products.rb" - # - # Consequently, assert_migration accepts the same arguments has assert_file. - 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_name, *contents, &block - end - - # Asserts a given migration does not exist. You need to supply an absolute path or a - # path relative to the configured destination: - # - # assert_no_migration "db/migrate/create_products.rb" - 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 - - # Asserts the given class method exists in the given content. This method does not detect - # class methods inside (class << self), only class methods which starts with "self.". - # When a block is given, it yields the content of the method. - # - # assert_migration "db/migrate/create_products.rb" do |migration| - # assert_class_method :up, migration do |up| - # assert_match(/create_table/, up) - # end - # end - def assert_class_method(method, content, &block) - assert_instance_method "self.#{method}", content, &block - end - - # Asserts the given method exists in the given content. When a block is given, - # it yields the content of the method. - # - # assert_file "app/controllers/products_controller.rb" do |controller| - # assert_instance_method :index, controller do |index| - # assert_match(/Product\.all/, index) - # end - # end - def assert_instance_method(method, content) - assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}" - yield $2.strip if block_given? - end - alias :assert_method :assert_instance_method - - # Asserts the given attribute type gets translated to a field type - # properly: - # - # assert_field_type :date, :date_select - def assert_field_type(attribute_type, field_type) - assert_equal(field_type, create_generated_attribute(attribute_type).field_type) - end - - # Asserts the given attribute type gets a proper default value: - # - # assert_field_default_value :string, "MyString" - def assert_field_default_value(attribute_type, value) - assert_equal(value, create_generated_attribute(attribute_type).default) - end - - # Runs the generator configured for this class. The first argument is an array like - # command line arguments: - # - # class AppGeneratorTest < Rails::Generators::TestCase - # tests AppGenerator - # destination File.expand_path("../tmp", File.dirname(__FILE__)) - # teardown :cleanup_destination_root - # - # test "database.yml is not created when skipping Active Record" do - # run_generator %w(myapp --skip-active-record) - # assert_no_file "config/database.yml" - # end - # end - # - # You can provide a configuration hash as second argument. This method returns the output - # printed by the generator. - def run_generator(args=self.default_arguments, config={}) - capture(:stdout) { self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) } - end - - # Instantiate the generator. - def generator(args=self.default_arguments, options={}, config={}) - @generator ||= self.generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) - end - - # Create a Rails::Generators::GeneratedAttribute by supplying the - # attribute type and, optionally, the attribute name: - # - # create_generated_attribute(:string, 'name') - def create_generated_attribute(attribute_type, name = 'test', index = nil) - Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) - end - - protected - - def destination_root_is_set? # :nodoc: - raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root - end - - def ensure_current_path # :nodoc: - cd current_path - end - - def prepare_destination # :nodoc: - rm_rf(destination_root) - mkdir_p(destination_root) - end - - def migration_file_name(relative) # :nodoc: - absolute = File.expand_path(relative, destination_root) - dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '') - Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first - end end end end diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb new file mode 100644 index 0000000000..d7307398ce --- /dev/null +++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb @@ -0,0 +1,26 @@ +require 'rails/generators/test_unit' + +module TestUnit # :nodoc: + module Generators # :nodoc: + class GeneratorGenerator < Base # :nodoc: + check_class_collision suffix: "GeneratorTest" + + class_option :namespace, type: :boolean, default: true, + desc: "Namespace generator under lib/generators/name" + + def create_generator_files + template 'generator_test.rb', File.join('test/lib/generators', class_path, "#{file_name}_generator_test.rb") + end + + protected + + def generator_path + if options[:namespace] + File.join("generators", regular_class_path, file_name, "#{file_name}_generator") + else + File.join("generators", regular_class_path, "#{file_name}_generator") + end + end + end + end +end diff --git a/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb new file mode 100644 index 0000000000..a7f1fc4fba --- /dev/null +++ b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' +require '<%= generator_path %>' + +<% module_namespacing do -%> +class <%= class_name %>GeneratorTest < Rails::Generators::TestCase + tests <%= class_name %>Generator + destination Rails.root.join('tmp/generators') + setup :prepare_destination + + # test "generator runs without errors" do + # assert_nothing_raised do + # run_generator ["arguments"] + # end + # end +end +<% end -%> diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb index 2801749ffe..2826a3ffa1 100644 --- a/railties/lib/rails/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -3,6 +3,9 @@ require 'rails/generators/test_unit' module TestUnit # :nodoc: module Generators # :nodoc: class ModelGenerator < Base # :nodoc: + + RESERVED_YAML_KEYWORDS = %w(y yes n no true false on off null) + argument :attributes, type: :array, default: [], banner: "field:type field:type" class_option :fixture, type: :boolean @@ -19,6 +22,15 @@ module TestUnit # :nodoc: template 'fixtures.yml', File.join('test/fixtures', class_path, "#{plural_file_name}.yml") end end + + private + def yaml_key_value(key, value) + if RESERVED_YAML_KEYWORDS.include?(key.downcase) + "'#{key}': #{value}" + else + "#{key}: #{value}" + end + end end end end diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index 5c8780aa64..f19e9d1d87 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml @@ -1,16 +1,20 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html - +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html <% unless attributes.empty? -%> -one: +<% %w(one two).each do |name| %> +<%= name %>: <% attributes.each do |attribute| -%> - <%= attribute.name %>: <%= attribute.default %> + <%- if attribute.password_digest? -%> + password_digest: <%%= BCrypt::Password.create('secret') %> + <%- else -%> + <%= yaml_key_value(attribute.column_name, attribute.default) %> + <%- end -%> + <%- if attribute.polymorphic? -%> + <%= yaml_key_value("#{attribute.name}_type", attribute.human_name) %> + <%- end -%> <% end -%> - -two: -<% attributes.each do |attribute| -%> - <%= attribute.name %>: <%= attribute.default %> <% end -%> <% else -%> + # This model initially had no columns defined. If you add columns to the # model remove the '{}' from the fixture names and add the columns immediately # below each fixture, per the syntax in the comments below diff --git a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb deleted file mode 100644 index 64fe694a8b..0000000000 --- a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'rails/generators/test_unit' - -module TestUnit # :nodoc: - module Generators # :nodoc: - class ObserverGenerator < Base # :nodoc: - check_class_collision suffix: "ObserverTest" - - def create_test_files - template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_observer_test.rb") - end - end - end -end diff --git a/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb deleted file mode 100644 index 28aa23626a..0000000000 --- a/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'test_helper' - -<% module_namespacing do -%> -class <%= class_name %>ObserverTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end -<% end -%> diff --git a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb deleted file mode 100644 index 5552edeee4..0000000000 --- a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'rails/generators/test_unit' - -module TestUnit # :nodoc: - module Generators # :nodoc: - class PerformanceGenerator < Base # :nodoc: - 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/generators/test_unit/performance/templates/performance_test.rb b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb deleted file mode 100644 index 2bcb482d68..0000000000 --- a/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'test_helper' -require 'rails/performance_test_help' - -class <%= class_name %>Test < ActionDispatch::PerformanceTest - # Refer to the documentation for all available options - # self.profile_options = { runs: 5, metrics: [:wall_time, :memory], - # output: 'tmp/performance', formats: [:flat] } - - test "homepage" do - get '/' - end -end diff --git a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb index c9af2ca832..30a861f09d 100644 --- a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb @@ -1,2 +1,2 @@ -require 'minitest/autorun' +require 'active_support/testing/autorun' require 'active_support' diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index 3b4fec2e83..2e1f55f2a6 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -18,17 +18,16 @@ module TestUnit # :nodoc: private def attributes_hash - return if accessible_attributes.empty? - - accessible_attributes.map do |a| - name = a.name - "#{name}: @#{singular_table_name}.#{name}" + return if attributes_names.empty? + + attributes_names.map do |name| + if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?) + "#{name}: 'secret'" + else + "#{name}: @#{singular_table_name}.#{name}" + end end.sort.join(', ') end - - def accessible_attributes - attributes.reject(&:reference?) - end end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb index 30e1650555..18bd1ece9d 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb @@ -36,7 +36,7 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase end test "should update <%= singular_table_name %>" do - put :update, id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> + patch :update, id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>)) end diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb new file mode 100644 index 0000000000..2e877f8762 --- /dev/null +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -0,0 +1,121 @@ +module Rails + module Generators + module Testing + module Assertions + # Asserts a given file exists. You need to supply an absolute path or a path relative + # to the configured destination: + # + # assert_file "config/environment.rb" + # + # You can also give extra arguments. If the argument is a regexp, it will check if the + # regular expression matches the given file content. If it's a string, it compares the + # file with the given string: + # + # assert_file "config/environment.rb", /initialize/ + # + # Finally, when a block is given, it yields the file content: + # + # assert_file "app/controllers/products_controller.rb" do |controller| + # assert_instance_method :index, controller do |index| + # assert_match(/Product\.all/, index) + # end + # end + def assert_file(relative, *contents) + absolute = File.expand_path(relative, destination_root).shellescape + assert File.exist?(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 + alias :assert_directory :assert_file + + # Asserts a given file does not exist. You need to supply an absolute path or a + # path relative to the configured destination: + # + # assert_no_file "config/random.rb" + def assert_no_file(relative) + absolute = File.expand_path(relative, destination_root) + assert !File.exist?(absolute), "Expected file #{relative.inspect} to not exist, but does" + end + alias :assert_no_directory :assert_no_file + + # Asserts a given migration exists. You need to supply an absolute path or a + # path relative to the configured destination: + # + # assert_migration "db/migrate/create_products.rb" + # + # This method manipulates the given path and tries to find any migration which + # matches the migration name. For example, the call above is converted to: + # + # assert_file "db/migrate/003_create_products.rb" + # + # Consequently, assert_migration accepts the same arguments has assert_file. + 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_name, *contents, &block + end + + # Asserts a given migration does not exist. You need to supply an absolute path or a + # path relative to the configured destination: + # + # assert_no_migration "db/migrate/create_products.rb" + 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 + + # Asserts the given class method exists in the given content. This method does not detect + # class methods inside (class << self), only class methods which starts with "self.". + # When a block is given, it yields the content of the method. + # + # assert_migration "db/migrate/create_products.rb" do |migration| + # assert_class_method :up, migration do |up| + # assert_match(/create_table/, up) + # end + # end + def assert_class_method(method, content, &block) + assert_instance_method "self.#{method}", content, &block + end + + # Asserts the given method exists in the given content. When a block is given, + # it yields the content of the method. + # + # assert_file "app/controllers/products_controller.rb" do |controller| + # assert_instance_method :index, controller do |index| + # assert_match(/Product\.all/, index) + # end + # end + def assert_instance_method(method, content) + assert content =~ /(\s+)def #{method}(\(.+\))?(.*?)\n\1end/m, "Expected to have method #{method}" + yield $3.strip if block_given? + end + alias :assert_method :assert_instance_method + + # Asserts the given attribute type gets translated to a field type + # properly: + # + # assert_field_type :date, :date_select + def assert_field_type(attribute_type, field_type) + assert_equal(field_type, create_generated_attribute(attribute_type).field_type) + end + + # Asserts the given attribute type gets a proper default value: + # + # assert_field_default_value :string, "MyString" + def assert_field_default_value(attribute_type, value) + assert_equal(value, create_generated_attribute(attribute_type).default) + end + end + end + end +end diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb new file mode 100644 index 0000000000..7576eba6e0 --- /dev/null +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -0,0 +1,106 @@ +require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/hash/reverse_merge' +require 'active_support/core_ext/kernel/reporting' +require 'active_support/concern' +require 'rails/generators' + +module Rails + module Generators + module Testing + module Behaviour + extend ActiveSupport::Concern + + included do + class_attribute :destination_root, :current_path, :generator_class, :default_arguments + + # Generators frequently change the current path using +FileUtils.cd+. + # So we need to store the path at file load and revert back to it after each test. + self.current_path = File.expand_path(Dir.pwd) + self.default_arguments = [] + end + + module ClassMethods + # Sets which generator should be tested: + # + # tests AppGenerator + def tests(klass) + self.generator_class = klass + end + + # Sets default arguments on generator invocation. This can be overwritten when + # invoking it. + # + # arguments %w(app_name --skip-active-record) + def arguments(array) + self.default_arguments = array + end + + # Sets the destination of generator files: + # + # destination File.expand_path("../tmp", File.dirname(__FILE__)) + def destination(path) + self.destination_root = path + end + end + + # Runs the generator configured for this class. The first argument is an array like + # command line arguments: + # + # class AppGeneratorTest < Rails::Generators::TestCase + # tests AppGenerator + # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # teardown :cleanup_destination_root + # + # test "database.yml is not created when skipping Active Record" do + # run_generator %w(myapp --skip-active-record) + # assert_no_file "config/database.yml" + # end + # end + # + # You can provide a configuration hash as second argument. This method returns the output + # printed by the generator. + def run_generator(args=self.default_arguments, config={}) + capture(:stdout) do + args += ['--skip-bundle'] unless args.include? '--dev' + self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) + end + end + + # Instantiate the generator. + def generator(args=self.default_arguments, options={}, config={}) + @generator ||= self.generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) + end + + # Create a Rails::Generators::GeneratedAttribute by supplying the + # attribute type and, optionally, the attribute name: + # + # create_generated_attribute(:string, 'name') + def create_generated_attribute(attribute_type, name = 'test', index = nil) + Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) + end + + protected + + def destination_root_is_set? # :nodoc: + raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root + end + + def ensure_current_path # :nodoc: + cd current_path + end + + def prepare_destination # :nodoc: + rm_rf(destination_root) + mkdir_p(destination_root) + end + + def migration_file_name(relative) # :nodoc: + absolute = File.expand_path(relative, destination_root) + dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '') + Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first + end + end + end + end +end diff --git a/railties/lib/rails/generators/testing/setup_and_teardown.rb b/railties/lib/rails/generators/testing/setup_and_teardown.rb new file mode 100644 index 0000000000..73102a283f --- /dev/null +++ b/railties/lib/rails/generators/testing/setup_and_teardown.rb @@ -0,0 +1,18 @@ +module Rails + module Generators + module Testing + module SetupAndTeardown + def setup # :nodoc: + destination_root_is_set? + ensure_current_path + super + end + + def teardown # :nodoc: + ensure_current_path + super + end + end + end + end +end diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index aacc1be2fc..edadeaca0e 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -23,13 +23,13 @@ module Rails end def frameworks - %w( active_record action_pack action_mailer active_support ) + %w( active_record action_pack action_view action_mailer active_support ) end def framework_version(framework) if Object.const_defined?(framework.classify) require "#{framework}/version" - "#{framework.classify}::VERSION::STRING".constantize + framework.classify.constantize.version.to_s end end @@ -46,7 +46,7 @@ module Rails alias inspect to_s def to_html - (table = '<table>').tap do + '<table>'.tap do |table| properties.each do |(name, value)| table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>) formatted_value = if value.kind_of?(Array) @@ -61,8 +61,10 @@ module Rails end end - # The Ruby version and platform, e.g. "1.8.2 (powerpc-darwin8.2.0)". - property 'Ruby version', "#{RUBY_VERSION} (#{RUBY_PLATFORM})" + # The Ruby version and platform, e.g. "2.0.0-p247 (x86_64-darwin12.4.0)". + property 'Ruby version' do + "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})" + end # The RubyGems version, if it's installed. property 'RubyGems version' do @@ -75,7 +77,7 @@ module Rails # The Rails version. property 'Rails version' do - Rails::VERSION::STRING + Rails.version.to_s end property 'JavaScript Runtime' do diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index e94c6a2030..fa5668a5b5 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,13 +1,14 @@ require 'action_dispatch/routing/inspector' -class Rails::InfoController < ActionController::Base - self.view_paths = File.join(File.dirname(__FILE__), 'templates') - layout 'application' +class Rails::InfoController < ActionController::Base # :nodoc: + self.view_paths = File.expand_path('../templates', __FILE__) + prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH + layout -> { request.xhr? ? nil : 'application' } before_filter :require_local! def index - redirect_to '/rails/info/routes' + redirect_to action: :routes end def properties @@ -15,8 +16,7 @@ class Rails::InfoController < ActionController::Base end def routes - inspector = ActionDispatch::Routing::RoutesInspector.new - @info = inspector.format(_routes.routes).join("\n") + @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes) end protected diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 8af4130e87..f512aefb23 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -55,9 +55,9 @@ module Rails add(path, with: value, glob: glob) end - def add(path, options={}) - with = options[:with] || path - @root[path] = Path.new(self, path, [with].flatten, options) + def add(path, options = {}) + with = Array(options.fetch(:with, path)) + @root[path] = Path.new(self, path, with, options) end def [](path) @@ -81,34 +81,28 @@ module Rails end def autoload_once - filter_by(:autoload_once?) + filter_by { |p| p.autoload_once? } end def eager_load - filter_by(:eager_load?) + filter_by { |p| p.eager_load? } end def autoload_paths - filter_by(:autoload?) + filter_by { |p| p.autoload? } end def load_paths - filter_by(:load_path?) + filter_by { |p| p.load_path? } end - protected + private - def filter_by(constraint) - all = [] - all_paths.each do |path| - if path.send(constraint) - paths = path.existent - paths -= path.children.map { |p| p.send(constraint) ? [] : p.existent }.flatten - all.concat(paths) - end - end - all.uniq! - all + def filter_by(&block) + all_paths.find_all(&block).flat_map { |path| + paths = path.existent + paths - path.children.map { |p| yield(p) ? [] : p.existent }.flatten + }.uniq end end @@ -130,8 +124,9 @@ module Rails end def children - keys = @root.keys.select { |k| k.include?(@current) } - keys.delete(@current) + keys = @root.keys.find_all { |k| + k.start_with?(@current) && k != @current + } @root.values_at(*keys.sort) end @@ -189,9 +184,9 @@ module Rails path = File.expand_path(p, @root.path) if @glob && File.directory?(path) - result.concat Dir.chdir(path) { - Dir.glob(@glob).map { |file| File.join path, file }.sort - } + Dir.chdir(path) do + result.concat(Dir.glob(@glob).map { |file| File.join path, file }.sort) + end else result << path end @@ -203,7 +198,7 @@ module Rails # Returns all expanded paths but only if they exist in the filesystem. def existent - expanded.select { |f| File.exists?(f) } + expanded.select { |f| File.exist?(f) } end def existent_directories diff --git a/railties/lib/rails/performance_test_help.rb b/railties/lib/rails/performance_test_help.rb deleted file mode 100644 index b1285efde2..0000000000 --- a/railties/lib/rails/performance_test_help.rb +++ /dev/null @@ -1,3 +0,0 @@ -ActionController::Base.perform_caching = true -ActiveSupport::Dependencies.mechanism = :require -Rails.logger.level = ActiveSupport::Logger::INFO diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb index 902361ce77..f7b77bcb3b 100644 --- a/railties/lib/rails/rack/debugger.rb +++ b/railties/lib/rails/rack/debugger.rb @@ -12,8 +12,8 @@ module Rails ::Debugger.settings[:autoeval] = true if ::Debugger.respond_to?(:settings) puts "=> Debugger enabled" rescue LoadError - puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again." - exit + puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again." + exit(1) end def call(env) diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb index 18f22e8089..50d0eb96fc 100644 --- a/railties/lib/rails/rack/log_tailer.rb +++ b/railties/lib/rails/rack/log_tailer.rb @@ -7,7 +7,7 @@ module Rails path = Pathname.new(log || "#{::File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath @cursor = @file = nil - if ::File.exists?(path) + if ::File.exist?(path) @cursor = ::File.size(path) @file = ::File.open(path, 'r') end diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 3f59bb8733..3b35798679 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -1,19 +1,23 @@ require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/object/blank' +require 'active_support/log_subscriber' +require 'action_dispatch/http/request' +require 'rack/body_proxy' module Rails module Rack # Sets log tags, logs the request, calls the app, and flushes the logs. class Logger < ActiveSupport::LogSubscriber def initialize(app, taggers = nil) - @app, @taggers = app, taggers || [] + @app = app + @taggers = taggers || [] end def call(env) request = ActionDispatch::Request.new(env) - if Rails.logger.respond_to?(:tagged) - Rails.logger.tagged(compute_tags(request)) { call_app(request, env) } + if logger.respond_to?(:tagged) + logger.tagged(compute_tags(request)) { call_app(request, env) } else call_app(request, env) end @@ -23,13 +27,20 @@ module Rails def call_app(request, env) # Put some space between requests in development logs. - if Rails.env.development? - Rails.logger.info '' - Rails.logger.info '' + if development? + logger.debug '' + logger.debug '' end - Rails.logger.info started_request_message(request) - @app.call(env) + instrumenter = ActiveSupport::Notifications.instrumenter + instrumenter.start 'request.action_dispatch', request: request + logger.info started_request_message(request) + resp = @app.call(env) + resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) } + resp + rescue Exception + finish(request) + raise ensure ActiveSupport::LogSubscriber.flush_all! end @@ -55,6 +66,21 @@ module Rails end end end + + private + + def finish(request) + instrumenter = ActiveSupport::Notifications.instrumenter + instrumenter.finish 'request.action_dispatch', request: request + end + + def development? + Rails.env.development? + end + + def logger + Rails.logger + end end end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 5b454e7f20..89ca8cbe11 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -112,7 +112,6 @@ module Rails # Be sure to look at the documentation of those specific classes for more information. # class Railtie - autoload :Configurable, "rails/railtie/configurable" autoload :Configuration, "rails/railtie/configuration" include Initializable @@ -121,6 +120,7 @@ module Rails class << self private :new + delegate :config, to: :instance def subclasses @subclasses ||= [] @@ -128,7 +128,6 @@ module Rails def inherited(base) unless base.abstract_railtie? - base.send(:include, Railtie::Configurable) subclasses << base end end @@ -166,13 +165,50 @@ module Rails @railtie_name ||= generate_railtie_name(self.name) end + # Since Rails::Railtie cannot be instantiated, any methods that call + # +instance+ are intended to be called only on subclasses of a Railtie. + def instance + @instance ||= new + end + + def respond_to_missing?(*args) + instance.respond_to?(*args) || super + end + + # Allows you to configure the railtie. This is the same method seen in + # Railtie::Configurable, but this module is no longer required for all + # subclasses of Railtie so we provide the class method here. + def configure(&block) + instance.configure(&block) + end + protected def generate_railtie_name(class_or_module) ActiveSupport::Inflector.underscore(class_or_module).tr("/", "_") end + + # If the class method does not have a method, then send the method call + # to the Railtie instance. + def method_missing(name, *args, &block) + if instance.respond_to?(name) + instance.public_send(name, *args, &block) + else + super + end + end + end + + delegate :railtie_name, to: :class + + def initialize + if self.class.abstract_railtie? + raise "#{self.class.name} is abstract, you cannot instantiate it directly." + end end - delegate :railtie_name, to: "self.class" + def configure(&block) + instance_eval(&block) + end def config @config ||= Railtie::Configuration.new diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 0cbbf04da2..eb3b2d8ef4 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -80,7 +80,7 @@ module Rails to_prepare_blocks << blk if blk end - def respond_to?(name) + def respond_to?(name, include_private = false) super || @@options.key?(name.to_sym) end diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 4536fedaa3..3b7f358a5b 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -2,12 +2,12 @@ if RUBY_VERSION < '1.9.3' desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message - Rails 4 requires Ruby 1.9.3+. + Rails 4 prefers to run on Ruby 2.0. You're running #{desc} - Please upgrade to continue. + Please upgrade to Ruby 1.9.3 or newer to continue. end_message end diff --git a/railties/lib/rails/script_rails_loader.rb b/railties/lib/rails/script_rails_loader.rb deleted file mode 100644 index 7054089614..0000000000 --- a/railties/lib/rails/script_rails_loader.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'pathname' - -module Rails - module ScriptRailsLoader - RUBY = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) + RbConfig::CONFIG["EXEEXT"] - SCRIPT_RAILS = File.join('script', 'rails') - - def self.exec_script_rails! - cwd = Dir.pwd - return unless in_rails_application? || in_rails_application_subdirectory? - exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application? - Dir.chdir("..") do - # Recurse in a chdir block: if the search fails we want to be sure - # the application is generated in the original working directory. - exec_script_rails! unless cwd == Dir.pwd - end - rescue SystemCallError - # could not chdir, no problem just return - end - - def self.in_rails_application? - File.exists?(SCRIPT_RAILS) - end - - def self.in_rails_application_subdirectory?(path = Pathname.new(Dir.pwd)) - File.exists?(File.join(path, SCRIPT_RAILS)) || !path.root? && in_rails_application_subdirectory?(path.parent) - end - end -end
\ No newline at end of file diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 3474b02af4..b806b922b7 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -15,7 +15,7 @@ class SourceAnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) def self.directories - @@directories ||= %w(app config lib script test) + (ENV['SOURCE_ANNOTATION_DIRECTORIES'] || '').split(',') + @@directories ||= %w(app config db lib test) + (ENV['SOURCE_ANNOTATION_DIRECTORIES'] || '').split(',') end # Returns a representation of the annotation that looks like this: @@ -31,16 +31,25 @@ class SourceAnnotationExtractor end end - # Prints all annotations with tag +tag+ under the root directories +app+, +config+, +lib+, - # +script+, and +test+ (recursively). Filenames with extension - # +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, +.scss+, +.js+, - # +.coffee+, and +.rake+ are taken into account. The +options+ hash is passed to each - # annotation's +to_s+. + # Prints all annotations with tag +tag+ under the root directories +app+, + # +config+, +db+, +lib+, and +test+ (recursively). + # + # Additional directories may be added using a comma-delimited list set using + # <tt>ENV['SOURCE_ANNOTATION_DIRECTORIES']</tt>. + # + # Directories may also be explicitly set using the <tt>:dirs</tt> key in +options+. + # + # SourceAnnotationExtractor.enumerate 'TODO|FIXME', dirs: %w(app lib), tag: true + # + # If +options+ has a <tt>:tag</tt> flag, it will be passed to each annotation's +to_s+. + # + # See <tt>#find_in</tt> for a list of file extensions that will be taken into account. # # This class method is the single entry point for the rake tasks. def self.enumerate(tag, options={}) extractor = new(tag) - extractor.display(extractor.find, options) + dirs = options.delete(:dirs) || Annotation.directories + extractor.display(extractor.find(dirs), options) end attr_reader :tag @@ -51,7 +60,7 @@ class SourceAnnotationExtractor # Returns a hash that maps filenames under +dirs+ (recursively) to arrays # with their annotations. - def find(dirs = Annotation.directories) + def find(dirs) dirs.inject({}) { |h, dir| h.update(find_in(dir)) } end @@ -68,16 +77,22 @@ class SourceAnnotationExtractor if File.directory?(item) results.update(find_in(item)) - elsif item =~ /\.(builder|rb|coffee|rake)$/ - results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/)) - elsif item =~ /\.(css|scss|js)$/ - results.update(extract_annotations_from(item, /\/\/\s*(#{tag}):?\s*(.*)$/)) - elsif item =~ /\.erb$/ - results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/)) - elsif item =~ /\.haml$/ - results.update(extract_annotations_from(item, /-\s*#\s*(#{tag}):?\s*(.*)$/)) - elsif item =~ /\.slim$/ - results.update(extract_annotations_from(item, /\/\s*\s*(#{tag}):?\s*(.*)$/)) + else + pattern = + case item + when /\.(builder|rb|coffee|rake)$/ + /#\s*(#{tag}):?\s*(.*)$/ + when /\.(css|scss|sass|less|js)$/ + /\/\/\s*(#{tag}):?\s*(.*)$/ + when /\.erb$/ + /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/ + when /\.haml$/ + /-\s*#\s*(#{tag}):?\s*(.*)$/ + when /\.slim$/ + /\/\s*\s*(#{tag}):?\s*(.*)$/ + else nil + end + results.update(extract_annotations_from(item, pattern)) if pattern end end diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb index 9807000578..af5f2707b1 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -1,6 +1,4 @@ -$VERBOSE = nil - -# Load Rails rakefile extensions +# Load Rails Rakefile extensions %w( annotations documentation diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index 2851ca4189..8544890553 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -1,105 +1,70 @@ -require 'rdoc/task' - -# Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise -class RDocTaskWithoutDescriptions < RDoc::Task - include ::Rake::DSL - - def define - task rdoc_task_name - - task rerdoc_task_name => [clobber_task_name, rdoc_task_name] - - task clobber_task_name do - rm_r rdoc_dir rescue nil - end - - task :clobber => [clobber_task_name] +begin + require 'rdoc/task' +rescue LoadError + # Rubinius installs RDoc as a gem, and for this interpreter "rdoc/task" is + # available only if the application bundle includes "rdoc" (normally as a + # dependency of the "sdoc" gem.) + # + # If RDoc is not available it is fine that we do not generate the tasks that + # depend on it. Just be robust to this gotcha and go on. +else + require 'rails/api/task' + + # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise + class RDocTaskWithoutDescriptions < RDoc::Task + include ::Rake::DSL + + def define + task rdoc_task_name + + task rerdoc_task_name => [clobber_task_name, rdoc_task_name] + + task clobber_task_name do + rm_r rdoc_dir rescue nil + end - directory @rdoc_dir - task rdoc_task_name => [rdoc_target] - file rdoc_target => @rdoc_files + [Rake.application.rakefile] do - rm_r @rdoc_dir rescue nil - @before_running_rdoc.call if @before_running_rdoc - args = option_list + @rdoc_files - if @external - argstring = args.join(' ') - sh %{ruby -Ivendor vendor/rd #{argstring}} - else - require 'rdoc/rdoc' - RDoc::RDoc.new.document(args) + task :clobber => [clobber_task_name] + + directory @rdoc_dir + task rdoc_task_name => [rdoc_target] + file rdoc_target => @rdoc_files + [Rake.application.rakefile] do + rm_r @rdoc_dir rescue nil + @before_running_rdoc.call if @before_running_rdoc + args = option_list + @rdoc_files + if @external + argstring = args.join(' ') + sh %{ruby -Ivendor vendor/rd #{argstring}} + else + require 'rdoc/rdoc' + RDoc::RDoc.new.document(args) + end end + self end - self end -end -namespace :doc do - def gem_path(gem_name) - path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first - yield File.dirname(path) if path + namespace :doc do + RDocTaskWithoutDescriptions.new("app") { |rdoc| + rdoc.rdoc_dir = 'doc/app' + rdoc.template = ENV['template'] if ENV['template'] + rdoc.title = ENV['title'] || "Rails Application Documentation" + rdoc.options << '--line-numbers' + rdoc.options << '--charset' << 'utf-8' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('app/**/*.rb') + rdoc.rdoc_files.include('lib/**/*.rb') + } + Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" + + # desc 'Generate documentation for the Rails framework.' + Rails::API::AppTask.new('rails') end +end - RDocTaskWithoutDescriptions.new("app") { |rdoc| - rdoc.rdoc_dir = 'doc/app' - rdoc.template = ENV['template'] if ENV['template'] - rdoc.title = ENV['title'] || "Rails Application Documentation" - rdoc.options << '--line-numbers' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('doc/README_FOR_APP') - rdoc.rdoc_files.include('app/**/*.rb') - rdoc.rdoc_files.include('lib/**/*.rb') - } - Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" - - # desc 'Generate documentation for the Rails framework.' - RDocTaskWithoutDescriptions.new("rails") { |rdoc| - rdoc.rdoc_dir = 'doc/api' - rdoc.template = "#{ENV['template']}.rb" if ENV['template'] - rdoc.title = "Rails Framework Documentation" - rdoc.options << '--line-numbers' - rdoc.rdoc_files.include('README.rdoc') - - gem_path('actionmailer') do |actionmailer| - %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/action_mailer/base.rb).each do |file| - rdoc.rdoc_files.include("#{actionmailer}/#{file}") - end - end - - gem_path('actionpack') do |actionpack| - %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{actionpack}/#{file}") - end - end - - gem_path('activemodel') do |activemodel| - %w(README.rdoc CHANGELOG.md MIT-LICENSE lib/active_model/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{activemodel}/#{file}") - end - end - - gem_path('activerecord') do |activerecord| - %w(README.rdoc CHANGELOG.md lib/active_record/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{activerecord}/#{file}") - end - end - - gem_path('activesupport') do |activesupport| - %w(README.rdoc CHANGELOG.md lib/active_support/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{activesupport}/#{file}") - end - end - - gem_path('railties') do |railties| - %w(README.rdoc CHANGELOG.md lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| - rdoc.rdoc_files.include("#{railties}/#{file}") - end - end - } - - # desc "Generate Rails Guides" +namespace :doc do task :guides do - # FIXME: Reaching outside lib directory is a bad idea - require File.expand_path('../../../../guides/rails_guides', __FILE__) + rails_gem_dir = Gem::Specification.find_by_name("rails").gem_dir + require File.expand_path(File.join(rails_gem_dir, "/guides/rails_guides")) RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate end end diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index 70370be3f5..16ad1bfc84 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -26,7 +26,7 @@ namespace :db do desc "Display status of migrations" app_task "migrate:status" - desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)' + desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)' app_task "create" app_task "create:all" diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 50499304cb..e669315934 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -1,6 +1,6 @@ namespace :rails do - desc "Update configs and some other initially generated files (or use just update:configs, update:scripts, or update:application_controller)" - task update: [ "update:configs", "update:scripts", "update:application_controller" ] + desc "Update configs and some other initially generated files (or use just update:configs or update:bin)" + task update: [ "update:configs", "update:bin" ] desc "Applies the template supplied by LOCATION=(/path/to/template) or URL" task :template do @@ -46,8 +46,8 @@ namespace :rails do require 'rails/generators/rails/app/app_generator' gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: Rails.root - File.exists?(Rails.root.join("config", "application.rb")) ? - gen.send(:app_const) : gen.send(:valid_app_const?) + File.exist?(Rails.root.join("config", "application.rb")) ? + gen.send(:app_const) : gen.send(:valid_const?) gen end end @@ -58,19 +58,9 @@ namespace :rails do invoke_from_app_generator :create_config_files end - # desc "Adds 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' - new_style = Rails.root + '/app/controllers/application_controller.rb' - if File.exists?(old_style) && !File.exists?(new_style) - FileUtils.mv(old_style, new_style) - puts "#{old_style} has been renamed to #{new_style}, update your SCM as necessary" - end + # desc "Adds new executables to the application bin/ directory" + task :bin do + invoke_from_app_generator :create_bin_files end end end diff --git a/railties/lib/rails/tasks/log.rake b/railties/lib/rails/tasks/log.rake index 6e1334692e..877f175ef3 100644 --- a/railties/lib/rails/tasks/log.rake +++ b/railties/lib/rails/tasks/log.rake @@ -1,9 +1,23 @@ namespace :log do - desc "Truncates all *.log files in log/ to zero bytes" + desc "Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)" task :clear do - FileList["log/*.log"].each do |log_file| - f = File.open(log_file, "w") - f.close + log_files.each do |file| + clear_log_file(file) end end + + def log_files + if ENV['LOGS'] + ENV['LOGS'].split(',') + .map { |file| "log/#{file.strip}.log" } + .select { |file| File.exist?(file) } + else + FileList["log/*.log"] + end + end + + def clear_log_file(file) + f = File.open(file, "w") + f.close + end end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 676b475640..1815c2fdc7 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -2,6 +2,6 @@ desc 'Print out all defined routes in match order, with names. Target specific c task routes: :environment do all_routes = Rails.application.routes.routes require 'action_dispatch/routing/inspector' - inspector = ActionDispatch::Routing::RoutesInspector.new - puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n" + inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes) + puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER']) end diff --git a/railties/lib/rails/templates/layouts/application.html.erb b/railties/lib/rails/templates/layouts/application.html.erb index 53276d3e7c..7352d48e7b 100644 --- a/railties/lib/rails/templates/layouts/application.html.erb +++ b/railties/lib/rails/templates/layouts/application.html.erb @@ -22,6 +22,10 @@ a { color: #000; } a:visited { color: #666; } a:hover { color: #fff; background-color:#000; } + + h2 { padding-left: 10px; } + + <%= yield :style %> </style> </head> <body> diff --git a/railties/lib/rails/templates/rails/info/routes.html.erb b/railties/lib/rails/templates/rails/info/routes.html.erb index 890f6f5b03..2d8a190986 100644 --- a/railties/lib/rails/templates/rails/info/routes.html.erb +++ b/railties/lib/rails/templates/rails/info/routes.html.erb @@ -6,4 +6,4 @@ Routes match in priority from top to bottom </p> -<p><pre><%= @info %></pre></p>
\ No newline at end of file +<%= @routes_inspector.format(ActionDispatch::Routing::HtmlTableFormatter.new(self)) %> diff --git a/railties/lib/rails/templates/rails/welcome/index.html.erb b/railties/lib/rails/templates/rails/welcome/index.html.erb new file mode 100644 index 0000000000..eb620caa00 --- /dev/null +++ b/railties/lib/rails/templates/rails/welcome/index.html.erb @@ -0,0 +1,245 @@ +<!DOCTYPE html> +<html> + <head> + <title>Ruby on Rails: Welcome aboard</title> + <style media="screen"> + body { + margin: 0; + margin-bottom: 25px; + padding: 0; + background-color: #f0f0f0; + font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana"; + font-size: 13px; + color: #333; + } + + h1 { + font-size: 28px; + color: #000; + } + + a {color: #03c} + a:hover { + background-color: #03c; + color: white; + text-decoration: none; + } + + + #page { + background-color: #f0f0f0; + width: 750px; + margin: 0; + margin-left: auto; + margin-right: auto; + } + + #content { + float: left; + background-color: white; + border: 3px solid #aaa; + border-top: none; + padding: 25px; + width: 500px; + } + + #sidebar { + float: right; + width: 175px; + } + + #footer { + clear: both; + } + + #header, #about, #getting-started { + padding-left: 75px; + padding-right: 30px; + } + + + #header { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAABACAYAAABY1SR7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAGZhJREFUeNqsWwmUXGWV/t5Sr9aurl6qO0l3Z9/DEoJh18gZQGAUxPHIyQHH7eioZ8bjnAFHZ0RndNxxRBhGcUbxoKIHBkTEcUYREIHIGpKQjUDS6U660/tSVV3Lq/fefPf/Xy2dBFGYx3npqvde/e/e/97v3u/e/8e4Lt2L8DCCAFcGwF8ZBjYbgM1rAZoO+WLwZhDMu9y4+YcOozbAqzwXNA3GdzX/5hV+KnKO2+GXFj/AvzmW8e72iG202CYiphbY403f9/k3QHZtJ9oWtyCQe7wGX79TKVb7rP9pXJPDVxf0Rz+oyxm4HNWrahFNixdk3EAJbERMWOm4ulctVODNVeEVK0DeRVDgb1wfJgcqUo6duaKnFOH7bm6JmH+5LOEgZprwRIHAV3JYfLjKM55Noz3bBqdcgt0Wg52Kq/cHHkXns0qIukKBlltk9rU2QaiouiefPQ+RdBuseAJeqYTK1CTH8mE4NsyIpRWu8nssCs+xULWpjGVwTvieKl/sV6mIXzOib/OftzuG8d6l8SiVMODyRb46oazg8YPP2Wnvy9ISNqplzsxYAW6hjGhHEmYiBoPC+hRMfFMrESgrBC5n0KS+lq1nPahZh2OXymg9bSNWX/u3FKyKI//7Exx96B4Y8RiCEseq8t0VznyxjMDidFIJ8QSf3hJEOFbZEAHVhIkFTX54fxtnIW5pJUQIeZ8ooZShkInuDOLpFIX1ldtCBix7KI/k4E7OwbTjcNIdiCQzsONp2LEk7GgUnZsuQN9lW2En45xlukrUghWzeZq8FsXsi8+gND6MSCqD9k3nwulIUShKZxt0LYPWortRSY0NXreC8J6pZNDChEDh53PT1NIPLaEnLbQKNTETEaR7sycA0jD1INXZAnzObjTbiWh7Vr1A3Knn4nciu+lCvstUig09cp96cVCtcELoFpEIFUjjyIM/osWIg+IMXS3DcfNwZ3NQHmmKU9OqroX2jWdgatduuPkpmA4ViZrK9RqKABEBtg9tDeW+oUIyTIYuFaX7eCG4aqbU+hhKocD3UBoZISBLiC9cpAQKyq5SQo6OjVswtec5VHLTiHUuIN4WonXlqUj2riS0DIUXwZlERFHSK+SQGzqI3MHdmNm7CzMvvowF527B8qvejZ3/+iXk9vVTao5tiTKN0OUHISZEGS/8W6UbRdoTSHe3E1f+CRaR3xhBLVJSIQ7qleZQGBigZYoYdR+ElUjBaW3H6JMPIrV0Hdo2bEayZ7my0KsdLctPBS64EuWZMYw/9wTGnvod0mtzWH71Vuz66o10bVpK8FIx6orUMejpCKYBTvfM9HXBJtA8z3/1BKDivaksVJmaYsgsYPDnd6LzzAuw8I1XUIGleC1HtDWLnguv5BiX4+jDD2D4sQeV1bQvNXBi6vAb1MGtrEEHjRPgqfZ0qMRJElYYSudfq12nmzAvtJ2yib69iRadRGnySD0Uv5bDtCPou/gqnPY3N6DnLRczgtHxCf4aVnUeUdgw6i6FqM1w292Ujo/TJdB5wHcJ2iDCaBTRmVfw4rkw4yksuvQyJJf0YvrgNiayvBLESS9AYuFqJLLLCPb4SQWulosojhxmeCeoDeaQSoVuy8lPtSKxYKnC2Bmf+DwtvBgv3/qfTI6uEtGuJV7PCBTIq5zNtt5uxBgyvap30pf55TISfX1Y/PatGPrVvcgPvEyAJ1GenaPZLSy//G2IL+qki43CNCMwk620iovy9FGUJgYwm8gwpK/guRJOS5dyD688h+n9z2L28F4Ujx2ia04jEl8Ad3oGVTePaGcnQ3sKLb1rkD3nIqx594dRIh733n6PmmrrvGj671sjVlxczRWAkxZ0r+rTrhfMJ0uEM8xKUYXONR+5nr57BdpP24TCsX6M/f5F5AYLWPauK9F11htUwjOIL8GNZH1qpKwiyVGELk0OoDj2EtziFOaODSN3aC/v24xmZzAU51TgcJKd/DktHo9jyRXvg0Or7PvejTj22KPKiyafew6zg8MYypVLNsLkJ2bxaZXM4i5EmCBPsEaoWJUUpfeSK7DgvEtQmh4ihTDQdf5FOHDHr7HqPVeh99KL4OVzpE50N18CtqnCdBCY6rsEcTsqIGUGD6rY9e3bMPzIHmTWLsbqa7ai84wL6YrTqEyOqEmwonEExSoO//R7dLcJWiWCueF+7P7mjZAUY8YdJZqySMo24j5zQSybQdeyhdrX5imho4NhEEnkRbkDQyjSRVJLeziCgef/6avIrFuOtR95P2lJNSSshg4l6rdm+Ht9inWsqIOX7voN+u/eRoEM5PvHMbbjGcwcfg7jO3YxbCcRiaaYQOXnpEaFGeahGQaMCidJRidt8RghS6Q344XQIowmFq2QXdLNdwsx8zUFqCOQNIECVqdp8pESB53Fvhdux9T2FxBb1AWX4XbjDX/HFzjEmgedB4XYKT5D4T0VTLRCtIiTwOBvfovpvS8T+Bm4MyW6jw13tIIDt/9G/TTWk8HKvzgbmd4+YldYQIdixgHJYkC82Ul6UDnQSbEGdsFGZlEWyUyLyiEyYwajRVAoAXNlEjR+pjUCUmiDQcKOORwwgpFfP4cg5mPzTZ9FoqePdGVWuZRPYQNPcgrd0/dCpqpdy3DIsQ4fxtiTu7Hxkx8iRXkcB+94iM86/K0Jx4opi5aOzGJs14toWeLAdYXWxFQCtJlkA+LUq+bI7QR3mj3YoqVNgGcXd5NWUOiZAk9GH86S4jK25jWBLVREl1uK5Voywz6WXf1WLHjTm0lPigSyxoUpnEqU8c26Wyk/Y24RMjhw/yMoj+cQbWvH0isuwuijL6BwaJwcyq7XUTaBP7N3HOU3ke7HSONJb8RTBGoGKZPFyTE8saTZyCPtrC2coxOoTuY5+x4UTzHNsNjR6d6Qa8JJ5BIV8ksVtKzpwcr3v5dyOrzHKMWXizsZAnK6k1ImPDmAqjOmdr9AwXcodzr4kwfQfuY6VKbzyhpGU96S75WxIqb2DaPnvNWKklQD4WSuzB+sVILjOYjm/VARSWKTBQQzlZCFmErYeubzVJJR14SlQtVQMjO0xrXvoulXkq3OKnxAXqSsoSmNUbOM/BV35RjDDz9JrBXpnnEM3vsYjj38LLyZihI8QNAgQhITOCmTO46i+6w1MPm86RVIiC09/RJUGcECCe2UU0G6QIyUjEC5hGaCNd4RqHKU6VuDylQlI2N8hfXDWibEdyhCKXREuZUVUX8lyhh2+Jl5Q/6akSgT4izGn3wBFu+JwYOKj8qwtsbJaYmJuYEZ5AYmFOWXPCN1jTodzeuqM0WtSI1rzXrV0LSNKRFuZLYQ2EYVPjEQVuQUMsCya65GvL1HWUwJS+FNUcBsUiZUQv7aLGlndr+I8ug4XUMVAJw4U7FmI8SFETTmUaGK2gas1SeeP8znoizIEso9DaUIy2FWkNU5V0VYs/azWXKncuCHqgQq1CHiY831H8TGr34erRvXKdD6LD3b+HnRn12qGgdqlmxHZe2aRcy6NbQScl8y8dSOfWQE1yK9YYmqXYww3xhNObemUI2IWraF2d1HMTeeh83MbkUiylKiiMdy2wjzXBjxWYdRiSkhfDVVKGSstxM9l16JxZe/E2+848c49bPXK9D2vPUyEsBOVZMINmpCW6HgEOuIQjXF6FYuAV2aHsWyrVfj9C9er5SR5Kms0PTf8QoZtIo7WSJW+mmRJLGSpDK2ipzV2bK6X6fxtWOCicYVqyhGXkXn+WeTcfape5ZDsPGM91C5iy8LI0s445bd9FkrAFHICt1N8DE+gdyeQczs34+uzeei68LNLGfdea50st6VbiyYmHq+nxTFRSSRVsD3ii7xyeQbdt/M5h/MERMT4i6GjlAWeUxh6HCN8+LIz+5H5zlUbtHSOnVp4MCa51JaIQ16i0kwP9CP0uExPP+JL2DggfuYN8jTJClYxnH4aNimdpp0r7nDkyx9h5gE0+RqSVTyZXXTsMz5FaJyMJrrGLNopyWUIImj//1LjPzuUZLCC5gzVqMwPIglV7/rxCaihFaCPCDOxDUl1EoylFP4mUlFCgPDStLKWB47PnUjrSSsNqrJsa/zR02ZwGjYRoVkEZh0ZHzbfmTPXE85SWrnKip6GeFE2I1iKVBCzNK9pmiVhS1x+Axx7myRJesvgHvvR3rNKmQ3n/OKPVGND1MVXTqHiFK6qVFiwlXgTVDhkq+ChhnyJCW9GeaoIGQOdV0M9YhYZWbvUXrIJJ+rKL6lJ9CYj5Fai0iKqyPkx0HcUsJYrBbtREIJ2H72GxTI/2CL1zAbLkZ8WIxYgUvsKebq6Zl3rEZvymx6echo1N+au9XcS3oHsxWMPrGTFH+CLhsmbhMNRWrNB4SZVSwyJ5WDFRb3DAAmaXf2rPP+6BpbkmStkBLAWwkHmdNWKfYqFaZRp2GGdo+mhpv6bBkNhepRzERpdASeW1aKSZ5RidpoUsRAvQ+NJCnJHHl+bcZ80vjkij661vo/rWMQSitWskgnNv7LP+MNN38NadYuCPtYCItIFTjMRgfeqClkhkFZ+FXCQmpFuyKXii7xNI93LT9szdrUMsNZnJkuwZX6zlKdaqRXrESiq/e19kBC3NisLt+Gc/7jW0gtZ51Bl1MCmUaoM//aRv0aapnF0l362KIUnI6EyuhCUOuWrIVfAZcRAj5NJWJ0C5epP19y1awJLWhdt/a1t3KcGF8Yxb5bbsLItoeYmxZRkRWq46IrR9StX/tcw4oKsYH+nlrZpmbcZQ7R1tDPBvMbdIwofLpVKIfcJy5nCa5WRhnDFkVOx+s5kr29GPzpfUxsuxg0zlQUxSZudG/CqNOSIJxYCclGCA7fDRDpiCK6gIVfidVmWXrHRh0fmBd+eSYIIEcWdRhdJJsWp+aQT1vI9nYjnl3wuhSJLuhAJJ1WQWDisadUELCi0bD1WlscMpq6lrV1Ft0riC9tVcFD8odfDVS9bod5pNGgC3+XFnxsXA2rsw25/gHMTcwiRxdbvLgPsY7s61IktWSZinw6l8SbupNGvUlphB1yZY3aIhfZtRmz4XS3oMoA5JP6BywdvBIr24ytMdzsWjHaMcnI0nXRG5FkdCrnS6gy6QzccxeMZDsJW+r1KbJ4pbKAVy6huXoyauVUaAUjRK5WjN9cH05PCiZl84VfsXaSVTKf191C6F61qCXjtjAORtvTSPb0sgYoEi/UmEmnMj6JkpXA6z2cTAbxxV26GdEEZB12DVVV63BrIuwYaWpCGZyuJBWSFSxPLTB5PH1+rhDDKlQbuvajNUzE+UVyRTTdQt+zWIrGWIJOozo8hjmashq8PkXsZAoty1Yqi/gVnq6ru+p1pUKFTM3dENJzu421TiqKKq3hhUp45apSyM1VGMH0xOi+liz0yOxUyijs2w2DlRjI+8tHB3XUIP+fGBxA9+LFr1kRgwV769p1fPkEQ+9KRq+dKE9MsGKc1BmxltEC7W6CEdW0aUtocIvw0tcSt5JGu3R4OA+zIxW1uKoUOUZzFxmxRp/ai+iz+xi9CK5EVJGdqBNBlG4xdvBlRq9eTQteawhm0MgPLsSGj92gVqjKk8ew/TOfxPjjz8BKxhvLFGHjWUBuJh0Cu6pqD7WCTGz4BDqKpE30rIlj05rw6sKFxuCXPP9O8MEjxQqOTuQwNjJLa1mItaRRGB3GLHnO6znaNmxC/nA/cocPKNoS61iEZVdfEy5LBHVKUieCLY5eeKIiXp6RapJuNVJFMCamYGnOUFyslBo0Xronai0dIfXmnZIqtKhgNIaj/F3ULSLx4j60dnXXy8s/OZe0dyGW7cLOL34arevXI9rayWgYhZPtoJtNqsTbyPKUgwzamyCw867MtG5NBUF9bSBXLCkeKOzDroUutaZODax52yUk5sfgsyrL897+PXtQHTmK7vWnomPpCkSTf3pI7j7/Qmz/5HWY3r5LNziYeC3WPlYsovOJJ7VKVbuPENcgXEyvuV3IbKXpPlcqqh0acqGe2S1oq1jzqmZ+b0mGDJNaM2bnjrHuPnYUifZOtDMKda9ah1RnZ30F99WO9jM2MzouZw0vLdJIuCsiUInOz0vbiVNa9DSBtITyWo3VAV/XG/KmPEuBKrmard7rNxKiyCoN7EBnpXlLCiYTmfibuEHSSSkLV4uzGNr5NEYP7EZb31J0rd6AzMIevtf+g4oIg+7e8iYM3H03J5muw9n3ZquqfwU3aGDdMBqdztr+lXBbhyg+R2xYTb5jN7YG6SKnyh870r8Ki6Py0CiO3fcTNWaCBU3E8FVDr7ZPRjbcDLHO30N/TmazdLk+JFMxVoZh6errUrcmnDQp5o4MocrI4o3N6dmXhp1hoHkOFV2R5CXtVwm3Qc0aBip8Z6lY0HtRpJ8GYz5pVFgxgkaHiaCuDE1gfOAhFdNbJIKxplCKNJqqyoqi0CT9tp9/IyyPE2SryYyDKD9LVKxKUqXbuFOM+yVDN/Rq+0ia1mLmtYNqK8rhTiSpLLNbLkDLuZvQ0X8QBoG+//5fIMjP4AQ/kJkuM+vW+sS1wkgiVSTi0Fq2XqoLFfFYMMkyHSFL2mOpHQmy+aU4xXHoLk6rrIkYiE1JNpZOJjO1ivduOLSkZeuk6/YBwR54jaVv6chXpmZQmJnEssveQjwVcPCXv1IWt4//sUVB7K4WpGTREqhvJCrO5MhtGLMTKWU5pUSpDKs1glhbB4W3VCSpTM6gOl2GQzxJt+RQUMFcOoENrXG0FEhESSvMmIVIZ6uaHL9QZn6Y067VNJueV4bdmYDdktJ7pAJNKKfG+pG/cz8GH/gfGLIARF4o9fs8RWSrUmZxN7Z+9za0sooTPiRuI22bsUMHsevWW1B+iFnYdOgqFWTPPxWnXPdxtK5eV8fB9IH92Pn1m1hz7MQh00Xm/C34+K23MiOXsPvLX8bgbXej5bz1OPs7tzIhduHgnXfghX/8OplEsr6U4ZtV9G69HMvf8wEkKUfgaUeWbs4zX/8Sxm/+AbzxCRVF1VpFM9hrvS2ZmZbuRUh2LpxPw7t60EWK8vgHPoCZ5w4i1pvBps99Bu2nbJ73XLyzB4kvLcAPt27F2LFR9MTjSKbb1L1h4mIq4iNL14u2ZRFJysazZCNHqA0DZXRcuBGnf+bz6v4JLDqVgk3r247DnMdJDkOzffJtDfoY2b0dg08/gbZlq7BiyyWk+MuQ2bAGU9v2snTtQnxBj3pu9OnfYXr/Hiq1EZ0bz0ZsUS+sFUvgDB+DFfh1v3X9Kg4xknfLRNZ21h2/RYTX29avU0pUSwUcuP07KLw0oBZrA5bGozt2MlA5updgzGuJnYyp6rt7778HP37fX+OJW77ZaKzKoo5eOdfRhMehO3+EbXzu8H/dXW/SOTwj0gZqeoVck+h3xES9LDjpVp3QXeRdqSVLkDllrepy5oeHMPH0brq2qdteRmNJwj7pYKFVlr75YrztKw6ya9aFTzF8Tk+pBZrmXRGRdCsSLMiQbKlfE7PLrjarCcSSA0QZvQQevGKncnrfXpVwZTde3+XvqN9b8d4PYfuNn8O+b9zO56K6oGpOiMYreNfSc7eoE+FO00P334XJx3fQzM685zd8/Hqs/uCHGGEy9QEslaT0Cm9t7rVyYqnGWogEGIl+nqUTmyxwTj62HTs/91ks3XqN2u8VBLKZoVt14pe/42oc/O6dzB2+qnEMNGHEPHHbSfiSqloakGP7D7+Dpz79BfT6cRXu5rHatk51Nh9aEaOJu2mOZIf36uDu6EDi3PVoIQGV5efiwSG1Rjny8COY3P4sI1WM2HKx4bpPYdEFlzA9RMOlhCAsLJssYqGxRbcZI8//9MfIrliDvjPOwqqL/xwD996P6rY9zGHWPNMNPf8UJl9+Cdm169G9YWOdapjB8auShsJMc85YdekVWL7lQgroKHd68qMfRcAEu+lrX1GdSdmBKjQn0aOrU9lso5bK53uSLiyscNu10tAy66FganAQD9zwD6jM5ZBe2IeLbvoGWs5YofZQyfKXxbpejl133omfXfth7P/Fz8NRLbXgb0nGNe26GhGST5MzFmEYll2oCl+sd2IZCcWtTKxd6rokwdYVpyK9fB1z1KnIrD0NDt1WiNGB738X3kxJVapiWVmR5pCurc2iSaIkmNJ0Hr+9+WYkMu0YfHI7Dv9+J+766Eew8vSNiFP4WGsGBanhh6bw1K3fRjSdwfSel5FikTT67At4+t9vgVssojA0Rp6VwOyhfjx9262qABrfw1KaJW15YprXvsVcEG1sT5eCji40fXSURVyAvTd9TSmv6nTVifQx/uwzmHiU7kb3Clu+GC27MsY247p07+SihN0m/Kgc6EXRIjmMgDvCF9mcsXJxDgniZSnN3xFLIcc6Yormd1mhCX2QpWc7SteolNUpNUQkIUvJpDkUrsrfqy1L8ZjaFSTrJKLsCbvz6BqxaBwdBReWbJmF3kTa2NYRVYFGHEYKqqFKFXtzMg6uUhaJyzZyQ/d/FdUm8LwmAuYwO/vhQBU+m+ddmy+NpBKNWpIzF7EdRSxrOygMMl6LruUw2tQXOTy1akNFk/XtU/V70H3g6YyNNk5GtOIp/DYvlKp9LoJLWuIl2fADfJ/X71PQ8Jo2Vzbv620OAFI9jtIqCQ7tnfC/JxhNT4dShds4UKvB66s1ftPnRqOh/l13hDDqWGhxqUgTsIV1Fzg5Y7TEpKsK+B/w+sdqUWuqv1CxUN8K/MqHLMnhj/g/J/4/juDky9VSg0kh/zQj322897Pao/8nwAC+AZicLeuzngAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + background-position: top left; + height: 64px; + } + #header h1, #header h2 {margin: 0} + #header h2 { + color: #888; + font-weight: normal; + font-size: 16px; + } + + + #about h3 { + margin: 0; + margin-bottom: 10px; + font-size: 14px; + } + + #about-content { + background-color: #ffd; + border: 1px solid #fc0; + margin-left: -55px; + margin-right: -10px; + } + #about-content table { + margin-top: 10px; + margin-bottom: 10px; + font-size: 11px; + border-collapse: collapse; + } + #about-content td { + padding: 10px; + padding-top: 3px; + padding-bottom: 3px; + } + #about-content td.name {color: #555} + #about-content td.value {color: #000} + + #about-content ul { + padding: 0; + list-style-type: none; + } + + #about-content.failure { + background-color: #fcc; + border: 1px solid #f00; + } + #about-content.failure p { + margin: 0; + padding: 10px; + } + + + #getting-started { + border-top: 1px solid #ccc; + margin-top: 25px; + padding-top: 15px; + } + #getting-started h1 { + margin: 0; + font-size: 20px; + } + #getting-started h2 { + margin: 0; + font-size: 14px; + font-weight: normal; + color: #333; + margin-bottom: 25px; + } + #getting-started ol { + margin-left: 0; + padding-left: 0; + } + #getting-started li { + font-size: 18px; + color: #888; + margin-bottom: 25px; + } + #getting-started li h2 { + margin: 0; + font-weight: normal; + font-size: 18px; + color: #333; + } + #getting-started li p { + color: #555; + font-size: 13px; + } + + + #sidebar ul { + margin-left: 0; + padding-left: 0; + } + #sidebar ul h3 { + margin-top: 25px; + font-size: 16px; + padding-bottom: 10px; + border-bottom: 1px solid #ccc; + } + #sidebar li { + list-style-type: none; + } + #sidebar ul.links li { + margin-bottom: 5px; + } + + .filename { + font-style: italic; + } + </style> + <script> + function about() { + var info = document.getElementById('about-content'), + xhr; + + if (info.innerHTML === '') { + xhr = new XMLHttpRequest(); + xhr.open("GET", "/rails/info/properties", false); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + xhr.send(""); + info.innerHTML = xhr.responseText; + } + + info.style.display = info.style.display === 'none' ? 'block' : 'none'; + } + </script> + </head> + <body> + <div id="page"> + <div id="sidebar"> + <ul id="sidebar-items"> + <li> + <h3>Browse the documentation</h3> + <ul class="links"> + <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li> + <li><a href="http://api.rubyonrails.org/">Rails API</a></li> + <li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li> + <li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li> + </ul> + </li> + </ul> + </div> + + <div id="content"> + <div id="header"> + <h1>Welcome aboard</h1> + <h2>You’re riding Ruby on Rails!</h2> + </div> + + <div id="about"> + <h3><a href="/rails/info/properties" onclick="about(); return false">About your application’s environment</a></h3> + <div id="about-content" style="display: none"></div> + </div> + + <div id="getting-started"> + <h1>Getting started</h1> + <h2>Here’s how to get rolling:</h2> + + <ol> + <li> + <h2>Use <code>rails generate</code> to create your models and controllers</h2> + <p>To see all available options, run it without parameters.</p> + </li> + + <li> + <h2>Set up a root route to replace this page</h2> + <p>You're seeing this page because you're running in development mode and you haven't set a root route yet.</p> + <p>Routes are set up in <span class="filename">config/routes.rb</span>.</p> + </li> + + <li> + <h2>Configure your database</h2> + <p>If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p> + </li> + </ol> + </div> + </div> + + <div id="footer"> </div> + </div> + </body> +</html> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index aed7fd4b14..46f7466551 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -2,25 +2,16 @@ # so fixtures aren't loaded into that environment abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production? -require 'minitest/autorun' +require 'active_support/testing/autorun' require 'active_support/test_case' require 'action_controller/test_case' require 'action_dispatch/testing/integration' +require 'rails/generators/test_case' # Config Rails backtrace in tests. require 'rails/backtrace_cleaner' MiniTest.backtrace_filter = Rails.backtrace_cleaner -# Enable turn if it is available -begin - require 'turn' - - Turn.config do |c| - c.natural = true - end -rescue LoadError -end - if defined?(ActiveRecord::Base) class ActiveSupport::TestCase include ActiveRecord::TestFixtures diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index ed89ce4128..75180ff978 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,3 +1,7 @@ +if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? + ENV['RAILS_ENV'] ||= 'test' +end + module Rails class TestUnitRailtie < Rails::Railtie config.app_generators do |c| @@ -5,7 +9,6 @@ module Rails fixture_replacement: nil c.integration_tool :test_unit - c.performance_tool :test_unit end rake_tasks do diff --git a/railties/lib/rails/test_unit/sub_test_task.rb b/railties/lib/rails/test_unit/sub_test_task.rb index 87b6f9b5a4..d9bffba4d7 100644 --- a/railties/lib/rails/test_unit/sub_test_task.rb +++ b/railties/lib/rails/test_unit/sub_test_task.rb @@ -1,6 +1,124 @@ +require 'rake/testtask' + module Rails + class TestTask < Rake::TestTask # :nodoc: all + # A utility class which is used primarily in "rails/test_unit/testing.rake" + # to help define rake tasks corresponding to <tt>rake test</tt>. + # + # This class takes a TestInfo class and defines the appropriate rake task + # based on the information, then invokes it. + class TestCreator + def initialize(info) + @info = info + end + + def invoke_rake_task + if @info.files.any? + create_and_run_single_test + reset_application_tasks + else + Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke + end + end + + private + + def create_and_run_single_test + Rails::TestTask.new('test:single') { |t| + t.test_files = @info.files + } + ENV['TESTOPTS'] ||= @info.opts + Rake::Task['test:single'].invoke + end + + def reset_application_tasks + Rake.application.top_level_tasks.replace @info.tasks + end + end + + # This is a utility class used by the <tt>TestTask::TestCreator</tt> class. + # This class takes a set of test tasks and checks to see if they correspond + # to test files (or can be transformed into test files). Calling <tt>files</tt> + # provides the set of test files and is used when initializing tests after + # a call to <tt>rake test</tt>. + class TestInfo + def initialize(tasks) + @tasks = tasks + @files = nil + end + + def files + @files ||= @tasks.map { |task| + [task, translate(task)].find { |file| test_file?(file) } + }.compact + end + + def translate(file) + if file =~ /^app\/(.*)$/ + "test/#{$1.sub(/\.rb$/, '')}_test.rb" + else + "test/#{file}_test.rb" + end + end + + def tasks + @tasks - test_file_tasks - opt_names + end + + def opts + opts = opt_names + if opts.any? + "-n #{opts.join ' '}" + end + end + + private + + def test_file_tasks + @tasks.find_all { |task| + [task, translate(task)].any? { |file| test_file?(file) } + } + end + + def test_file?(file) + file =~ /^test/ && File.file?(file) && !File.directory?(file) + end + + def opt_names + (@tasks - test_file_tasks).reject { |t| task_defined? t } + end + + def task_defined?(task) + Rake::Task.task_defined? task + end + end + + def self.test_creator(tasks) + info = TestInfo.new(tasks) + TestCreator.new(info) + end + + def initialize(name = :test) + super + @libs << "test" # lib *and* test seem like a better default + end + + def define + task @name do + if ENV['TESTOPTS'] + ARGV.replace Shellwords.split ENV['TESTOPTS'] + end + libs = @libs - $LOAD_PATH + $LOAD_PATH.unshift(*libs) + file_list.each { |fl| + FileList[fl].to_a.each { |f| require File.expand_path f } + } + end + end + end + # Silence the default description to cut down on `rake -T` noise. - class SubTestTask < Rake::TestTask + class SubTestTask < Rake::TestTask # :nodoc: def desc(string) # Ignore the description. end diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index cd59fbe599..38107e77b2 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -2,52 +2,11 @@ require 'rbconfig' require 'rake/testtask' require 'rails/test_unit/sub_test_task' -TEST_CHANGES_SINCE = Time.now - 600 - -# Look up tests for recently modified sources. -def recent_tests(source_pattern, test_path, touched_since = 10.minutes.ago) - FileList[source_pattern].map do |path| - if File.mtime(path) > touched_since - tests = [] - source_dir = File.dirname(path).split("/") - source_file = File.basename(path, '.rb') - - # Support subdirs in app/models and app/controllers - modified_test_path = source_dir.length > 2 ? "#{test_path}/" << source_dir[1..source_dir.length].join('/') : test_path - - # For modified files in app/ run the tests for it. ex. /test/controllers/account_controller.rb - test = "#{modified_test_path}/#{source_file}_test.rb" - tests.push test if File.exist?(test) - - # For modified files in app, run tests in subdirs too. ex. /test/controllers/account/*_test.rb - test = "#{modified_test_path}/#{File.basename(path, '.rb').sub("_controller","")}" - FileList["#{test}/*_test.rb"].each { |f| tests.push f } if File.exist?(test) - - return tests - - end - end.flatten.compact -end - - -# Recreated here from Active Support because :uncommitted needs it before Rails is available -module Kernel - remove_method :silence_stderr # Removing old method to prevent method redefined warning - def silence_stderr - old_stderr = STDERR.dup - STDERR.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') - STDERR.sync = true - yield - ensure - STDERR.reopen(old_stderr) - end -end - task default: :test -desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile)' +desc 'Runs test:units, test:functionals, test:generators, test:integration together' task :test do - Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke + Rails::TestTask.test_creator(Rake.application.top_level_tasks).invoke_rake_task end namespace :test do @@ -55,106 +14,36 @@ namespace :test do # Placeholder task for other Railtie and plugins to enhance. See Active Record for an example. end - task :run do - errors = %w(test:units test:functionals test:integration).collect do |task| - begin - Rake::Task[task].invoke - nil - rescue => e - { task: task, exception: e } - end - end.compact + task :run => ['test:units', 'test:functionals', 'test:generators', 'test:integration'] - if errors.any? - puts errors.map { |e| "Errors running #{e[:task]}! #{e[:exception].inspect}" }.join("\n") - abort - end + # Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html + desc "Run tests quickly by merging all types and not resetting db" + Rails::TestTask.new(:all) do |t| + t.pattern = "test/**/*_test.rb" end - Rake::TestTask.new(recent: "test:prepare") do |t| - since = TEST_CHANGES_SINCE - touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } + - recent_tests('app/models/**/*.rb', 'test/models', since) + - recent_tests('app/models/**/*.rb', 'test/unit', since) + - recent_tests('app/controllers/**/*.rb', 'test/controllers', since) + - recent_tests('app/controllers/**/*.rb', 'test/functional', since) - - t.libs << 'test' - t.test_files = touched.uniq + namespace :all do + desc "Run tests quickly, but also reset db" + task :db => %w[db:test:prepare test:all] end - Rake::Task['test:recent'].comment = "Test recent changes" - - Rake::TestTask.new(uncommitted: "test:prepare") do |t| - def t.file_list - if File.directory?(".svn") - changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] } - elsif File.directory?(".git") - changed_since_checkin = silence_stderr { `git ls-files --modified --others --exclude-standard` }.split.map { |path| path.chomp } - else - abort "Not a Subversion or Git checkout." - end - models = changed_since_checkin.select { |path| path =~ /app[\\\/]models[\\\/].*\.rb$/ } - controllers = changed_since_checkin.select { |path| path =~ /app[\\\/]controllers[\\\/].*\.rb$/ } + Rails::TestTask.new(single: "test:prepare") - unit_tests = models.map { |model| "test/models/#{File.basename(model, '.rb')}_test.rb" } + - models.map { |model| "test/unit/#{File.basename(model, '.rb')}_test.rb" } + - functional_tests = controllers.map { |controller| "test/controllers/#{File.basename(controller, '.rb')}_test.rb" } + - controllers.map { |controller| "test/functional/#{File.basename(controller, '.rb')}_test.rb" } - (unit_tests + functional_tests).uniq.select { |file| File.exist?(file) } + ["models", "helpers", "controllers", "mailers", "integration"].each do |name| + Rails::TestTask.new(name => "test:prepare") do |t| + t.pattern = "test/#{name}/**/*_test.rb" end - - t.libs << 'test' - end - Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)" - - Rake::TestTask.new(single: "test:prepare") do |t| - t.libs << "test" - end - - Rails::SubTestTask.new(models: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/models/**/*_test.rb' end - Rails::SubTestTask.new(helpers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/helpers/**/*_test.rb' + Rails::TestTask.new(generators: "test:prepare") do |t| + t.pattern = "test/lib/generators/**/*_test.rb" end - Rails::SubTestTask.new(units: "test:prepare") do |t| - t.libs << "test" + Rails::TestTask.new(units: "test:prepare") do |t| t.pattern = 'test/{models,helpers,unit}/**/*_test.rb' end - Rails::SubTestTask.new(controllers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/controllers/**/*_test.rb' - end - - Rails::SubTestTask.new(mailers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/mailers/**/*_test.rb' - end - - Rails::SubTestTask.new(functionals: "test:prepare") do |t| - t.libs << "test" + Rails::TestTask.new(functionals: "test:prepare") do |t| t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb' end - - Rails::SubTestTask.new(integration: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/integration/**/*_test.rb' - end - - Rails::SubTestTask.new(benchmark: 'test:prepare') do |t| - t.libs << 'test' - t.pattern = 'test/performance/**/*_test.rb' - t.options = '-- --benchmark' - end - - Rails::SubTestTask.new(profile: 'test:prepare') do |t| - t.libs << 'test' - t.pattern = 'test/performance/**/*_test.rb' - end end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index ec878f9dcf..5a6d8d0983 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,10 +1,10 @@ module Rails - module VERSION #:nodoc: + module VERSION MAJOR = 4 - MINOR = 0 + MINOR = 1 TINY = 0 PRE = "beta" - STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') + STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end end diff --git a/railties/lib/rails/welcome_controller.rb b/railties/lib/rails/welcome_controller.rb new file mode 100644 index 0000000000..45b764fa6b --- /dev/null +++ b/railties/lib/rails/welcome_controller.rb @@ -0,0 +1,7 @@ +class Rails::WelcomeController < ActionController::Base # :nodoc: + self.view_paths = File.expand_path('../templates', __FILE__) + layout nil + + def index + end +end diff --git a/railties/railties.gemspec b/railties/railties.gemspec index 6d28947e83..56b8736800 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -1,4 +1,4 @@ -version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip +version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY @@ -6,24 +6,28 @@ Gem::Specification.new do |s| s.version = version s.summary = 'Tools for creating, working with, and running Rails applications.' s.description = 'Rails internals: application bootup, plugins, generators, and rake tasks.' + s.required_ruby_version = '>= 1.9.3' - s.license = 'MIT' - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://www.rubyonrails.org' + s.license = 'MIT' + + s.author = 'David Heinemeier Hansson' + s.email = 'david@loudthinking.com' + s.homepage = 'http://www.rubyonrails.org' - s.files = Dir['CHANGELOG.md', 'README.rdoc', 'bin/**/*', 'lib/**/{*,.[a-z]*}'] - s.require_path = 'lib' + s.files = Dir['CHANGELOG.md', 'README.rdoc', 'RDOC_MAIN.rdoc', 'bin/**/*', 'lib/**/{*,.[a-z]*}'] + s.require_path = 'lib' - s.bindir = 'bin' - s.executables = ['rails'] + s.bindir = 'bin' + s.executables = ['rails'] s.rdoc_options << '--exclude' << '.' - s.add_dependency('rake', '>= 0.8.7') - s.add_dependency('thor', '>= 0.15.4', '< 2.0') - s.add_dependency('rdoc', '~> 3.4') - s.add_dependency('activesupport', version) - s.add_dependency('actionpack', version) + s.add_dependency 'activesupport', version + s.add_dependency 'actionpack', version + + s.add_dependency 'rake', '>= 0.8.7' + s.add_dependency 'thor', '>= 0.18.1', '< 2.0' + + s.add_development_dependency 'actionview', version end diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index dfcf5aa27d..643cc6b0ee 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -3,16 +3,17 @@ ENV["RAILS_ENV"] ||= "test" require File.expand_path("../../../load_paths", __FILE__) require 'stringio' -require 'minitest/autorun' +require 'active_support/testing/autorun' require 'fileutils' require 'active_support' - require 'action_controller' +require 'action_view' require 'rails/all' module TestApp class Application < Rails::Application config.root = File.dirname(__FILE__) + config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' end end diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb new file mode 100644 index 0000000000..92cb3233d8 --- /dev/null +++ b/railties/test/app_rails_loader_test.rb @@ -0,0 +1,68 @@ +require 'tmpdir' +require 'abstract_unit' +require 'rails/app_rails_loader' + +class AppRailsLoaderTest < ActiveSupport::TestCase + def write(filename, contents=nil) + FileUtils.mkdir_p(File.dirname(filename)) + File.write(filename, contents) + end + + def expects_exec(exe) + Rails::AppRailsLoader.expects(:exec).with(Rails::AppRailsLoader::RUBY, exe) + end + + setup do + @tmp = Dir.mktmpdir('railties-rails-loader-test-suite') + @cwd = Dir.pwd + Dir.chdir(@tmp) + end + + ['bin', 'script'].each do |script_dir| + exe = "#{script_dir}/rails" + + test "is not in a Rails application if #{exe} is not found in the current or parent directories" do + File.stubs(:exist?).with('bin/rails').returns(false) + File.stubs(:exist?).with('script/rails').returns(false) + + assert !Rails::AppRailsLoader.exec_app_rails + end + + ['APP_PATH', 'ENGINE_PATH'].each do |keyword| + test "is in a Rails application if #{exe} exists and contains #{keyword}" do + write exe, keyword + + expects_exec exe + Rails::AppRailsLoader.exec_app_rails + end + + test "is not in a Rails application if #{exe} exists but doesn't contain #{keyword}" do + write exe + + assert !Rails::AppRailsLoader.exec_app_rails + end + + test "is in a Rails application if parent directory has #{exe} containing #{keyword} and chdirs to the root directory" do + write "foo/bar/#{exe}" + write "foo/#{exe}", keyword + + Dir.chdir('foo/bar') + + expects_exec exe + Rails::AppRailsLoader.exec_app_rails + + # Compare the realpath in case either of them has symlinks. + # + # This happens in particular in Mac OS X, where @tmp starts + # with "/var", and Dir.pwd with "/private/var", due to a + # default system symlink var -> private/var. + assert_equal File.realpath("#@tmp/foo"), File.realpath(Dir.pwd) + end + end + end + + teardown do + Dir.chdir(@cwd) + FileUtils.rm_rf(@tmp) + end +end diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb index 1eddfac664..9a571fac3a 100644 --- a/railties/test/application/asset_debugging_test.rb +++ b/railties/test/application/asset_debugging_test.rb @@ -14,7 +14,7 @@ module ApplicationTests app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/posts', to: "posts#index" end RUBY @@ -48,7 +48,7 @@ module ApplicationTests assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body) end - test "assets aren't concatened when compile is true is on and debug_assets params is true" do + test "assets aren't concatenated when compile is true is on and debug_assets params is true" do add_to_env_config "production", "config.assets.compile = true" ENV["RAILS_ENV"] = "production" diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 2506d19e6d..b235b51d90 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- require 'isolation/abstract_unit' require 'rack/test' +require 'active_support/json' module ApplicationTests class AssetsTest < ActiveSupport::TestCase @@ -27,24 +28,25 @@ module ApplicationTests def clean_assets! quietly do - assert Dir.chdir(app_path) { system('bundle exec rake assets:clean') } + assert Dir.chdir(app_path) { system('bundle exec rake assets:clobber') } end end def assert_file_exists(filename) - assert File.exists?(filename), "missing #{filename}" + assert Dir[filename].first, "missing #{filename}" end def assert_no_file_exists(filename) - assert !File.exists?(filename), "#{filename} does exist" + assert !File.exist?(filename), "#{filename} does exist" end test "assets routes have higher priority" do + app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;" app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do - get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] } + Rails.application.routes.draw do + get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, ["Not an asset"]] } end RUBY @@ -75,15 +77,39 @@ module ApplicationTests precompile! files = Dir["#{app_path}/public/assets/application-*.js"] - files << Dir["#{app_path}/public/assets/application.js"].first files << Dir["#{app_path}/public/assets/foo/application-*.js"].first - files << Dir["#{app_path}/public/assets/foo/application.js"].first files.each do |file| assert_not_nil file, "Expected application.js asset to be generated, but none found" - assert_equal "alert();", File.read(file) + assert_equal "alert();\n", File.read(file) end end + def test_precompile_does_not_hit_the_database + app_file "app/assets/javascripts/application.js", "alert();" + app_file "app/assets/javascripts/foo/application.js", "alert();" + app_file "app/controllers/users_controller.rb", <<-eoruby + class UsersController < ApplicationController; end + eoruby + app_file "app/models/user.rb", <<-eoruby + class User < ActiveRecord::Base; raise 'should not be reached'; end + eoruby + + ENV['RAILS_ENV'] = 'production' + ENV['DATABASE_URL'] = 'postgresql://baduser:badpass@127.0.0.1/dbname' + + precompile! + + files = Dir["#{app_path}/public/assets/application-*.js"] + files << Dir["#{app_path}/public/assets/foo/application-*.js"].first + files.each do |file| + assert_not_nil file, "Expected application.js asset to be generated, but none found" + assert_equal "alert();".strip, File.read(file).strip + end + ensure + ENV.delete 'RAILS_ENV' + ENV.delete 'DATABASE_URL' + end + test "precompile application.js and application.css and all other non JS/CSS files" do app_file "app/assets/javascripts/application.js", "alert();" app_file "app/assets/stylesheets/application.css", "body{}" @@ -108,21 +134,26 @@ module ApplicationTests precompile! + images_should_compile = ["a-*.png", "happyface-*.png", "happy_face-*.png", "happy.face-*.png", + "happy-face-*.png", "happy.happy_face-*.png", "happy_happy.face-*.png", + "happy.happy.face-*.png", "-happy-*.png", "-happy.face-*.png", + "_happy.face-*.png", "_happy-*.png"] + images_should_compile.each do |filename| assert_file_exists("#{app_path}/public/assets/#{filename}") end - assert_file_exists("#{app_path}/public/assets/application.js") - assert_file_exists("#{app_path}/public/assets/application.css") + assert_file_exists("#{app_path}/public/assets/application-*.js") + assert_file_exists("#{app_path}/public/assets/application-*.css") - assert_no_file_exists("#{app_path}/public/assets/someapplication.js") - assert_no_file_exists("#{app_path}/public/assets/someapplication.css") + assert_no_file_exists("#{app_path}/public/assets/someapplication-*.js") + assert_no_file_exists("#{app_path}/public/assets/someapplication-*.css") - assert_no_file_exists("#{app_path}/public/assets/something.min.js") - assert_no_file_exists("#{app_path}/public/assets/something.min.css") + assert_no_file_exists("#{app_path}/public/assets/something.min-*.js") + assert_no_file_exists("#{app_path}/public/assets/something.min-*.css") - assert_no_file_exists("#{app_path}/public/assets/something.else.js") - assert_no_file_exists("#{app_path}/public/assets/something.else.css") + assert_no_file_exists("#{app_path}/public/assets/something.else-*.js") + assert_no_file_exists("#{app_path}/public/assets/something.else-*.css") end test "precompile something.js for directory containing index file" do @@ -131,7 +162,30 @@ module ApplicationTests precompile! - assert_file_exists("#{app_path}/public/assets/something.js") + assert_file_exists("#{app_path}/public/assets/something-*.js") + end + + test 'precompile use assets defined in app env config' do + add_to_env_config 'production', 'config.assets.precompile = [ "something.js" ]' + + app_file 'app/assets/javascripts/something.js.erb', 'alert();' + + precompile! 'RAILS_ENV=production' + + assert_file_exists("#{app_path}/public/assets/something-*.js") + end + + test 'precompile use assets defined in app config and reassigned in app env config' do + add_to_config 'config.assets.precompile = [ "something.js" ]' + add_to_env_config 'production', 'config.assets.precompile += [ "another.js" ]' + + app_file 'app/assets/javascripts/something.js.erb', 'alert();' + app_file 'app/assets/javascripts/another.js.erb', 'alert();' + + precompile! 'RAILS_ENV=production' + + assert_file_exists("#{app_path}/public/assets/something-*.js") + assert_file_exists("#{app_path}/public/assets/another-*.js") end test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do @@ -151,11 +205,11 @@ module ApplicationTests add_to_config "config.assets.digest = true" precompile! - manifest = "#{app_path}/public/assets/manifest.yml" + manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first - assets = YAML.load_file(manifest) - assert_match(/application-([0-z]+)\.js/, assets["application.js"]) - assert_match(/application-([0-z]+)\.css/, assets["application.css"]) + assets = ActiveSupport::JSON.decode(File.read(manifest)) + assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"]) + assert_match(/application-([0-z]+)\.css/, assets["assets"]["application.css"]) end test "the manifest file should be saved by default in the same assets folder" do @@ -166,26 +220,9 @@ module ApplicationTests precompile! - manifest = "#{app_path}/public/x/manifest.yml" - assets = YAML.load_file(manifest) - assert_match(/application-([0-z]+)\.js/, assets["application.js"]) - end - - test "precompile does not append asset digests when config.assets.digest is false" do - app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - app_file "app/assets/javascripts/application.js", "alert();" - add_to_config "config.assets.digest = false" - - precompile! - - assert_file_exists("#{app_path}/public/assets/application.js") - assert_file_exists("#{app_path}/public/assets/application.css") - - manifest = "#{app_path}/public/assets/manifest.yml" - - assets = YAML.load_file(manifest) - assert_equal "application.js", assets["application.js"] - assert_equal "application.css", assets["application.css"] + manifest = Dir["#{app_path}/public/x/manifest-*.json"].first + assets = ActiveSupport::JSON.decode(File.read(manifest)) + assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"]) end test "assets do not require any assets group gem when manifest file is present" do @@ -195,9 +232,9 @@ module ApplicationTests ENV["RAILS_ENV"] = "production" precompile! - manifest = "#{app_path}/public/assets/manifest.yml" - assets = YAML.load_file(manifest) - asset_path = assets["application.js"] + manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first + assets = ActiveSupport::JSON.decode(File.read(manifest)) + asset_path = assets["assets"]["application.js"] require "#{app_path}/config/environment" @@ -208,92 +245,43 @@ module ApplicationTests assert !defined?(Uglifier) end - test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled" do - app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>" - - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - get '/posts', :to => "posts#index" - end - RUBY - - ENV["RAILS_ENV"] = "production" - precompile! - - # Create file after of precompile - app_file "app/assets/javascripts/app.js", "alert();" - - require "#{app_path}/config/environment" - class ::PostsController < ActionController::Base - def show_detailed_exceptions?() true end - end - - get '/posts' - assert_match(/AssetNotPrecompiledError/, last_response.body) - assert_match(/app\.js isn't precompiled/, last_response.body) - end - - test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled if digest is disabled" do - app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>" - add_to_config "config.assets.compile = false" - add_to_config "config.assets.digest = false" - - app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - get '/posts', :to => "posts#index" - end - RUBY - - ENV["RAILS_ENV"] = "production" - precompile! - - # Create file after of precompile - app_file "app/assets/javascripts/app.js", "alert();" - - require "#{app_path}/config/environment" - class ::PostsController < ActionController::Base - def show_detailed_exceptions?() true end - end - - get '/posts' - assert_match(/AssetNotPrecompiledError/, last_response.body) - assert_match(/app\.js isn't precompiled/, last_response.body) - end - - test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do + test "precompile properly refers files referenced with asset_path and runs in the provided RAILS_ENV" do + app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" # digest is default in false, we must enable it for test environment add_to_env_config "test", "config.assets.digest = true" precompile!('RAILS_ENV=test') - file = Dir["#{app_path}/public/assets/application.css"].first - assert_match(/\/assets\/rails\.png/, File.read(file)) file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) end - test "precompile shouldn't use the digests present in manifest.yml" do - app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + test "precompile shouldn't use the digests present in manifest.json" do + app_file "app/assets/images/rails.png", "notactuallyapng" + + app_file "app/assets/stylesheets/application.css.erb", "//= depend_on rails.png\np { url: <%= asset_path('rails.png') %> }" ENV["RAILS_ENV"] = "production" precompile! - manifest = "#{app_path}/public/assets/manifest.yml" - assets = YAML.load_file(manifest) - asset_path = assets["application.css"] + manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first + assets = ActiveSupport::JSON.decode(File.read(manifest)) + asset_path = assets["assets"]["application.css"] - app_file "app/assets/images/rails.png", "image changed" + app_file "app/assets/images/rails.png", "p { url: change }" precompile! - assets = YAML.load_file(manifest) + assets = ActiveSupport::JSON.decode(File.read(manifest)) - assert_not_equal asset_path, assets["application.css"] + assert_not_equal asset_path, assets["assets"]["application.css"] end - test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do + test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do + app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" add_to_config "config.assets.compile = true" + add_to_config "config.assets.digest = true" ENV["RAILS_ENV"] = nil @@ -305,15 +293,20 @@ module ApplicationTests test "precompile should handle utf8 filenames" do filename = "レイルズ.png" - app_file "app/assets/images/#{filename}", "not a image really" + app_file "app/assets/images/#{filename}", "not an image really" add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]" precompile! + + manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first + assets = ActiveSupport::JSON.decode(File.read(manifest)) + assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1] + require "#{app_path}/config/environment" - get "/assets/#{URI.parser.escape(filename)}" - assert_match "not a image really", last_response.body - assert_file_exists("#{app_path}/public/assets/#{filename}") + get "/assets/#{URI.parser.escape(asset_path)}" + assert_match "not an image really", last_response.body + assert_file_exists("#{app_path}/public/assets/#{asset_path}") end test "assets are cleaned up properly" do @@ -343,7 +336,7 @@ module ApplicationTests app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/omg', :to => "omg#index" end RUBY @@ -403,19 +396,7 @@ module ApplicationTests add_to_config "config.assets.digest = false" precompile! - assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js") - end - - test "assets can't access model information when precompiling if not initializing the app" do - app_file "app/models/post.rb", "class Post; end" - app_file "app/assets/javascripts/application.js", "//= require_tree ." - app_file "app/assets/javascripts/xmlhr.js.erb", "<%= defined?(Post) || :NoPost %>" - - add_to_config "config.assets.digest = false" - add_to_config "config.assets.initialize_on_precompile = false" - - precompile! - assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js") + assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first) end test "initialization on the assets group should set assets_dir" do @@ -449,7 +430,7 @@ module ApplicationTests clean_assets! - files = Dir["#{app_path}/public/production_assets/application.js"] + files = Dir["#{app_path}/public/production_assets/application-*.js"] assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists" end @@ -466,34 +447,24 @@ module ApplicationTests end test "asset urls should be protocol-relative if no request is in scope" do + app_file "app/assets/images/rails.png", "notreallyapng" app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";' add_to_config "config.assets.precompile = %w{image_loader.js}" add_to_config "config.asset_host = 'example.com'" precompile! - assert_match 'src="//example.com/assets/rails.png"', File.read("#{app_path}/public/assets/image_loader.js") + assert_match 'src="//example.com/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) end test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri" + app_file "app/assets/images/rails.png", "notreallyapng" app_file "app/assets/javascripts/app.js.erb", 'var src="<%= image_path("rails.png") %>";' add_to_config "config.assets.precompile = %w{app.js}" precompile! - assert_match 'src="/sub/uri/assets/rails.png"', File.read("#{app_path}/public/assets/app.js") - end - - test "html assets are compiled when executing precompile" do - app_file "app/assets/pages/page.html.erb", "<%= javascript_include_tag :application %>" - ENV["RAILS_ENV"] = "production" - ENV["RAILS_GROUP"] = "assets" - - quietly do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end - - assert_file_exists("#{app_path}/public/assets/page.html") + assert_match 'src="/sub/uri/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/app-*.js"].first) end test "assets:cache:clean should clean cache" do @@ -501,11 +472,10 @@ module ApplicationTests precompile! quietly do - Dir.chdir(app_path){ `bundle exec rake assets:cache:clean` } + Dir.chdir(app_path){ `bundle exec rake assets:clobber` } end - require "#{app_path}/config/environment" - assert_equal 0, Dir.entries(Rails.application.assets.cache.cache_path).size - 2 # reject [".", ".."] + assert !File.exist?("#{app_path}/tmp/cache/assets") end private @@ -516,7 +486,7 @@ module ApplicationTests app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/posts', :to => "posts#index" end RUBY diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7a120410ba..03a735b1c1 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1,5 +1,6 @@ require "isolation/abstract_unit" require 'rack/test' +require 'env_helpers' class ::MyMailInterceptor def self.delivering_email(email); email; end @@ -17,6 +18,7 @@ module ApplicationTests class ConfigurationTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation include Rack::Test::Methods + include EnvHelpers def new_app File.expand_path("#{app_path}/../new_app") @@ -41,6 +43,16 @@ module ApplicationTests FileUtils.rm_rf(new_app) if File.directory?(new_app) end + test "Rails.env does not set the RAILS_ENV environment variable which would leak out into rake tasks" do + require "rails" + + switch_env "RAILS_ENV", nil do + Rails.env = "development" + assert_equal "development", Rails.env + assert_nil ENV['RAILS_ENV'] + end + end + test "a renders exception on pending migration" do add_to_config <<-RUBY config.active_record.migration_error = :page_load @@ -50,6 +62,7 @@ module ApplicationTests require "#{app_path}/config/environment" ActiveRecord::Migrator.stubs(:needs_migration?).returns(true) + ActiveRecord::NullMigration.any_instance.stubs(:mtime).returns(1) get "/foo" assert_equal 500, last_response.status @@ -146,17 +159,12 @@ module ApplicationTests RUBY require "#{app_path}/config/application" - assert AppTemplate::Application.initialize! + assert Rails.application.initialize! end test "application is always added to eager_load namespaces" do require "#{app_path}/config/application" - assert AppTemplate::Application, AppTemplate::Application.config.eager_load_namespaces - end - - test "asset_path defaults to nil for application" do - require "#{app_path}/config/environment" - assert_equal nil, AppTemplate::Application.config.asset_path + assert Rails.application, Rails.application.config.eager_load_namespaces end test "the application can be eager loaded even when there are no frameworks" do @@ -185,6 +193,16 @@ module ApplicationTests end end + test "filter_parameters should be able to set via config.filter_parameters in an initializer" do + app_file 'config/initializers/filter_parameters_logging.rb', <<-RUBY + Rails.application.config.filter_parameters += [ :password, :foo, 'bar' ] + RUBY + + require "#{app_path}/config/environment" + + assert_equal [:password, :foo, 'bar'], Rails.application.env_config['action_dispatch.parameter_filter'] + end + test "config.to_prepare is forwarded to ActionDispatch" do $prepared = false @@ -230,21 +248,24 @@ module ApplicationTests assert_equal Pathname.new(app_path).join("somewhere"), Rails.public_path end - test "config.secret_token is sent in env" do + test "Use key_generator when secret_key_base is set" do make_basic_app do |app| - app.config.secret_token = 'b3c631c314c0bbca50c1b2843150fe33' + app.config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' app.config.session_store :disabled end class ::OmgController < ActionController::Base def index cookies.signed[:some_key] = "some_value" - render text: env["action_dispatch.secret_token"] + render text: cookies[:some_key] end end get "/" - assert_equal 'b3c631c314c0bbca50c1b2843150fe33', last_response.body + + secret = app.key_generator.generate_key('signed cookie') + verifier = ActiveSupport::MessageVerifier.new(secret) + assert_equal 'some_value', verifier.verify(last_response.body) end test "protect from forgery is the default in a new app" do @@ -433,21 +454,6 @@ module ApplicationTests end end - test "config.asset_path is not passed through env" do - make_basic_app do |app| - app.config.asset_path = "/omg%s" - end - - class ::OmgController < ActionController::Base - def index - render inline: "<%= image_path('foo.jpg') %>" - end - end - - get "/" - assert_equal "/omg/images/foo.jpg", last_response.body - end - test "config.action_view.cache_template_loading with cache_classes default" do add_to_config "config.cache_classes = true" require "#{app_path}/config/environment" @@ -562,6 +568,54 @@ module ApplicationTests assert_equal 'permitted', last_response.body end + test "config.action_controller.action_on_unpermitted_parameters = :raise" do + app_file 'app/controllers/posts_controller.rb', <<-RUBY + class PostsController < ActionController::Base + def create + render text: params.require(:post).permit(:name) + end + end + RUBY + + add_to_config <<-RUBY + routes.prepend do + resources :posts + end + config.action_controller.action_on_unpermitted_parameters = :raise + RUBY + + require "#{app_path}/config/environment" + + assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters + + post "/posts", {post: {"title" =>"zomg"}} + assert_match "We're sorry, but something went wrong", last_response.body + end + + test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do + ENV["RAILS_ENV"] = "development" + + require "#{app_path}/config/environment" + + assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters + end + + test "config.action_controller.action_on_unpermitted_parameters is :log by default on test" do + ENV["RAILS_ENV"] = "test" + + require "#{app_path}/config/environment" + + assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters + end + + test "config.action_controller.action_on_unpermitted_parameters is false by default on production" do + ENV["RAILS_ENV"] = "production" + + require "#{app_path}/config/environment" + + assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters + end + test "config.action_dispatch.ignore_accept_header" do make_basic_app do |app| app.config.action_dispatch.ignore_accept_header = true @@ -588,7 +642,6 @@ module ApplicationTests assert_respond_to app, :env_config assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters - assert_equal app.env_config['action_dispatch.secret_token'], app.config.secret_token assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions assert_equal app.env_config['action_dispatch.logger'], Rails.logger assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner @@ -600,27 +653,6 @@ module ApplicationTests assert app.config.colorize_logging end - test "config.active_record.observers" do - add_to_config <<-RUBY - config.active_record.observers = :foo_observer - RUBY - - app_file 'app/models/foo.rb', <<-RUBY - class Foo < ActiveRecord::Base - end - RUBY - - app_file 'app/models/foo_observer.rb', <<-RUBY - class FooObserver < ActiveRecord::Observer - end - RUBY - - require "#{app_path}/config/environment" - - ActiveRecord::Base - assert defined?(FooObserver) - end - test "config.session_store with :active_record_store with activerecord-session_store gem" do begin make_basic_app do |app| @@ -639,5 +671,20 @@ module ApplicationTests end end end + + test "config.log_level with custom logger" do + make_basic_app do |app| + app.config.logger = Logger.new(STDOUT) + app.config.log_level = :info + end + assert_equal Logger::INFO, Rails.logger.level + end + + test "respond_to? accepts include_private" do + make_basic_app + + assert_not Rails.configuration.respond_to?(:method_missing) + assert Rails.configuration.respond_to?(:method_missing, true) + end end end diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index f372afa51c..31bc003dcb 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -81,35 +81,73 @@ class ConsoleTest < ActiveSupport::TestCase assert_equal 'Once upon a time in a world...', helper.truncate('Once upon a time in a world far far away') end +end + +begin + require "pty" +rescue LoadError +end - def test_with_sandbox - require 'rails/all' - value = false +class FullStackConsoleTest < ActiveSupport::TestCase + def setup + skip "PTY unavailable" unless defined?(PTY) && PTY.respond_to?(:open) - Class.new(Rails::Railtie) do - console do |app| - value = app.sandbox? + build_app + app_file 'app/models/post.rb', <<-CODE + class Post < ActiveRecord::Base end - end + CODE + system "#{app_path}/bin/rails runner 'Post.connection.create_table :posts'" - load_environment(true) - assert value + @master, @slave = PTY.open end - def test_active_record_does_not_panic_when_referencing_an_observed_constant - add_to_config "config.active_record.observers = :user_observer" + def teardown + teardown_app + end - app_file "app/models/user.rb", <<-MODEL - class User < ActiveRecord::Base - end - MODEL + def assert_output(expected, timeout = 1) + timeout = Time.now + timeout - app_file "app/models/user_observer.rb", <<-MODEL - class UserObserver < ActiveRecord::Observer + output = "" + until output.include?(expected) || Time.now > timeout + if IO.select([@master], [], [], 0.1) + output << @master.read(1) end - MODEL + end - load_environment - assert_nothing_raised { User } + assert output.include?(expected), "#{expected.inspect} expected, but got:\n\n#{output}" + end + + def write_prompt(command, expected_output = nil) + @master.puts command + assert_output command + assert_output expected_output if expected_output + assert_output "> " + end + + def spawn_console + Process.spawn( + "#{app_path}/bin/rails console --sandbox", + in: @slave, out: @slave, err: @slave + ) + + assert_output "> ", 30 + end + + def test_sandbox + spawn_console + + write_prompt "Post.count", "=> 0" + write_prompt "Post.create" + write_prompt "Post.count", "=> 1" + @master.puts "quit" + + spawn_console + + write_prompt "Post.count", "=> 0" + write_prompt "Post.transaction { Post.create; raise }" + write_prompt "Post.count", "=> 0" + @master.puts "quit" end end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index bc0af499c1..78ada58ec8 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -30,7 +30,7 @@ module ApplicationTests end test "allow running plugin new generator inside Rails app directory" do - FileUtils.cd(rails_root){ `ruby script/rails plugin new vendor/plugins/bukkits` } + FileUtils.cd(rails_root){ `ruby bin/rails plugin new vendor/plugins/bukkits` } assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) end diff --git a/railties/test/application/initializers/boot_test.rb b/railties/test/application/initializers/boot_test.rb deleted file mode 100644 index 7eda15894e..0000000000 --- a/railties/test/application/initializers/boot_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require "isolation/abstract_unit" - -module ApplicationTests - class BootTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation - - def setup - # build_app - # boot_rails - end - - def teardown - # teardown_app - end - - test "booting rails sets the load paths correctly" do - # This test is pending reworking the boot process - end - end -end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 528bec58ef..83104acf3c 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -41,7 +41,7 @@ module ApplicationTests test "allows me to configure default url options for ActionMailer" do app_file "config/environments/development.rb", <<-RUBY - AppTemplate::Application.configure do + Rails.application.configure do config.action_mailer.default_url_options = { :host => "test.rails" } end RUBY @@ -50,25 +50,9 @@ module ApplicationTests assert_equal "test.rails", ActionMailer::Base.default_url_options[:host] end - test "uses the default queue for ActionMailer" do - require "#{app_path}/config/environment" - assert_kind_of ActiveSupport::Queue, ActionMailer::Base.queue - end - - test "allows me to configure queue for ActionMailer" do - app_file "config/environments/development.rb", <<-RUBY - AppTemplate::Application.configure do - config.action_mailer.queue = ActiveSupport::TestQueue.new - end - RUBY - - require "#{app_path}/config/environment" - assert_kind_of ActiveSupport::TestQueue, ActionMailer::Base.queue - end - test "does not include url helpers as action methods" do app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo end RUBY @@ -131,7 +115,7 @@ module ApplicationTests RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/:controller(/:action)" end RUBY @@ -198,7 +182,7 @@ module ApplicationTests end require "#{app_path}/config/environment" ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test. - assert ActiveRecord::Base.connection.schema_cache.tables["posts"] + assert ActiveRecord::Base.connection.schema_cache.tables("posts") end test "expire schema cache dump" do @@ -208,7 +192,7 @@ module ApplicationTests end silence_warnings { require "#{app_path}/config/environment" - assert !ActiveRecord::Base.connection.schema_cache.tables["posts"] + assert !ActiveRecord::Base.connection.schema_cache.tables("posts") } end @@ -219,7 +203,7 @@ module ApplicationTests orig_rails_env, Rails.env = Rails.env, 'development' ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection - assert_match /#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database] + assert_match(/#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]) ensure ActiveRecord::Base.remove_connection ENV["DATABASE_URL"] = orig_database_url if orig_database_url @@ -236,7 +220,7 @@ module ApplicationTests ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}" ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection - assert_match /#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database] + assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) ensure ActiveRecord::Base.remove_connection ENV["DATABASE_URL"] = orig_database_url if orig_database_url diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 489b7ddb92..97df073ec7 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -45,7 +45,7 @@ module ApplicationTests end # Load paths - test "no config locales dir present should return empty load path" do + test "no config locales directory present should return empty load path" do FileUtils.rm_rf "#{app_path}/config/locales" load_app assert_equal [], Rails.application.config.i18n.load_path @@ -84,7 +84,7 @@ en: RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [Foo.instance_variable_get('@foo')]] } end RUBY @@ -108,7 +108,7 @@ en: YAML app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } end RUBY diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index 31811e7f92..b36628ee37 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -23,7 +23,7 @@ module ApplicationTests assert $:.include?("#{app_path}/app/models") end - test "initializing an application allows to load code on lib path inside application class definitation" do + test "initializing an application allows to load code on lib path inside application class definition" do app_file "lib/foo.rb", <<-RUBY module Foo; end RUBY @@ -72,9 +72,10 @@ module ApplicationTests end test "load environment with global" do + $initialize_test_set_from_env = nil app_file "config/environments/development.rb", <<-RUBY $initialize_test_set_from_env = 'success' - AppTemplate::Application.configure do + Rails.application.configure do config.cache_classes = true config.time_zone = "Brasilia" end @@ -88,8 +89,8 @@ module ApplicationTests require "#{app_path}/config/environment" assert_equal "success", $initialize_test_set_from_env - assert AppTemplate::Application.config.cache_classes - assert_equal "Brasilia", AppTemplate::Application.config.time_zone + assert Rails.application.config.cache_classes + assert_equal "Brasilia", Rails.application.config.time_zone end end end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index ad7172c514..4f30f30f95 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -36,7 +36,7 @@ class LoadingTest < ActiveSupport::TestCase test "models without table do not panic on scope definitions when loaded" do app_file "app/models/user.rb", <<-MODEL class User < ActiveRecord::Base - default_scope where(published: true) + default_scope { where(published: true) } end MODEL @@ -48,7 +48,7 @@ class LoadingTest < ActiveSupport::TestCase test "load config/environments/environment before Bootstrap initializers" do app_file "config/environments/development.rb", <<-RUBY - AppTemplate::Application.configure do + Rails.application.configure do config.development_environment_loaded = true end RUBY @@ -60,7 +60,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY require "#{app_path}/config/environment" - assert ::AppTemplate::Application.config.loaded + assert ::Rails.application.config.loaded end test "descendants loaded after framework initialization are cleaned on each request without cache classes" do @@ -75,7 +75,7 @@ class LoadingTest < ActiveSupport::TestCase MODEL app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/load', to: lambda { |env| [200, {}, Post.all] } get '/unload', to: lambda { |env| [200, {}, []] } end @@ -96,7 +96,7 @@ class LoadingTest < ActiveSupport::TestCase test "initialize cant be called twice" do require "#{app_path}/config/environment" - assert_raise(RuntimeError) { ::AppTemplate::Application.initialize! } + assert_raise(RuntimeError) { Rails.application.initialize! } end test "reload constants on development" do @@ -105,7 +105,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -144,7 +144,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -179,8 +179,8 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file 'config/routes.rb', <<-RUBY - $counter = 0 - AppTemplate::Application.routes.draw do + $counter ||= 0 + Rails.application.routes.draw do get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } end RUBY @@ -205,13 +205,46 @@ class LoadingTest < ActiveSupport::TestCase assert_equal "2", last_response.body end + test "dependencies reloading is followed by routes reloading" do + add_to_config <<-RUBY + config.cache_classes = false + RUBY + + app_file 'config/routes.rb', <<-RUBY + $counter ||= 1 + $counter *= 2 + Rails.application.routes.draw do + get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } + end + RUBY + + app_file "app/models/user.rb", <<-MODEL + class User + $counter += 1 + end + MODEL + + require 'rack/test' + extend Rack::Test::Methods + + require "#{rails_root}/config/environment" + + get "/c" + assert_equal "3", last_response.body + + app_file "db/schema.rb", "" + + get "/c" + assert_equal "7", last_response.body + end + test "columns migrations also trigger reloading" do add_to_config <<-RUBY config.cache_classes = false RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/title', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] } get '/body', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] } end @@ -270,7 +303,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/:controller(/:action)" end RUBY @@ -288,10 +321,10 @@ class LoadingTest < ActiveSupport::TestCase require "#{app_path}/config/application" assert !Rails.initialized? - assert !AppTemplate::Application.initialized? + assert !Rails.application.initialized? Rails.initialize! assert Rails.initialized? - assert AppTemplate::Application.initialized? + assert Rails.application.initialized? end protected diff --git a/railties/test/application/middleware/best_practices_test.rb b/railties/test/application/middleware/best_practices_test.rb deleted file mode 100644 index f6783c6ca2..0000000000 --- a/railties/test/application/middleware/best_practices_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'isolation/abstract_unit' - -module ApplicationTests - class BestPracticesTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - require 'rack/test' - extend Rack::Test::Methods - simple_controller - end - - def teardown - teardown_app - end - - test "simple controller in production mode returns best standards" do - get '/foo' - assert_equal "IE=Edge,chrome=1", last_response.headers["X-UA-Compatible"] - end - - test "simple controller in development mode leaves out Chrome" do - app("development") - get "/foo" - assert_equal "IE=Edge", last_response.headers["X-UA-Compatible"] - end - end -end diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index 9b6c76e7aa..b4db840e68 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -45,12 +45,10 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY - - add_to_config "config.action_dispatch.rack_cache = true" end def test_cache_keeps_if_modified_since @@ -80,9 +78,11 @@ module ApplicationTests def test_cache_works_with_expires simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_header" - assert_equal "miss, store", last_response.headers["X-Rack-Cache"] - assert_equal "max-age=10, public", last_response.headers["Cache-Control"] + assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] + assert_equal "max-age=10, public", last_response.headers["Cache-Control"] body = last_response.body @@ -96,6 +96,8 @@ module ApplicationTests def test_cache_works_with_expires_private simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_header", private: true assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_equal "private, max-age=10", last_response.headers["Cache-Control"] @@ -110,9 +112,11 @@ module ApplicationTests def test_cache_works_with_etags simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_etag" - assert_equal "miss, store", last_response.headers["X-Rack-Cache"] - assert_equal "public", last_response.headers["Cache-Control"] + assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] + assert_equal "public", last_response.headers["Cache-Control"] body = last_response.body etag = last_response.headers["ETag"] @@ -125,6 +129,8 @@ module ApplicationTests def test_cache_works_with_etags_private simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_etag", private: true assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_equal "must-revalidate, private, max-age=0", last_response.headers["Cache-Control"] @@ -140,9 +146,11 @@ module ApplicationTests def test_cache_works_with_last_modified simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_last_modified" - assert_equal "miss, store", last_response.headers["X-Rack-Cache"] - assert_equal "public", last_response.headers["Cache-Control"] + assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] + assert_equal "public", last_response.headers["Cache-Control"] body = last_response.body last = last_response.headers["Last-Modified"] @@ -155,6 +163,8 @@ module ApplicationTests def test_cache_works_with_last_modified_private simple_controller + add_to_config "config.action_dispatch.rack_cache = true" + get "/expires/expires_last_modified", private: true assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_equal "must-revalidate, private, max-age=0", last_response.headers["Cache-Control"] diff --git a/railties/test/application/middleware/cookies_test.rb b/railties/test/application/middleware/cookies_test.rb index 18af7abafc..bbb7627be9 100644 --- a/railties/test/application/middleware/cookies_test.rb +++ b/railties/test/application/middleware/cookies_test.rb @@ -33,7 +33,7 @@ module ApplicationTests assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie end - test 'always_write_cookie can be overrided' do + test 'always_write_cookie can be overridden' do add_to_config <<-RUBY config.action_dispatch.always_write_cookie = false RUBY diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 9d97bae9ae..946b82eeb3 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -1,4 +1,5 @@ require 'isolation/abstract_unit' +require 'active_support/key_generator' module ApplicationTests class RemoteIpTest < ActiveSupport::TestCase @@ -8,7 +9,7 @@ module ApplicationTests remote_ip = nil env = Rack::MockRequest.env_for("/").merge(env).merge!( 'action_dispatch.show_exceptions' => false, - 'action_dispatch.secret_token' => 'b3c631c314c0bbca50c1b2843150fe33' + 'action_dispatch.key_generator' => ActiveSupport::LegacyKeyGenerator.new('b3c631c314c0bbca50c1b2843150fe33') ) endpoint = Proc.new do |e| @@ -32,13 +33,23 @@ module ApplicationTests end end + test "works with both headers individually" do + make_basic_app + assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_equal "1.1.1.1", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1") + end + assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_equal "1.1.1.2", remote_ip("HTTP_CLIENT_IP" => "1.1.1.2") + end + end + test "can disable IP spoofing check" do make_basic_app do |app| app.config.action_dispatch.ip_spoofing_check = false end assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do - assert_equal "1.1.1.2", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2") + assert_equal "1.1.1.1", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2") end end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 5ce41caf61..14a56176f5 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -49,7 +49,7 @@ module ApplicationTests test "session is empty and isn't saved on unverified request when using :null_session protect method" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' end @@ -90,7 +90,7 @@ module ApplicationTests test "cookie jar is empty and isn't saved on unverified request when using :null_session protect method" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' end @@ -128,5 +128,216 @@ module ApplicationTests get '/foo/read_cookie' # Cookie shouldn't be changed assert_equal '"1"', last_response.body end + + test "session using encrypted cookie store" do + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':controller(/:action)' + end + RUBY + + controller :foo, <<-RUBY + class FooController < ActionController::Base + def write_session + session[:foo] = 1 + render nothing: true + end + + def read_session + render text: session[:foo] + end + + def read_encrypted_cookie + render text: cookies.encrypted[:_myapp_session]['foo'] + end + + def read_raw_cookie + render text: cookies[:_myapp_session] + end + end + RUBY + + require "#{app_path}/config/environment" + + get '/foo/write_session' + get '/foo/read_session' + assert_equal '1', last_response.body + + get '/foo/read_encrypted_cookie' + assert_equal '1', last_response.body + + secret = app.key_generator.generate_key('encrypted cookie') + sign_secret = app.key_generator.generate_key('signed encrypted cookie') + encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + + get '/foo/read_raw_cookie' + assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo'] + end + + test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':controller(/:action)' + end + RUBY + + controller :foo, <<-RUBY + class FooController < ActionController::Base + def write_session + session[:foo] = 1 + render nothing: true + end + + def read_session + render text: session[:foo] + end + + def read_encrypted_cookie + render text: cookies.encrypted[:_myapp_session]['foo'] + end + + def read_raw_cookie + render text: cookies[:_myapp_session] + end + end + RUBY + + add_to_config <<-RUBY + config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + RUBY + + require "#{app_path}/config/environment" + + get '/foo/write_session' + get '/foo/read_session' + assert_equal '1', last_response.body + + get '/foo/read_encrypted_cookie' + assert_equal '1', last_response.body + + secret = app.key_generator.generate_key('encrypted cookie') + sign_secret = app.key_generator.generate_key('signed encrypted cookie') + encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + + get '/foo/read_raw_cookie' + assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo'] + end + + test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':controller(/:action)' + end + RUBY + + controller :foo, <<-RUBY + class FooController < ActionController::Base + def write_raw_session + # {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1} + cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749" + render nothing: true + end + + def write_session + session[:foo] = session[:foo] + 1 + render nothing: true + end + + def read_session + render text: session[:foo] + end + + def read_encrypted_cookie + render text: cookies.encrypted[:_myapp_session]['foo'] + end + + def read_raw_cookie + render text: cookies[:_myapp_session] + end + end + RUBY + + add_to_config <<-RUBY + config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + RUBY + + require "#{app_path}/config/environment" + + get '/foo/write_raw_session' + get '/foo/read_session' + assert_equal '1', last_response.body + + get '/foo/write_session' + get '/foo/read_session' + assert_equal '2', last_response.body + + get '/foo/read_encrypted_cookie' + assert_equal '2', last_response.body + + secret = app.key_generator.generate_key('encrypted cookie') + sign_secret = app.key_generator.generate_key('signed encrypted cookie') + encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) + + get '/foo/read_raw_cookie' + assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo'] + end + + test "session upgrading legacy signed cookies to new signed cookies" do + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':controller(/:action)' + end + RUBY + + controller :foo, <<-RUBY + class FooController < ActionController::Base + def write_raw_session + # {"session_id"=>"1965d95720fffc123941bdfb7d2e6870", "foo"=>1} + cookies[:_myapp_session] = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJTE5NjVkOTU3MjBmZmZjMTIzOTQxYmRmYjdkMmU2ODcwBjsAVEkiCGZvbwY7AEZpBg==--315fb9931921a87ae7421aec96382f0294119749" + render nothing: true + end + + def write_session + session[:foo] = session[:foo] + 1 + render nothing: true + end + + def read_session + render text: session[:foo] + end + + def read_signed_cookie + render text: cookies.signed[:_myapp_session]['foo'] + end + + def read_raw_cookie + render text: cookies[:_myapp_session] + end + end + RUBY + + add_to_config <<-RUBY + config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + config.secret_key_base = nil + RUBY + + require "#{app_path}/config/environment" + + get '/foo/write_raw_session' + get '/foo/read_session' + assert_equal '1', last_response.body + + get '/foo/write_session' + get '/foo/read_session' + assert_equal '2', last_response.body + + get '/foo/read_signed_cookie' + assert_equal '2', last_response.body + + verifier = ActiveSupport::MessageVerifier.new(app.config.secret_token) + + get '/foo/read_raw_cookie' + assert_equal 2, verifier.verify(last_response.body)['foo'] + end end end diff --git a/railties/test/application/middleware/static_test.rb b/railties/test/application/middleware/static_test.rb new file mode 100644 index 0000000000..0a793f8f60 --- /dev/null +++ b/railties/test/application/middleware/static_test.rb @@ -0,0 +1,31 @@ +# encoding: utf-8 +require 'isolation/abstract_unit' +require 'rack/test' + +module ApplicationTests + class MiddlewareStaticTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + FileUtils.rm_rf "#{app_path}/config/environments" + end + + def teardown + teardown_app + end + + # Regression test to #8907 + # See https://github.com/rails/rails/commit/9cc82b77196d21a5c7021f6dca59ab9b2b158a45#commitcomment-2416514 + test "doesn't set Cache-Control header when it is nil" do + app_file "public/foo.html", 'static' + + require "#{app_path}/config/environment" + + get 'foo' + + assert_not last_response.headers.has_key?('Cache-Control'), "Cache-Control should not be set" + end + end +end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index c03d35e926..20d1d76d78 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -19,7 +19,7 @@ module ApplicationTests end test "default middleware stack" do - add_to_config "config.action_dispatch.x_sendfile_header = 'X-Sendfile'" + add_to_config "config.active_record.migration_error = :page_load" boot! @@ -37,6 +37,7 @@ module ApplicationTests "ActionDispatch::RemoteIp", "ActionDispatch::Reloader", "ActionDispatch::Callbacks", + "ActiveRecord::Migration::CheckPending", "ActiveRecord::ConnectionAdapters::ConnectionManagement", "ActiveRecord::QueryCache", "ActionDispatch::Cookies", @@ -45,32 +46,30 @@ module ApplicationTests "ActionDispatch::ParamsParser", "Rack::Head", "Rack::ConditionalGet", - "Rack::ETag", - "ActionDispatch::BestStandardsSupport" + "Rack::ETag" ], middleware end - test "Rack::Sendfile is not included by default" do + test "Rack::Cache is not included by default" do boot! - assert !middleware.include?("Rack::Sendfile"), "Rack::Sendfile is not included in the default stack unless you set config.action_dispatch.x_sendfile_header" + assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" end - test "Rack::Cache is not included by default" do - add_to_config "config.action_controller.perform_caching = true" + test "Rack::Cache is present when action_dispatch.rack_cache is set" do + add_to_config "config.action_dispatch.rack_cache = true" boot! - assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" + assert_equal "Rack::Cache", middleware.first end - test "Rack::Cache is present when action_controller.perform_caching is set and action_dispatch.rack_cache is set" do - add_to_config "config.action_controller.perform_caching = true" - add_to_config "config.action_dispatch.rack_cache = true" + test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do + add_to_config "config.active_record.migration_error = :page_load" boot! - assert_equal "Rack::Cache", middleware.first + assert middleware.include?("ActiveRecord::Migration::CheckPending") end test "ActionDispatch::SSL is present when force_ssl is set" do @@ -84,7 +83,7 @@ module ApplicationTests add_to_config "config.ssl_options = { host: 'example.com' }" boot! - assert_equal AppTemplate::Application.middleware.first.args, [{host: 'example.com'}] + assert_equal Rails.application.middleware.first.args, [{host: 'example.com'}] end test "removing Active Record omits its middleware" do @@ -92,6 +91,7 @@ module ApplicationTests boot! assert !middleware.include?("ActiveRecord::ConnectionAdapters::ConnectionManagement") assert !middleware.include?("ActiveRecord::QueryCache") + assert !middleware.include?("ActiveRecord::Migration::CheckPending") end test "removes lock if cache classes is set" do @@ -100,6 +100,12 @@ module ApplicationTests assert !middleware.include?("Rack::Lock") end + test "removes lock if allow concurrency is set" do + add_to_config "config.allow_concurrency = true" + boot! + assert !middleware.include?("Rack::Lock") + end + test "removes static asset server if serve_static_assets is disabled" do add_to_config "config.serve_static_assets = false" boot! @@ -133,24 +139,30 @@ module ApplicationTests end test "insert middleware after" do - add_to_config "config.middleware.insert_after ActionDispatch::Static, Rack::Config" + add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config" boot! assert_equal "Rack::Config", middleware.second end + test 'unshift middleware' do + add_to_config 'config.middleware.unshift Rack::Config' + boot! + assert_equal 'Rack::Config', middleware.first + end + test "Rails.cache does not respond to middleware" do add_to_config "config.cache_store = :memory_store" boot! - assert_equal "Rack::Runtime", middleware.third + assert_equal "Rack::Runtime", middleware.fourth end test "Rails.cache does respond to middleware" do boot! - assert_equal "Rack::Runtime", middleware.fourth + assert_equal "Rack::Runtime", middleware.fifth end test "insert middleware before" do - add_to_config "config.middleware.insert_before ActionDispatch::Static, Rack::Config" + add_to_config "config.middleware.insert_before Rack::Sendfile, Rack::Config" boot! assert_equal "Rack::Config", middleware.first end @@ -215,7 +227,7 @@ module ApplicationTests end def middleware - AppTemplate::Application.middleware.map(&:klass).map(&:name) + Rails.application.middleware.map(&:klass).map(&:name) end end end diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb new file mode 100644 index 0000000000..5bfea599e0 --- /dev/null +++ b/railties/test/application/multiple_applications_test.rb @@ -0,0 +1,148 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class MultipleApplicationsTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app(initializers: true) + boot_rails + require "#{rails_root}/config/environment" + end + + def teardown + teardown_app + end + + def test_cloning_an_application_makes_a_shallow_copy_of_config + clone = Rails.application.clone + + assert_equal Rails.application.config, clone.config, "The cloned application should get a copy of the config" + assert_equal Rails.application.config.secret_key_base, clone.config.secret_key_base, "The base secret key on the config should be the same" + end + + def test_initialization_of_multiple_copies_of_same_application + application1 = AppTemplate::Application.new + application2 = AppTemplate::Application.new + + assert_not_equal Rails.application.object_id, application1.object_id, "New applications should not be the same as the original application" + assert_not_equal Rails.application.object_id, application2.object_id, "New applications should not be the same as the original application" + end + + def test_initialization_of_application_with_previous_config + application1 = AppTemplate::Application.new(config: Rails.application.config) + application2 = AppTemplate::Application.new + + assert_equal Rails.application.config, application1.config, "Creating a new application while setting an initial config should result in the same config" + assert_not_equal Rails.application.config, application2.config, "New applications without setting an initial config should not have the same config" + end + + def test_initialization_of_application_with_previous_railties + application1 = AppTemplate::Application.new(railties: Rails.application.railties) + application2 = AppTemplate::Application.new + + assert_equal Rails.application.railties, application1.railties + assert_not_equal Rails.application.railties, application2.railties + end + + def test_initialize_new_application_with_all_previous_initialization_variables + application1 = AppTemplate::Application.new( + config: Rails.application.config, + railties: Rails.application.railties, + routes_reloader: Rails.application.routes_reloader, + reloaders: Rails.application.reloaders, + routes: Rails.application.routes, + helpers: Rails.application.helpers, + app_env_config: Rails.application.env_config + ) + + assert_equal Rails.application.config, application1.config + assert_equal Rails.application.railties, application1.railties + assert_equal Rails.application.routes_reloader, application1.routes_reloader + assert_equal Rails.application.reloaders, application1.reloaders + assert_equal Rails.application.routes, application1.routes + assert_equal Rails.application.helpers, application1.helpers + assert_equal Rails.application.env_config, application1.env_config + end + + def test_rake_tasks_defined_on_different_applications_go_to_the_same_class + $run_count = 0 + + application1 = AppTemplate::Application.new + application1.rake_tasks do + $run_count += 1 + end + + application2 = AppTemplate::Application.new + application2.rake_tasks do + $run_count += 1 + end + + require "#{app_path}/config/environment" + + assert_equal 0, $run_count, "The count should stay at zero without any calls to the rake tasks" + require 'rake' + require 'rake/testtask' + require 'rdoc/task' + Rails.application.load_tasks + assert_equal 2, $run_count, "Calling a rake task should result in two increments to the count" + end + + def test_multiple_applications_can_be_initialized + assert_nothing_raised { AppTemplate::Application.new } + end + + def test_initializers_run_on_different_applications_go_to_the_same_class + application1 = AppTemplate::Application.new + $run_count = 0 + + AppTemplate::Application.initializer :init0 do + $run_count += 1 + end + + application1.initializer :init1 do + $run_count += 1 + end + + AppTemplate::Application.new.initializer :init2 do + $run_count += 1 + end + + assert_equal 0, $run_count, "Without loading the initializers, the count should be 0" + + # Set config.eager_load to false so that an eager_load warning doesn't pop up + AppTemplate::Application.new { config.eager_load = false }.initialize! + + assert_equal 3, $run_count, "There should have been three initializers that incremented the count" + end + + def test_runners_run_on_different_applications_go_to_the_same_class + $run_count = 0 + AppTemplate::Application.runner { $run_count += 1 } + AppTemplate::Application.new.runner { $run_count += 1 } + + assert_equal 0, $run_count, "Without loading the runners, the count should be 0" + Rails.application.load_runner + assert_equal 2, $run_count, "There should have been two runners that increment the count" + end + + def test_isolate_namespace_on_an_application + assert_nil Rails.application.railtie_namespace, "Before isolating namespace, the railtie namespace should be nil" + Rails.application.isolate_namespace(AppTemplate) + assert_equal Rails.application.railtie_namespace, AppTemplate, "After isolating namespace, we should have a namespace" + end + + def test_inserting_configuration_into_application + app = AppTemplate::Application.new(config: Rails.application.config) + new_config = Rails::Application::Configuration.new("root_of_application") + new_config.secret_key_base = "some_secret_key_dude" + app.config.secret_key_base = "a_different_secret_key" + + assert_equal "a_different_secret_key", app.config.secret_key_base, "The configuration's secret key should be set." + app.config = new_config + assert_equal "some_secret_key_dude", app.config.secret_key_base, "The configuration's secret key should have changed." + assert_equal "root_of_application", app.config.root, "The root should have changed to the new config's root." + assert_equal new_config, app.config, "The application's config should have changed to the new config." + end + end +end diff --git a/railties/test/application/queue_test.rb b/railties/test/application/queue_test.rb deleted file mode 100644 index b0b3cf18e9..0000000000 --- a/railties/test/application/queue_test.rb +++ /dev/null @@ -1,153 +0,0 @@ -require 'isolation/abstract_unit' - -module ApplicationTests - class QueueTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - boot_rails - end - - def teardown - teardown_app - end - - def app_const - @app_const ||= Class.new(Rails::Application) - end - - test "the queue is a SynchronousQueue in test mode" do - app("test") - assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue - assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue - end - - test "the queue is a SynchronousQueue in development mode" do - app("development") - assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue - assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue - end - - class ThreadTrackingJob - def initialize - @origin = Thread.current.object_id - end - - def run - @target = Thread.current.object_id - end - - def ran_in_different_thread? - @origin != @target - end - - def ran? - @target - end - end - - test "in development mode, an enqueued job will be processed in the same thread" do - app("development") - - job = ThreadTrackingJob.new - Rails.queue.push job - sleep 0.1 - - assert job.ran?, "Expected job to be run" - refute job.ran_in_different_thread?, "Expected job to run in the same thread" - end - - test "in test mode, an enqueued job will be processed in the same thread" do - app("test") - - job = ThreadTrackingJob.new - Rails.queue.push job - sleep 0.1 - - assert job.ran?, "Expected job to be run" - refute job.ran_in_different_thread?, "Expected job to run in the same thread" - end - - test "in production, automatically spawn a queue consumer in a background thread" do - add_to_env_config "production", <<-RUBY - config.queue = ActiveSupport::Queue.new - RUBY - - app("production") - - assert_nil Rails.application.config.queue_consumer - assert_kind_of ActiveSupport::ThreadedQueueConsumer, Rails.application.queue_consumer - end - - test "attempting to marshal a queue will raise an exception" do - app("test") - assert_raises TypeError do - Marshal.dump Rails.queue - end - end - - def setup_custom_queue - add_to_env_config "production", <<-RUBY - require "my_queue" - config.queue = MyQueue.new - RUBY - - app_file "lib/my_queue.rb", <<-RUBY - class MyQueue - def push(job) - job.run - end - end - RUBY - - app("production") - end - - test "a custom queue implementation can be provided" do - setup_custom_queue - - assert_kind_of MyQueue, Rails.queue - - job = Struct.new(:id, :ran) do - def run - self.ran = true - end - end - - job1 = job.new(1) - Rails.queue.push job1 - - assert_equal true, job1.ran - end - - test "a custom consumer implementation can be provided" do - add_to_env_config "production", <<-RUBY - require "my_queue_consumer" - config.queue = ActiveSupport::Queue.new - config.queue_consumer = MyQueueConsumer.new - RUBY - - app_file "lib/my_queue_consumer.rb", <<-RUBY - class MyQueueConsumer - attr_reader :started - - def start - @started = true - end - end - RUBY - - app("production") - - assert_kind_of MyQueueConsumer, Rails.application.queue_consumer - assert Rails.application.queue_consumer.started - end - - test "default consumer is not used with custom queue implementation" do - setup_custom_queue - - assert_nil Rails.application.queue_consumer - end - end -end diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 03798d572a..4d348c6b4b 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -21,6 +21,8 @@ module ApplicationTests def set_database_url ENV['DATABASE_URL'] = "sqlite3://:@localhost/#{database_url_db_name}" + # ensure it's using the DATABASE_URL + FileUtils.rm_rf("#{app_path}/config/database.yml") end def expected @@ -31,12 +33,12 @@ module ApplicationTests Dir.chdir(app_path) do output = `bundle exec rake db:create` assert_equal output, "" - assert File.exists?(expected[:database]) + assert File.exist?(expected[:database]) assert_equal expected[:database], ActiveRecord::Base.connection_config[:database] output = `bundle exec rake db:drop` assert_equal output, "" - assert !File.exists?(expected[:database]) + assert !File.exist?(expected[:database]) end end @@ -55,8 +57,8 @@ module ApplicationTests def db_migrate_and_status Dir.chdir(app_path) do - `rails generate model book title:string` - `bundle exec rake db:migrate` + `rails generate model book title:string; + bundle exec rake db:migrate` output = `bundle exec rake db:migrate:status` assert_match(/database:\s+\S+#{expected[:database]}/, output) assert_match(/up\s+\d{14}\s+Create books/, output) @@ -78,9 +80,8 @@ module ApplicationTests def db_schema_dump Dir.chdir(app_path) do - `rails generate model book title:string` - `rake db:migrate` - `rake db:schema:dump` + `rails generate model book title:string; + rake db:migrate db:schema:dump` schema_dump = File.read("db/schema.rb") assert_match(/create_table \"books\"/, schema_dump) end @@ -97,9 +98,8 @@ module ApplicationTests def db_fixtures_load Dir.chdir(app_path) do - `rails generate model book title:string` - `bundle exec rake db:migrate` - `bundle exec rake db:fixtures:load` + `rails generate model book title:string; + bundle exec rake db:migrate db:fixtures:load` assert_match(/#{expected[:database]}/, ActiveRecord::Base.connection_config[:database]) require "#{app_path}/app/models/book" @@ -122,13 +122,11 @@ module ApplicationTests def db_structure_dump_and_load Dir.chdir(app_path) do - `rails generate model book title:string` - `bundle exec rake db:migrate` - `bundle exec rake db:structure:dump` + `rails generate model book title:string; + bundle exec rake db:migrate db:structure:dump` structure_dump = File.read("db/structure.sql") assert_match(/CREATE TABLE \"books\"/, structure_dump) - `bundle exec rake db:drop` - `bundle exec rake db:structure:load` + `bundle exec rake db:drop db:structure:load` assert_match(/#{expected[:database]}/, ActiveRecord::Base.connection_config[:database]) require "#{app_path}/app/models/book" @@ -152,10 +150,8 @@ module ApplicationTests def db_test_load_structure Dir.chdir(app_path) do - `rails generate model book title:string` - `bundle exec rake db:migrate` - `bundle exec rake db:structure:dump` - `bundle exec rake db:test:load_structure` + `rails generate model book title:string; + bundle exec rake db:migrate db:structure:dump db:test:load_structure` ActiveRecord::Base.configurations = Rails.application.config.database_configuration ActiveRecord::Base.establish_connection 'test' require "#{app_path}/app/models/book" @@ -170,12 +166,6 @@ module ApplicationTests require "#{app_path}/config/environment" db_test_load_structure end - - test 'db:test:load_structure with database_url' do - require "#{app_path}/config/environment" - set_database_url - db_test_load_structure - end end end -end
\ No newline at end of file +end diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb index 0a47fd014c..33c753868c 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -50,9 +50,9 @@ module ApplicationTests assert_match(/AddEmailToUsers: migrated/, output) output = `rake db:rollback STEP=2` - assert_match(/drop_table\("users"\)/, output) + assert_match(/drop_table\(:users\)/, output) assert_match(/CreateUsers: reverted/, output) - assert_match(/remove_column\("users", :email\)/, output) + assert_match(/remove_column\(:users, :email, :string\)/, output) assert_match(/AddEmailToUsers: reverted/, output) end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 7a227098ba..01d751e822 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -24,6 +24,8 @@ module ApplicationTests app_file "app/assets/javascripts/application.js", "// TODO: note in js" app_file "app/assets/stylesheets/application.css", "// TODO: note in css" app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" + app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" + app_file "app/assets/stylesheets/application.css.less", "// TODO: note in less" app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby" app_file "lib/tasks/task.rake", "# TODO: note in rake" @@ -46,9 +48,11 @@ module ApplicationTests assert_match(/note in js/, output) assert_match(/note in css/, output) assert_match(/note in scss/, output) + assert_match(/note in sass/, output) + assert_match(/note in less/, output) assert_match(/note in rake/, output) - assert_equal 9, lines.size + assert_equal 11, lines.size lines.each do |line| assert_equal 4, line[0].size @@ -60,8 +64,8 @@ module ApplicationTests test 'notes finds notes in default directories' do app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "db/some_seeds.rb", "# TODO: note in db directory" app_file "lib/some_file.rb", "# TODO: note in lib directory" - app_file "script/run_something.rb", "# TODO: note in script directory" app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" @@ -80,8 +84,8 @@ module ApplicationTests assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) + assert_match(/note in db directory/, output) assert_match(/note in lib directory/, output) - assert_match(/note in script directory/, output) assert_match(/note in test directory/, output) assert_no_match(/note in some_other directory/, output) @@ -96,8 +100,8 @@ module ApplicationTests test 'notes finds notes in custom directories' do app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" + app_file "db/some_seeds.rb", "# TODO: note in db directory" app_file "lib/some_file.rb", "# TODO: note in lib directory" - app_file "script/run_something.rb", "# TODO: note in script directory" app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" @@ -116,8 +120,8 @@ module ApplicationTests assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) + assert_match(/note in db directory/, output) assert_match(/note in lib directory/, output) - assert_match(/note in script directory/, output) assert_match(/note in test directory/, output) assert_match(/note in some_other directory/, output) @@ -130,6 +134,45 @@ module ApplicationTests end end + test 'custom rake task finds specific notes in specific directories' do + app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" + app_file "lib/some_file.rb", "# OPTIMIZE: note in lib directory\n" << "# FIXME: note in lib directory" + app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" + + app_file "lib/tasks/notes_custom.rake", <<-EOS + require 'rails/source_annotation_extractor' + task :notes_custom do + tags = 'TODO|FIXME' + opts = { dirs: %w(lib test), tag: true } + SourceAnnotationExtractor.enumerate(tags, opts) + end + EOS + + boot_rails + + require 'rake' + require 'rdoc/task' + require 'rake/testtask' + + Rails.application.load_tasks + + Dir.chdir(app_path) do + output = `bundle exec rake notes_custom` + lines = output.scan(/\[([0-9\s]+)\]/).flatten + + assert_match(/\[FIXME\] note in lib directory/, output) + assert_match(/\[TODO\] note in test directory/, output) + assert_no_match(/OPTIMIZE/, output) + assert_no_match(/note in app directory/, output) + + assert_equal 2, lines.size + + lines.each do |line_number| + assert_equal 4, line_number.size + end + end + end + private def boot_rails super diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index c5a68a5152..2169304aa4 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -1,5 +1,6 @@ # coding:utf-8 require "isolation/abstract_unit" +require "active_support/core_ext/string/strip" module ApplicationTests class RakeTest < ActiveSupport::TestCase @@ -8,7 +9,6 @@ module ApplicationTests def setup build_app boot_rails - FileUtils.rm_rf("#{app_path}/config/environments") end def teardown @@ -29,11 +29,11 @@ module ApplicationTests app_file "config/environment.rb", <<-RUBY SuperMiddleware = Struct.new(:app) - AppTemplate::Application.configure do + Rails.application.configure do config.middleware.use SuperMiddleware end - AppTemplate::Application.initialize! + Rails.application.initialize! RUBY assert_match("SuperMiddleware", Dir.chdir(app_path){ `rake middleware` }) @@ -55,10 +55,8 @@ module ApplicationTests assert_match "Doing something...", output end - def test_does_not_explode_when_accessing_a_model_with_eager_load + def test_does_not_explode_when_accessing_a_model add_to_config <<-RUBY - config.eager_load = true - rake_tasks do task do_nothing: :environment do Hello.new.world @@ -66,16 +64,38 @@ module ApplicationTests end RUBY - app_file "app/models/hello.rb", <<-RUBY - class Hello - def world - puts "Hello world" + app_file 'app/models/hello.rb', <<-RUBY + class Hello + def world + puts 'Hello world' + end end - end RUBY - output = Dir.chdir(app_path){ `rake do_nothing` } - assert_match "Hello world", output + output = Dir.chdir(app_path) { `rake do_nothing` } + assert_match 'Hello world', output + end + + def test_should_not_eager_load_model_for_rake + add_to_config <<-RUBY + rake_tasks do + task do_nothing: :environment do + end + end + RUBY + + add_to_env_config 'production', <<-RUBY + config.eager_load = true + RUBY + + app_file 'app/models/hello.rb', <<-RUBY + raise 'should not be pre-required for rake even eager_load=true' + RUBY + + Dir.chdir(app_path) do + assert system('rake do_nothing RAILS_ENV=production'), + 'should not be pre-required for rake even eager_load=true' + end end def test_code_statistics_sanity @@ -83,36 +103,43 @@ module ApplicationTests Dir.chdir(app_path){ `rake stats` } end - def test_rake_test_error_output - Dir.chdir(app_path){ `rake db:migrate` } - - app_file "test/models/one_model_test.rb", <<-RUBY - raise 'models' + def test_rake_routes_calls_the_route_inspector + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/cart', to: 'cart#show' + end RUBY - app_file "test/controllers/one_controller_test.rb", <<-RUBY - raise 'controllers' - RUBY + output = Dir.chdir(app_path){ `rake routes` } + assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + end - app_file "test/integration/one_integration_test.rb", <<-RUBY - raise 'integration' + def test_rake_routes_with_controller_environment + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/cart', to: 'cart#show' + get '/basketball', to: 'basketball#index' + end RUBY - silence_stderr do - output = Dir.chdir(app_path) { `rake test 2>&1` } - assert_match 'models', output - assert_match 'controllers', output - assert_match 'integration', output - end + ENV['CONTROLLER'] = 'cart' + output = Dir.chdir(app_path){ `rake routes` } + assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output end - def test_rake_routes_calls_the_route_inspector + def test_rake_routes_displays_message_when_no_routes_are_defined app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do - get '/cart', to: 'cart#show' + Rails.application.routes.draw do end RUBY - assert_equal "cart GET /cart(.:format) cart#show\n", Dir.chdir(app_path){ `rake routes` } + + assert_equal <<-MESSAGE.strip_heredoc, Dir.chdir(app_path){ `rake routes` } + You don't have any routes defined! + + Please add some routes in config/routes.rb. + + For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html. + MESSAGE end def test_logger_is_flushed_when_exiting_production_rake_tasks @@ -163,7 +190,17 @@ module ApplicationTests bundle exec rake db:migrate db:test:clone test` end - assert_match(/7 tests, 13 assertions, 0 failures, 0 errors/, output) + assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) + assert_no_match(/Errors running/, output) + end + + def test_scaffold_with_references_columns_tests_pass_by_default + output = Dir.chdir(app_path) do + `rails generate scaffold LineItems product:references cart:belongs_to; + bundle exec rake db:migrate db:test:clone test` + end + + assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) assert_no_match(/Errors running/, output) end @@ -190,7 +227,7 @@ module ApplicationTests # ensure we have a schema_migrations table to dump `bundle exec rake db:migrate db:structure:dump DB_STRUCTURE=db/my_structure.sql` end - assert File.exists?(File.join(app_path, 'db', 'my_structure.sql')) + assert File.exist?(File.join(app_path, 'db', 'my_structure.sql')) end def test_rake_dump_structure_should_be_called_twice_when_migrate_redo @@ -211,46 +248,24 @@ module ApplicationTests rails generate model product name:string; bundle exec rake db:migrate db:schema:cache:dump` end - assert File.exists?(File.join(app_path, 'db', 'schema_cache.dump')) + assert File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) end def test_rake_clear_schema_cache Dir.chdir(app_path) do `bundle exec rake db:schema:cache:dump db:schema:cache:clear` end - assert !File.exists?(File.join(app_path, 'db', 'schema_cache.dump')) - end - - def test_load_activerecord_base_when_we_use_observers - Dir.chdir(app_path) do - `bundle exec rails g model user; - bundle exec rake db:migrate; - bundle exec rails g observer user;` - - add_to_config "config.active_record.observers = :user_observer" - - assert_equal "0", `bundle exec rails r "puts User.count"`.strip - - app_file "lib/tasks/count_user.rake", <<-RUBY - namespace :user do - task count: :environment do - puts User.count - end - end - RUBY - - assert_equal "0", `bundle exec rake user:count`.strip - end + assert !File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) end def test_copy_templates Dir.chdir(app_path) do `bundle exec rake rails:templates:copy` %w(controller mailer scaffold).each do |dir| - assert File.exists?(File.join(app_path, 'lib', 'templates', 'erb', dir)) + assert File.exist?(File.join(app_path, 'lib', 'templates', 'erb', dir)) end %w(controller helper scaffold_controller assets).each do |dir| - assert File.exists?(File.join(app_path, 'lib', 'templates', 'rails', dir)) + assert File.exist?(File.join(app_path, 'lib', 'templates', 'rails', dir)) end end end diff --git a/railties/test/application/rendering_test.rb b/railties/test/application/rendering_test.rb new file mode 100644 index 0000000000..b01febd768 --- /dev/null +++ b/railties/test/application/rendering_test.rb @@ -0,0 +1,45 @@ +require 'isolation/abstract_unit' +require 'rack/test' + +module ApplicationTests + class RoutingTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + boot_rails + end + + def teardown + teardown_app + end + + test "Unknown format falls back to HTML template" do + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get 'pages/:id', to: 'pages#show' + end + RUBY + + app_file 'app/controllers/pages_controller.rb', <<-RUBY + class PagesController < ApplicationController + layout false + + def show + end + end + RUBY + + app_file 'app/views/pages/show.html.erb', <<-RUBY + <%= params[:id] %> + RUBY + + get '/pages/foo' + assert_equal 200, last_response.status + + get '/pages/foo.bar' + assert_equal 200, last_response.status + end + end +end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index ffcdeac7f0..8576a2b738 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -15,6 +15,12 @@ module ApplicationTests teardown_app end + test "rails/welcome in development" do + app("development") + get "/" + assert_equal 200, last_response.status + end + test "rails/info/routes in development" do app("development") get "/rails/info/routes" @@ -27,6 +33,36 @@ module ApplicationTests assert_equal 200, last_response.status end + test "root takes precedence over internal welcome controller" do + app("development") + + get '/' + assert_match %r{<h1>Getting started</h1>} , last_response.body + + controller :foo, <<-RUBY + class FooController < ApplicationController + def index + render text: "foo" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + root to: "foo#index" + end + RUBY + + get '/' + assert_equal 'foo', last_response.body + end + + test "rails/welcome in production" do + app("production") + get "/" + assert_equal 404, last_response.status + end + test "rails/info/routes in production" do app("production") get "/rails/info/routes" @@ -64,7 +100,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -75,7 +111,7 @@ module ApplicationTests test "mount rack app" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog" # The line below is required because mount sometimes # fails when a resource route is added. @@ -105,7 +141,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -137,7 +173,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'admin/foo', to: 'admin/foo#index' get 'foo', to: 'foo#index' end @@ -152,7 +188,7 @@ module ApplicationTests test "routes appending blocks" do app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller/:action' end RUBY @@ -169,7 +205,7 @@ module ApplicationTests assert_equal 'WIN', last_response.body app_file 'config/routes.rb', <<-R - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'lol' => 'hello#index' end R @@ -193,7 +229,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#bar' end RUBY @@ -204,7 +240,7 @@ module ApplicationTests assert_equal 'bar', last_response.body app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: 'foo#baz' end RUBY @@ -225,7 +261,7 @@ module ApplicationTests end app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', to: ::InitializeRackApp end RUBY @@ -241,6 +277,146 @@ module ApplicationTests end end + def test_root_path + app('development') + + controller :foo, <<-RUBY + class FooController < ApplicationController + def index + render :text => "foo" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get 'foo', :to => 'foo#index' + root :to => 'foo#index' + end + RUBY + + remove_file 'public/index.html' + + get '/' + assert_equal 'foo', last_response.body + end + + test 'routes are added and removed when reloading' do + app('development') + + controller :foo, <<-RUBY + class FooController < ApplicationController + def index + render text: "foo" + end + end + RUBY + + controller :bar, <<-RUBY + class BarController < ApplicationController + def index + render text: "bar" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index' + end + RUBY + + get '/foo' + assert_equal 'foo', last_response.body + assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + + get '/bar' + assert_equal 404, last_response.status + assert_raises NoMethodError do + assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + end + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index' + get 'bar', to: 'bar#index' + end + RUBY + + Rails.application.reload_routes! + + get '/foo' + assert_equal 'foo', last_response.body + assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + + get '/bar' + assert_equal 'bar', last_response.body + assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index' + end + RUBY + + Rails.application.reload_routes! + + get '/foo' + assert_equal 'foo', last_response.body + assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + + get '/bar' + assert_equal 404, last_response.status + assert_raises NoMethodError do + assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + end + end + + test 'named routes are cleared when reloading' do + app('development') + + controller :foo, <<-RUBY + class FooController < ApplicationController + def index + render text: "foo" + end + end + RUBY + + controller :bar, <<-RUBY + class BarController < ApplicationController + def index + render text: "bar" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':locale/foo', to: 'foo#index', as: 'foo' + end + RUBY + + get '/en/foo' + assert_equal 'foo', last_response.body + assert_equal '/en/foo', Rails.application.routes.url_helpers.foo_path(:locale => 'en') + + app_file 'config/routes.rb', <<-RUBY + Rails.application.routes.draw do + get ':locale/bar', to: 'bar#index', as: 'foo' + end + RUBY + + Rails.application.reload_routes! + + get '/en/foo' + assert_equal 404, last_response.status + + get '/en/bar' + assert_equal 'bar', last_response.body + assert_equal '/en/bar', Rails.application.routes.url_helpers.foo_path(:locale => 'en') + end + test 'resource routing with irregular inflection' do app_file 'config/initializers/inflection.rb', <<-RUBY ActiveSupport::Inflector.inflections do |inflect| @@ -249,7 +425,7 @@ module ApplicationTests RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do resources :yazilar end RUBY diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb index 81ed5873a5..6595c40f8b 100644 --- a/railties/test/application/runner_test.rb +++ b/railties/test/application/runner_test.rb @@ -1,8 +1,10 @@ require 'isolation/abstract_unit' +require 'env_helpers' module ApplicationTests class RunnerTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation + include EnvHelpers def setup build_app @@ -35,27 +37,27 @@ module ApplicationTests end def test_should_run_file - app_file "script/count_users.rb", <<-SCRIPT + app_file "bin/count_users.rb", <<-SCRIPT puts User.count SCRIPT - assert_match "42", Dir.chdir(app_path) { `bundle exec rails runner "script/count_users.rb"` } + assert_match "42", Dir.chdir(app_path) { `bundle exec rails runner "bin/count_users.rb"` } end def test_should_set_dollar_0_to_file - app_file "script/dollar0.rb", <<-SCRIPT + app_file "bin/dollar0.rb", <<-SCRIPT puts $0 SCRIPT - assert_match "script/dollar0.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/dollar0.rb"` } + assert_match "bin/dollar0.rb", Dir.chdir(app_path) { `bundle exec rails runner "bin/dollar0.rb"` } end def test_should_set_dollar_program_name_to_file - app_file "script/program_name.rb", <<-SCRIPT + app_file "bin/program_name.rb", <<-SCRIPT puts $PROGRAM_NAME SCRIPT - assert_match "script/program_name.rb", Dir.chdir(app_path) { `bundle exec rails runner "script/program_name.rb"` } + assert_match "bin/program_name.rb", Dir.chdir(app_path) { `bundle exec rails runner "bin/program_name.rb"` } end def test_with_hook @@ -67,5 +69,21 @@ module ApplicationTests assert_match "true", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.application.config.ran"` } end + + def test_default_environment + assert_match "development", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.env"` } + end + + def test_environment_with_rails_env + with_rails_env "production" do + assert_match "production", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.env"` } + end + end + + def test_environment_with_rack_env + with_rack_env "production" do + assert_match "production", Dir.chdir(app_path) { `bundle exec rails runner "puts Rails.env"` } + end + end end end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb new file mode 100644 index 0000000000..118f22995e --- /dev/null +++ b/railties/test/application/test_runner_test.rb @@ -0,0 +1,320 @@ +require 'isolation/abstract_unit' +require 'active_support/core_ext/string/strip' + +module ApplicationTests + class TestRunnerTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + ENV['RAILS_ENV'] = nil + create_schema + end + + def teardown + teardown_app + end + + def test_run_in_test_environment + app_file 'test/unit/env_test.rb', <<-RUBY + require 'test_helper' + + class EnvTest < ActiveSupport::TestCase + def test_env + puts "Current Environment: \#{Rails.env}" + end + end + RUBY + + assert_match "Current Environment: test", run_test_command('test/unit/env_test.rb') + end + + def test_run_single_file + create_test_file :models, 'foo' + create_test_file :models, 'bar' + assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb") + end + + def test_run_multiple_files + create_test_file :models, 'foo' + create_test_file :models, 'bar' + assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb") + end + + def test_run_file_with_syntax_error + app_file 'test/models/error_test.rb', <<-RUBY + require 'test_helper' + def; end + RUBY + + error_stream = Tempfile.new('error') + redirect_stderr(error_stream) { run_test_command('test/models/error_test.rb') } + assert_match "syntax error", error_stream.read + end + + def test_run_models + create_test_file :models, 'foo' + create_test_file :models, 'bar' + create_test_file :controllers, 'foobar_controller' + run_test_models_command.tap do |output| + assert_match "FooTest", output + assert_match "BarTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + + def test_run_helpers + create_test_file :helpers, 'foo_helper' + create_test_file :helpers, 'bar_helper' + create_test_file :controllers, 'foobar_controller' + run_test_helpers_command.tap do |output| + assert_match "FooHelperTest", output + assert_match "BarHelperTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + + def test_run_units + create_test_file :models, 'foo' + create_test_file :helpers, 'bar_helper' + create_test_file :unit, 'baz_unit' + create_test_file :controllers, 'foobar_controller' + run_test_units_command.tap do |output| + assert_match "FooTest", output + assert_match "BarHelperTest", output + assert_match "BazUnitTest", output + assert_match "3 runs, 3 assertions, 0 failures", output + end + end + + def test_run_controllers + create_test_file :controllers, 'foo_controller' + create_test_file :controllers, 'bar_controller' + create_test_file :models, 'foo' + run_test_controllers_command.tap do |output| + assert_match "FooControllerTest", output + assert_match "BarControllerTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + + def test_run_mailers + create_test_file :mailers, 'foo_mailer' + create_test_file :mailers, 'bar_mailer' + create_test_file :models, 'foo' + run_test_mailers_command.tap do |output| + assert_match "FooMailerTest", output + assert_match "BarMailerTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + + def test_run_functionals + create_test_file :mailers, 'foo_mailer' + create_test_file :controllers, 'bar_controller' + create_test_file :functional, 'baz_functional' + create_test_file :models, 'foo' + run_test_functionals_command.tap do |output| + assert_match "FooMailerTest", output + assert_match "BarControllerTest", output + assert_match "BazFunctionalTest", output + assert_match "3 runs, 3 assertions, 0 failures", output + end + end + + def test_run_integration + create_test_file :integration, 'foo_integration' + create_test_file :models, 'foo' + run_test_integration_command.tap do |output| + assert_match "FooIntegration", output + assert_match "1 runs, 1 assertions, 0 failures", output + end + end + + def test_run_all_suites + suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] + suites.each { |suite| create_test_file suite, "foo_#{suite}" } + run_test_command('') .tap do |output| + suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output } + assert_match "7 runs, 7 assertions, 0 failures", output + end + end + + def test_run_named_test + app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY + require 'test_helper' + + class Chu2KoiTest < ActiveSupport::TestCase + def test_rikka + puts 'Rikka' + end + + def test_sanae + puts 'Sanae' + end + end + RUBY + + run_test_command('test/unit/chu_2_koi_test.rb test_rikka').tap do |output| + assert_match "Rikka", output + assert_no_match "Sanae", output + end + end + + def test_run_matched_test + app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY + require 'test_helper' + + class Chu2KoiTest < ActiveSupport::TestCase + def test_rikka + puts 'Rikka' + end + + def test_sanae + puts 'Sanae' + end + end + RUBY + + run_test_command('test/unit/chu_2_koi_test.rb /rikka/').tap do |output| + assert_match "Rikka", output + assert_no_match "Sanae", output + end + end + + def test_load_fixtures_when_running_test_suites + create_model_with_fixture + suites = [:models, :helpers, [:units, :unit], :controllers, :mailers, + [:functionals, :functional], :integration] + + suites.each do |suite, directory| + directory ||= suite + create_fixture_test directory + assert_match "3 users", run_task(["test:#{suite}"]) + Dir.chdir(app_path) { FileUtils.rm_f "test/#{directory}" } + end + end + + def test_run_with_model + create_model_with_fixture + create_fixture_test 'models', 'user' + assert_match "3 users", run_task(["test models/user"]) + assert_match "3 users", run_task(["test app/models/user.rb"]) + end + + def test_run_different_environment_using_env_var + app_file 'test/unit/env_test.rb', <<-RUBY + require 'test_helper' + + class EnvTest < ActiveSupport::TestCase + def test_env + puts Rails.env + end + end + RUBY + + ENV['RAILS_ENV'] = 'development' + assert_match "development", run_test_command('test/unit/env_test.rb') + end + + def test_run_different_environment_using_e_tag + env = "development" + app_file 'test/unit/env_test.rb', <<-RUBY + require 'test_helper' + + class EnvTest < ActiveSupport::TestCase + def test_env + puts Rails.env + end + end + RUBY + + assert_match env, run_test_command("test/unit/env_test.rb RAILS_ENV=#{env}") + end + + def test_generated_scaffold_works_with_rails_test + create_scaffold + assert_match "0 failures, 0 errors, 0 skips", run_test_command('') + end + + private + def run_task(tasks) + Dir.chdir(app_path) { `bundle exec rake #{tasks.join ' '}` } + end + + def run_test_command(arguments = 'test/unit/test_test.rb') + run_task ['test', arguments] + end + %w{ mailers models helpers units controllers functionals integration }.each do |type| + define_method("run_test_#{type}_command") do + run_task ["test:#{type}"] + end + end + + def create_model_with_fixture + script 'generate model user name:string' + + app_file 'test/fixtures/users.yml', <<-YAML.strip_heredoc + vampire: + id: 1 + name: Koyomi Araragi + crab: + id: 2 + name: Senjougahara Hitagi + cat: + id: 3 + name: Tsubasa Hanekawa + YAML + + run_migration + end + + def create_fixture_test(path = :unit, name = 'test') + app_file "test/#{path}/#{name}_test.rb", <<-RUBY + require 'test_helper' + + class #{name.camelize}Test < ActiveSupport::TestCase + def test_fixture + puts "\#{User.count} users (\#{__FILE__})" + end + end + RUBY + end + + def create_schema + app_file 'db/schema.rb', '' + end + + def redirect_stderr(target_stream) + previous_stderr = STDERR.dup + $stderr.reopen(target_stream) + yield + target_stream.rewind + ensure + $stderr = previous_stderr + end + + def create_test_file(path = :unit, name = 'test') + app_file "test/#{path}/#{name}_test.rb", <<-RUBY + require 'test_helper' + + class #{name.camelize}Test < ActiveSupport::TestCase + def test_truth + puts "#{name.camelize}Test" + assert true + end + end + RUBY + end + + def create_scaffold + script 'generate scaffold user name:string' + Dir.chdir(app_path) { File.exist?('app/models/user.rb') } + run_migration + end + + def run_migration + Dir.chdir(app_path) { `bundle exec rake db:migrate` } + end + end +end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index f6bcaa466a..c7ad2fba8f 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -52,31 +52,6 @@ module ApplicationTests run_test_file 'integration/posts_test.rb' end - test "performance test" do - controller 'posts', <<-RUBY - class PostsController < ActionController::Base - end - RUBY - - app_file 'app/views/posts/index.html.erb', <<-HTML - Posts#index - HTML - - app_file 'test/performance/posts_test.rb', <<-RUBY - require 'test_helper' - require 'rails/performance_test_help' - - class PostsTest < ActionDispatch::PerformanceTest - def test_index - get '/posts' - assert_response :success - end - end - RUBY - - run_test_file 'performance/posts_test.rb' - end - private def run_test_file(name) result = ruby '-Itest', "#{app_path}/test/#{name}" diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 4ecb94b65e..efbc853d7b 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -12,14 +12,16 @@ module ApplicationTests boot_rails require "rails" require "action_controller/railtie" + require "action_view/railtie" class MyApp < Rails::Application - config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log + config.eager_load = false end - MyApp.initialize! + Rails.application.initialize! class ::ApplicationController < ActionController::Base end diff --git a/railties/test/code_statistics_calculator_test.rb b/railties/test/code_statistics_calculator_test.rb new file mode 100644 index 0000000000..b3eabf5024 --- /dev/null +++ b/railties/test/code_statistics_calculator_test.rb @@ -0,0 +1,288 @@ +require 'abstract_unit' +require 'rails/code_statistics_calculator' + +class CodeStatisticsCalculatorTest < ActiveSupport::TestCase + def setup + @code_statistics_calculator = CodeStatisticsCalculator.new + end + + test 'add statistics to another using #add' do + code_statistics_calculator_1 = CodeStatisticsCalculator.new(1, 2, 3, 4) + @code_statistics_calculator.add(code_statistics_calculator_1) + + assert_equal 1, @code_statistics_calculator.lines + assert_equal 2, @code_statistics_calculator.code_lines + assert_equal 3, @code_statistics_calculator.classes + assert_equal 4, @code_statistics_calculator.methods + + code_statistics_calculator_2 = CodeStatisticsCalculator.new(2, 3, 4, 5) + @code_statistics_calculator.add(code_statistics_calculator_2) + + assert_equal 3, @code_statistics_calculator.lines + assert_equal 5, @code_statistics_calculator.code_lines + assert_equal 7, @code_statistics_calculator.classes + assert_equal 9, @code_statistics_calculator.methods + end + + test 'accumulate statistics using #add_by_io' do + code_statistics_calculator_1 = CodeStatisticsCalculator.new(1, 2, 3, 4) + @code_statistics_calculator.add(code_statistics_calculator_1) + + code = <<-'CODE' + def foo + puts 'foo' + end + + def bar; end + class A; end + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :rb) + + assert_equal 7, @code_statistics_calculator.lines + assert_equal 7, @code_statistics_calculator.code_lines + assert_equal 4, @code_statistics_calculator.classes + assert_equal 6, @code_statistics_calculator.methods + end + + test 'calculate statistics using #add_by_file_path' do + tmp_path = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'tmp')) + FileUtils.mkdir_p(tmp_path) + + code = <<-'CODE' + def foo + puts 'foo' + # bar + end + CODE + + file_path = "#{tmp_path}/stats.rb" + File.open(file_path, 'w') { |f| f.write(code) } + + @code_statistics_calculator.add_by_file_path(file_path) + + assert_equal 4, @code_statistics_calculator.lines + assert_equal 3, @code_statistics_calculator.code_lines + assert_equal 0, @code_statistics_calculator.classes + assert_equal 1, @code_statistics_calculator.methods + + FileUtils.rm_rf(tmp_path) + end + + test 'calculate number of Ruby methods' do + code = <<-'CODE' + def foo + puts 'foo' + end + + def bar; end + + class Foo + def bar(abc) + end + end + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :rb) + + assert_equal 3, @code_statistics_calculator.methods + end + + test 'calculate Ruby LOCs' do + code = <<-'CODE' + def foo + puts 'foo' + end + + # def bar; end + + class A < B + end + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :rb) + + assert_equal 8, @code_statistics_calculator.lines + assert_equal 5, @code_statistics_calculator.code_lines + end + + test 'calculate number of Ruby classes' do + code = <<-'CODE' + class Foo < Bar + def foo + puts 'foo' + end + end + + class Z; end + + # class A + # end + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :rb) + + assert_equal 2, @code_statistics_calculator.classes + end + + test 'skip Ruby comments' do + code = <<-'CODE' +=begin + class Foo + def foo + puts 'foo' + end + end +=end + + # class A + # end + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :rb) + + assert_equal 10, @code_statistics_calculator.lines + assert_equal 0, @code_statistics_calculator.code_lines + assert_equal 0, @code_statistics_calculator.classes + assert_equal 0, @code_statistics_calculator.methods + end + + test 'calculate number of JS methods' do + code = <<-'CODE' + function foo(x, y, z) { + doX(); + } + + $(function () { + bar(); + }) + + var baz = function ( x ) { + } + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :js) + + assert_equal 3, @code_statistics_calculator.methods + end + + test 'calculate JS LOCs' do + code = <<-'CODE' + function foo() + alert('foo'); + end + + // var b = 2; + + var a = 1; + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :js) + + assert_equal 7, @code_statistics_calculator.lines + assert_equal 4, @code_statistics_calculator.code_lines + end + + test 'skip JS comments' do + code = <<-'CODE' + /* + * var f = function () { + 1 / 2; + } + */ + + // call(); + // + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :js) + + assert_equal 8, @code_statistics_calculator.lines + assert_equal 0, @code_statistics_calculator.code_lines + assert_equal 0, @code_statistics_calculator.classes + assert_equal 0, @code_statistics_calculator.methods + end + + test 'calculate number of CoffeeScript methods' do + code = <<-'CODE' + square = (x) -> x * x + + math = + cube: (x) -> x * square x + + fill = (container, liquid = "coffee") -> + "Filling the #{container} with #{liquid}..." + + $('.shopping_cart').bind 'click', (event) => + @customer.purchase @cart + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :coffee) + + assert_equal 4, @code_statistics_calculator.methods + end + + test 'calculate CoffeeScript LOCs' do + code = <<-'CODE' + # Assignment: + number = 42 + opposite = true + + ### + CoffeeScript Compiler v1.4.0 + Released under the MIT License + ### + + # Conditions: + number = -42 if opposite + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :coffee) + + assert_equal 11, @code_statistics_calculator.lines + assert_equal 3, @code_statistics_calculator.code_lines + end + + test 'calculate number of CoffeeScript classes' do + code = <<-'CODE' + class Animal + constructor: (@name) -> + + move: (meters) -> + alert @name + " moved #{meters}m." + + class Snake extends Animal + move: -> + alert "Slithering..." + super 5 + + # class Horse + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :coffee) + + assert_equal 2, @code_statistics_calculator.classes + end + + test 'skip CoffeeScript comments' do + code = <<-'CODE' +### +class Animal + constructor: (@name) -> + + move: (meters) -> + alert @name + " moved #{meters}m." + ### + + # class Horse + alert 'hello' + CODE + + @code_statistics_calculator.add_by_io(StringIO.new(code), :coffee) + + assert_equal 10, @code_statistics_calculator.lines + assert_equal 1, @code_statistics_calculator.code_lines + assert_equal 0, @code_statistics_calculator.classes + assert_equal 0, @code_statistics_calculator.methods + end +end diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index e047d4882d..a34beaedb3 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -1,14 +1,14 @@ require 'abstract_unit' +require 'env_helpers' require 'rails/commands/console' class Rails::ConsoleTest < ActiveSupport::TestCase + include EnvHelpers + class FakeConsole def self.start; end end - def setup - end - def test_sandbox_option console = Rails::Console.new(app, parse_arguments(["--sandbox"])) assert console.sandbox? @@ -58,10 +58,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_defaults_to_IRB - config = mock("config", console: nil) - app = mock("app", config: config) - app.expects(:load_console).returns(nil) - + app = build_app(console: nil) assert_equal IRB, Rails::Console.new(app).console end @@ -78,7 +75,14 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert_match(/\sspecial-production\s/, output) end end - + + def test_default_environment_with_rack_env + with_rack_env 'production' do + start + assert_match(/\sproduction\s/, output) + end + end + def test_e_option start ['-e', 'special-production'] assert_match(/\sspecial-production\s/, output) @@ -104,34 +108,35 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert_match(/\sdevelopment\s/, output) end - private + def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present + Rails::Console.stubs(:available_environments).returns(['dev']) + options = Rails::Console.parse_arguments(['dev']) + assert_match('dev', options[:environment]) + end attr_reader :output + private :output + + private def start(argv = []) rails_console = Rails::Console.new(app, parse_arguments(argv)) - @output = output = capture(:stdout) { rails_console.start } + @output = capture(:stdout) { rails_console.start } end def app - @app ||= begin - config = mock("config", console: FakeConsole) - app = mock("app", config: config) - app.stubs(:sandbox=).returns(nil) - app.expects(:load_console) - app - end + @app ||= build_app(console: FakeConsole) end - def parse_arguments(args) - Rails::Console.parse_arguments(args) + def build_app(config) + config = mock("config", config) + app = mock("app", config: config) + app.stubs(:sandbox=).returns(nil) + app.expects(:load_console) + app end - def with_rails_env(env) - original_rails_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = env - yield - ensure - ENV['RAILS_ENV'] = original_rails_env + def parse_arguments(args) + Rails::Console.parse_arguments(args) end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index d45bdaabf5..edb92b3aa2 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -45,6 +45,18 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase ENV['RAILS_ENV'] = "test" end + def test_rails_env_is_development_when_argument_is_dev + Rails::DBConsole.stubs(:available_environments).returns(['development', 'test']) + options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) + assert_match('development', options[:environment]) + end + + def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present + Rails::DBConsole.stubs(:available_environments).returns(['dev']) + options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) + assert_match('dev', options[:environment]) + end + def test_mysql dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], 'db') start(adapter: 'mysql', database: 'db') @@ -116,6 +128,14 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase assert !aborted end + def test_sqlite3_db_without_defined_rails_root + Rails.stubs(:respond_to?) + Rails.expects(:respond_to?).with(:root).once.returns(false) + dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('../config/db.sqlite3').to_s) + start(adapter: 'sqlite3', database: 'config/db.sqlite3') + assert !aborted + end + def test_oracle dbconsole.expects(:find_cmd_and_exec).with('sqlplus', 'user@db') start(adapter: 'oracle', database: 'db', username: 'user', password: 'secret') @@ -152,8 +172,10 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase assert_match(/Usage:.*dbconsole/, stdout) end - private attr_reader :aborted, :output + private :aborted, :output + + private def dbconsole @dbconsole ||= Rails::DBConsole.new(nil) diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index 4a3ea82e3d..ba688f1e9e 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -1,7 +1,9 @@ require 'abstract_unit' +require 'env_helpers' require 'rails/commands/server' class Rails::ServerTest < ActiveSupport::TestCase + include EnvHelpers def test_environment_with_server_option args = ["thin", "-e", "production"] @@ -23,4 +25,64 @@ class Rails::ServerTest < ActiveSupport::TestCase assert_nil options[:environment] assert_equal 'thin', options[:server] end + + def test_environment_with_rails_env + with_rack_env nil do + with_rails_env 'production' do + server = Rails::Server.new + assert_equal 'production', server.options[:environment] + end + end + end + + def test_environment_with_rack_env + with_rails_env nil do + with_rack_env 'production' do + server = Rails::Server.new + assert_equal 'production', server.options[:environment] + end + end + end + + def test_log_stdout + with_rack_env nil do + with_rails_env nil do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + + args = ["-e", "development"] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + + args = ["-e", "production"] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + + with_rack_env 'development' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + end + + with_rack_env 'production' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + end + + with_rails_env 'development' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal true, options[:log_stdout] + end + + with_rails_env 'production' do + args = [] + options = Rails::Server::Options.new.parse!(args) + assert_equal false, options[:log_stdout] + end + end + end + end end diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index 5984c0b425..2442cb995d 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -1,6 +1,7 @@ -require 'minitest/autorun' +require 'active_support/testing/autorun' require 'rails/configuration' require 'active_support/test_case' +require 'minitest/mock' module Rails module Configuration diff --git a/railties/test/engine_test.rb b/railties/test/engine_test.rb index addf49cdb6..7970913d21 100644 --- a/railties/test/engine_test.rb +++ b/railties/test/engine_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' class EngineTest < ActiveSupport::TestCase - it "reports routes as available only if they're actually present" do + test "reports routes as available only if they're actually present" do engine = Class.new(Rails::Engine) do def initialize(*args) @routes = nil diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb new file mode 100644 index 0000000000..330fe150ca --- /dev/null +++ b/railties/test/env_helpers.rb @@ -0,0 +1,30 @@ +require 'rails' + +module EnvHelpers + private + + def with_rails_env(env) + Rails.instance_variable_set :@_env, nil + switch_env 'RAILS_ENV', env do + switch_env 'RACK_ENV', nil do + yield + end + end + end + + def with_rack_env(env) + Rails.instance_variable_set :@_env, nil + switch_env 'RACK_ENV', env do + switch_env 'RAILS_ENV', nil do + yield + end + end + end + + def switch_env(key, value) + old, ENV[key] = ENV[key], value + yield + ensure + ENV[key] = old + end +end diff --git a/railties/test/fixtures/lib/app_builders/empty_builder.rb b/railties/test/fixtures/lib/app_builders/empty_builder.rb deleted file mode 100644 index babd9c2461..0000000000 --- a/railties/test/fixtures/lib/app_builders/empty_builder.rb +++ /dev/null @@ -1,2 +0,0 @@ -class AppBuilder -end
\ No newline at end of file diff --git a/railties/test/fixtures/lib/app_builders/simple_builder.rb b/railties/test/fixtures/lib/app_builders/simple_builder.rb deleted file mode 100644 index 993d3a2aa2..0000000000 --- a/railties/test/fixtures/lib/app_builders/simple_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppBuilder - def gitignore - create_file ".gitignore", <<-R.strip -foobar - R - end -end diff --git a/railties/test/fixtures/lib/app_builders/tweak_builder.rb b/railties/test/fixtures/lib/app_builders/tweak_builder.rb deleted file mode 100644 index cb50be01cb..0000000000 --- a/railties/test/fixtures/lib/app_builders/tweak_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppBuilder < Rails::AppBuilder - def gitignore - create_file ".gitignore", <<-R.strip -foobar - R - end -end diff --git a/railties/test/fixtures/lib/plugin_builders/empty_builder.rb b/railties/test/fixtures/lib/plugin_builders/empty_builder.rb deleted file mode 100644 index 5c5607621c..0000000000 --- a/railties/test/fixtures/lib/plugin_builders/empty_builder.rb +++ /dev/null @@ -1,2 +0,0 @@ -class PluginBuilder -end diff --git a/railties/test/fixtures/lib/plugin_builders/simple_builder.rb b/railties/test/fixtures/lib/plugin_builders/simple_builder.rb deleted file mode 100644 index 08f6c5535d..0000000000 --- a/railties/test/fixtures/lib/plugin_builders/simple_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class PluginBuilder - def gitignore - create_file ".gitignore", <<-R.strip -foobar - R - end -end diff --git a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb deleted file mode 100644 index 2721429599..0000000000 --- a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb +++ /dev/null @@ -1,19 +0,0 @@ -class PluginBuilder < Rails::PluginBuilder - def test - create_file "spec/spec_helper.rb" - append_file "Rakefile", <<-EOF -# spec tasks in rakefile - -task default: :spec - EOF - end - - def generate_test_dummy - dummy_path("spec/dummy") - super - end - - def skip_test_unit? - true - end -end diff --git a/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb b/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb deleted file mode 100644 index 1e801409a4..0000000000 --- a/railties/test/fixtures/lib/plugin_builders/tweak_builder.rb +++ /dev/null @@ -1,7 +0,0 @@ -class PluginBuilder < Rails::PluginBuilder - def gitignore - create_file ".gitignore", <<-R.strip -foobar - R - end -end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 8af92479c3..0db40c1d32 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -1,8 +1,11 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' +require 'env_helpers' class ActionsTest < Rails::Generators::TestCase include GeneratorsTestHelper + include EnvHelpers + tests Rails::Generators::AppGenerator arguments [destination_root] @@ -100,7 +103,7 @@ class ActionsTest < Rails::Generators::TestCase run_generator autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' action :environment, autoload_paths, env: 'development' - assert_file "config/environments/development.rb", /Application\.configure do\n #{Regexp.escape(autoload_paths)}/ + assert_file "config/environments/development.rb", /Rails\.application\.configure do\n #{Regexp.escape(autoload_paths)}/ end def test_environment_with_block_should_include_block_contents_in_environment_initializer_block @@ -148,16 +151,15 @@ class ActionsTest < Rails::Generators::TestCase end def test_generate_should_run_script_generate_with_argument_and_options - generator.expects(:run_ruby_script).once.with('script/rails generate model MyModel', verbose: false) + generator.expects(:run_ruby_script).once.with('bin/rails generate model MyModel', verbose: false) action :generate, 'model', 'MyModel' end def test_rake_should_run_rake_command_with_default_env generator.expects(:run).once.with("rake log:clear RAILS_ENV=development", verbose: false) - old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil - action :rake, 'log:clear' - ensure - ENV["RAILS_ENV"] = old_env + with_rails_env nil do + action :rake, 'log:clear' + end end def test_rake_with_env_option_should_run_rake_command_in_env @@ -167,26 +169,23 @@ class ActionsTest < Rails::Generators::TestCase def test_rake_with_rails_env_variable_should_run_rake_command_in_env generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false) - old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production" - action :rake, 'log:clear' - ensure - ENV["RAILS_ENV"] = old_env + with_rails_env "production" do + action :rake, 'log:clear' + end end def test_env_option_should_win_over_rails_env_variable_when_running_rake generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false) - old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "staging" - action :rake, 'log:clear', env: 'production' - ensure - ENV["RAILS_ENV"] = old_env + with_rails_env "staging" do + action :rake, 'log:clear', env: 'production' + end 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) - old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil - action :rake, 'log:clear', sudo: true - ensure - ENV["RAILS_ENV"] = old_env + with_rails_env nil do + action :rake, 'log:clear', sudo: true + end end def test_capify_should_run_the_capify_command @@ -204,14 +203,14 @@ class ActionsTest < Rails::Generators::TestCase def test_readme run_generator Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root) - assert_match(/Welcome to Rails/, action(:readme, "README.rdoc")) + assert_match "application up and running", action(:readme, "README.rdoc") end def test_readme_with_quiet generator(default_arguments, quiet: true) run_generator Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root) - assert_no_match(/Welcome to Rails/, action(:readme, "README.rdoc")) + assert_no_match "application up and running", action(:readme, "README.rdoc") end def test_log diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index e5397bf4f3..39d4acb7b2 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -4,6 +4,7 @@ require 'generators/shared_generator_tests' DEFAULT_APP_FILES = %w( .gitignore + README.rdoc Gemfile Rakefile config.ru @@ -11,27 +12,29 @@ DEFAULT_APP_FILES = %w( app/assets/stylesheets app/assets/images app/controllers + app/controllers/concerns app/helpers app/mailers app/models + app/models/concerns app/views/layouts + bin/bundle + bin/rails + bin/rake config/environments config/initializers config/locales db - doc lib lib/tasks lib/assets log - script/rails test/fixtures test/controllers test/models test/helpers test/mailers test/integration - test/performance vendor vendor/assets tmp/cache @@ -51,11 +54,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file "app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application"/ - assert_file "app/views/layouts/application.html.erb", /javascript_include_tag\s+"application"/ - assert_file "app/assets/stylesheets/application.css" - assert_file "config/application.rb", /config\.assets\.enabled = true/ - assert_file "public/index.html", /url\("assets\/rails.png"\);/ + + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application", media: "all", "data-turbolinks-track" => true/) + assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+"application", "data-turbolinks-track" => true/) + assert_file("app/assets/stylesheets/application.css") end def test_invalid_application_name_raises_an_error @@ -65,12 +67,12 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_invalid_application_name_is_fixed run_generator [File.join(destination_root, "things-43")] - assert_file "things-43/config/environment.rb", /Things43::Application\.initialize!/ + assert_file "things-43/config/environment.rb", /Rails\.application\.initialize!/ assert_file "things-43/config/application.rb", /^module Things43$/ end def test_application_new_exits_with_non_zero_code_on_invalid_application_name - quietly { system 'rails new test' } + quietly { system 'rails new test --no-rc' } assert_equal false, $?.success? end @@ -111,7 +113,7 @@ class AppGeneratorTest < Rails::Generators::TestCase destination_root: app_moved_root, shell: @shell generator.send(:app_const) quietly { generator.send(:create_config_files) } - assert_file "myapp_moved/config/environment.rb", /Myapp::Application\.initialize!/ + assert_file "myapp_moved/config/environment.rb", /Rails\.application\.initialize!/ assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/ end @@ -131,7 +133,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_application_names_are_not_singularized run_generator [File.join(destination_root, "hats")] - assert_file "hats/config/environment.rb", /Hats::Application\.initialize!/ + assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/ end def test_gemfile_has_no_whitespace_errors @@ -164,6 +166,11 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_config_database_app_name_with_period + run_generator [File.join(destination_root, "common.usage.com"), "-d", "postgresql"] + assert_file "common.usage.com/config/database.yml", /common_usage_com/ + end + def test_config_postgresql_database run_generator([destination_root, "-d", "postgresql"]) assert_file "config/database.yml", /postgresql/ @@ -178,9 +185,6 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator([destination_root, "-d", "jdbcmysql"]) assert_file "config/database.yml", /mysql/ assert_gem "activerecord-jdbcmysql-adapter" - # TODO: When the JRuby guys merge jruby-openssl in - # jruby this will be removed - assert_gem "jruby-openssl" if defined?(JRUBY_VERSION) end def test_config_jdbcsqlite3_database @@ -217,28 +221,33 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test/test_helper.rb" do |helper_content| assert_no_match(/fixtures :all/, helper_content) end - assert_file "test/performance/browsing_test.rb" + end + + def test_generator_if_skip_action_view_is_given + run_generator [destination_root, "--skip-action-view"] + assert_file "config/application.rb", /#\s+require\s+["']action_view\/railtie["']/ end def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] assert_file "config/application.rb" do |content| - assert_match(/#\s+require\s+["']sprockets\/rails\/railtie["']/, content) - assert_no_match(/config\.assets\.enabled = true/, content) + assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) + assert_match(/config\.assets\.enabled = false/, content) end assert_file "Gemfile" do |content| assert_no_match(/sass-rails/, content) - assert_no_match(/coffee-rails/, content) assert_no_match(/uglifier/, content) + assert_match(/coffee-rails/, content) end assert_file "config/environments/development.rb" do |content| assert_no_match(/config\.assets\.debug = true/, content) end assert_file "config/environments/production.rb" do |content| assert_no_match(/config\.assets\.digest = true/, content) - assert_no_match(/config\.assets\.compress = true/, content) + assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) + assert_no_match(/config\.assets\.css_compressor = :sass/, content) + assert_no_match(/config\.assets\.version = '1\.0'/, content) end - assert_file "test/performance/browsing_test.rb" end def test_inclusion_of_javascript_runtime @@ -246,22 +255,20 @@ class AppGeneratorTest < Rails::Generators::TestCase if defined?(JRUBY_VERSION) assert_gem "therubyrhino" else - assert_file "Gemfile", /# gem\s+["']therubyracer["']+, platforms: :ruby$/ + assert_file "Gemfile", /# gem\s+["']therubyracer["']+, \s+platforms: :ruby$/ end end - def test_generator_if_skip_index_html_is_given - run_generator [destination_root, '--skip-index-html'] - assert_no_file 'public/index.html' - assert_no_file 'app/assets/images/rails.png' - assert_file 'app/assets/images/.keep' - end - def test_creation_of_a_test_directory run_generator assert_file 'test' end + def test_creation_of_app_assets_images_directory + run_generator + assert_file "app/assets/images" + end + def test_creation_of_vendor_assets_javascripts_directory run_generator assert_file "vendor/assets/javascripts" @@ -278,7 +285,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_match %r{^//= require jquery}, contents assert_match %r{^//= require jquery_ujs}, contents end - assert_gem "jquery-rails" + assert_file "Gemfile", /^gem 'jquery-rails'/ end def test_other_javascript_libraries @@ -292,9 +299,28 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_javascript_is_skipped_if_required run_generator [destination_root, "--skip-javascript"] - assert_file "app/assets/javascripts/application.js" do |contents| - assert_no_match %r{^//=\s+require\s}, contents + + assert_no_file "app/assets/javascripts" + assert_no_file "vendor/assets/javascripts" + + assert_file "app/views/layouts/application.html.erb" do |contents| + assert_match(/stylesheet_link_tag\s+"application", media: "all" %>/, contents) + assert_no_match(/javascript_include_tag\s+"application" \%>/, contents) end + + assert_file "Gemfile" do |content| + assert_no_match(/coffee-rails/, content) + end + end + + def test_inclusion_of_web_console + run_generator + assert_file "Gemfile", /gem 'web-console', \s+group: :development/ + end + + def test_inclusion_of_jbuilder + run_generator + assert_file "Gemfile", /gem 'jbuilder'/ end def test_inclusion_of_debugger @@ -302,6 +328,11 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile", /# gem 'debugger'/ end + def test_inclusion_of_lazy_loaded_sdoc + run_generator + assert_file 'Gemfile', /gem 'sdoc', \s+group: :doc, require: false/ + end + def test_template_from_dir_pwd FileUtils.cd(Rails.root) assert_match(/It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"])) @@ -344,52 +375,28 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_generated_environments_file_for_auto_explain - run_generator [destination_root, "--skip-active-record"] - %w(development production).each do |env| - assert_file "config/environments/#{env}.rb" do |file| - assert_no_match %r(auto_explain_threshold_in_seconds), file - end - end - end - def test_pretend_option output = run_generator [File.join(destination_root, "myapp"), "--pretend"] assert_no_match(/run bundle install/, output) end -protected + def test_application_name_with_spaces + path = File.join(destination_root, "foo bar".shellescape) - def action(*args, &block) - silence(:stdout) { generator.send(*args, &block) } - end + # This also applies to MySQL apps but not with SQLite + run_generator [path, "-d", 'postgresql'] - def assert_gem(gem) - assert_file "Gemfile", /^gem\s+["']#{gem}["']$/ + assert_file "foo bar/config/database.yml", /database: foo_bar_development/ + assert_file "foo bar/config/initializers/session_store.rb", /key: '_foo_bar/ end -end - -class CustomAppGeneratorTest < Rails::Generators::TestCase - include GeneratorsTestHelper - tests Rails::Generators::AppGenerator - - arguments [destination_root] - include SharedCustomGeneratorTests protected - def default_files - ::DEFAULT_APP_FILES - end - - def builders_dir - "app_builders" - end - - def builder_class - :AppBuilder - end def action(*args, &block) silence(:stdout) { generator.send(*args, &block) } end + + def assert_gem(gem) + assert_file "Gemfile", /^gem\s+["']#{gem}["']$/ + end end diff --git a/railties/test/generators/argv_scrubber_test.rb b/railties/test/generators/argv_scrubber_test.rb new file mode 100644 index 0000000000..a94350cbd7 --- /dev/null +++ b/railties/test/generators/argv_scrubber_test.rb @@ -0,0 +1,136 @@ +require 'active_support/test_case' +require 'active_support/testing/autorun' +require 'rails/generators/rails/app/app_generator' +require 'tempfile' + +module Rails + module Generators + class ARGVScrubberTest < ActiveSupport::TestCase # :nodoc: + # Future people who read this... These tests are just to surround the + # current behavior of the ARGVScrubber, they do not mean that the class + # *must* act this way, I just want to prevent regressions. + + def test_version + ['-v', '--version'].each do |str| + scrubber = ARGVScrubber.new [str] + output = nil + exit_code = nil + scrubber.extend(Module.new { + define_method(:puts) { |str| output = str } + define_method(:exit) { |code| exit_code = code } + }) + scrubber.prepare! + assert_equal "Rails #{Rails::VERSION::STRING}", output + assert_equal 0, exit_code + end + end + + def test_default_help + argv = ['zomg', 'how', 'are', 'you'] + scrubber = ARGVScrubber.new argv + args = scrubber.prepare! + assert_equal ['--help'] + argv.drop(1), args + end + + def test_prepare_returns_args + scrubber = ARGVScrubber.new ['hi mom'] + args = scrubber.prepare! + assert_equal '--help', args.first + end + + def test_no_mutations + scrubber = ARGVScrubber.new ['hi mom'].freeze + args = scrubber.prepare! + assert_equal '--help', args.first + end + + def test_new_command_no_rc + scrubber = Class.new(ARGVScrubber) { + def self.default_rc_file + File.join(Dir.tmpdir, 'whatever') + end + }.new ['new'] + args = scrubber.prepare! + assert_equal [], args + end + + def test_new_homedir_rc + file = Tempfile.new 'myrcfile' + file.puts '--hello-world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_singleton_method(:default_rc_file) do + file.path + end + define_method(:puts) { |msg| message = msg } + }.new ['new'] + args = scrubber.prepare! + assert_equal ['--hello-world'], args + assert_match 'hello-world', message + assert_match file.path, message + ensure + file.close + file.unlink + end + + def test_rc_whitespace_separated + file = Tempfile.new 'myrcfile' + file.puts '--hello --world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| message = msg } + }.new ['new', "--rc=#{file.path}"] + args = scrubber.prepare! + assert_equal ['--hello', '--world'], args + ensure + file.close + file.unlink + end + + def test_new_rc_option + file = Tempfile.new 'myrcfile' + file.puts '--hello-world' + file.flush + + message = nil + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| message = msg } + }.new ['new', "--rc=#{file.path}"] + args = scrubber.prepare! + assert_equal ['--hello-world'], args + assert_match 'hello-world', message + assert_match file.path, message + ensure + file.close + file.unlink + end + + def test_new_rc_option_and_custom_options + file = Tempfile.new 'myrcfile' + file.puts '--hello' + file.puts '--world' + file.flush + + scrubber = Class.new(ARGVScrubber) { + define_method(:puts) { |msg| } + }.new ['new', 'tenderapp', '--love', "--rc=#{file.path}"] + + args = scrubber.prepare! + assert_equal ["tenderapp", "--hello", "--world", "--love"], args + ensure + file.close + file.unlink + end + + def test_no_rc + scrubber = ARGVScrubber.new ['new', '--no-rc'] + args = scrubber.prepare! + assert_equal [], args + end + end + end +end diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 5205deafd9..9c664a903a 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -82,4 +82,9 @@ class ControllerGeneratorTest < Rails::Generators::TestCase assert_instance_method :bar, controller end end + + def test_namespaced_routes_are_created_in_routes + run_generator ["admin/dashboard", "index"] + assert_file "config/routes.rb", /namespace :admin do\n\s+get "dashboard\/index"\n/ + end end diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb index 6ab1cd58c7..c48bc20899 100644 --- a/railties/test/generators/generated_attribute_test.rb +++ b/railties/test/generators/generated_attribute_test.rb @@ -117,13 +117,13 @@ class GeneratedAttributeTest < Rails::Generators::TestCase assert create_generated_attribute("#{attribute_type}{polymorphic}").polymorphic? end end - + def test_polymorphic_reference_is_false %w(foo bar baz).each do |attribute_type| assert !create_generated_attribute("#{attribute_type}{polymorphic}").polymorphic? end end - + def test_blank_type_defaults_to_string_raises_exception assert_equal :string, create_generated_attribute(nil, 'title').type assert_equal :string, create_generated_attribute("", 'title').type @@ -132,6 +132,13 @@ class GeneratedAttributeTest < Rails::Generators::TestCase def test_handles_index_names_for_references assert_equal "post", create_generated_attribute('string', 'post').index_name assert_equal "post_id", create_generated_attribute('references', 'post').index_name + assert_equal "post_id", create_generated_attribute('belongs_to', 'post').index_name assert_equal ["post_id", "post_type"], create_generated_attribute('references{polymorphic}', 'post').index_name end + + def test_handles_column_names_for_references + assert_equal "post", create_generated_attribute('string', 'post').column_name + assert_equal "post_id", create_generated_attribute('references', 'post').column_name + assert_equal "post_id", create_generated_attribute('belongs_to', 'post').column_name + end end diff --git a/railties/test/generators/generator_generator_test.rb b/railties/test/generators/generator_generator_test.rb index f4c975fc18..dcfeaaa8e0 100644 --- a/railties/test/generators/generator_generator_test.rb +++ b/railties/test/generators/generator_generator_test.rb @@ -16,6 +16,9 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase assert_file "lib/generators/awesome/awesome_generator.rb", /class AwesomeGenerator < Rails::Generators::NamedBase/ + assert_file "test/lib/generators/awesome_generator_test.rb", + /class AwesomeGeneratorTest < Rails::Generators::TestCase/, + /require 'generators\/awesome\/awesome_generator'/ end def test_namespaced_generator_skeleton @@ -29,6 +32,9 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase assert_file "lib/generators/rails/awesome/awesome_generator.rb", /class Rails::AwesomeGenerator < Rails::Generators::NamedBase/ + assert_file "test/lib/generators/rails/awesome_generator_test.rb", + /class Rails::AwesomeGeneratorTest < Rails::Generators::TestCase/, + /require 'generators\/rails\/awesome\/awesome_generator'/ end def test_generator_skeleton_is_created_without_file_name_namespace @@ -42,6 +48,9 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase assert_file "lib/generators/awesome_generator.rb", /class AwesomeGenerator < Rails::Generators::NamedBase/ + assert_file "test/lib/generators/awesome_generator_test.rb", + /class AwesomeGeneratorTest < Rails::Generators::TestCase/, + /require 'generators\/awesome_generator'/ end def test_namespaced_generator_skeleton_without_file_name_namespace @@ -55,5 +64,8 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase assert_file "lib/generators/rails/awesome_generator.rb", /class Rails::AwesomeGenerator < Rails::Generators::NamedBase/ + assert_file "test/lib/generators/rails/awesome_generator_test.rb", + /class Rails::AwesomeGeneratorTest < Rails::Generators::TestCase/, + /require 'generators\/rails\/awesome_generator'/ end end diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb new file mode 100644 index 0000000000..7871399dd7 --- /dev/null +++ b/railties/test/generators/generator_test.rb @@ -0,0 +1,85 @@ +require 'active_support/test_case' +require 'active_support/testing/autorun' +require 'rails/generators/app_base' + +module Rails + module Generators + class GeneratorTest < ActiveSupport::TestCase + def make_builder_class + Class.new(AppBase) do + add_shared_options_for "application" + + # include a module to get around thor's method_added hook + include(Module.new { + def gemfile_entries; super; end + def invoke_all; super; self; end + def add_gem_entry_filter; super; end + def gemfile_entry(*args); super; end + }) + end + end + + def test_construction + klass = make_builder_class + assert klass.start(['new', 'blah']) + end + + def test_add_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove' + assert_includes generator.gemfile_entries.map(&:name), 'tenderlove' + end + + def test_add_gem_with_version + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', '2.0.0' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.version == '2.0.0' + } + end + + def test_add_github_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', github: 'hello world' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.options[:github] == 'hello world' + } + end + + def test_add_path_gem + klass = make_builder_class + generator = klass.start(['new', 'blah']) + generator.gemfile_entry 'tenderlove', path: 'hello world' + assert generator.gemfile_entries.find { |gfe| + gfe.name == 'tenderlove' && gfe.options[:path] == 'hello world' + } + end + + def test_filter + klass = make_builder_class + generator = klass.start(['new', 'blah']) + gems = generator.gemfile_entries + generator.add_gem_entry_filter { |gem| + gem.name != gems.first.name + } + assert_equal gems.drop(1), generator.gemfile_entries + end + + def test_two_filters + klass = make_builder_class + generator = klass.start(['new', 'blah']) + gems = generator.gemfile_entries + generator.add_gem_entry_filter { |gem| + gem.name != gems.first.name + } + generator.add_gem_entry_filter { |gem| + gem.name != gems[1].name + } + assert_equal gems.drop(2), generator.gemfile_entries + end + end + end +end diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 7fdd54fc30..32a3d072c9 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -16,6 +16,7 @@ Rails.application.load_generators require 'active_record' require 'action_dispatch' +require 'action_view' module GeneratorsTestHelper def self.included(base) diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 15e5a0b92b..d876597944 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -28,7 +28,7 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration] assert_migration "db/migrate/change_title_body_from_posts.rb", /class #{migration} < ActiveRecord::Migration/ end - + def test_migration_with_invalid_file_name migration = "add_something:datetime" assert_raise ActiveRecord::IllegalMigrationNameError do @@ -41,9 +41,9 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string", "body:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_column :posts, :title, :string/, up) - assert_match(/add_column :posts, :body, :text/, up) + assert_method :change, content do |change| + assert_match(/add_column :posts, :title, :string/, change) + assert_match(/add_column :posts, :body, :text/, change) end end end @@ -53,15 +53,10 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string:index", "body:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :up, content do |up| - assert_match(/remove_column :posts, :title/, up) - assert_match(/remove_column :posts, :body/, up) - end - - assert_method :down, content do |down| - assert_match(/add_column :posts, :title, :string/, down) - assert_match(/add_column :posts, :body, :text/, down) - assert_match(/add_index :posts, :title/, down) + assert_method :change, content do |change| + assert_match(/remove_column :posts, :title, :string/, change) + assert_match(/remove_column :posts, :body, :text/, change) + assert_match(/remove_index :posts, :title/, change) end end end @@ -71,14 +66,9 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string", "body:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :up, content do |up| - assert_match(/remove_column :posts, :title/, up) - assert_match(/remove_column :posts, :body/, up) - end - - assert_method :down, content do |down| - assert_match(/add_column :posts, :title, :string/, down) - assert_match(/add_column :posts, :body, :text/, down) + assert_method :change, content do |change| + assert_match(/remove_column :posts, :title, :string/, change) + assert_match(/remove_column :posts, :body, :text/, change) end end end @@ -88,14 +78,9 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "author:belongs_to", "distributor:references{polymorphic}"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :up, content do |up| - assert_match(/remove_reference :books, :author/, up) - assert_match(/remove_reference :books, :distributor, polymorphic: true/, up) - end - - assert_method :down, content do |down| - assert_match(/add_reference :books, :author, index: true/, down) - assert_match(/add_reference :books, :distributor, polymorphic: true, index: true/, down) + assert_method :change, content do |change| + assert_match(/remove_reference :books, :author, index: true/, change) + assert_match(/remove_reference :books, :distributor, polymorphic: true, index: true/, change) end end end @@ -105,13 +90,13 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string:index", "body:text", "user_id:integer:uniq"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_column :posts, :title, :string/, up) - assert_match(/add_column :posts, :body, :text/, up) - assert_match(/add_column :posts, :user_id, :integer/, up) + assert_method :change, content do |change| + assert_match(/add_column :posts, :title, :string/, change) + assert_match(/add_column :posts, :body, :text/, change) + assert_match(/add_column :posts, :user_id, :integer/, change) + assert_match(/add_index :posts, :title/, change) + assert_match(/add_index :posts, :user_id, unique: true/, change) end - assert_match(/add_index :posts, :title/, content) - assert_match(/add_index :posts, :user_id, unique: true/, content) end end @@ -120,10 +105,10 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string:inex", "content:text", "user_id:integer:unik"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_column :books, :title, :string/, up) - assert_match(/add_column :books, :content, :text/, up) - assert_match(/add_column :books, :user_id, :integer/, up) + assert_method :change, content do |change| + assert_match(/add_column :books, :title, :string/, change) + assert_match(/add_column :books, :content, :text/, change) + assert_match(/add_column :books, :user_id, :integer/, change) end assert_no_match(/add_index :books, :title/, content) assert_no_match(/add_index :books, :user_id/, content) @@ -135,13 +120,13 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:index", "body:text", "user_uuid:uniq"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_column :posts, :title, :string/, up) - assert_match(/add_column :posts, :body, :text/, up) - assert_match(/add_column :posts, :user_uuid, :string/, up) + assert_method :change, content do |change| + assert_match(/add_column :posts, :title, :string/, change) + assert_match(/add_column :posts, :body, :text/, change) + assert_match(/add_column :posts, :user_uuid, :string/, change) + assert_match(/add_index :posts, :title/, change) + assert_match(/add_index :posts, :user_uuid, unique: true/, change) end - assert_match(/add_index :posts, :title/, content) - assert_match(/add_index :posts, :user_uuid, unique: true/, content) end end @@ -150,11 +135,11 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string{40}:index", "content:string{255}", "price:decimal{1,2}:index", "discount:decimal{3.4}:uniq"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_column :books, :title, :string, limit: 40/, up) - assert_match(/add_column :books, :content, :string, limit: 255/, up) - assert_match(/add_column :books, :price, :decimal, precision: 1, scale: 2/, up) - assert_match(/add_column :books, :discount, :decimal, precision: 3, scale: 4/, up) + assert_method :change, content do |change| + assert_match(/add_column :books, :title, :string, limit: 40/, change) + assert_match(/add_column :books, :content, :string, limit: 255/, change) + assert_match(/add_column :books, :price, :decimal, precision: 1, scale: 2/, change) + assert_match(/add_column :books, :discount, :decimal, precision: 3, scale: 4/, change) end assert_match(/add_index :books, :title/, content) assert_match(/add_index :books, :price/, content) @@ -167,9 +152,9 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "author:belongs_to", "distributor:references{polymorphic}"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/add_reference :books, :author, index: true/, up) - assert_match(/add_reference :books, :distributor, polymorphic: true, index: true/, up) + assert_method :change, content do |change| + assert_match(/add_reference :books, :author, index: true/, change) + assert_match(/add_reference :books, :distributor, polymorphic: true, index: true/, change) end end end @@ -179,29 +164,36 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "artist_id", "musics:uniq"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :change, content do |up| - assert_match(/create_join_table :artists, :musics/, up) - assert_match(/# t.index \[:artist_id, :music_id\]/, up) - assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, up) + assert_method :change, content do |change| + assert_match(/create_join_table :artists, :musics/, change) + assert_match(/# t.index \[:artist_id, :music_id\]/, change) + assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, change) end end end - def test_should_create_empty_migrations_if_name_not_start_with_add_or_remove - migration = "create_books" + def test_create_table_migration + run_generator ["create_books", "title:string", "content:text"] + assert_migration "db/migrate/create_books.rb" do |content| + assert_method :change, content do |change| + assert_match(/create_table :books/, change) + assert_match(/ t\.string :title/, change) + assert_match(/ t\.text :content/, change) + end + end + end + + def test_should_create_empty_migrations_if_name_not_start_with_add_or_remove_or_create + migration = "delete_books" run_generator [migration, "title:string", "content:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_method :up, content do |up| - assert_match(/^\s*$/, up) - end - - assert_method :down, content do |down| - assert_match(/^\s*$/, down) + assert_method :change, content do |change| + assert_match(/^\s*$/, change) end end end - + def test_properly_identifies_usage_file assert generator_class.send(:usage_path) end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 0c7ff0ebe7..01ab77ee20 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -264,13 +264,40 @@ class ModelGeneratorTest < Rails::Generators::TestCase error = capture(:stderr) { run_generator ["Account", "--force"] } assert_no_match(/Another migration is already named create_accounts/, error) assert_no_file old_migration - assert_migration 'db/migrate/create_accounts.rb' + assert_migration "db/migrate/create_accounts.rb" end def test_invokes_default_test_framework run_generator assert_file "test/models/account_test.rb", /class AccountTest < ActiveSupport::TestCase/ + assert_file "test/fixtures/accounts.yml", /name: MyString/, /age: 1/ + assert_generated_fixture("test/fixtures/accounts.yml", + {"one"=>{"name"=>"MyString", "age"=>1}, "two"=>{"name"=>"MyString", "age"=>1}}) + end + + def test_fixtures_use_the_references_ids + run_generator ["LineItem", "product:references", "cart:belongs_to"] + + assert_file "test/fixtures/line_items.yml", /product_id: \n cart_id: / + assert_generated_fixture("test/fixtures/line_items.yml", + {"one"=>{"product_id"=>nil, "cart_id"=>nil}, "two"=>{"product_id"=>nil, "cart_id"=>nil}}) + end + + def test_fixtures_use_the_references_ids_and_type + run_generator ["LineItem", "product:references{polymorphic}", "cart:belongs_to"] + + assert_file "test/fixtures/line_items.yml", /product_id: \n product_type: Product\n cart_id: / + assert_generated_fixture("test/fixtures/line_items.yml", + {"one"=>{"product_id"=>nil, "product_type"=>"Product", "cart_id"=>nil}, + "two"=>{"product_id"=>nil, "product_type"=>"Product", "cart_id"=>nil}}) + end + + def test_fixtures_respect_reserved_yml_keywords + run_generator ["LineItem", "no:integer", "Off:boolean", "ON:boolean"] + + assert_generated_fixture("test/fixtures/line_items.yml", + {"one"=>{"no"=>1, "Off"=>false, "ON"=>false}, "two"=>{"no"=>1, "Off"=>false, "ON"=>false}}) end def test_fixture_is_skipped @@ -328,4 +355,10 @@ class ModelGeneratorTest < Rails::Generators::TestCase end end end + + private + def assert_generated_fixture(path, parsed_contents) + fixture_file = File.new File.expand_path(path, destination_root) + assert_equal(parsed_contents, YAML.load(fixture_file)) + end end diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 2bc2c33a72..ac5cfff229 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -117,6 +117,25 @@ class NamedBaseTest < Rails::Generators::TestCase assert Rails::Generators.hidden_namespaces.include?('hidden') end + def test_scaffold_plural_names_with_model_name_option + g = generator ['Admin::Foo'], model_name: 'User' + assert_name g, 'user', :singular_name + assert_name g, 'User', :name + assert_name g, 'user', :file_path + assert_name g, 'User', :class_name + assert_name g, 'user', :file_name + assert_name g, 'User', :human_name + assert_name g, 'users', :plural_name + assert_name g, 'user', :i18n_scope + assert_name g, 'users', :table_name + assert_name g, 'Admin::Foos', :controller_name + assert_name g, %w(admin), :controller_class_path + assert_name g, 'Admin::Foos', :controller_class_name + assert_name g, 'admin/foos', :controller_file_path + assert_name g, 'foos', :controller_file_name + assert_name g, 'admin.foos', :controller_i18n_scope + end + protected def assert_name(generator, value, method) diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index 4b168ae110..e17925ff65 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -1,18 +1,19 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/controller/controller_generator' require 'rails/generators/rails/model/model_generator' -require 'rails/generators/rails/observer/observer_generator' require 'rails/generators/mailer/mailer_generator' require 'rails/generators/rails/scaffold/scaffold_generator' class NamespacedGeneratorTestCase < Rails::Generators::TestCase + include GeneratorsTestHelper + def setup + super Rails::Generators.namespace = TestApp end end class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase - include GeneratorsTestHelper arguments %w(Account foo bar) tests Rails::Generators::ControllerGenerator @@ -43,7 +44,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase end end - def test_helpr_is_also_namespaced + def test_helper_is_also_namespaced run_generator assert_file "app/helpers/test_app/account_helper.rb", /module TestApp/, / module AccountHelper/ assert_file "test/helpers/test_app/account_helper_test.rb", /module TestApp/, / class AccountHelperTest/ @@ -81,7 +82,6 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase end class NamespacedModelGeneratorTest < NamespacedGeneratorTestCase - include GeneratorsTestHelper arguments %w(Account name:string age:integer) tests Rails::Generators::ModelGenerator @@ -141,29 +141,7 @@ class NamespacedModelGeneratorTest < NamespacedGeneratorTestCase end end -class NamespacedObserverGeneratorTest < NamespacedGeneratorTestCase - include GeneratorsTestHelper - arguments %w(account) - tests Rails::Generators::ObserverGenerator - - def test_invokes_default_orm - run_generator - assert_file "app/models/test_app/account_observer.rb", /module TestApp/, / class AccountObserver < ActiveRecord::Observer/ - end - - def test_invokes_default_orm_with_class_path - run_generator ["admin/account"] - assert_file "app/models/test_app/admin/account_observer.rb", /module TestApp/, / class Admin::AccountObserver < ActiveRecord::Observer/ - end - - def test_invokes_default_test_framework - run_generator - assert_file "test/models/test_app/account_observer_test.rb", /module TestApp/, / class AccountObserverTest < ActiveSupport::TestCase/ - end -end - class NamespacedMailerGeneratorTest < NamespacedGeneratorTestCase - include GeneratorsTestHelper arguments %w(notifier foo bar) tests Rails::Generators::MailerGenerator @@ -244,13 +222,9 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase /module TestApp\n class ProductLinesControllerTest < ActionController::TestCase/ # Views - %w( - index - edit - new - show - _form - ).each { |view| assert_file "app/views/test_app/product_lines/#{view}.html.erb" } + %w(index edit new show _form).each do |view| + assert_file "app/views/test_app/product_lines/#{view}.html.erb" + end assert_no_file "app/views/layouts/test_app/product_lines.html.erb" # Helpers @@ -316,13 +290,9 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase /module TestApp\n class Admin::RolesControllerTest < ActionController::TestCase/ # Views - %w( - index - edit - new - show - _form - ).each { |view| assert_file "app/views/test_app/admin/roles/#{view}.html.erb" } + %w(index edit new show _form).each do |view| + assert_file "app/views/test_app/admin/roles/#{view}.html.erb" + end assert_no_file "app/views/layouts/admin/roles.html.erb" # Helpers @@ -389,13 +359,9 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase /module TestApp\n class Admin::User::Special::RolesControllerTest < ActionController::TestCase/ # Views - %w( - index - edit - new - show - _form - ).each { |view| assert_file "app/views/test_app/admin/user/special/roles/#{view}.html.erb" } + %w(index edit new show _form).each do |view| + assert_file "app/views/test_app/admin/user/special/roles/#{view}.html.erb" + end assert_no_file "app/views/layouts/admin/user/special/roles.html.erb" # Helpers diff --git a/railties/test/generators/observer_generator_test.rb b/railties/test/generators/observer_generator_test.rb deleted file mode 100644 index 1231827466..0000000000 --- a/railties/test/generators/observer_generator_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/observer/observer_generator' - -class ObserverGeneratorTest < Rails::Generators::TestCase - include GeneratorsTestHelper - arguments %w(account) - - 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/models/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 -end diff --git a/railties/test/generators/performance_test_generator_test.rb b/railties/test/generators/performance_test_generator_test.rb deleted file mode 100644 index 37f9857193..0000000000 --- a/railties/test/generators/performance_test_generator_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/performance_test/performance_test_generator' - -class PerformanceTestGeneratorTest < Rails::Generators::TestCase - include GeneratorsTestHelper - arguments %w(performance) - - def test_performance_test_skeleton_is_created - run_generator - assert_file "test/performance/performance_test.rb", /class PerformanceTest < ActionDispatch::PerformanceTest/ - end -end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 6974db5751..068eb66bc6 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -1,5 +1,5 @@ require 'generators/generators_test_helper' -require 'rails/generators/rails/plugin_new/plugin_new_generator' +require 'rails/generators/rails/plugin/plugin_generator' require 'generators/shared_generator_tests' DEFAULT_PLUGIN_FILES = %w( @@ -18,7 +18,7 @@ DEFAULT_PLUGIN_FILES = %w( test/dummy ) -class PluginNewGeneratorTest < Rails::Generators::TestCase +class PluginGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper destination File.join(Rails.root, "tmp/bukkits") arguments [destination_root] @@ -63,7 +63,24 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_directory "test/integration/" assert_no_file "test" - assert_no_match(/APP_RAKEFILE/, File.read(File.join(destination_root, "Rakefile"))) + assert_file "Rakefile" do |contents| + assert_no_match(/APP_RAKEFILE/, contents) + end + end + + def test_generating_adds_dummy_app_rake_tasks_without_unit_test_files + run_generator [destination_root, "-T", "--mountable", '--dummy-path', 'my_dummy_app'] + assert_file "Rakefile", /APP_RAKEFILE/ + end + + def test_generating_adds_dummy_app_without_javascript_and_assets_deps + run_generator [destination_root] + + assert_file "test/dummy/app/assets/stylesheets/application.css" + + assert_file "test/dummy/app/assets/javascripts/application.js" do |contents| + assert_no_match(/jquery/, contents) + end end def test_ensure_that_plugin_options_are_not_passed_to_app_generator @@ -106,7 +123,9 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_ensure_that_skip_active_record_option_is_passed_to_app_generator run_generator [destination_root, "--skip_active_record"] assert_no_file "test/dummy/config/database.yml" - assert_no_match(/ActiveRecord/, File.read(File.join(destination_root, "test/test_helper.rb"))) + assert_file "test/test_helper.rb" do |contents| + assert_no_match(/ActiveRecord/, contents) + end end def test_ensure_that_database_option_is_passed_to_app_generator @@ -128,8 +147,6 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_skipping_javascripts_without_mountable_option run_generator assert_no_file "app/assets/javascripts/bukkits/application.js" - assert_no_file "vendor/assets/javascripts/jquery.js" - assert_no_file "vendor/assets/javascripts/jquery_ujs.js" end def test_javascripts_generation @@ -137,33 +154,9 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/assets/javascripts/bukkits/application.js" end - def test_jquery_is_the_default_javascript_library - run_generator [destination_root, "--mountable"] - assert_file "app/assets/javascripts/bukkits/application.js" do |contents| - assert_match %r{^//= require jquery}, contents - assert_match %r{^//= require jquery_ujs}, contents - end - assert_file 'bukkits.gemspec' do |contents| - assert_match(/jquery-rails/, contents) - end - end - - def test_other_javascript_libraries - run_generator [destination_root, "--mountable", '-j', 'prototype'] - assert_file "app/assets/javascripts/bukkits/application.js" do |contents| - assert_match %r{^//= require prototype}, contents - assert_match %r{^//= require prototype_ujs}, contents - end - assert_file 'bukkits.gemspec' do |contents| - assert_match(/prototype-rails/, contents) - end - end - def test_skip_javascripts run_generator [destination_root, "--skip-javascript", "--mountable"] assert_no_file "app/assets/javascripts/bukkits/application.js" - assert_no_file "vendor/assets/javascripts/jquery.js" - assert_no_file "vendor/assets/javascripts/jquery_ujs.js" end def test_template_from_dir_pwd @@ -175,14 +168,14 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase run_generator FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) end def test_ensure_that_tests_works_in_full_mode run_generator [destination_root, "--full", "--skip_active_record"] FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) end def test_ensure_that_migration_tasks_work_with_mountable_option @@ -203,10 +196,10 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/views" assert_file "app/helpers" assert_file "app/mailers" + assert_file "bin/rails" assert_file "config/routes.rb", /Rails.application.routes.draw do/ assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < ::Rails::Engine\n end\nend/ assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ - assert_file "script/rails" end def test_being_quiet_while_creating_dummy_application @@ -240,15 +233,15 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_usage_of_engine_commands run_generator [destination_root, "--full"] - assert_file "script/rails", /ENGINE_PATH = File.expand_path\('..\/..\/lib\/bukkits\/engine', __FILE__\)/ - assert_file "script/rails", /ENGINE_ROOT = File.expand_path\('..\/..', __FILE__\)/ - assert_file "script/rails", /require 'rails\/all'/ - assert_file "script/rails", /require 'rails\/engine\/commands'/ + assert_file "bin/rails", /ENGINE_PATH = File.expand_path\('..\/..\/lib\/bukkits\/engine', __FILE__\)/ + assert_file "bin/rails", /ENGINE_ROOT = File.expand_path\('..\/..', __FILE__\)/ + assert_file "bin/rails", /require 'rails\/all'/ + assert_file "bin/rails", /require 'rails\/engine\/commands'/ end def test_shebang run_generator [destination_root, "--full"] - assert_file "script/rails", /#!\/usr\/bin\/env ruby/ + assert_file "bin/rails", /#!\/usr\/bin\/env ruby/ end def test_passing_dummy_path_as_a_parameter @@ -299,7 +292,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails::VERSION::STRING}"/, contents) + assert_match(/gem "rails", "~> #{Rails.version}"/, contents) assert_match(/group :development do\n gem "sqlite3"\nend/, contents) assert_no_match(/# gem "jquery-rails"/, contents) end @@ -310,18 +303,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails::VERSION::STRING}"/, contents) + assert_match(/gem "rails", "~> #{Rails.version}"/, contents) assert_match(/group :development do\n gem "sqlite3"\nend/, contents) - assert_match(/# gem "jquery-rails"/, contents) - assert_no_match(/# jquery-rails is used by the dummy application\ngem "jquery-rails"/, contents) - end - end - - def test_skipping_gemspec_in_full_mode_with_javascript_option - run_generator [destination_root, "--skip-gemspec", "--full", "--javascript=prototype"] - assert_file "Gemfile" do |contents| - assert_match(/# gem "prototype-rails"/, contents) - assert_match(/# jquery-rails is used by the dummy application\ngem "jquery-rails"/, contents) end end @@ -365,38 +348,3 @@ protected ::DEFAULT_PLUGIN_FILES end end - -class CustomPluginGeneratorTest < Rails::Generators::TestCase - include GeneratorsTestHelper - tests Rails::Generators::PluginNewGenerator - - destination File.join(Rails.root, "tmp/bukkits") - arguments [destination_root] - include SharedCustomGeneratorTests - - def test_overriding_test_framework - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/spec_builder.rb"]) - assert_file 'spec/spec_helper.rb' - assert_file 'spec/dummy' - assert_file 'Rakefile', /task default: :spec/ - assert_file 'Rakefile', /# spec tasks in rakefile/ - end - -protected - def default_files - ::DEFAULT_PLUGIN_FILES - end - - def builder_class - :PluginBuilder - end - - def builders_dir - "plugin_builders" - end - - def action(*args, &block) - silence(:stdout){ generator.send(*args, &block) } - end -end diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index 38454dfb8b..26e56a162c 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -20,33 +20,30 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_match(/@users = User\.all/, m) end - assert_instance_method :show, content do |m| - assert_match(/@user = User\.find\(params\[:id\]\)/, m) - end + assert_instance_method :show, content assert_instance_method :new, content do |m| assert_match(/@user = User\.new/, m) end - assert_instance_method :edit, content do |m| - assert_match(/@user = User\.find\(params\[:id\]\)/, m) - end + assert_instance_method :edit, content assert_instance_method :create, content do |m| assert_match(/@user = User\.new\(user_params\)/, m) assert_match(/@user\.save/, m) - assert_match(/@user\.errors/, m) end assert_instance_method :update, content do |m| - assert_match(/@user = User\.find\(params\[:id\]\)/, m) - assert_match(/@user\.update_attributes\(user_params\)/, m) - assert_match(/@user\.errors/, m) + assert_match(/@user\.update\(user_params\)/, m) end assert_instance_method :destroy, content do |m| - assert_match(/@user = User\.find\(params\[:id\]\)/, m) assert_match(/@user\.destroy/, m) + assert_match(/User was successfully destroyed/, m) + end + + assert_instance_method :set_user, content do |m| + assert_match(/@user = User\.find\(params\[:id\]\)/, m) end assert_match(/def user_params/, content) @@ -54,6 +51,33 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase end end + def test_dont_use_require_or_permit_if_there_are_no_attributes + run_generator ["User"] + + assert_file "app/controllers/users_controller.rb" do |content| + assert_match(/def user_params/, content) + assert_match(/params\[:user\]/, content) + end + end + + def test_controller_permit_references_attributes + run_generator ["LineItem", "product:references", "cart:belongs_to"] + + assert_file "app/controllers/line_items_controller.rb" do |content| + assert_match(/def line_item_params/, content) + assert_match(/params\.require\(:line_item\)\.permit\(:product_id, :cart_id\)/, content) + end + end + + def test_controller_permit_polymorphic_references_attributes + run_generator ["LineItem", "product:references{polymorphic}"] + + assert_file "app/controllers/line_items_controller.rb" do |content| + assert_match(/def line_item_params/, content) + assert_match(/params\.require\(:line_item\)\.permit\(:product_id, :product_type\)/, content) + end + end + def test_helper_are_invoked_with_a_pluralized_name run_generator assert_file "app/helpers/users_helper.rb", /module UsersHelper/ @@ -63,23 +87,20 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_views_are_generated run_generator - %w( - index - edit - new - show - ).each { |view| assert_file "app/views/users/#{view}.html.erb" } + %w(index edit new show).each do |view| + assert_file "app/views/users/#{view}.html.erb" + end assert_no_file "app/views/layouts/users.html.erb" end def test_functional_tests - run_generator + run_generator ["User", "name:string", "age:integer", "organization:references{polymorphic}"] assert_file "test/controllers/users_controller_test.rb" do |content| assert_match(/class UsersControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) - assert_match(/post :create, user: \{ age: @user.age, name: @user.name \}/, content) - assert_match(/put :update, id: @user, user: \{ age: @user.age, name: @user.name \}/, content) + assert_match(/post :create, user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \}/, content) + assert_match(/patch :update, id: @user, user: \{ age: @user\.age, name: @user\.name, organization_id: @user\.organization_id, organization_type: @user\.organization_type \}/, content) end end @@ -90,7 +111,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_match(/class UsersControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) assert_match(/post :create, user: \{ \}/, content) - assert_match(/put :update, id: @user, user: \{ \}/, content) + assert_match(/patch :update, id: @user, user: \{ \}/, content) end end @@ -142,7 +163,16 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_new_hash_style run_generator assert_file "app/controllers/users_controller.rb" do |content| - assert_match(/\{ render action: "new" \}/, content) + assert_match(/render action: 'new'/, content) + end + end + + def test_model_name_option + run_generator ["Admin::User", "--model-name=User"] + assert_file "app/controllers/admin/users_controller.rb" do |content| + assert_instance_method :index, content do |m| + assert_match("@users = User.all", m) + end end end end diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index efe47cdfcb..524bbde2b7 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -30,50 +30,42 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_match(/@product_lines = ProductLine\.all/, m) end - assert_instance_method :show, content do |m| - assert_match(/@product_line = ProductLine\.find\(params\[:id\]\)/, m) - end + assert_instance_method :show, content assert_instance_method :new, content do |m| assert_match(/@product_line = ProductLine\.new/, m) end - assert_instance_method :edit, content do |m| - assert_match(/@product_line = ProductLine\.find\(params\[:id\]\)/, m) - end + assert_instance_method :edit, content assert_instance_method :create, content do |m| assert_match(/@product_line = ProductLine\.new\(product_line_params\)/, m) assert_match(/@product_line\.save/, m) - assert_match(/@product_line\.errors/, m) end assert_instance_method :update, content do |m| - assert_match(/@product_line = ProductLine\.find\(params\[:id\]\)/, m) - assert_match(/@product_line\.update_attributes\(product_line_params\)/, m) - assert_match(/@product_line\.errors/, m) + assert_match(/@product_line\.update\(product_line_params\)/, m) end assert_instance_method :destroy, content do |m| - assert_match(/@product_line = ProductLine\.find\(params\[:id\]\)/, m) assert_match(/@product_line\.destroy/, m) end + + assert_instance_method :set_product_line, content do |m| + assert_match(/@product_line = ProductLine\.find\(params\[:id\]\)/, m) + end end assert_file "test/controllers/product_lines_controller_test.rb" do |test| assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, test) - assert_match(/post :create, product_line: \{ title: @product_line.title \}/, test) - assert_match(/put :update, id: @product_line, product_line: \{ title: @product_line.title \}/, test) + assert_match(/post :create, product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \}/, test) + assert_match(/patch :update, id: @product_line, product_line: \{ product_id: @product_line\.product_id, title: @product_line\.title, user_id: @product_line\.user_id \}/, test) end # Views - %w( - index - edit - new - show - _form - ).each { |view| assert_file "app/views/product_lines/#{view}.html.erb" } + %w(index edit new show _form).each do |view| + assert_file "app/views/product_lines/#{view}.html.erb" + end assert_no_file "app/views/layouts/product_lines.html.erb" # Helpers @@ -93,7 +85,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, content) assert_match(/test "should get index"/, content) assert_match(/post :create, product_line: \{ \}/, content) - assert_match(/put :update, id: @product_line, product_line: \{ \}/, content) + assert_match(/patch :update, id: @product_line, product_line: \{ \}/, content) end end @@ -153,47 +145,39 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_match(/@admin_roles = Admin::Role\.all/, m) end - assert_instance_method :show, content do |m| - assert_match(/@admin_role = Admin::Role\.find\(params\[:id\]\)/, m) - end + assert_instance_method :show, content assert_instance_method :new, content do |m| assert_match(/@admin_role = Admin::Role\.new/, m) end - assert_instance_method :edit, content do |m| - assert_match(/@admin_role = Admin::Role\.find\(params\[:id\]\)/, m) - end + assert_instance_method :edit, content assert_instance_method :create, content do |m| assert_match(/@admin_role = Admin::Role\.new\(admin_role_params\)/, m) assert_match(/@admin_role\.save/, m) - assert_match(/@admin_role\.errors/, m) end assert_instance_method :update, content do |m| - assert_match(/@admin_role = Admin::Role\.find\(params\[:id\]\)/, m) - assert_match(/@admin_role\.update_attributes\(admin_role_params\)/, m) - assert_match(/@admin_role\.errors/, m) + assert_match(/@admin_role\.update\(admin_role_params\)/, m) end assert_instance_method :destroy, content do |m| - assert_match(/@admin_role = Admin::Role\.find\(params\[:id\]\)/, m) assert_match(/@admin_role\.destroy/, m) end + + assert_instance_method :set_admin_role, content do |m| + assert_match(/@admin_role = Admin::Role\.find\(params\[:id\]\)/, m) + end end assert_file "test/controllers/admin/roles_controller_test.rb", /class Admin::RolesControllerTest < ActionController::TestCase/ # Views - %w( - index - edit - new - show - _form - ).each { |view| assert_file "app/views/admin/roles/#{view}.html.erb" } + %w(index edit new show _form).each do |view| + assert_file "app/views/admin/roles/#{view}.html.erb" + end assert_no_file "app/views/layouts/admin/roles.html.erb" # Helpers @@ -211,7 +195,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase run_generator [ "admin/role" ], :behavior => :revoke # Model - assert_file "app/models/admin.rb" # ( should not be remove ) + assert_file "app/models/admin.rb" # ( should not be remove ) assert_no_file "app/models/admin/role.rb" assert_no_file "test/models/admin/role_test.rb" assert_no_file "test/fixtures/admin/roles.yml" @@ -255,13 +239,27 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "config/routes.rb", /\.routes\.draw do\s*\|map\|\s*$/ end - def test_scaffold_generator_no_assets + def test_scaffold_generator_no_assets_with_switch_no_assets run_generator [ "posts", "--no-assets" ] - assert_file "app/assets/stylesheets/scaffold.css" + assert_no_file "app/assets/stylesheets/scaffold.css" + assert_no_file "app/assets/javascripts/posts.js" + assert_no_file "app/assets/stylesheets/posts.css" + end + + def test_scaffold_generator_no_assets_with_switch_assets_false + run_generator [ "posts", "--assets=false" ] + assert_no_file "app/assets/stylesheets/scaffold.css" assert_no_file "app/assets/javascripts/posts.js" assert_no_file "app/assets/stylesheets/posts.css" end + def test_scaffold_generator_no_assets_with_switch_resource_route_false + run_generator [ "posts", "--resource-route=false" ] + assert_file "config/routes.rb" do |route| + assert_no_match(/resources :posts$/, route) + end + end + def test_scaffold_generator_no_stylesheets run_generator [ "posts", "--no-stylesheets" ] assert_no_file "app/assets/stylesheets/scaffold.css" @@ -287,4 +285,69 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end end end + + def test_scaffold_generator_belongs_to + run_generator ["account", "name", "currency:belongs_to"] + + assert_file "app/models/account.rb", /belongs_to :currency/ + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.string :name/, up) + assert_match(/t\.belongs_to :currency/, up) + end + end + + assert_file "app/controllers/accounts_controller.rb" do |content| + assert_instance_method :account_params, content do |m| + assert_match(/permit\(:name, :currency_id\)/, m) + end + end + + assert_file "app/views/accounts/_form.html.erb" do |content| + assert_match(/^\W{4}<%= f\.text_field :name %>/, content) + assert_match(/^\W{4}<%= f\.text_field :currency_id %>/, content) + end + end + + def test_scaffold_generator_password_digest + run_generator ["user", "name", "password:digest"] + + assert_file "app/models/user.rb", /has_secure_password/ + + assert_migration "db/migrate/create_users.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.string :name/, up) + assert_match(/t\.string :password_digest/, up) + end + end + + assert_file "app/controllers/users_controller.rb" do |content| + assert_instance_method :user_params, content do |m| + assert_match(/permit\(:name, :password, :password_confirmation\)/, m) + end + end + + assert_file "app/views/users/_form.html.erb" do |content| + assert_match(/<%= f\.password_field :password %>/, content) + assert_match(/<%= f\.password_field :password_confirmation %>/, content) + end + + assert_file "app/views/users/index.html.erb" do |content| + assert_no_match(/password/, content) + end + + assert_file "app/views/users/show.html.erb" do |content| + assert_no_match(/password/, content) + end + + assert_file "test/controllers/users_controller_test.rb" do |content| + assert_match(/password: 'secret'/, content) + assert_match(/password_confirmation: 'secret'/, content) + end + + assert_file "test/fixtures/users.yml" do |content| + assert_match(/password_digest: <%= BCrypt::Password.create\('secret'\) %>/, content) + end + end end diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 1e5a4545a1..7184639d23 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -46,11 +46,6 @@ module SharedGeneratorTests assert_no_file "test" end - def test_options_before_application_name_raises_an_error - content = capture(:stderr){ run_generator(["--pretend", destination_root]) } - assert_match(/Options should be given after the \w+ name. For details run: rails( plugin)? --help\n/, content) - end - def test_name_collision_raises_an_error reserved_words = %w[application destroy plugin runner test] reserved_words.each do |reserved| @@ -68,22 +63,22 @@ module SharedGeneratorTests def test_shebang_is_added_to_rails_file run_generator [destination_root, "--ruby", "foo/bar/baz", "--full"] - assert_file "script/rails", /#!foo\/bar\/baz/ + assert_file "bin/rails", /#!foo\/bar\/baz/ end def test_shebang_when_is_the_same_as_default_use_env run_generator [destination_root, "--ruby", Thor::Util.ruby_command, "--full"] - assert_file "script/rails", /#!\/usr\/bin\/env/ + assert_file "bin/rails", /#!\/usr\/bin\/env/ end def test_template_raises_an_error_with_invalid_path - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existant/path"]) } + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } assert_match(/The template \[.*\] could not be loaded/, content) - assert_match(/non\/existant\/path/, content) + assert_match(/non\/existent\/path/, content) end def test_template_is_executed_when_supplied - path = "http://gist.github.com/103208.txt" + path = "https://gist.github.com/josevalim/103208/raw/" template = %{ say "It works!" } template.instance_eval "def read; self; end" # Make the string respond to read @@ -92,7 +87,7 @@ module SharedGeneratorTests end def test_template_is_executed_when_supplied_an_https_path - path = "https://gist.github.com/103208.txt" + path = "https://gist.github.com/josevalim/103208/raw/" template = %{ say "It works!" } template.instance_eval "def read; self; end" # Make the string respond to read @@ -140,61 +135,3 @@ module SharedGeneratorTests assert_no_file('app/mailers/.keep') end end - -module SharedCustomGeneratorTests - def setup - Rails.application = TestApp::Application - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - end - - def teardown - super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) - Object.class_eval do - remove_const :AppBuilder if const_defined?(:AppBuilder) - remove_const :PluginBuilder if const_defined?(:PluginBuilder) - end - Rails.application = TestApp::Application.instance - end - - def test_builder_option_with_empty_app_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/empty_builder.rb"]) - default_files.each{ |path| assert_no_file path } - end - - def test_builder_option_with_simple_plugin_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/simple_builder.rb"]) - (default_files - ['.gitignore']).each{ |path| assert_no_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_relative_path - here = File.expand_path(File.dirname(__FILE__)) - FileUtils.cd(here) - run_generator([destination_root, "-b", "../fixtures/lib/#{builders_dir}/simple_builder.rb"]) - FileUtils.cd(destination_root) - (default_files - ['.gitignore']).each{ |path| assert_no_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_tweak_plugin_builder - FileUtils.cd(destination_root) - run_generator([destination_root, "-b", "#{Rails.root}/lib/#{builders_dir}/tweak_builder.rb"]) - default_files.each{ |path| assert_file path } - assert_file ".gitignore", "foobar" - end - - def test_builder_option_with_http - url = "http://gist.github.com/103208.txt" - template = "class #{builder_class}; end" - template.instance_eval "def read; self; end" # Make the string respond to read - - generator([destination_root], builder: url).expects(:open).with(url, 'Accept' => 'application/x-thor-template').returns(template) - quietly { generator.invoke_all } - - default_files.each{ |path| assert_no_file(path) } - end -end diff --git a/railties/test/generators/task_generator_test.rb b/railties/test/generators/task_generator_test.rb index f810a21d1e..9399be9510 100644 --- a/railties/test/generators/task_generator_test.rb +++ b/railties/test/generators/task_generator_test.rb @@ -5,7 +5,7 @@ class TaskGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(feeds foo bar) - def test_controller_skeleton_is_created + def test_task_is_created run_generator assert_file "lib/tasks/feeds.rake", /namespace :feeds/ end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 9953aa929b..eac28badfe 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -15,7 +15,7 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_simple_invoke - assert File.exists?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke("test_unit:model", ["Account"]) end @@ -31,7 +31,7 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_should_give_higher_preference_to_rails_generators - assert File.exists?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) Rails::Generators::ModelGenerator.expects(:start).with(["Account"], {}) warnings = capture(:stderr){ Rails::Generators.invoke :model, ["Account"] } assert warnings.empty? @@ -106,7 +106,7 @@ class GeneratorsTest < Rails::Generators::TestCase def test_rails_generators_help_does_not_include_app_nor_plugin_new output = capture(:stdout){ Rails::Generators.help } assert_no_match(/app/, output) - assert_no_match(/plugin_new/, output) + assert_no_match(/[^:]plugin/, output) end def test_rails_generators_with_others_information @@ -164,7 +164,7 @@ class GeneratorsTest < Rails::Generators::TestCase Rails::Generators.invoke "super_shoulda:model", ["Account"] end - def test_developer_options_are_overwriten_by_user_options + def test_developer_options_are_overwritten_by_user_options Rails::Generators.options[:with_options] = { generate: false } self.class.class_eval(<<-end_eval, __FILE__, __LINE__ + 1) diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index 16e259be5d..ed9573453b 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -20,14 +20,6 @@ module InitializableTests end end - module Word - include Rails::Initializable - - initializer :word do - $word = "bird" - end - end - class Parent include Rails::Initializable @@ -235,4 +227,4 @@ module InitializableTests assert_equal [1, 2, 3, 4], $arr end end -end
\ No newline at end of file +end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index e59488f97d..913e2b5e29 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -9,7 +9,7 @@ require 'fileutils' require 'bundler/setup' unless defined?(Bundler) -require 'minitest/autorun' +require 'active_support/testing/autorun' require 'active_support/test_case' RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..") @@ -119,7 +119,7 @@ module TestHelpers add_to_config <<-RUBY config.eager_load = false - config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log config.action_controller.allow_forgery_protection = false @@ -135,10 +135,11 @@ module TestHelpers def make_basic_app require "rails" require "action_controller/railtie" + require "action_view/railtie" app = Class.new(Rails::Application) app.config.eager_load = false - app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" + app.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" app.config.session_store :cookie_store, key: "_myapp_session" app.config.active_support.deprecation = :log @@ -163,7 +164,7 @@ module TestHelpers RUBY app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get ':controller(/:action)' end RUBY @@ -206,7 +207,7 @@ module TestHelpers def script(script) Dir.chdir(app_path) do - `#{Gem.ruby} #{app_path}/script/rails #{script}` + `#{Gem.ruby} #{app_path}/bin/rails #{script}` end end @@ -242,6 +243,12 @@ module TestHelpers end end + def gsub_app_file(path, regexp, *args, &block) + path = "#{app_path}/#{path}" + content = File.read(path).gsub(regexp, *args, &block) + File.open(path, 'wb') { |f| f.write(content) } + end + def remove_file(path) FileUtils.rm_rf "#{app_path}/#{path}" end @@ -279,7 +286,7 @@ Module.new do environment = File.expand_path('../../../../load_paths', __FILE__) require_environment = "-r #{environment}" - `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails new #{app_template_path} --skip-gemfile` + `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/bin/rails new #{app_template_path} --skip-gemfile --no-rc` File.open("#{app_template_path}/config/boot.rb", 'w') do |f| f.puts "require '#{environment}'" f.puts "require 'rails/all'" diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 12f18b9dbf..ed4559ec6f 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -3,7 +3,7 @@ require 'rails/paths' class PathsTest < ActiveSupport::TestCase def setup - File.stubs(:exists?).returns(true) + File.stubs(:exist?).returns(true) @root = Rails::Paths::Root.new("/foo/bar") end @@ -180,7 +180,7 @@ class PathsTest < ActiveSupport::TestCase assert_equal 1, @root.eager_load.select {|p| p == @root["app"].expanded.first }.size end - test "paths added to a eager_load path should be added to the eager_load collection" do + test "paths added to an eager_load path should be added to the eager_load collection" do @root["app"] = "/app" @root["app"].eager_load! @root["app"] << "/app2" diff --git a/railties/test/rack_logger_test.rb b/railties/test/rack_logger_test.rb new file mode 100644 index 0000000000..6ebd47fff9 --- /dev/null +++ b/railties/test/rack_logger_test.rb @@ -0,0 +1,75 @@ +require 'abstract_unit' +require 'active_support/testing/autorun' +require 'active_support/test_case' +require 'rails/rack/logger' +require 'logger' + +module Rails + module Rack + class LoggerTest < ActiveSupport::TestCase + class TestLogger < Rails::Rack::Logger + NULL = ::Logger.new File::NULL + + attr_reader :logger + + def initialize(logger = NULL, taggers = nil, &block) + super(->(_) { block.call; [200, {}, []] }, taggers) + @logger = logger + end + + def development?; false; end + end + + class Subscriber < Struct.new(:starts, :finishes) + def initialize(starts = [], finishes = []) + super + end + + def start(name, id, payload) + starts << [name, id, payload] + end + + def finish(name, id, payload) + finishes << [name, id, payload] + end + end + + attr_reader :subscriber, :notifier + + def setup + @subscriber = Subscriber.new + @notifier = ActiveSupport::Notifications.notifier + notifier.subscribe 'request.action_dispatch', subscriber + end + + def teardown + notifier.unsubscribe subscriber + end + + def test_notification + logger = TestLogger.new { } + + assert_difference('subscriber.starts.length') do + assert_difference('subscriber.finishes.length') do + logger.call('REQUEST_METHOD' => 'GET').last.close + end + end + end + + def test_notification_on_raise + logger = TestLogger.new do + # using an exception class that is not a StandardError subclass on purpose + raise NotImplementedError + end + + assert_difference('subscriber.starts.length') do + assert_difference('subscriber.finishes.length') do + assert_raises(NotImplementedError) do + logger.call 'REQUEST_METHOD' => 'GET' + end + end + end + end + end + end +end diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index 08fcddd4bf..e45a5228a1 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,5 +1,7 @@ require 'abstract_unit' +ActionController::Base.superclass.send(:include, ActionView::Layouts) + module ActionController class Base include ActionController::Testing @@ -50,7 +52,7 @@ class InfoControllerTest < ActionController::TestCase test "info controller renders with routes" do get :routes - assert_select 'pre' + assert_response :success end end diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index b9fb071d23..44a5fd1904 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -37,8 +37,13 @@ class InfoTest < ActiveSupport::TestCase assert_property 'Goodbye', 'World' end + def test_rails_version + assert_property 'Rails version', + File.read(File.realpath('../../../RAILS_VERSION', __FILE__)).chomp + end + def test_framework_version - assert_property 'Active Support version', ActiveSupport::VERSION::STRING + assert_property 'Active Support version', ActiveSupport.version.to_s end def test_frameworks_exist diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index fcbe7b6cda..3075ffee0d 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -90,8 +90,8 @@ module RailtiesTest Dir.chdir(app_path) do output = `bundle exec rake bukkits:install:migrations` - assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb") - assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/2_create_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb") assert_match(/Copied migration 2_create_users.bukkits.rb from bukkits/, output) assert_match(/Copied migration 3_add_last_name_to_users.bukkits.rb from bukkits/, output) assert_match(/NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output) @@ -105,7 +105,7 @@ module RailtiesTest assert_not_nil bukkits_migration_order, "Expected migration to be skipped" migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length - output = `bundle exec rake railties:install:migrations` + `bundle exec rake railties:install:migrations` assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length end @@ -136,7 +136,7 @@ module RailtiesTest Dir.chdir(@plugin.path) do output = `bundle exec rake app:bukkits:install:migrations` - assert File.exists?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb") + assert File.exist?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb") assert_match(/Copied migration 0_add_first_name_to_users.bukkits.rb from bukkits/, output) assert_equal 1, Dir["#{app_path}/db/migrate/*.rb"].length end @@ -187,7 +187,7 @@ module RailtiesTest assert_equal "Hello bukkits\n", response[2].body end - test "adds its views to view paths with lower proriority than app ones" do + test "adds its views to view paths with lower priority than app ones" do @plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY class BukkitController < ActionController::Base def index @@ -270,7 +270,7 @@ module RailtiesTest RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get 'foo', :to => 'foo#index' end RUBY @@ -345,7 +345,7 @@ YAML #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml - #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml + #{RAILS_FRAMEWORK_ROOT}/actionview/lib/action_view/locale/en.yml #{@plugin.path}/config/locales/en.yml #{app_path}/config/locales/en.yml #{app_path}/app/locales/en.yml @@ -416,11 +416,6 @@ YAML boot_rails end - test "Rails::Engine itself does not respond to config" do - boot_rails - assert !Rails::Engine.respond_to?(:config) - end - test "initializers are executed after application configuration initializers" do @plugin.write "lib/bukkits.rb", <<-RUBY module Bukkits @@ -472,7 +467,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount(Bukkits::Engine => "/bukkits") end RUBY @@ -568,7 +563,7 @@ YAML @plugin.write "lib/bukkits.rb", <<-RUBY module Bukkits class Engine < ::Rails::Engine - endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'hello'] } + endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, ['hello']] } end end RUBY @@ -607,7 +602,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get "/bar" => "bar#index", as: "bar" mount Bukkits::Engine => "/bukkits", as: "bukkits" end @@ -725,7 +720,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Bukkits::Engine => "/bukkits", as: "bukkits" end RUBY @@ -769,7 +764,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Bukkits::Awesome::Engine => "/bukkits", :as => "bukkits" end RUBY @@ -833,7 +828,7 @@ YAML add_to_config "isolate_namespace AppTemplate" app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do end + Rails.application.routes.draw do end RUBY boot_rails @@ -1211,7 +1206,7 @@ YAML RUBY app_file "config/routes.rb", <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do get '/bar' => 'bar#index', :as => 'bar' mount Bukkits::Engine => "/bukkits", :as => "bukkits" end diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index 0abb2b7578..7348d70c56 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -44,7 +44,7 @@ module RailtiesTests Dir.chdir(engine_path) do File.open("Gemfile", "w") do |f| f.write <<-GEMFILE.gsub(/^ {12}/, '') - source "http://rubygems.org" + source "https://rubygems.org" gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}' gem 'sqlite3' diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index a1c52f01dc..0ef2ff2e2e 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -13,9 +13,10 @@ module ApplicationTests @simple_plugin = engine "weblog" @plugin = engine "blog" + @metrics_plugin = engine "metrics" app_file 'config/routes.rb', <<-RUBY - AppTemplate::Application.routes.draw do + Rails.application.routes.draw do mount Weblog::Engine, :at => '/', :as => 'weblog' resources :posts get "/engine_route" => "application_generating#engine_route" @@ -28,6 +29,7 @@ module ApplicationTests scope "/:user", :user => "anonymous" do mount Blog::Engine => "/blog" end + mount Metrics::Engine => "/metrics" root :to => 'main#index' end RUBY @@ -54,6 +56,34 @@ module ApplicationTests end RUBY + @metrics_plugin.write "lib/metrics.rb", <<-RUBY + module Metrics + class Engine < ::Rails::Engine + isolate_namespace(Metrics) + end + end + RUBY + + @metrics_plugin.write "config/routes.rb", <<-RUBY + Metrics::Engine.routes.draw do + get '/generate_blog_route', to: 'generating#generate_blog_route' + get '/generate_blog_route_in_view', to: 'generating#generate_blog_route_in_view' + end + RUBY + + @metrics_plugin.write "app/controllers/metrics/generating_controller.rb", <<-RUBY + module Metrics + class GeneratingController < ActionController::Base + def generate_blog_route + render text: blog.post_path(1) + end + + def generate_blog_route_in_view + render inline: "<%= blog.post_path(1) -%>" + end + end + end + RUBY @plugin.write "app/models/blog/post.rb", <<-RUBY module Blog @@ -89,6 +119,7 @@ module ApplicationTests get '/generate_application_route', to: 'posts#generate_application_route' get '/application_route_in_view', to: 'posts#application_route_in_view' get '/engine_polymorphic_path', to: 'posts#engine_polymorphic_path' + get '/engine_asset_path', to: 'posts#engine_asset_path' end RUBY @@ -113,6 +144,10 @@ module ApplicationTests def engine_polymorphic_path render text: polymorphic_path(Post.new) end + + def engine_asset_path + render inline: "<%= asset_path 'images/foo.png' %>" + end end end RUBY @@ -196,6 +231,21 @@ module ApplicationTests get "/somone/blog/application_route_in_view" assert_equal "/", last_response.body + # test generating engine's route from other engine + get "/metrics/generate_blog_route" + assert_equal '/anonymous/blog/posts/1', last_response.body + + get "/metrics/generate_blog_route_in_view" + assert_equal '/anonymous/blog/posts/1', last_response.body + + # test generating engine's route from other engine with default_url_options + get "/metrics/generate_blog_route", {}, 'SCRIPT_NAME' => '/foo' + assert_equal '/foo/anonymous/blog/posts/1', last_response.body + + get "/metrics/generate_blog_route_in_view", {}, 'SCRIPT_NAME' => '/foo' + assert_equal '/foo/anonymous/blog/posts/1', last_response.body + + # test generating application's route from engine with default_url_options get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo' assert_equal "/foo/", last_response.body @@ -211,6 +261,10 @@ module ApplicationTests # and in an application get "/application_polymorphic_path" assert_equal "/posts/44", last_response.body + + # test that asset path will not get script_name when generated in the engine + get "/someone/blog/engine_asset_path" + assert_equal "/images/foo.png", last_response.body end test "route path for controller action when engine is mounted at root" do diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index c80b0f63af..4cbd4822be 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -19,33 +19,26 @@ module RailtiesTest @app ||= Rails.application end - test "Rails::Railtie itself does not respond to config" do - assert !Rails::Railtie.respond_to?(:config) + test "cannot instantiate a Railtie object" do + assert_raise(RuntimeError) { Rails::Railtie.new } end test "Railtie provides railtie_name" do begin class ::FooBarBaz < Rails::Railtie ; end - assert_equal "foo_bar_baz", ::FooBarBaz.railtie_name + assert_equal "foo_bar_baz", FooBarBaz.railtie_name ensure Object.send(:remove_const, :"FooBarBaz") end end - test "railtie_name can be set manualy" do + test "railtie_name can be set manually" do class Foo < Rails::Railtie railtie_name "bar" end assert_equal "bar", Foo.railtie_name end - test "cannot inherit from a railtie" do - class Foo < Rails::Railtie ; end - assert_raise RuntimeError do - class Bar < Foo; end - end - end - test "config is available to railtie" do class Foo < Rails::Railtie ; end assert_nil Foo.config.action_controller.foo @@ -65,7 +58,7 @@ module RailtiesTest config.foo.greetings = "hello" end require "#{app_path}/config/application" - assert_equal "hello", AppTemplate::Application.config.foo.greetings + assert_equal "hello", Rails.application.config.foo.greetings end test "railtie can add to_prepare callbacks" do @@ -103,7 +96,7 @@ module RailtiesTest require 'rake/testtask' require 'rdoc/task' - AppTemplate::Application.load_tasks + Rails.application.load_tasks assert $ran_block end @@ -127,7 +120,7 @@ module RailtiesTest require 'rake/testtask' require 'rdoc/task' - AppTemplate::Application.load_tasks + Rails.application.load_tasks assert $ran_block.include?("my_tie") end @@ -143,7 +136,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_generators + Rails.application.load_generators assert $ran_block end @@ -159,7 +152,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_console + Rails.application.load_console assert $ran_block end @@ -175,7 +168,7 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - AppTemplate::Application.load_runner + Rails.application.load_runner assert $ran_block end diff --git a/railties/test/script_rails_loader_test.rb b/railties/test/script_rails_loader_test.rb deleted file mode 100644 index 3ccc147749..0000000000 --- a/railties/test/script_rails_loader_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'abstract_unit' -require 'rails/script_rails_loader' - -class ScriptRailsLoaderTest < ActiveSupport::TestCase - - test "is in a rails application if script/rails exists" do - File.stubs(:exists?).returns(true) - assert Rails::ScriptRailsLoader.in_rails_application? - end - - test "is in a rails application if parent directory has script/rails" do - File.stubs(:exists?).with("/foo/bar/script/rails").returns(false) - File.stubs(:exists?).with("/foo/script/rails").returns(true) - assert Rails::ScriptRailsLoader.in_rails_application_subdirectory?(Pathname.new("/foo/bar")) - end - - test "is not in a rails application if at the root directory and doesn't have script/rails" do - Pathname.any_instance.stubs(:root?).returns true - assert !Rails::ScriptRailsLoader.in_rails_application? - end - -end
\ No newline at end of file diff --git a/railties/test/test_info_test.rb b/railties/test/test_info_test.rb new file mode 100644 index 0000000000..b9c3a9c0c7 --- /dev/null +++ b/railties/test/test_info_test.rb @@ -0,0 +1,60 @@ +require 'abstract_unit' +require 'rails/test_unit/sub_test_task' + +module Rails + class TestInfoTest < ActiveSupport::TestCase + def test_test_files + info = new_test_info ['test'] + assert_predicate info.files, :empty? + assert_nil info.opts + assert_equal ['test'], info.tasks + end + + def test_with_file + info = new_test_info ['test', __FILE__] + assert_equal [__FILE__], info.files + assert_nil info.opts + assert_equal ['test'], info.tasks + end + + def test_with_opts + info = new_test_info ['test', __FILE__, '/foo/'] + assert_equal [__FILE__], info.files + assert_equal '-n /foo/', info.opts + assert_equal ['test'], info.tasks + end + + def test_with_model_shorthand + info = new_test_info ['test', 'models/foo', '/foo/'] + + def info.test_file?(file) + file == "test/models/foo_test.rb" || super + end + + assert_equal ['test/models/foo_test.rb'], info.files + assert_equal '-n /foo/', info.opts + assert_equal ['test'], info.tasks + end + + def test_with_model_path + info = new_test_info ['test', 'app/models/foo.rb', '/foo/'] + + def info.test_file?(file) + file == "test/models/foo_test.rb" || super + end + + assert_equal ['test/models/foo_test.rb'], info.files + assert_equal '-n /foo/', info.opts + assert_equal ['test'], info.tasks + end + + private + def new_test_info(tasks) + Class.new(TestTask::TestInfo) { + def task_defined?(task) + task == "test" + end + }.new tasks + end + end +end |