diff options
213 files changed, 2009 insertions, 2967 deletions
@@ -6,9 +6,9 @@ gem 'arel', github: 'rails/arel', branch: 'master' gem 'mocha', '>= 0.11.2', :require => false gem 'rack-test', github: 'brynary/rack-test' -gem 'rack-cache', "~> 1.2" +gem 'rack-cache', '~> 1.2' gem 'bcrypt-ruby', '~> 3.0.0' -gem 'jquery-rails' +gem 'jquery-rails', '~> 2.1.4', github: 'rails/jquery-rails' gem 'turbolinks' gem 'coffee-rails', github: 'rails/coffee-rails' @@ -28,7 +28,7 @@ group :doc do # for some weeks unapplied. As a temporary solution # this is our own fork with the fix. gem 'sdoc', github: 'fxn/sdoc' - gem 'redcarpet', '~> 2.1.1' + gem 'redcarpet', '~> 2.1.1', :platforms => :ruby gem 'w3c_validators' end @@ -41,8 +41,8 @@ instance_eval File.read local_gemfile if File.exists? local_gemfile platforms :mri do group :test do - gem 'ruby-prof', '~> 0.11.2' - gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < "2.0" + gem 'ruby-prof', '~> 0.11.2' if RUBY_VERSION < '2.0' + gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < '2.0' && RUBY_PATCHLEVEL < 286 end end diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index e29890f2d8..68b34805ff 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -27,4 +27,8 @@ * Asynchronously send messages via the Rails Queue *Brian Cardarella* +* Allow callbacks to be defined in mailers similar to `ActionController::Base`. You can configure default + settings, headers, attachments, delivery settings or change delivery using + `before_filter`, `after_filter` etc. *Justin S. Leitgeb* + Please check [3-2-stable](https://github.com/rails/rails/blob/3-2-stable/actionmailer/CHANGELOG.md) for previous changes. diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index cf10bfffdb..59c33b7940 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -83,7 +83,7 @@ Note that every value you set with this method will get over written if you use Example: class AuthenticationMailer < ActionMailer::Base - default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" } + default from: "awesome@application.com", subject: Proc.new { "E-mail was generated at #{Time.now}" } ..... end @@ -100,13 +100,13 @@ Example: def receive(email) page = Page.find_by_address(email.to.first) page.emails.create( - :subject => email.subject, :body => email.body + subject: email.subject, body: email.body ) if email.has_attachments? email.attachments.each do |attachment| page.attachments.create({ - :file => attachment, :description => email.subject + file: attachment, description: email.subject }) end end @@ -127,11 +127,11 @@ a limited number of email. The Base class has the full list of configuration options. Here's an example: ActionMailer::Base.smtp_settings = { - :address => 'smtp.yourserver.com', # default: localhost - :port => '25', # default: 25 - :user_name => 'user', - :password => 'pass', - :authentication => :plain # :plain, :login or :cram_md5 + address: 'smtp.yourserver.com', # default: localhost + port: '25', # default: 25 + user_name: 'user', + password: 'pass', + authentication: :plain # :plain, :login or :cram_md5 } diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index abf6ad80cf..59dc26841f 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -22,7 +22,6 @@ module ActionMailer options.queue ||= app.queue # make sure readers methods get compiled - options.asset_path ||= app.config.asset_path options.asset_host ||= app.config.asset_host options.relative_url_root ||= app.config.relative_url_root diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 77010ecc70..c8773c9179 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,12 @@ ## Rails 4.0.0 (unreleased) ## +* `assert_template` can be used to assert on the same template with different locals + Fix #3675 + + *Yves Senn* + +* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline). *Josh Peek* + * Accept :remote as symbolic option for `link_to` helper. *Riley Lynch* * Warn when the `:locals` option is passed to `assert_template` outside of a view test case diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index 822254b1a4..e6170228d9 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -3,7 +3,7 @@ module AbstractController extend ActiveSupport::Concern included do - config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, + config_accessor :asset_host, :assets_dir, :javascripts_dir, :stylesheets_dir, :default_asset_host_protocol, :relative_url_root end end diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 9c3960961b..388e043f0b 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -217,8 +217,10 @@ module AbstractController # * <tt>string</tt> - The name of the method that handles the action # * <tt>nil</tt> - No method name could be found. Raise ActionNotFound. def method_for_action(action_name) - if action_method?(action_name) then action_name - elsif respond_to?(:action_missing, true) then "_handle_action_missing" + if action_method?(action_name) + action_name + elsif respond_to?(:action_missing, true) + "_handle_action_missing" end end end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 6b8d9384d4..9b3bf99fc3 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -43,7 +43,7 @@ module ActionController # # def server_ip # location = request.env["SERVER_ADDR"] - # render :text => "This server hosted at #{location}" + # render text: "This server hosted at #{location}" # end # # == Parameters @@ -113,9 +113,9 @@ module ActionController # def search # @results = Search.find(params[:query]) # case @results.count - # when 0 then render :action => "no_results" - # when 1 then render :action => "show" - # when 2..10 then render :action => "show_many" + # when 0 then render action: "no_results" + # when 1 then render action: "show" + # when 2..10 then render action: "show_many" # end # end # @@ -131,7 +131,7 @@ module ActionController # @entry = Entry.new(params[:entry]) # if @entry.save # # The entry was saved correctly, redirect to show - # redirect_to :action => 'show', :id => @entry.id + # redirect_to action: 'show', id: @entry.id # else # # things didn't go so well, do something else # end @@ -148,15 +148,15 @@ module ActionController # An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError: # # def do_something - # redirect_to :action => "elsewhere" - # render :action => "overthere" # raises DoubleRenderError + # redirect_to action: "elsewhere" + # render action: "overthere" # raises DoubleRenderError # end # # If you need to redirect on the condition of something, then be sure to add "and return" to halt execution. # # def do_something - # redirect_to(:action => "elsewhere") and return if monkeys.nil? - # render :action => "overthere" # won't be called if monkeys is nil + # redirect_to(action: "elsewhere") and return if monkeys.nil? + # render action: "overthere" # won't be called if monkeys is nil # end # class Base < Metal diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 398454d39f..6f46954266 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -171,13 +171,38 @@ module ActionController # permitted[:person][:age] # => nil # permitted[:person][:pets][0][:name] # => "Purplish" # permitted[:person][:pets][0][:category] # => nil + # + # Note that if you use +permit+ in a key that points to a hash, + # it won't allow all the hash. You also need to specify which + # attributes inside the hash should be whitelisted. + # + # params = ActionController::Parameters.new({ + # person: { + # contact: { + # email: 'none@test.com' + # phone: '555-1234' + # } + # } + # }) + # + # params.require(:person).permit(:contact) + # # => {} + # + # params.require(:person).permit(contact: :phone) + # # => {"contact"=>{"phone"=>"555-1234"}} + # + # params.require(:person).permit(contact: [ :email, :phone ]) + # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}} def permit(*filters) params = self.class.new filters.each do |filter| case filter when Symbol, String then - params[filter] = self[filter] if has_key?(filter) + if has_key?(filter) + _value = self[filter] + params[filter] = _value unless Hash === _value + end keys.grep(/\A#{Regexp.escape(filter)}\(\di\)\z/) { |key| params[key] = self[key] } when Hash then self.slice(*filter.keys).each do |key, values| diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index ee0f053bad..3e44155f73 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -34,7 +34,6 @@ module ActionController options.stylesheets_dir ||= paths["public/stylesheets"].first # Ensure readers methods get compiled - options.asset_path ||= app.config.asset_path options.asset_host ||= app.config.asset_host options.relative_url_root ||= app.config.relative_url_root diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index ace5a2c822..d911d47a1d 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -123,11 +123,12 @@ module ActionController if expected_partial = options[:partial] if expected_locals = options[:locals] - if defined?(@locals) - actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')] - expected_locals.each_pair do |k,v| - assert_equal(v, actual_locals[k]) - end + if defined?(@_rendered_views) + view = expected_partial.to_s.sub(/^_/,'') + msg = 'expecting %s to be rendered with %s but was with %s' % [expected_partial, + expected_locals, + @_rendered_views.locals_for(view)] + assert(@_rendered_views.view_rendered?(view, options[:locals]), msg) else warn "the :locals option to #assert_template is only supported in a ActionView::TestCase" end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 402f29cd76..0de10695e0 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -6,7 +6,7 @@ module ActionDispatch # and calls an exceptions app that will wrap it in a format for the end user. # # The exceptions app should be passed as parameter on initialization - # of ShowExceptions. Everytime there is an exception, ShowExceptions will + # of ShowExceptions. Every time there is an exception, ShowExceptions will # store the exception in env["action_dispatch.exception"], rewrite the # PATH_INFO to the exception status code and call the rack app. # diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 091b0d8cd2..8bbf52382a 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -29,7 +29,6 @@ module ActionView extend ActiveSupport::Autoload eager_autoload do - autoload :AssetPaths autoload :Base autoload :Context autoload :CompiledTemplates, "action_view/context" diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb deleted file mode 100644 index 4bbb31b3ee..0000000000 --- a/actionpack/lib/action_view/asset_paths.rb +++ /dev/null @@ -1,143 +0,0 @@ -require 'zlib' -require 'active_support/core_ext/file' - -module ActionView - class AssetPaths #:nodoc: - URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//} - - attr_reader :config, :controller - - def initialize(config, controller = nil) - @config = config - @controller = controller - end - - # Add the extension +ext+ if not present. Return full or scheme-relative URLs otherwise untouched. - # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL - # roots. Rewrite the asset path for cache-busting asset ids. Include - # asset host, if configured, with the correct request protocol. - # - # When :relative (default), the protocol will be determined by the client using current protocol - # When :request, the protocol will be the request protocol - # Otherwise, the protocol is used (E.g. :http, :https, etc) - def compute_public_path(source, dir, options = {}) - source = source.to_s - return source if is_uri?(source) - - source = rewrite_extension(source, dir, options[:ext]) if options[:ext] - source = rewrite_asset_path(source, dir, options) - source = rewrite_relative_url_root(source, relative_url_root) - source = rewrite_host_and_protocol(source, options[:protocol]) - source - end - - # Return the filesystem path for the source - def compute_source_path(source, dir, ext) - source = rewrite_extension(source, dir, ext) if ext - - sources = [] - sources << config.assets_dir - sources << dir unless source[0] == ?/ - sources << source - - File.join(sources) - end - - def is_uri?(path) - path =~ URI_REGEXP - end - - private - - def rewrite_extension(source, dir, ext) - raise NotImplementedError - end - - def rewrite_asset_path(source, path = nil) - raise NotImplementedError - end - - def rewrite_relative_url_root(source, relative_url_root) - relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source - end - - def has_request? - controller.respond_to?(:request) - end - - def rewrite_host_and_protocol(source, protocol = nil) - host = compute_asset_host(source) - if host && !is_uri?(host) - if (protocol || default_protocol) == :request && !has_request? - host = nil - else - host = "#{compute_protocol(protocol)}#{host}" - end - end - host ? "#{host}#{source}" : source - end - - def compute_protocol(protocol) - protocol ||= default_protocol - case protocol - when :relative - "//" - when :request - unless @controller - invalid_asset_host!("The protocol requested was :request. Consider using :relative instead.") - end - @controller.request.protocol - else - "#{protocol}://" - end - end - - def default_protocol - @config.default_asset_host_protocol || (has_request? ? :request : :relative) - end - - def invalid_asset_host!(help_message) - raise ActionView::MissingRequestError, "This asset host cannot be computed without a request in scope. #{help_message}" - end - - # Pick an asset host for this source. Returns +nil+ if no host is set, - # the host if no wildcard is set, the host interpolated with the - # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4), - # or the value returned from invoking call on an object responding to call - # (proc or otherwise). - def compute_asset_host(source) - if host = asset_host_config - if host.respond_to?(:call) - args = [source] - arity = arity_of(host) - if (arity > 1 || arity < -2) && !has_request? - invalid_asset_host!("Remove the second argument to your asset_host Proc if you do not need the request, or make it optional.") - end - args << current_request if (arity > 1 || arity < 0) && has_request? - host.call(*args) - else - (host =~ /%d/) ? host % (Zlib.crc32(source) % 4) : host - end - end - end - - def relative_url_root - config.relative_url_root || current_request.try(:script_name) - end - - def asset_host_config - config.asset_host - end - - # Returns the current request if one exists. - def current_request - controller.request if has_request? - end - - # Returns the arity of a callable - def arity_of(callable) - callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity - end - - end -end diff --git a/actionpack/lib/action_view/digestor.rb b/actionpack/lib/action_view/digestor.rb index 5d3add4091..f5852dbe73 100644 --- a/actionpack/lib/action_view/digestor.rb +++ b/actionpack/lib/action_view/digestor.rb @@ -64,7 +64,7 @@ module ActionView end def directory - name.split("/").first + name.split("/")[0..-2].join("/") end def partial? diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index f2a3a494bc..269e78a021 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -4,6 +4,7 @@ module ActionView #:nodoc: autoload :ActiveModelHelper autoload :AssetTagHelper + autoload :AssetUrlHelper autoload :AtomFeedHelper autoload :BenchmarkHelper autoload :CacheHelper @@ -28,12 +29,9 @@ module ActionView #:nodoc: extend ActiveSupport::Concern - included do - extend SanitizeHelper::ClassMethods - end - include ActiveModelHelper include AssetTagHelper + include AssetUrlHelper include AtomFeedHelper include BenchmarkHelper include CacheHelper diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 5b5fc84e90..4eac6514df 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -1,8 +1,6 @@ require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/hash/keys' -require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers' -require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers' -require 'action_view/helpers/asset_tag_helpers/asset_paths' +require 'action_view/helpers/asset_url_helper' require 'action_view/helpers/tag_helper' module ActionView @@ -17,187 +15,87 @@ module ActionView # stylesheet_link_tag("application") # # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" /> # - # - # === Using asset hosts - # - # By default, Rails links to these assets on the current host in the public - # folder, but you can direct Rails to link to assets from a dedicated asset - # server by setting <tt>ActionController::Base.asset_host</tt> in the application - # configuration, typically in <tt>config/environments/production.rb</tt>. - # For example, you'd define <tt>assets.example.com</tt> to be your asset - # host this way, inside the <tt>configure</tt> block of your environment-specific - # configuration files or <tt>config/application.rb</tt>: - # - # config.action_controller.asset_host = "assets.example.com" - # - # Helpers take that into account: - # - # image_tag("rails.png") - # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" /> - # stylesheet_link_tag("application") - # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" /> - # - # Browsers typically open at most two simultaneous connections to a single - # host, which means your assets often have to wait for other assets to finish - # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the - # +asset_host+. For example, "assets%d.example.com". If that wildcard is - # present Rails distributes asset requests among the corresponding four hosts - # "assets0.example.com", ..., "assets3.example.com". With this trick browsers - # will open eight simultaneous connections rather than two. - # - # image_tag("rails.png") - # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" /> - # stylesheet_link_tag("application") - # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" /> - # - # To do this, you can either setup four actual hosts, or you can use wildcard - # DNS to CNAME the wildcard to a single asset host. You can read more about - # setting up your DNS CNAME records from your ISP. - # - # Note: This is purely a browser performance optimization and is not meant - # for server load balancing. See http://www.die.net/musings/page_load_time/ - # for background. - # - # Alternatively, you can exert more control over the asset host by setting - # +asset_host+ to a proc like this: - # - # ActionController::Base.asset_host = Proc.new { |source| - # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com" - # } - # image_tag("rails.png") - # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" /> - # stylesheet_link_tag("application") - # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" /> - # - # The example above generates "http://assets1.example.com" and - # "http://assets2.example.com". This option is useful for example if - # you need fewer/more than four hosts, custom host names, etc. - # - # As you see the proc takes a +source+ parameter. That's a string with the - # absolute path of the asset, for example "/assets/rails.png". - # - # ActionController::Base.asset_host = Proc.new { |source| - # if source.ends_with?('.css') - # "http://stylesheets.example.com" - # else - # "http://assets.example.com" - # end - # } - # image_tag("rails.png") - # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" /> - # stylesheet_link_tag("application") - # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" /> - # - # Alternatively you may ask for a second parameter +request+. That one is - # particularly useful for serving assets from an SSL-protected page. The - # example proc below disables asset hosting for HTTPS connections, while - # still sending assets for plain HTTP requests from asset hosts. If you don't - # have SSL certificates for each of the asset hosts this technique allows you - # to avoid warnings in the client about mixed media. - # - # config.action_controller.asset_host = Proc.new { |source, request| - # if request.ssl? - # "#{request.protocol}#{request.host_with_port}" - # else - # "#{request.protocol}assets.example.com" - # end - # } - # - # You can also implement a custom asset host object that responds to +call+ - # and takes either one or two parameters just like the proc. - # - # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new( - # "http://asset%d.example.com", "https://asset1.example.com" - # ) - # - # === Customizing the asset path - # - # By default, Rails appends asset's timestamps to all asset paths. This allows - # you to set a cache-expiration date for the asset far into the future, but - # still be able to instantly invalidate it by simply updating the file (and - # hence updating the timestamp, which then updates the URL as the timestamp - # is part of that, which in turn busts the cache). - # - # It's the responsibility of the web server you use to set the far-future - # expiration date on cache assets that you need to take advantage of this - # feature. Here's an example for Apache: - # - # # Asset Expiration - # ExpiresActive On - # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$"> - # ExpiresDefault "access plus 1 year" - # </FilesMatch> - # - # Also note that in order for this to work, all your application servers must - # return the same timestamps. This means that they must have their clocks - # synchronized. If one of them drifts out of sync, you'll see different - # timestamps at random and the cache won't work. In that case the browser - # will request the same assets over and over again even thought they didn't - # change. You can use something like Live HTTP Headers for Firefox to verify - # that the cache is indeed working. - # - # This strategy works well enough for most server setups and requires the - # least configuration, but if you deploy several application servers at - # different times - say to handle a temporary spike in load - then the - # asset time stamps will be out of sync. In a setup like this you may want - # to set the way that asset paths are generated yourself. - # - # Altering the asset paths that Rails generates can be done in two ways. - # The easiest is to define the RAILS_ASSET_ID environment variable. The - # contents of this variable will always be used in preference to - # calculated timestamps. A more complex but flexible way is to set - # <tt>ActionController::Base.config.asset_path</tt> to a proc - # that takes the unmodified asset path and returns the path needed for - # your asset caching to work. Typically you'd do something like this in - # <tt>config/environments/production.rb</tt>: - # - # # Normally you'd calculate RELEASE_NUMBER at startup. - # RELEASE_NUMBER = 12345 - # config.action_controller.asset_path = proc { |asset_path| - # "/release-#{RELEASE_NUMBER}#{asset_path}" - # } - # - # This example would cause the following behavior on all servers no - # matter when they were deployed: - # - # image_tag("rails.png") - # # => <img alt="Rails" src="/release-12345/images/rails.png" /> - # stylesheet_link_tag("application") - # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" /> - # - # Changing the asset_path does require that your web servers have - # knowledge of the asset template paths that you rewrite to so it's not - # suitable for out-of-the-box use. To use the example given above you - # could use something like this in your Apache VirtualHost configuration: - # - # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$"> - # # Some browsers still send conditional-GET requests if there's a - # # Last-Modified header or an ETag header even if they haven't - # # reached the expiry date sent in the Expires header. - # Header unset Last-Modified - # Header unset ETag - # FileETag None - # - # # Assets requested using a cache-busting filename should be served - # # only once and then cached for a really long time. The HTTP/1.1 - # # spec frowns on hugely-long expiration times though and suggests - # # that assets which never expire be served with an expiration date - # # 1 year from access. - # ExpiresActive On - # ExpiresDefault "access plus 1 year" - # </LocationMatch> - # - # # We use cached-busting location names with the far-future expires - # # headers to ensure that if a file does change it can force a new - # # request. The actual asset filenames are still the same though so we - # # need to rewrite the location from the cache-busting location to the - # # real asset location so that we can serve it. - # RewriteEngine On - # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L] module AssetTagHelper + extend ActiveSupport::Concern + + include AssetUrlHelper include TagHelper - include JavascriptTagHelpers - include StylesheetTagHelpers + + # Returns an HTML script tag for each of the +sources+ provided. + # + # Sources may be paths to JavaScript files. Relative paths are assumed to be relative + # to <tt>public/javascripts</tt>, full paths are assumed to be relative to the document + # root. Relative paths are idiomatic, use absolute paths only when needed. + # + # When passing paths, the ".js" extension is optional. + # + # You can modify the HTML attributes of the script tag by passing a hash as the + # last argument. + # + # javascript_include_tag "xmlhr" + # # => <script src="/javascripts/xmlhr.js?1284139606"></script> + # + # javascript_include_tag "xmlhr.js" + # # => <script src="/javascripts/xmlhr.js?1284139606"></script> + # + # javascript_include_tag "common.javascript", "/elsewhere/cools" + # # => <script src="/javascripts/common.javascript?1284139606"></script> + # # <script src="/elsewhere/cools.js?1423139606"></script> + # + # javascript_include_tag "http://www.example.com/xmlhr" + # # => <script src="http://www.example.com/xmlhr"></script> + # + # javascript_include_tag "http://www.example.com/xmlhr.js" + # # => <script src="http://www.example.com/xmlhr.js"></script> + # + def javascript_include_tag(*sources) + options = sources.extract_options!.stringify_keys + sources.uniq.map { |source| + tag_options = { + "src" => path_to_javascript(source) + }.merge(options) + content_tag(:script, "", tag_options) + }.join("\n").html_safe + end + + # Returns a stylesheet link tag for the sources specified as arguments. If + # you don't specify an extension, <tt>.css</tt> will be appended automatically. + # You can modify the link attributes by passing a hash as the last argument. + # For historical reasons, the 'media' attribute will always be present and defaults + # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to + # apply to all media types. + # + # stylesheet_link_tag "style" # => + # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" /> + # + # stylesheet_link_tag "style.css" # => + # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" /> + # + # stylesheet_link_tag "http://www.example.com/style.css" # => + # <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" /> + # + # stylesheet_link_tag "style", :media => "all" # => + # <link href="/stylesheets/style.css" media="all" rel="stylesheet" /> + # + # stylesheet_link_tag "style", :media => "print" # => + # <link href="/stylesheets/style.css" media="print" rel="stylesheet" /> + # + # stylesheet_link_tag "random.styles", "/css/stylish" # => + # <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" /> + # <link href="/css/stylish.css" media="screen" rel="stylesheet" /> + # + def stylesheet_link_tag(*sources) + options = sources.extract_options!.stringify_keys + sources.uniq.map { |source| + tag_options = { + "rel" => "stylesheet", + "media" => "screen", + "href" => path_to_stylesheet(source) + }.merge(options) + tag(:link, tag_options) + }.join("\n").html_safe + end + # Returns a link tag that browsers and news readers can use to auto-detect # an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or # <tt>:atom</tt>. Control the link options in url_for format using the @@ -268,93 +166,6 @@ module ActionView }.merge(options.symbolize_keys)) end - # Computes the path to an image asset. - # Full paths from the document root will be passed through. - # Used internally by +image_tag+ to build the image path: - # - # image_path("edit") # => "/assets/edit" - # image_path("edit.png") # => "/assets/edit.png" - # image_path("icons/edit.png") # => "/assets/icons/edit.png" - # image_path("/icons/edit.png") # => "/icons/edit.png" - # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png" - # - # If you have images as application resources this method may conflict with their named routes. - # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and - # plugin authors are encouraged to do so. - def image_path(source) - source.present? ? asset_paths.compute_public_path(source, 'images') : "" - end - alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route - - # Computes the full URL to an image asset. - # This will use +image_path+ internally, so most of their behaviors will be the same. - def image_url(source) - URI.join(current_host, path_to_image(source)).to_s - end - alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route - - # Computes the path to a video asset in the public videos directory. - # Full paths from the document root will be passed through. - # Used internally by +video_tag+ to build the video path. - # - # video_path("hd") # => /videos/hd - # video_path("hd.avi") # => /videos/hd.avi - # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi - # video_path("/trailers/hd.avi") # => /trailers/hd.avi - # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi - def video_path(source) - asset_paths.compute_public_path(source, 'videos') - end - alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route - - # Computes the full URL to a video asset in the public videos directory. - # This will use +video_path+ internally, so most of their behaviors will be the same. - def video_url(source) - URI.join(current_host, path_to_video(source)).to_s - end - alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route - - # Computes the path to an audio asset in the public audios directory. - # Full paths from the document root will be passed through. - # Used internally by +audio_tag+ to build the audio path. - # - # audio_path("horse") # => /audios/horse - # audio_path("horse.wav") # => /audios/horse.wav - # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav - # audio_path("/sounds/horse.wav") # => /sounds/horse.wav - # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav - def audio_path(source) - asset_paths.compute_public_path(source, 'audios') - end - alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route - - # Computes the full URL to an audio asset in the public audios directory. - # This will use +audio_path+ internally, so most of their behaviors will be the same. - def audio_url(source) - URI.join(current_host, path_to_audio(source)).to_s - end - alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route - - # Computes the path to a font asset. - # Full paths from the document root will be passed through. - # - # font_path("font") # => /assets/font - # font_path("font.ttf") # => /assets/font.ttf - # font_path("dir/font.ttf") # => /assets/dir/font.ttf - # font_path("/dir/font.ttf") # => /dir/font.ttf - # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf - def font_path(source) - asset_paths.compute_public_path(source, 'fonts') - end - alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route - - # Computes the full URL to a font asset. - # This will use +font_path+ internally, so most of their behaviors will be the same. - def font_url(source) - URI.join(current_host, path_to_font(source)).to_s - end - alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route - # Returns an html image tag for the +source+. The +source+ can be a full # path or a file. # @@ -462,11 +273,6 @@ module ActionView end private - - def asset_paths - @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller) - end - def multiple_sources_tag(type, sources) options = sources.extract_options!.symbolize_keys sources.flatten! @@ -482,10 +288,6 @@ module ActionView content_tag(type, nil, options) end end - - def current_host - url_for(:only_path => false) - end end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb deleted file mode 100644 index e42e49fb04..0000000000 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ /dev/null @@ -1,145 +0,0 @@ -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/file' -require 'action_view/helpers/tag_helper' - -module ActionView - module Helpers - module AssetTagHelper - - class AssetIncludeTag #:nodoc: - include TagHelper - - attr_reader :config, :asset_paths - class_attribute :expansions - - def self.inherited(base) - base.expansions = { } - end - - def initialize(config, asset_paths) - @config = config - @asset_paths = asset_paths - end - - def asset_name - raise NotImplementedError - end - - def extension - raise NotImplementedError - end - - def custom_dir - raise NotImplementedError - end - - def asset_tag(source, options) - raise NotImplementedError - end - - def include_tag(*sources) - options = sources.extract_options!.stringify_keys - concat = options.delete("concat") - cache = concat || options.delete("cache") - recursive = options.delete("recursive") - - if concat || (config.perform_caching && cache) - joined_name = (cache == true ? "all" : cache) + ".#{extension}" - joined_path = File.join((joined_name[/^#{File::SEPARATOR}/] ? config.assets_dir : custom_dir), joined_name) - unless config.perform_caching && File.exists?(joined_path) - write_asset_file_contents(joined_path, compute_paths(sources, recursive)) - end - asset_tag(joined_name, options) - else - sources = expand_sources(sources, recursive) - ensure_sources!(sources) if cache - sources.collect { |source| asset_tag(source, options) }.join("\n").html_safe - end - end - - private - - def path_to_asset(source, options = {}) - asset_paths.compute_public_path(source, asset_name.to_s.pluralize, options.merge(:ext => extension)) - end - - def path_to_asset_source(source) - asset_paths.compute_source_path(source, asset_name.to_s.pluralize, extension) - end - - def compute_paths(*args) - expand_sources(*args).collect { |source| path_to_asset_source(source) } - end - - def expand_sources(sources, recursive) - if sources.first == :all - collect_asset_files(custom_dir, ('**' if recursive), "*.#{extension}") - else - sources.inject([]) do |list, source| - determined_source = determine_source(source, expansions) - update_source_list(list, determined_source) - end - end - end - - def update_source_list(list, source) - case source - when String - list.delete(source) - list << source - when Array - updated_sources = source - list - list.concat(updated_sources) - end - end - - def ensure_sources!(sources) - sources.each do |source| - asset_file_path!(path_to_asset_source(source)) - end - end - - def collect_asset_files(*path) - dir = path.first - - Dir[File.join(*path.compact)].collect do |file| - file[-(file.size - dir.size - 1)..-1].sub(/\.\w+$/, '') - end.sort - end - - def determine_source(source, collection) - case source - when Symbol - collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}") - else - source - end - end - - def join_asset_file_contents(paths) - paths.collect { |path| File.read(asset_file_path!(path, true)) }.join("\n\n") - end - - def write_asset_file_contents(joined_asset_path, asset_paths) - FileUtils.mkdir_p(File.dirname(joined_asset_path)) - File.atomic_write(joined_asset_path) { |cache| cache.write(join_asset_file_contents(asset_paths)) } - - # Set mtime to the latest of the combined files to allow for - # consistent ETag without a shared filesystem. - mt = asset_paths.map { |p| File.mtime(asset_file_path!(p)) }.max - File.utime(mt, mt, joined_asset_path) - end - - def asset_file_path!(absolute_path, error_if_file_is_uri = false) - if asset_paths.is_uri?(absolute_path) - raise(Errno::ENOENT, "Asset file #{path} is uri and cannot be merged into single file") if error_if_file_is_uri - else - raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path) - return absolute_path - end - end - end - - end - end -end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb deleted file mode 100644 index 35f91cec18..0000000000 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +++ /dev/null @@ -1,93 +0,0 @@ -require 'thread' -require 'active_support/core_ext/file' -require 'active_support/core_ext/module/attribute_accessors' - -module ActionView - module Helpers - module AssetTagHelper - - class AssetPaths < ::ActionView::AssetPaths #:nodoc: - # You can enable or disable the asset tag ids cache. - # With the cache enabled, the asset tag helper methods will make fewer - # expensive file system calls (the default implementation checks the file - # system timestamp). However this prevents you from modifying any asset - # files while the server is running. - # - # ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false - mattr_accessor :cache_asset_ids - - # Add or change an asset id in the asset id cache. This can be used - # for SASS on Heroku. - # :api: public - def add_to_asset_ids_cache(source, asset_id) - self.asset_ids_cache_guard.synchronize do - self.asset_ids_cache[source] = asset_id - end - end - - private - - def rewrite_extension(source, dir, ext) - source_ext = File.extname(source) - - source_with_ext = if source_ext.empty? - "#{source}.#{ext}" - elsif ext != source_ext[1..-1] - with_ext = "#{source}.#{ext}" - with_ext if File.exist?(File.join(config.assets_dir, dir, with_ext)) - end - - source_with_ext || source - end - - # Break out the asset path rewrite in case plugins wish to put the asset id - # someplace other than the query string. - def rewrite_asset_path(source, dir, options = nil) - source = "/#{dir}/#{source}" unless source[0] == ?/ - path = config.asset_path - - if path && path.respond_to?(:call) - return path.call(source) - elsif path && path.is_a?(String) - return path % [source] - end - - asset_id = rails_asset_id(source) - if asset_id.empty? - source - else - "#{source}?#{asset_id}" - end - end - - mattr_accessor :asset_ids_cache - self.asset_ids_cache = {} - - mattr_accessor :asset_ids_cache_guard - self.asset_ids_cache_guard = Mutex.new - - # Use the RAILS_ASSET_ID environment variable or the source's - # modification time as its cache-busting asset id. - def rails_asset_id(source) - if asset_id = ENV["RAILS_ASSET_ID"] - asset_id - else - if self.cache_asset_ids && (asset_id = self.asset_ids_cache[source]) - asset_id - else - path = File.join(config.assets_dir, source) - asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : '' - - if self.cache_asset_ids - add_to_asset_ids_cache(source, asset_id) - end - - asset_id - end - end - end - end - - end - end -end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb deleted file mode 100644 index 139f4d19ab..0000000000 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +++ /dev/null @@ -1,195 +0,0 @@ -require 'active_support/core_ext/file' -require 'action_view/helpers/asset_tag_helpers/asset_include_tag' - -module ActionView - module Helpers - module AssetTagHelper - - class JavascriptIncludeTag < AssetIncludeTag #:nodoc: - def asset_name - 'javascript' - end - - def extension - 'js' - end - - def asset_tag(source, options) - content_tag("script", "", { "src" => path_to_asset(source) }.merge(options)) - end - - def custom_dir - config.javascripts_dir - end - - private - - def expand_sources(sources, recursive = false) - if sources.include?(:all) - all_asset_files = (collect_asset_files(custom_dir, ('**' if recursive), "*.#{extension}") - ['application']) - add_application_js(all_asset_files, sources) - ((determine_source(:defaults, expansions).dup & all_asset_files) + all_asset_files).uniq - else - expanded_sources = sources.inject([]) do |list, source| - determined_source = determine_source(source, expansions) - update_source_list(list, determined_source) - end - add_application_js(expanded_sources, sources) - expanded_sources - end - end - - def add_application_js(expanded_sources, sources) - if (sources.include?(:defaults) || sources.include?(:all)) && File.exist?(File.join(custom_dir, "application.#{extension}")) - expanded_sources.delete('application') - expanded_sources << "application" - end - end - end - - - module JavascriptTagHelpers - extend ActiveSupport::Concern - - module ClassMethods - # Register one or more javascript files to be included when <tt>symbol</tt> - # is passed to <tt>javascript_include_tag</tt>. This method is typically intended - # to be called from plugin initialization to register javascript files - # that the plugin installed in <tt>public/javascripts</tt>. - # - # ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"] - # - # javascript_include_tag :monkey # => - # <script src="/javascripts/head.js"></script> - # <script src="/javascripts/body.js"></script> - # <script src="/javascripts/tail.js"></script> - def register_javascript_expansion(expansions) - js_expansions = JavascriptIncludeTag.expansions - expansions.each do |key, values| - js_expansions[key] = (js_expansions[key] || []) | Array(values) - end - end - end - - # Computes the path to a javascript asset in the public javascripts directory. - # If the +source+ filename has no extension, .js will be appended (except for explicit URIs) - # Full paths from the document root will be passed through. - # Used internally by javascript_include_tag to build the script path. - # - # javascript_path "xmlhr" # => /javascripts/xmlhr.js - # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js - # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js - # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr - # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js - def javascript_path(source) - asset_paths.compute_public_path(source, 'javascripts', :ext => 'js') - end - alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route - - # Computes the full URL to a javascript asset in the public javascripts directory. - # This will use +javascript_path+ internally, so most of their behaviors will be the same. - def javascript_url(source) - URI.join(current_host, path_to_javascript(source)).to_s - end - alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route - - # Returns an HTML script tag for each of the +sources+ provided. - # - # Sources may be paths to JavaScript files. Relative paths are assumed to be relative - # to <tt>public/javascripts</tt>, full paths are assumed to be relative to the document - # root. Relative paths are idiomatic, use absolute paths only when needed. - # - # When passing paths, the ".js" extension is optional. - # - # If the application is not using the asset pipeline, to include the default JavaScript - # expansion pass <tt>:defaults</tt> as source. By default, <tt>:defaults</tt> loads jQuery, - # and that can be overridden in <tt>config/application.rb</tt>: - # - # config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js) - # - # When using <tt>:defaults</tt> or <tt>:all</tt>, if an <tt>application.js</tt> file exists - # in <tt>public/javascripts</tt> it will be included as well at the end. - # - # You can modify the HTML attributes of the script tag by passing a hash as the - # last argument. - # - # javascript_include_tag "xmlhr" - # # => <script src="/javascripts/xmlhr.js?1284139606"></script> - # - # javascript_include_tag "xmlhr.js" - # # => <script src="/javascripts/xmlhr.js?1284139606"></script> - # - # javascript_include_tag "common.javascript", "/elsewhere/cools" - # # => <script src="/javascripts/common.javascript?1284139606"></script> - # # <script src="/elsewhere/cools.js?1423139606"></script> - # - # javascript_include_tag "http://www.example.com/xmlhr" - # # => <script src="http://www.example.com/xmlhr"></script> - # - # javascript_include_tag "http://www.example.com/xmlhr.js" - # # => <script src="http://www.example.com/xmlhr.js"></script> - # - # javascript_include_tag :defaults - # # => <script src="/javascripts/jquery.js?1284139606"></script> - # # <script src="/javascripts/rails.js?1284139606"></script> - # # <script src="/javascripts/application.js?1284139606"></script> - # - # Note: The application.js file is only referenced if it exists - # - # You can also include all JavaScripts in the +javascripts+ directory using <tt>:all</tt> as the source: - # - # javascript_include_tag :all - # # => <script src="/javascripts/jquery.js?1284139606"></script> - # # <script src="/javascripts/rails.js?1284139606"></script> - # # <script src="/javascripts/shop.js?1284139606"></script> - # # <script src="/javascripts/checkout.js?1284139606"></script> - # # <script src="/javascripts/application.js?1284139606"></script> - # - # Note that your defaults of choice will be included first, so they will be available to all subsequently - # included files. - # - # If you want Rails to search in all the subdirectories under <tt>public/javascripts</tt>, you should - # explicitly set <tt>:recursive</tt>: - # - # javascript_include_tag :all, :recursive => true - # - # == Caching multiple JavaScripts into one - # - # You can also cache multiple JavaScripts into one file, which requires less HTTP connections to download - # and can better be compressed by gzip (leading to faster transfers). Caching will only happen if - # <tt>config.perform_caching</tt> is set to true (which is the case by default for the Rails - # production environment, but not for the development environment). - # - # # assuming config.perform_caching is false - # javascript_include_tag :all, :cache => true - # # => <script src="/javascripts/jquery.js?1284139606"></script> - # # <script src="/javascripts/rails.js?1284139606"></script> - # # <script src="/javascripts/shop.js?1284139606"></script> - # # <script src="/javascripts/checkout.js?1284139606"></script> - # # <script src="/javascripts/application.js?1284139606"></script> - # - # # assuming config.perform_caching is true - # javascript_include_tag :all, :cache => true - # # => <script src="/javascripts/all.js?1344139789"></script> - # - # # assuming config.perform_caching is false - # javascript_include_tag "jquery", "cart", "checkout", :cache => "shop" - # # => <script src="/javascripts/jquery.js?1284139606"></script> - # # <script src="/javascripts/cart.js?1289139157"></script> - # # <script src="/javascripts/checkout.js?1299139816"></script> - # - # # assuming config.perform_caching is true - # javascript_include_tag "jquery", "cart", "checkout", :cache => "shop" - # # => <script src="/javascripts/shop.js?1299139816"></script> - # - # The <tt>:recursive</tt> option is also available for caching: - # - # javascript_include_tag :all, :cache => true, :recursive => true - def javascript_include_tag(*sources) - @javascript_include ||= JavascriptIncludeTag.new(config, asset_paths) - @javascript_include.include_tag(*sources) - end - end - end - end -end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb deleted file mode 100644 index e3a86a8889..0000000000 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ /dev/null @@ -1,151 +0,0 @@ -require 'active_support/core_ext/file' -require 'action_view/helpers/asset_tag_helpers/asset_include_tag' - -module ActionView - module Helpers - module AssetTagHelper - - class StylesheetIncludeTag < AssetIncludeTag #:nodoc: - def asset_name - 'stylesheet' - end - - def extension - 'css' - end - - def asset_tag(source, options) - # We force the :request protocol here to avoid a double-download bug in IE7 and IE8 - tag("link", { "rel" => "stylesheet", "media" => "screen", "href" => path_to_asset(source, :protocol => :request) }.merge(options)) - end - - def custom_dir - config.stylesheets_dir - end - end - - - module StylesheetTagHelpers - extend ActiveSupport::Concern - - module ClassMethods - # Register one or more stylesheet files to be included when <tt>symbol</tt> - # is passed to <tt>stylesheet_link_tag</tt>. This method is typically intended - # to be called from plugin initialization to register stylesheet files - # that the plugin installed in <tt>public/stylesheets</tt>. - # - # ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] - # - # stylesheet_link_tag :monkey # => - # <link href="/stylesheets/head.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/body.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" /> - def register_stylesheet_expansion(expansions) - style_expansions = StylesheetIncludeTag.expansions - expansions.each do |key, values| - style_expansions[key] = (style_expansions[key] || []) | Array(values) - end - end - end - - # Computes the path to a stylesheet asset in the public stylesheets directory. - # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs). - # Full paths from the document root will be passed through. - # Used internally by +stylesheet_link_tag+ to build the stylesheet path. - # - # stylesheet_path "style" # => /stylesheets/style.css - # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css - # stylesheet_path "/dir/style.css" # => /dir/style.css - # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style - # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css - def stylesheet_path(source) - asset_paths.compute_public_path(source, 'stylesheets', :ext => 'css', :protocol => :request) - end - alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route - - # Computes the full URL to a stylesheet asset in the public stylesheets directory. - # This will use +stylesheet_path+ internally, so most of their behaviors will be the same. - def stylesheet_url(source) - URI.join(current_host, path_to_stylesheet(source)).to_s - end - alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route - - # Returns a stylesheet link tag for the sources specified as arguments. If - # you don't specify an extension, <tt>.css</tt> will be appended automatically. - # You can modify the link attributes by passing a hash as the last argument. - # For historical reasons, the 'media' attribute will always be present and defaults - # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to - # apply to all media types. - # - # stylesheet_link_tag "style" # => - # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag "style.css" # => - # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag "http://www.example.com/style.css" # => - # <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag "style", :media => "all" # => - # <link href="/stylesheets/style.css" media="all" rel="stylesheet" /> - # - # stylesheet_link_tag "style", :media => "print" # => - # <link href="/stylesheets/style.css" media="print" rel="stylesheet" /> - # - # stylesheet_link_tag "random.styles", "/css/stylish" # => - # <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" /> - # <link href="/css/stylish.css" media="screen" rel="stylesheet" /> - # - # You can also include all styles in the stylesheets directory using <tt>:all</tt> as the source: - # - # stylesheet_link_tag :all # => - # <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" /> - # - # If you want Rails to search in all the subdirectories under stylesheets, you should explicitly set <tt>:recursive</tt>: - # - # stylesheet_link_tag :all, :recursive => true - # - # == Caching multiple stylesheets into one - # - # You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be - # compressed by gzip (leading to faster transfers). Caching will only happen if +config.perform_caching+ - # is set to true (which is the case by default for the Rails production environment, but not for the development - # environment). Examples: - # - # stylesheet_link_tag :all, :cache => true # when config.perform_caching is false => - # <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/styleX2.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag :all, :cache => true # when config.perform_caching is true => - # <link href="/stylesheets/all.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is false => - # <link href="/stylesheets/shop.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/cart.css" media="screen" rel="stylesheet" /> - # <link href="/stylesheets/checkout.css" media="screen" rel="stylesheet" /> - # - # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is true => - # <link href="/stylesheets/payment.css" media="screen" rel="stylesheet" /> - # - # The <tt>:recursive</tt> option is also available for caching: - # - # stylesheet_link_tag :all, :cache => true, :recursive => true - # - # To force concatenation (even in development mode) set <tt>:concat</tt> to true. This is useful if - # you have too many stylesheets for IE to load. - # - # stylesheet_link_tag :all, :concat => true - # - def stylesheet_link_tag(*sources) - @stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths) - @stylesheet_include.include_tag(*sources) - end - - end - - end - end -end diff --git a/actionpack/lib/action_view/helpers/asset_url_helper.rb b/actionpack/lib/action_view/helpers/asset_url_helper.rb new file mode 100644 index 0000000000..0bb5e739bb --- /dev/null +++ b/actionpack/lib/action_view/helpers/asset_url_helper.rb @@ -0,0 +1,355 @@ +require 'zlib' + +module ActionView + # = Action View Asset URL Helpers + module Helpers #:nodoc: + # This module provides methods for generating asset paths and + # urls. + # + # image_path("rails.png") + # # => "/assets/rails.png" + # + # image_url("rails.png") + # # => "http://www.example.com/assets/rails.png" + # + # === Using asset hosts + # + # By default, Rails links to these assets on the current host in the public + # folder, but you can direct Rails to link to assets from a dedicated asset + # server by setting <tt>ActionController::Base.asset_host</tt> in the application + # configuration, typically in <tt>config/environments/production.rb</tt>. + # For example, you'd define <tt>assets.example.com</tt> to be your asset + # host this way, inside the <tt>configure</tt> block of your environment-specific + # configuration files or <tt>config/application.rb</tt>: + # + # config.action_controller.asset_host = "assets.example.com" + # + # Helpers take that into account: + # + # image_tag("rails.png") + # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" /> + # stylesheet_link_tag("application") + # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" /> + # + # Browsers typically open at most two simultaneous connections to a single + # host, which means your assets often have to wait for other assets to finish + # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the + # +asset_host+. For example, "assets%d.example.com". If that wildcard is + # present Rails distributes asset requests among the corresponding four hosts + # "assets0.example.com", ..., "assets3.example.com". With this trick browsers + # will open eight simultaneous connections rather than two. + # + # image_tag("rails.png") + # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" /> + # stylesheet_link_tag("application") + # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" /> + # + # To do this, you can either setup four actual hosts, or you can use wildcard + # DNS to CNAME the wildcard to a single asset host. You can read more about + # setting up your DNS CNAME records from your ISP. + # + # Note: This is purely a browser performance optimization and is not meant + # for server load balancing. See http://www.die.net/musings/page_load_time/ + # for background. + # + # Alternatively, you can exert more control over the asset host by setting + # +asset_host+ to a proc like this: + # + # ActionController::Base.asset_host = Proc.new { |source| + # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com" + # } + # image_tag("rails.png") + # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" /> + # stylesheet_link_tag("application") + # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" /> + # + # The example above generates "http://assets1.example.com" and + # "http://assets2.example.com". This option is useful for example if + # you need fewer/more than four hosts, custom host names, etc. + # + # As you see the proc takes a +source+ parameter. That's a string with the + # absolute path of the asset, for example "/assets/rails.png". + # + # ActionController::Base.asset_host = Proc.new { |source| + # if source.ends_with?('.css') + # "http://stylesheets.example.com" + # else + # "http://assets.example.com" + # end + # } + # image_tag("rails.png") + # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" /> + # stylesheet_link_tag("application") + # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" /> + # + # Alternatively you may ask for a second parameter +request+. That one is + # particularly useful for serving assets from an SSL-protected page. The + # example proc below disables asset hosting for HTTPS connections, while + # still sending assets for plain HTTP requests from asset hosts. If you don't + # have SSL certificates for each of the asset hosts this technique allows you + # to avoid warnings in the client about mixed media. + # + # config.action_controller.asset_host = Proc.new { |source, request| + # if request.ssl? + # "#{request.protocol}#{request.host_with_port}" + # else + # "#{request.protocol}assets.example.com" + # end + # } + # + # You can also implement a custom asset host object that responds to +call+ + # and takes either one or two parameters just like the proc. + # + # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new( + # "http://asset%d.example.com", "https://asset1.example.com" + # ) + # + module AssetUrlHelper + URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//} + + # Computes the path to asset in public directory. If :type + # options is set, a file extension will be appended and scoped + # to the corresponding public directory. + # + # All other asset *_path helpers delegate through this method. + # + # asset_path "application.js" # => /application.js + # asset_path "application", type: :javascript # => /javascripts/application.js + # asset_path "application", type: :stylesheet # => /stylesheets/application.css + # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js + def asset_path(source, options = {}) + source = source.to_s + return "" unless source.present? + return source if source =~ URI_REGEXP + + tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '') + + if extname = compute_asset_extname(source, options) + source = "#{source}#{extname}" + end + + if source[0] != ?/ + source = compute_asset_path(source, options) + end + + relative_url_root = (defined?(config.relative_url_root) && config.relative_url_root) || + (respond_to?(:request) && request.try(:script_name)) + if relative_url_root + source = "#{relative_url_root}#{source}" unless source.starts_with?("#{relative_url_root}/") + end + + if host = compute_asset_host(source, options) + source = "#{host}#{source}" + end + + "#{source}#{tail}" + end + alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with a asset_path named route + + # Computes the full URL to a asset in the public directory. This + # will use +asset_path+ internally, so most of their behaviors + # will be the same. + def asset_url(source, options = {}) + path_to_asset(source, options.merge(:protocol => :request)) + end + alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route + + ASSET_EXTENSIONS = { + javascript: '.js', + stylesheet: '.css' + } + + # Compute extname to append to asset path. Returns nil if + # nothing should be added. + def compute_asset_extname(source, options = {}) + return if options[:extname] == false + extname = options[:extname] || ASSET_EXTENSIONS[options[:type]] + extname if extname && File.extname(source) != extname + end + + # Maps asset types to public directory. + ASSET_PUBLIC_DIRECTORIES = { + audio: '/audios', + font: '/fonts', + image: '/images', + javascript: '/javascripts', + stylesheet: '/stylesheets', + video: '/videos' + } + + # Computes asset path to public directory. Plugins and + # extensions can override this method to point to custom assets + # or generate digested paths or query strings. + def compute_asset_path(source, options = {}) + dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || "" + File.join(dir, source) + end + + # Pick an asset host for this source. Returns +nil+ if no host is set, + # the host if no wildcard is set, the host interpolated with the + # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4), + # or the value returned from invoking call on an object responding to call + # (proc or otherwise). + def compute_asset_host(source = "", options = {}) + request = self.request if respond_to?(:request) + host = config.asset_host if defined? config.asset_host + host ||= request.base_url if request && options[:protocol] == :request + return unless host + + if host.respond_to?(:call) + arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity + args = [source] + args << request if request && (arity > 1 || arity < 0) + host = host.call(*args) + elsif host =~ /%d/ + host = host % (Zlib.crc32(source) % 4) + end + + if host =~ URI_REGEXP + host + else + protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative) + case protocol + when :relative + "//#{host}" + when :request + "#{request.protocol}#{host}" + else + "#{protocol}://#{host}" + end + end + end + + # Computes the path to a javascript asset in the public javascripts directory. + # If the +source+ filename has no extension, .js will be appended (except for explicit URIs) + # Full paths from the document root will be passed through. + # Used internally by javascript_include_tag to build the script path. + # + # javascript_path "xmlhr" # => /javascripts/xmlhr.js + # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js + # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js + # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr + # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js + def javascript_path(source, options = {}) + path_to_asset(source, {type: :javascript}.merge!(options)) + end + alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route + + # Computes the full URL to a javascript asset in the public javascripts directory. + # This will use +javascript_path+ internally, so most of their behaviors will be the same. + def javascript_url(source, options = {}) + url_to_asset(source, {type: :javascript}.merge!(options)) + end + alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route + + # Computes the path to a stylesheet asset in the public stylesheets directory. + # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs). + # Full paths from the document root will be passed through. + # Used internally by +stylesheet_link_tag+ to build the stylesheet path. + # + # stylesheet_path "style" # => /stylesheets/style.css + # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css + # stylesheet_path "/dir/style.css" # => /dir/style.css + # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style + # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css + def stylesheet_path(source, options = {}) + path_to_asset(source, {type: :stylesheet}.merge!(options)) + end + alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route + + # Computes the full URL to a stylesheet asset in the public stylesheets directory. + # This will use +stylesheet_path+ internally, so most of their behaviors will be the same. + def stylesheet_url(source, options = {}) + url_to_asset(source, {type: :stylesheet}.merge!(options)) + end + alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route + + # Computes the path to an image asset. + # Full paths from the document root will be passed through. + # Used internally by +image_tag+ to build the image path: + # + # image_path("edit") # => "/assets/edit" + # image_path("edit.png") # => "/assets/edit.png" + # image_path("icons/edit.png") # => "/assets/icons/edit.png" + # image_path("/icons/edit.png") # => "/icons/edit.png" + # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png" + # + # If you have images as application resources this method may conflict with their named routes. + # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and + # plugin authors are encouraged to do so. + def image_path(source, options = {}) + path_to_asset(source, {type: :image}.merge!(options)) + end + alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route + + # Computes the full URL to an image asset. + # This will use +image_path+ internally, so most of their behaviors will be the same. + def image_url(source, options = {}) + url_to_asset(source, {type: :image}.merge!(options)) + end + alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route + + # Computes the path to a video asset in the public videos directory. + # Full paths from the document root will be passed through. + # Used internally by +video_tag+ to build the video path. + # + # video_path("hd") # => /videos/hd + # video_path("hd.avi") # => /videos/hd.avi + # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi + # video_path("/trailers/hd.avi") # => /trailers/hd.avi + # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi + def video_path(source, options = {}) + path_to_asset(source, {type: :video}.merge!(options)) + end + alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route + + # Computes the full URL to a video asset in the public videos directory. + # This will use +video_path+ internally, so most of their behaviors will be the same. + def video_url(source, options = {}) + url_to_asset(source, {type: :video}.merge!(options)) + end + alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route + + # Computes the path to an audio asset in the public audios directory. + # Full paths from the document root will be passed through. + # Used internally by +audio_tag+ to build the audio path. + # + # audio_path("horse") # => /audios/horse + # audio_path("horse.wav") # => /audios/horse.wav + # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav + # audio_path("/sounds/horse.wav") # => /sounds/horse.wav + # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav + def audio_path(source, options = {}) + path_to_asset(source, {type: :audio}.merge!(options)) + end + alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route + + # Computes the full URL to an audio asset in the public audios directory. + # This will use +audio_path+ internally, so most of their behaviors will be the same. + def audio_url(source, options = {}) + url_to_asset(source, {type: :audio}.merge!(options)) + end + alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route + + # Computes the path to a font asset. + # Full paths from the document root will be passed through. + # + # font_path("font") # => /assets/font + # font_path("font.ttf") # => /assets/font.ttf + # font_path("dir/font.ttf") # => /assets/dir/font.ttf + # font_path("/dir/font.ttf") # => /dir/font.ttf + # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf + def font_path(source, options = {}) + path_to_asset(source, {type: :font}.merge!(options)) + end + alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route + + # Computes the full URL to a font asset. + # This will use +font_path+ internally, so most of their behaviors will be the same. + def font_url(source, options = {}) + url_to_asset(source, {type: :font}.merge!(options)) + end + alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route + end + end +end diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index 2d36deaa78..3875d88a9f 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -5,8 +5,6 @@ module ActionView # = Action View Railtie class Railtie < Rails::Railtie config.action_view = ActiveSupport::OrderedOptions.new - config.action_view.stylesheet_expansions = {} - config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) } config.action_view.embed_authenticity_token_in_remote_forms = false config.eager_load_namespaces << ActionView @@ -22,26 +20,6 @@ module ActionView ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger } end - initializer "action_view.cache_asset_ids" do |app| - unless app.config.cache_classes - ActiveSupport.on_load(:action_view) do - ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false - end - end - end - - initializer "action_view.javascript_expansions" do |app| - ActiveSupport.on_load(:action_view) do - ActionView::Helpers::AssetTagHelper.register_javascript_expansion( - app.config.action_view.delete(:javascript_expansions) - ) - - ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion( - app.config.action_view.delete(:stylesheet_expansions) - ) - end - end - initializer "action_view.set_configs" do |app| ActiveSupport.on_load(:action_view) do app.config.action_view.each do |k,v| diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 5434b3421e..a548b44780 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -119,8 +119,29 @@ module ActionView output end - def locals - @locals ||= {} + def rendered_views + @_rendered_views ||= RenderedViewsCollection.new + end + + class RenderedViewsCollection + def initialize + @rendered_views ||= {} + end + + def add(view, locals) + @rendered_views[view] ||= [] + @rendered_views[view] << locals + end + + def locals_for(view) + @rendered_views[view] + end + + def view_rendered?(view, expected_locals) + locals_for(view).any? do |actual_locals| + expected_locals.all? {|key, value| value == actual_locals[key] } + end + end end included do @@ -156,18 +177,18 @@ module ActionView end module Locals - attr_accessor :locals + attr_accessor :rendered_views def render(options = {}, local_assigns = {}) case options when Hash if block_given? - locals[options[:layout]] = options[:locals] + rendered_views.add options[:layout], options[:locals] elsif options.key?(:partial) - locals[options[:partial]] = options[:locals] + rendered_views.add options[:partial], options[:locals] end else - locals[options] = local_assigns + rendered_views.add options, local_assigns end super @@ -180,7 +201,7 @@ module ActionView view = @controller.view_context view.singleton_class.send :include, _helpers view.extend(Locals) - view.locals = self.locals + view.rendered_views = self.rendered_views view.output_buffer = self.output_buffer view end @@ -197,7 +218,7 @@ module ActionView :@_routes, :@controller, :@_layouts, - :@locals, + :@_rendered_views, :@method_name, :@output_buffer, :@_partials, diff --git a/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb b/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb index 1eadfc0390..60b6783b19 100644 --- a/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb +++ b/actionpack/lib/action_view/vendor/html-scanner/html/selector.rb @@ -160,7 +160,7 @@ module HTML # * <tt>:not(selector)</tt> -- Match the element only if the element does not # match the simple selector. # - # As you can see, <tt>:nth-child<tt> pseudo class and its variant can get quite + # As you can see, <tt>:nth-child</tt> pseudo class and its variant can get quite # tricky and the CSS specification doesn't do a much better job explaining it. # But after reading the examples and trying a few combinations, it's easy to # figure out. diff --git a/actionpack/test/controller/parameters/nested_parameters_test.rb b/actionpack/test/controller/parameters/nested_parameters_test.rb index 41f5b6e127..d287e79cba 100644 --- a/actionpack/test/controller/parameters/nested_parameters_test.rb +++ b/actionpack/test/controller/parameters/nested_parameters_test.rb @@ -15,18 +15,22 @@ class NestedParametersTest < ActiveSupport::TestCase details: { pages: 200, genre: "Tragedy" + }, + id: { + isbn: 'x' } }, magazine: "Mjallo!" }) - permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages } ] + permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id ] assert permitted.permitted? assert_equal "Romeo and Juliet", permitted[:book][:title] assert_equal "William Shakespeare", permitted[:book][:authors][0][:name] assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name] assert_equal 200, permitted[:book][:details][:pages] + assert_nil permitted[:book][:id] assert_nil permitted[:book][:details][:genre] assert_nil permitted[:book][:authors][0][:born] assert_nil permitted[:magazine] diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb index 18bb51c5a3..ad970f0a9a 100644 --- a/actionpack/test/controller/parameters/parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/parameters_permit_test.rb @@ -3,7 +3,7 @@ require 'action_controller/metal/strong_parameters' class ParametersPermitTest < ActiveSupport::TestCase setup do - @params = ActionController::Parameters.new({ person: { + @params = ActionController::Parameters.new({ person: { age: "32", name: { first: "David", last: "Heinemeier Hansson" } }}) end diff --git a/actionpack/test/fixtures/digestor/level/below/_header.html.erb b/actionpack/test/fixtures/digestor/level/below/_header.html.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/digestor/level/below/_header.html.erb diff --git a/actionpack/test/fixtures/digestor/level/below/index.html.erb b/actionpack/test/fixtures/digestor/level/below/index.html.erb new file mode 100644 index 0000000000..b92f49a8f8 --- /dev/null +++ b/actionpack/test/fixtures/digestor/level/below/index.html.erb @@ -0,0 +1 @@ +<%= render partial: "header" %> diff --git a/actionpack/test/fixtures/test/render_two_partials.html.erb b/actionpack/test/fixtures/test/render_two_partials.html.erb new file mode 100644 index 0000000000..3db6025860 --- /dev/null +++ b/actionpack/test/fixtures/test/render_two_partials.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'partial', :locals => {'first' => '1'} %> +<%= render :partial => 'partial', :locals => {'second' => '2'} %> diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index a04694714d..eb1a54a81f 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -13,27 +13,10 @@ end class AssetTagHelperTest < ActionView::TestCase tests ActionView::Helpers::AssetTagHelper + attr_reader :request + def setup super - silence_warnings do - ActionView::Helpers::AssetTagHelper.send( - :const_set, - :JAVASCRIPTS_DIR, - File.dirname(__FILE__) + "/../fixtures/public/javascripts" - ) - - ActionView::Helpers::AssetTagHelper.send( - :const_set, - :STYLESHEETS_DIR, - File.dirname(__FILE__) + "/../fixtures/public/stylesheets" - ) - - ActionView::Helpers::AssetTagHelper.send( - :const_set, - :ASSETS_DIR, - File.dirname(__FILE__) + "/../fixtures/public" - ) - end @controller = BasicController.new @@ -42,24 +25,33 @@ class AssetTagHelperTest < ActionView::TestCase def protocol() 'http://' end def ssl?() false end def host_with_port() 'localhost' end + def base_url() 'http://www.example.com' end end.new @controller.request = @request - - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :defaults => ['prototype', 'effects', 'dragdrop', 'controls', 'rails'] end def url_for(*args) "http://www.example.com" end - def teardown - config.perform_caching = false - ENV.delete('RAILS_ASSET_ID') + AssetPathToTag = { + %(asset_path("foo")) => %(/foo), + %(asset_path("style.css")) => %(/style.css), + %(asset_path("xmlhr.js")) => %(/xmlhr.js), + %(asset_path("xml.png")) => %(/xml.png), + %(asset_path("dir/xml.png")) => %(/dir/xml.png), + %(asset_path("/dir/xml.png")) => %(/dir/xml.png), - JavascriptIncludeTag.expansions.clear - StylesheetIncludeTag.expansions.clear - end + %(asset_path("script.min")) => %(/script.min), + %(asset_path("script.min.js")) => %(/script.min.js), + %(asset_path("style.min")) => %(/style.min), + %(asset_path("style.min.css")) => %(/style.min.css), + + %(asset_path("style", type: :stylesheet)) => %(/stylesheets/style.css), + %(asset_path("xmlhr", type: :javascript)) => %(/javascripts/xmlhr.js), + %(asset_path("xml.png", type: :image)) => %(/images/xml.png) + } AutoDiscoveryToTag = { %(auto_discovery_link_tag) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />), @@ -79,7 +71,14 @@ class AssetTagHelperTest < ActionView::TestCase JavascriptPathToTag = { %(javascript_path("xmlhr")) => %(/javascripts/xmlhr.js), %(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js), - %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js) + %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js), + %(javascript_path("xmlhr.min")) => %(/javascripts/xmlhr.min.js), + %(javascript_path("xmlhr.min.js")) => %(/javascripts/xmlhr.min.js), + + %(javascript_path("xmlhr.js?123")) => %(/javascripts/xmlhr.js?123), + %(javascript_path("xmlhr.js?body=1")) => %(/javascripts/xmlhr.js?body=1), + %(javascript_path("xmlhr.js#hash")) => %(/javascripts/xmlhr.js#hash), + %(javascript_path("xmlhr.js?123#hash")) => %(/javascripts/xmlhr.js?123#hash) } PathToJavascriptToTag = { @@ -104,13 +103,6 @@ class AssetTagHelperTest < ActionView::TestCase %(javascript_include_tag("bank")) => %(<script src="/javascripts/bank.js" ></script>), %(javascript_include_tag("bank.js")) => %(<script src="/javascripts/bank.js" ></script>), %(javascript_include_tag("bank", :lang => "vbscript")) => %(<script lang="vbscript" src="/javascripts/bank.js" ></script>), - %(javascript_include_tag("common.javascript", "/elsewhere/cools")) => %(<script src="/javascripts/common.javascript" ></script>\n<script src="/elsewhere/cools.js" ></script>), - %(javascript_include_tag(:defaults)) => %(<script src="/javascripts/prototype.js" ></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), - %(javascript_include_tag(:all)) => %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - %(javascript_include_tag(:all, :recursive => true)) => %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/subdir/subdir.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - %(javascript_include_tag(:defaults, "bank")) => %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/application.js"></script>), - %(javascript_include_tag(:defaults, "application")) => %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), - %(javascript_include_tag("bank", :defaults)) => %(<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), %(javascript_include_tag("http://example.com/all")) => %(<script src="http://example.com/all"></script>), %(javascript_include_tag("http://example.com/all.js")) => %(<script src="http://example.com/all.js"></script>), @@ -121,14 +113,17 @@ class AssetTagHelperTest < ActionView::TestCase %(stylesheet_path("bank")) => %(/stylesheets/bank.css), %(stylesheet_path("bank.css")) => %(/stylesheets/bank.css), %(stylesheet_path('subdir/subdir')) => %(/stylesheets/subdir/subdir.css), - %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css) + %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css), + %(stylesheet_path("style.min")) => %(/stylesheets/style.min.css), + %(stylesheet_path("style.min.css")) => %(/stylesheets/style.min.css) } PathToStyleToTag = { %(path_to_stylesheet("style")) => %(/stylesheets/style.css), %(path_to_stylesheet("style.css")) => %(/stylesheets/style.css), %(path_to_stylesheet('dir/file')) => %(/stylesheets/dir/file.css), - %(path_to_stylesheet('/dir/file.rcss')) => %(/dir/file.rcss) + %(path_to_stylesheet('/dir/file.rcss', :extname => false)) => %(/dir/file.rcss), + %(path_to_stylesheet('/dir/file', :extname => '.rcss')) => %(/dir/file.rcss) } StyleUrlToTag = { @@ -142,7 +137,8 @@ class AssetTagHelperTest < ActionView::TestCase %(url_to_stylesheet("style")) => %(http://www.example.com/stylesheets/style.css), %(url_to_stylesheet("style.css")) => %(http://www.example.com/stylesheets/style.css), %(url_to_stylesheet('dir/file')) => %(http://www.example.com/stylesheets/dir/file.css), - %(url_to_stylesheet('/dir/file.rcss')) => %(http://www.example.com/dir/file.rcss) + %(url_to_stylesheet('/dir/file.rcss', :extname => false)) => %(http://www.example.com/dir/file.rcss), + %(url_to_stylesheet('/dir/file', :extname => '.rcss')) => %(http://www.example.com/dir/file.rcss) } StyleLinkToTag = { @@ -151,10 +147,6 @@ class AssetTagHelperTest < ActionView::TestCase %(stylesheet_link_tag("/elsewhere/file")) => %(<link href="/elsewhere/file.css" media="screen" rel="stylesheet" />), %(stylesheet_link_tag("subdir/subdir")) => %(<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />), %(stylesheet_link_tag("bank", :media => "all")) => %(<link href="/stylesheets/bank.css" media="all" rel="stylesheet" />), - %(stylesheet_link_tag(:all)) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - %(stylesheet_link_tag(:all, :recursive => true)) => %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - %(stylesheet_link_tag(:all, :media => "all")) => %(<link href="/stylesheets/bank.css" media="all" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="all" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="all" rel="stylesheet" />), - %(stylesheet_link_tag("random.styles", "/elsewhere/file")) => %(<link href="/stylesheets/random.styles" media="screen" rel="stylesheet" />\n<link href="/elsewhere/file.css" media="screen" rel="stylesheet" />), %(stylesheet_link_tag("http://www.example.com/styles/style")) => %(<link href="http://www.example.com/styles/style" media="screen" rel="stylesheet" />), %(stylesheet_link_tag("http://www.example.com/styles/style.css")) => %(<link href="http://www.example.com/styles/style.css" media="screen" rel="stylesheet" />), @@ -298,6 +290,14 @@ class AssetTagHelperTest < ActionView::TestCase %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>) } + FontPathToTag = { + %(font_path("font.eot")) => %(/fonts/font.eot), + %(font_path("font.eot#iefix")) => %(/fonts/font.eot#iefix), + %(font_path("font.woff")) => %(/fonts/font.woff), + %(font_path("font.ttf")) => %(/fonts/font.ttf), + %(font_path("font.ttf?123")) => %(/fonts/font.ttf?123) + } + def test_autodiscovery_link_tag_deprecated_types result = nil assert_deprecated do @@ -308,6 +308,18 @@ class AssetTagHelperTest < ActionView::TestCase assert_equal expected, result end + def test_asset_path_tag + AssetPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_compute_asset_public_path + assert_equal "/robots.txt", compute_asset_path("robots.txt") + assert_equal "/robots.txt", compute_asset_path("/robots.txt") + assert_equal "/javascripts/foo.js", compute_asset_path("foo.js", :type => :javascript) + assert_equal "/javascripts/foo.js", compute_asset_path("/foo.js", :type => :javascript) + assert_equal "/stylesheets/foo.css", compute_asset_path("foo.css", :type => :stylesheet) + end + def test_auto_discovery_link_tag AutoDiscoveryToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -328,8 +340,7 @@ class AssetTagHelperTest < ActionView::TestCase UrlToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end - def test_javascript_include_tag_with_blank_asset_id - ENV["RAILS_ASSET_ID"] = "" + def test_javascript_include_tag JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -339,104 +350,15 @@ class AssetTagHelperTest < ActionView::TestCase } assert_nothing_raised { - javascript_include_tag(:defaults, 'missing_security_guard') - } - - assert_nothing_raised { javascript_include_tag('http://example.com/css/missing_security_guard') } end - def test_javascript_include_tag_with_given_asset_id - ENV["RAILS_ASSET_ID"] = "1" - assert_dom_equal(%(<script src="/javascripts/prototype.js?1"></script>\n<script src="/javascripts/effects.js?1"></script>\n<script src="/javascripts/dragdrop.js?1"></script>\n<script src="/javascripts/controls.js?1"></script>\n<script src="/javascripts/rails.js?1"></script>\n<script src="/javascripts/application.js?1"></script>), javascript_include_tag(:defaults)) - end - def test_javascript_include_tag_is_html_safe - assert javascript_include_tag(:defaults).html_safe? assert javascript_include_tag("prototype").html_safe? end - def test_custom_javascript_expansions - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :robbery => ["bank", "robber"] - assert_dom_equal %(<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/effects.js"></script>), javascript_include_tag('controls', :robbery, 'effects') - end - - def test_custom_javascript_expansions_return_unique_set - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :defaults => %w(prototype effects dragdrop controls rails application) - assert_dom_equal %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag(:defaults) - end - - def test_custom_javascript_expansions_and_defaults_puts_application_js_at_the_end - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :robbery => ["bank", "robber"] - assert_dom_equal %(<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag('controls',:defaults, :robbery, 'effects') - end - - def test_javascript_include_tag_should_not_output_the_same_asset_twice - ENV["RAILS_ASSET_ID"] = "" - assert_dom_equal %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag('prototype', 'effects', :defaults) - end - - def test_javascript_include_tag_should_not_output_the_same_expansion_twice - ENV["RAILS_ASSET_ID"] = "" - assert_dom_equal %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag(:defaults, :defaults) - end - - def test_single_javascript_asset_keys_should_take_precedence_over_expansions - ENV["RAILS_ASSET_ID"] = "" - assert_dom_equal %(<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag('controls', :defaults, 'effects') - assert_dom_equal %(<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/rails.js"></script>\n<script src="/javascripts/application.js"></script>), javascript_include_tag('controls', 'effects', :defaults) - end - - def test_registering_javascript_expansions_merges_with_existing_expansions - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :can_merge => ['bank'] - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :can_merge => ['robber'] - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :can_merge => ['bank'] - assert_dom_equal %(<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>), javascript_include_tag(:can_merge) - end - - def test_custom_javascript_expansions_with_undefined_symbol - assert_raise(ArgumentError) { javascript_include_tag('first', :unknown, 'last') } - end - - def test_custom_javascript_expansions_with_nil_value - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :monkey => nil - assert_dom_equal %(<script src="/javascripts/first.js"></script>\n<script src="/javascripts/last.js"></script>), javascript_include_tag('first', :monkey, 'last') - end - - def test_custom_javascript_expansions_with_empty_array_value - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :monkey => [] - assert_dom_equal %(<script src="/javascripts/first.js"></script>\n<script src="/javascripts/last.js"></script>), javascript_include_tag('first', :monkey, 'last') - end - - def test_custom_javascript_and_stylesheet_expansion_with_same_name - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_javascript_expansion :robbery => ["bank", "robber"] - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :robbery => ["money", "security"] - assert_dom_equal %(<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/effects.js"></script>), javascript_include_tag('controls', :robbery, 'effects') - assert_dom_equal %(<link href="/stylesheets/style.css" rel="stylesheet" media="screen" />\n<link href="/stylesheets/money.css" rel="stylesheet" media="screen" />\n<link href="/stylesheets/security.css" rel="stylesheet" media="screen" />\n<link href="/stylesheets/print.css" rel="stylesheet" media="screen" />), stylesheet_link_tag('style', :robbery, 'print') - end - - def test_reset_javascript_expansions - JavascriptIncludeTag.expansions.clear - assert_raise(ArgumentError) { javascript_include_tag(:defaults) } - end - - def test_all_javascript_expansion_not_include_application_js_if_not_exists - FileUtils.mv(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.js'), - File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.bak')) - assert_no_match(/application\.js/, javascript_include_tag(:all)) - ensure - FileUtils.mv(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.bak'), - File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.js')) - end - def test_stylesheet_path - ENV["RAILS_ASSET_ID"] = "" StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -445,7 +367,6 @@ class AssetTagHelperTest < ActionView::TestCase end def test_stylesheet_url - ENV["RAILS_ASSET_ID"] = "" StyleUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -454,7 +375,6 @@ class AssetTagHelperTest < ActionView::TestCase end def test_stylesheet_link_tag - ENV["RAILS_ASSET_ID"] = "" StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -469,7 +389,6 @@ class AssetTagHelperTest < ActionView::TestCase end def test_stylesheet_link_tag_is_html_safe - ENV["RAILS_ASSET_ID"] = "" assert stylesheet_link_tag('dir/file').html_safe? assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe? end @@ -478,57 +397,10 @@ class AssetTagHelperTest < ActionView::TestCase assert_dom_equal %(<link href="/file.css" media="<script>" rel="stylesheet" />), stylesheet_link_tag('/file', :media => '<script>') end - def test_custom_stylesheet_expansions - ENV["RAILS_ASSET_ID"] = '' - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :robbery => ["bank", "robber"] - assert_dom_equal %(<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('version.1.0', :robbery, 'subdir/subdir') - end - - def test_custom_stylesheet_expansions_return_unique_set - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :cities => %w(wellington amsterdam london) - assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/london.css" media="screen" rel="stylesheet" />), stylesheet_link_tag(:cities) - end - def test_stylesheet_link_tag_should_not_output_the_same_asset_twice - ENV["RAILS_ASSET_ID"] = "" assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', 'wellington', 'amsterdam') end - def test_stylesheet_link_tag_should_not_output_the_same_expansion_twice - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :cities => %w(wellington amsterdam london) - assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/london.css" media="screen" rel="stylesheet" />), stylesheet_link_tag(:cities, :cities) - end - - def test_single_stylesheet_asset_keys_should_take_precedence_over_expansions - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :cities => %w(wellington amsterdam london) - assert_dom_equal %(<link href="/stylesheets/london.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('london', :cities) - end - - def test_custom_stylesheet_expansions_with_unknown_symbol - assert_raise(ArgumentError) { stylesheet_link_tag('first', :unknown, 'last') } - end - - def test_custom_stylesheet_expansions_with_nil_value - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :monkey => nil - assert_dom_equal %(<link href="/stylesheets/first.css" rel="stylesheet" media="screen" />\n<link href="/stylesheets/last.css" rel="stylesheet" media="screen" />), stylesheet_link_tag('first', :monkey, 'last') - end - - def test_custom_stylesheet_expansions_with_empty_array_value - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :monkey => [] - assert_dom_equal %(<link href="/stylesheets/first.css" rel="stylesheet" media="screen" />\n<link href="/stylesheets/last.css" rel="stylesheet" media="screen" />), stylesheet_link_tag('first', :monkey, 'last') - end - - def test_registering_stylesheet_expansions_merges_with_existing_expansions - ENV["RAILS_ASSET_ID"] = "" - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :can_merge => ['bank'] - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :can_merge => ['robber'] - ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :can_merge => ['bank'] - assert_dom_equal %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />), stylesheet_link_tag(:can_merge) - end - def test_image_path ImagePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -567,21 +439,6 @@ class AssetTagHelperTest < ActionView::TestCase FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end - def test_image_tag_windows_behaviour - old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" - # This simulates the behavior of File#exist? on windows when testing a file ending in "." - # If the file "rails.png" exists, windows will return true when asked if "rails.png." exists (notice trailing ".") - # OS X, linux etc will return false in this case. - File.stubs(:exist?).with('template/../fixtures/public/images/rails.png.').returns(true) - assert_equal '<img alt="Rails" src="/images/rails.png?1" />', image_tag('rails.png') - ensure - if old_asset_id - ENV["RAILS_ASSET_ID"] = old_asset_id - else - ENV.delete("RAILS_ASSET_ID") - end - end - def test_video_path VideoPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end @@ -622,6 +479,10 @@ class AssetTagHelperTest < ActionView::TestCase AudioLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_font_path + FontPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_video_audio_tag_does_not_modify_options options = {:autoplay => true} video_tag('video', options) @@ -630,27 +491,6 @@ class AssetTagHelperTest < ActionView::TestCase assert_equal({:autoplay => true}, options) end - def test_timebased_asset_id - expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s - assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png") - end - - def test_string_asset_id - @controller.config.asset_path = "/assets.v12345%s" - - expected_path = "/assets.v12345/images/rails.png" - assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png") - end - - def test_proc_asset_id - @controller.config.asset_path = Proc.new do |asset_path| - "/assets.v12345#{asset_path}" - end - - expected_path = "/assets.v12345/images/rails.png" - assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png") - end - def test_image_tag_interpreting_email_cid_correctly # An inline image has no need for an alt tag to be automatically generated from the cid: assert_equal '<img src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid") @@ -660,37 +500,6 @@ class AssetTagHelperTest < ActionView::TestCase assert_equal '<img alt="Image" src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid", :alt => "Image") end - def test_timebased_asset_id_with_relative_url_root - @controller.config.relative_url_root = "/collaboration/hieraki" - expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s - assert_equal %(<img alt="Rails" src="#{@controller.config.relative_url_root}/images/rails.png?#{expected_time}" />), image_tag("rails.png") - end - - # Same as above, but with script_name - def test_timebased_asset_id_with_script_name - @request.script_name = "/collaboration/hieraki" - expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s - assert_equal %(<img alt="Rails" src="#{@request.script_name}/images/rails.png?#{expected_time}" />), image_tag("rails.png") - end - - def test_should_skip_asset_id_on_complete_url - assert_equal %(<img alt="Rails" src="http://www.example.com/rails.png" />), image_tag("http://www.example.com/rails.png") - end - - def test_should_skip_asset_id_on_scheme_relative_url - assert_equal %(<img alt="Rails" src="//www.example.com/rails.png" />), image_tag("//www.example.com/rails.png") - end - - def test_should_use_preset_asset_id - ENV["RAILS_ASSET_ID"] = "4500" - assert_equal %(<img alt="Rails" src="/images/rails.png?4500" />), image_tag("rails.png") - end - - def test_preset_empty_asset_id - ENV["RAILS_ASSET_ID"] = "" - assert_equal %(<img alt="Rails" src="/images/rails.png" />), image_tag("rails.png") - end - def test_should_not_modify_source_string source = '/images/rails.png' copy = source.dup @@ -699,7 +508,6 @@ class AssetTagHelperTest < ActionView::TestCase end def test_caching_image_path_with_caching_and_proc_asset_host_using_request - ENV['RAILS_ASSET_ID'] = '' @controller.config.asset_host = Proc.new do |source, request| if request.ssl? "#{request.protocol}#{request.host_with_port}" @@ -714,630 +522,20 @@ class AssetTagHelperTest < ActionView::TestCase @controller.request.stubs(:ssl?).returns(true) assert_equal "http://localhost/images/xml.png", image_path("xml.png") end - - def test_caching_javascript_include_tag_when_caching_on - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'http://a0.example.com' - config.perform_caching = true - - assert_dom_equal( - %(<script src="http://a0.example.com/javascripts/all.js"></script>), - javascript_include_tag(:all, :cache => true) - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="http://a0.example.com/javascripts/money.js"></script>), - javascript_include_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - - assert_dom_equal( - %(<script src="http://a0.example.com/absolute/test.js"></script>), - javascript_include_tag(:all, :cache => "/absolute/test") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) - end - - def test_caching_javascript_include_tag_when_caching_on_with_proc_asset_host - ENV['RAILS_ASSET_ID'] = '' - @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" } - config.perform_caching = true - - assert_equal '/javascripts/scripts.js'.length, 23 - assert_dom_equal( - %(<script src="http://a23.example.com/javascripts/scripts.js"></script>), - javascript_include_tag(:all, :cache => 'scripts') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'scripts.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'scripts.js')) - end - - def test_caching_javascript_include_tag_when_caching_on_with_2_argument_proc_asset_host - ENV['RAILS_ASSET_ID'] = '' - @controller.config.asset_host = Proc.new { |source, request| - if request.ssl? - "#{request.protocol}#{request.host_with_port}" - else - "#{request.protocol}assets#{source.length}.example.com" - end - } - config.perform_caching = true - - assert_equal '/javascripts/vanilla.js'.length, 23 - assert_dom_equal( - %(<script src="http://assets23.example.com/javascripts/vanilla.js"></script>), - javascript_include_tag(:all, :cache => 'vanilla') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js')) - - class << @controller.request - def protocol() 'https://' end - def ssl?() true end - end - - assert_equal '/javascripts/secure.js'.length, 22 - assert_dom_equal( - %(<script src="https://localhost/javascripts/secure.js"></script>), - javascript_include_tag(:all, :cache => 'secure') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js')) - end - - def test_caching_javascript_include_tag_when_caching_on_with_2_argument_object_asset_host - ENV['RAILS_ASSET_ID'] = '' - @controller.config.asset_host = Class.new do - def call(source, request) - if request.ssl? - "#{request.protocol}#{request.host_with_port}" - else - "#{request.protocol}assets#{source.length}.example.com" - end - end - end.new - - config.perform_caching = true - - assert_equal '/javascripts/vanilla.js'.length, 23 - assert_dom_equal( - %(<script src="http://assets23.example.com/javascripts/vanilla.js"></script>), - javascript_include_tag(:all, :cache => 'vanilla') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js')) - - class << @controller.request - def protocol() 'https://' end - def ssl?() true end - end - - assert_equal '/javascripts/secure.js'.length, 22 - assert_dom_equal( - %(<script src="https://localhost/javascripts/secure.js"></script>), - javascript_include_tag(:all, :cache => 'secure') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'vanilla.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'secure.js')) - end - - def test_caching_javascript_include_tag_when_caching_on_and_using_subdirectory - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'http://a%d.example.com' - config.perform_caching = true - - number = Zlib.crc32('/javascripts/cache/money.js') % 4 - assert_dom_equal( - %(<script src="http://a#{number}.example.com/javascripts/cache/money.js"></script>), - javascript_include_tag(:all, :cache => "cache/money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'cache', 'money.js')) - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'cache', 'money.js')) - end - - def test_caching_javascript_include_tag_with_all_and_recursive_puts_defaults_at_the_start_of_the_file - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'http://a0.example.com' - config.perform_caching = true - - assert_dom_equal( - %(<script src="http://a0.example.com/javascripts/combined.js"></script>), - javascript_include_tag(:all, :cache => "combined", :recursive => true) - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - - assert_equal( - %(// prototype js\n\n// effects js\n\n// dragdrop js\n\n// controls js\n\n// bank js\n\n// robber js\n\n// subdir js\n\n\n// version.1.0 js\n\n// application js), - IO.read(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - ) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - end - - def test_caching_javascript_include_tag_with_all_puts_defaults_at_the_start_of_the_file - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'http://a0.example.com' - config.perform_caching = true - - assert_dom_equal( - %(<script src="http://a0.example.com/javascripts/combined.js"></script>), - javascript_include_tag(:all, :cache => "combined") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - - assert_equal( - %(// prototype js\n\n// effects js\n\n// dragdrop js\n\n// controls js\n\n// bank js\n\n// robber js\n\n// version.1.0 js\n\n// application js), - IO.read(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - ) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'combined.js')) - end - - def test_caching_javascript_include_tag_with_relative_url_root - ENV["RAILS_ASSET_ID"] = "" - @controller.config.relative_url_root = "/collaboration/hieraki" - config.perform_caching = true - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/all.js"></script>), - javascript_include_tag(:all, :cache => true) - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/money.js"></script>), - javascript_include_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - # Same as above, but with script_name - def test_caching_javascript_include_tag_with_script_name - ENV["RAILS_ASSET_ID"] = "" - @request.script_name = "/collaboration/hieraki" - config.perform_caching = true - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/all.js"></script>), - javascript_include_tag(:all, :cache => true) - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/money.js"></script>), - javascript_include_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - def test_caching_javascript_include_tag_with_named_paths_and_relative_url_root_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - @controller.config.relative_url_root = "/collaboration/hieraki" - config.perform_caching = false - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/robber.js"></script>), - javascript_include_tag('robber', :cache => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/robber.js"></script>), - javascript_include_tag('robber', :cache => "money", :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - # Same as above, but with script_name - def test_caching_javascript_include_tag_with_named_paths_and_script_name_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - @request.script_name = "/collaboration/hieraki" - config.perform_caching = false - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/robber.js"></script>), - javascript_include_tag('robber', :cache => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="/collaboration/hieraki/javascripts/robber.js"></script>), - javascript_include_tag('robber', :cache => "money", :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - def test_caching_javascript_include_tag_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = false - - assert_dom_equal( - %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - javascript_include_tag(:all, :cache => true) - ) - - assert_dom_equal( - %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/subdir/subdir.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - javascript_include_tag(:all, :cache => true, :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_dom_equal( - %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - javascript_include_tag(:all, :cache => "money") - ) - - assert_dom_equal( - %(<script src="/javascripts/prototype.js"></script>\n<script src="/javascripts/effects.js"></script>\n<script src="/javascripts/dragdrop.js"></script>\n<script src="/javascripts/controls.js"></script>\n<script src="/javascripts/bank.js"></script>\n<script src="/javascripts/robber.js"></script>\n<script src="/javascripts/subdir/subdir.js"></script>\n<script src="/javascripts/version.1.0.js"></script>\n<script src="/javascripts/application.js"></script>), - javascript_include_tag(:all, :cache => "money", :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - def test_caching_javascript_include_tag_when_caching_on_and_missing_javascript_file - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = true - - assert_raise(Errno::ENOENT) { - javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => true) - } - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_raise(Errno::ENOENT) { - javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => "money") - } - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - def test_caching_javascript_include_tag_when_caching_on_and_javascript_file_is_uri - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = true - - assert_raise(Errno::ENOENT) { - javascript_include_tag('bank', 'robber', 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.js', :cache => true) - } - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - end - - def test_caching_javascript_include_tag_when_caching_off_and_missing_javascript_file - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = false - - assert_raise(Errno::ENOENT) { - javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => true) - } - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) - - assert_raise(Errno::ENOENT) { - javascript_include_tag('bank', 'robber', 'missing_security_guard', :cache => "money") - } - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) - end - - def test_caching_stylesheet_link_tag_when_caching_on - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'a0.example.com' - config.perform_caching = true - - assert_dom_equal( - %(<link href="http://a0.example.com/stylesheets/all.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => true) - ) - - files_to_be_joined = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/[^all]*.css"] - - expected_mtime = files_to_be_joined.map { |p| File.mtime(p) }.max - assert_equal expected_mtime, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - bytes_added_by_join = "\n\n".size * files_to_be_joined.size - "\n\n".size - expected_size = files_to_be_joined.sum { |p| File.size(p) } + bytes_added_by_join - assert_equal expected_size, File.size(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="http://a0.example.com/stylesheets/money.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - - assert_dom_equal( - %(<link href="http://a0.example.com/absolute/test.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "/absolute/test") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.css')) - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) - end - - def test_concat_stylesheet_link_tag_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - - assert_dom_equal( - %(<link href="/stylesheets/all.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :concat => true) - ) - - expected = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/*.css"].map { |p| File.mtime(p) }.max - assert_equal expected, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/stylesheets/money.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :concat => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - - assert_dom_equal( - %(<link href="/absolute/test.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :concat => "/absolute/test") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute', 'test.css')) - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::ASSETS_DIR, 'absolute')) - end - - def test_caching_stylesheet_link_tag_when_caching_on_and_missing_css_file - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = true - - assert_raise(Errno::ENOENT) { - stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => true) - } - - assert ! File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_raise(Errno::ENOENT) { - stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => "money") - } - - assert ! File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - def test_caching_stylesheet_link_tag_when_caching_off_and_missing_css_file - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = false - - assert_raise(Errno::ENOENT) { - stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => true) - } - - assert ! File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_raise(Errno::ENOENT) { - stylesheet_link_tag('bank', 'robber', 'missing_security_guard', :cache => "money") - } - - assert ! File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host - ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = Proc.new { |source| "a#{source.length}.example.com" } - config.perform_caching = true - - assert_equal '/stylesheets/styles.css'.length, 23 - assert_dom_equal( - %(<link href="http://a23.example.com/stylesheets/styles.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => 'styles') - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'styles.css')) - - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'styles.css')) - end - - def test_caching_stylesheet_link_tag_with_relative_url_root - ENV["RAILS_ASSET_ID"] = "" - @controller.config.relative_url_root = "/collaboration/hieraki" - config.perform_caching = true - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/all.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => true) - ) - - files_to_be_joined = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/[^all]*.css"] - - expected_mtime = files_to_be_joined.map { |p| File.mtime(p) }.max - assert_equal expected_mtime, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/money.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - # Same as above, but with script_name - def test_caching_stylesheet_link_tag_with_script_name - ENV["RAILS_ASSET_ID"] = "" - @request.script_name = "/collaboration/hieraki" - config.perform_caching = true - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/all.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => true) - ) - - files_to_be_joined = Dir["#{ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR}/[^all]*.css"] - - expected_mtime = files_to_be_joined.map { |p| File.mtime(p) }.max - assert_equal expected_mtime, File.mtime(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/money.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "money") - ) - - assert File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - ensure - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - - def test_caching_stylesheet_link_tag_with_named_paths_and_relative_url_root_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - @controller.config.relative_url_root = "/collaboration/hieraki" - config.perform_caching = false - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/robber.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag('robber', :cache => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/robber.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag('robber', :cache => "money") - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - # Same as above, but with script_name - def test_caching_stylesheet_link_tag_with_named_paths_and_script_name_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - @request.script_name = "/collaboration/hieraki" - config.perform_caching = false - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/robber.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag('robber', :cache => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/collaboration/hieraki/stylesheets/robber.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag('robber', :cache => "money") - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - def test_caching_stylesheet_include_tag_when_caching_off - ENV["RAILS_ASSET_ID"] = "" - config.perform_caching = false - - assert_dom_equal( - %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => true) - ) - - assert_dom_equal( - %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => true, :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - - assert_dom_equal( - %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "money") - ) - - assert_dom_equal( - %(<link href="/stylesheets/bank.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/robber.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/version.1.0.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag(:all, :cache => "money", :recursive => true) - ) - - assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) - end - - def test_caching_stylesheet_include_tag_with_absolute_uri - ENV["RAILS_ASSET_ID"] = "" - - assert_dom_equal( - %(<link href="/stylesheets/all.css" media="screen" rel="stylesheet" />), - stylesheet_link_tag("/foo/baz", :cache => true) - ) - - FileUtils.rm(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) - end end class AssetTagHelperNonVhostTest < ActionView::TestCase tests ActionView::Helpers::AssetTagHelper + attr_reader :request + def setup super @controller = BasicController.new @controller.config.relative_url_root = "/collaboration/hieraki" - @request = Struct.new(:protocol).new("gopher://") + @request = Struct.new(:protocol, :base_url).new("gopher://", "gopher://www.example.com") @controller.request = @request - - JavascriptIncludeTag.expansions.clear end def url_for(options) @@ -1351,10 +549,33 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_dom_equal(%(/collaboration/hieraki/images/xml.png), image_path("xml.png")) end + def test_should_return_nothing_if_asset_host_isnt_configured + assert_equal nil, compute_asset_host("foo") + end + + def test_should_current_request_host_is_always_returned_for_request + assert_equal "gopher://www.example.com", compute_asset_host("foo", :protocol => :request) + end + def test_should_ignore_relative_root_path_on_complete_url assert_dom_equal(%(http://www.example.com/images/xml.png), image_path("http://www.example.com/images/xml.png")) end + def test_should_return_simple_string_asset_host + @controller.config.asset_host = "assets.example.com" + assert_equal "gopher://assets.example.com", compute_asset_host("foo") + end + + def test_should_return_relative_asset_host + @controller.config.asset_host = "assets.example.com" + assert_equal "//assets.example.com", compute_asset_host("foo", :protocol => :relative) + end + + def test_should_return_custom_protocol_asset_host + @controller.config.asset_host = "assets.example.com" + assert_equal "ftp://assets.example.com", compute_asset_host("foo", :protocol => "ftp") + end + def test_should_compute_proper_path_with_asset_host @controller.config.asset_host = "assets.example.com" assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag) @@ -1387,6 +608,11 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_url("xml.png")) end + def test_should_return_asset_host_with_protocol + @controller.config.asset_host = "http://assets.example.com" + assert_equal "http://assets.example.com", compute_asset_host("foo") + end + def test_should_ignore_asset_host_on_complete_url @controller.config.asset_host = "http://assets.example.com" assert_dom_equal(%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("http://bar.example.com/stylesheets/style.css")) @@ -1397,6 +623,11 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_dom_equal(%(<link href="//bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("//bar.example.com/stylesheets/style.css")) end + def test_should_wildcard_asset_host + @controller.config.asset_host = 'http://a%d.example.com' + assert_match(%r(http://a[0123].example.com), compute_asset_host("foo")) + end + def test_should_wildcard_asset_host_between_zero_and_four @controller.config.asset_host = 'http://a%d.example.com' assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png')) @@ -1420,3 +651,73 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_dom_equal(%(/collaboration/hieraki/stylesheets/foo.css), stylesheet_path("foo")) end end + +class AssetUrlHelperControllerTest < ActionView::TestCase + tests ActionView::Helpers::AssetUrlHelper + + def setup + super + + @controller = BasicController.new + @controller.extend ActionView::Helpers::AssetUrlHelper + + @request = Class.new do + attr_accessor :script_name + def protocol() 'http://' end + def ssl?() false end + def host_with_port() 'www.example.com' end + def base_url() 'http://www.example.com' end + end.new + + @controller.request = @request + end + + def test_asset_path + assert_equal "/foo", @controller.asset_path("foo") + end + + def test_asset_url + assert_equal "http://www.example.com/foo", @controller.asset_url("foo") + end +end + +class AssetUrlHelperEmptyModuleTest < ActionView::TestCase + tests ActionView::Helpers::AssetUrlHelper + + def setup + super + + @module = Module.new + @module.extend ActionView::Helpers::AssetUrlHelper + end + + def test_asset_path + assert_equal "/foo", @module.asset_path("foo") + end + + def test_asset_url + assert_equal "/foo", @module.asset_url("foo") + end + + def test_asset_url_with_request + @module.instance_eval do + def request + Struct.new(:base_url, :script_name).new("http://www.example.com", nil) + end + end + + assert @module.request + assert_equal "http://www.example.com/foo", @module.asset_url("foo") + end + + def test_asset_url_with_config_asset_host + @module.instance_eval do + def config + Struct.new(:asset_host).new("http://www.example.com") + end + end + + assert @module.config.asset_host + assert_equal "http://www.example.com/foo", @module.asset_url("foo") + end +end diff --git a/actionpack/test/template/digestor_test.rb b/actionpack/test/template/digestor_test.rb index 01b101cb49..8181aa11f7 100644 --- a/actionpack/test/template/digestor_test.rb +++ b/actionpack/test/template/digestor_test.rb @@ -59,6 +59,12 @@ class TemplateDigestorTest < ActionView::TestCase change_template("comments/_comment") end end + + def test_directory_depth_dependency + assert_digest_difference("level/below/index") do + change_template("level/below/_header") + end + end def test_logging_of_missing_template assert_logged "Couldn't find template for digesting: messages/something_missing.html" do diff --git a/actionpack/test/template/sanitize_helper_test.rb b/actionpack/test/template/sanitize_helper_test.rb index 7626cdf386..12d5260a9d 100644 --- a/actionpack/test/template/sanitize_helper_test.rb +++ b/actionpack/test/template/sanitize_helper_test.rb @@ -17,7 +17,7 @@ class SanitizeHelperTest < ActionView::TestCase end def test_sanitize_form - assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", '' + assert_equal '', sanitize("<form action=\"/foo/bar\" method=\"post\"><input></form>") end def test_should_sanitize_illegal_style_properties @@ -48,8 +48,4 @@ class SanitizeHelperTest < ActionView::TestCase def test_sanitize_is_marked_safe assert sanitize("<html><script></script></html>").html_safe? end - - def assert_sanitized(text, expected = nil) - assert_equal((expected || text), sanitize(text)) - end end diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb index 5265ae6b3a..c7231d9cd5 100644 --- a/actionpack/test/template/test_case_test.rb +++ b/actionpack/test/template/test_case_test.rb @@ -321,6 +321,14 @@ module ActionView assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "Somebody Else" } end end + + test 'supports different locals on the same partial' do + controller.controller_path = "test" + render(:template => "test/render_two_partials") + assert_template partial: '_partial', locals: { 'first' => '1' } + assert_template partial: '_partial', locals: { 'second' => '2' } + end + end module AHelperWithInitialize diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc index b4565b5881..fc34d69ff6 100644 --- a/activemodel/README.rdoc +++ b/activemodel/README.rdoc @@ -23,7 +23,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>. validates_presence_of :name end - person = Person.new(:name => 'bob', :age => '18') + person = Person.new(name: 'bob', age: '18') person.name # => 'bob' person.age # => '18' person.valid? # => true diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 19e74d3cc9..509e2fdbb5 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -55,7 +55,7 @@ class SecurePasswordTest < ActiveModel::TestCase end test "User should not be created with blank digest" do - assert_raise RuntimeError do + assert_raise RuntimeError do @user.run_callbacks :create end @user.password = "supersecretpassword" diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 6e0f1f31dd..5f5c9e4915 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,24 @@ ## Rails 4.0.0 (unreleased) ## +* Fix bug where sum(expression) returns string '0' for no matching records + Fixes #7439 + + *Tim Macfarlane* + +* PostgreSQL adapter correctly fetches default values when using multiple schemas and domains in a db. Fixes #7914 + + *Arturo Pie* + +* Learn ActiveRecord::QueryMethods#order work with hash arguments + + When symbol or hash passed we convert it to Arel::Nodes::Ordering. + If we pass invalid direction(like name: :DeSc) ActiveRecord::QueryMethods#order will raise an exception + + User.order(:name, email: :desc) + # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC + + *Tima Maslyuchenko* + * Rename `ActiveRecord::Fixtures` class to `ActiveRecord::FixtureSet`. Instances of this class normally hold a collection of fixtures (records) loaded either from a single YAML file, or from a file and a folder diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 258d602afa..69b95f814c 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -190,10 +190,10 @@ module ActiveRecord # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt> # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt> # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt> - # <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.all(options),</tt> - # <tt>Project#milestones.build, Project#milestones.create</tt> + # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(mileston), Project#milestones.find(milestone_id),</tt> + # <tt>Project#milestones.all(options), Project#milestones.build, Project#milestones.create</tt> # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt> - # <tt>Project#categories.delete(category1)</tt> + # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt> # # === A word of warning # @@ -236,6 +236,7 @@ module ActiveRecord # others.clear | X | X | X # others.delete(other,other,...) | X | X | X # others.delete_all | X | X | X + # others.destroy(other,other,...) | X | X | X # others.destroy_all | X | X | X # others.find(*args) | X | X | X # others.exists? | X | X | X @@ -1031,6 +1032,12 @@ module ActiveRecord # If the <tt>:through</tt> option is used, then the join records are deleted (rather than # nullified) by default, but you can specify <tt>:dependent => :destroy</tt> or # <tt>:dependent => :nullify</tt> to override this. + # [collection.destroy(object, ...)] + # Removes one or more objects from the collection by running <tt>destroy</tt> on + # each record, regardless of any dependent option, ensuring callbacks are run. + # + # If the <tt>:through</tt> option is used, then the join records are destroyed + # instead, not the objects themselves. # [collection=objects] # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt> # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is @@ -1074,6 +1081,7 @@ module ActiveRecord # * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</tt>) # * <tt>Firm#clients<<</tt> # * <tt>Firm#clients.delete</tt> + # * <tt>Firm#clients.destroy</tt> # * <tt>Firm#clients=</tt> # * <tt>Firm#client_ids</tt> # * <tt>Firm#client_ids=</tt> @@ -1425,6 +1433,9 @@ module ActiveRecord # [collection.delete(object, ...)] # Removes one or more objects from the collection by removing their associations from the join table. # This does not destroy the objects. + # [collection.destroy(object, ...)] + # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option. + # This does not destroy the objects. # [collection=objects] # Replaces the collection's content by deleting and adding objects as appropriate. # [collection_singular_ids] @@ -1461,6 +1472,7 @@ module ActiveRecord # * <tt>Developer#projects</tt> # * <tt>Developer#projects<<</tt> # * <tt>Developer#projects.delete</tt> + # * <tt>Developer#projects.destroy</tt> # * <tt>Developer#projects=</tt> # * <tt>Developer#project_ids</tt> # * <tt>Developer#project_ids=</tt> diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index ce5bf15f10..c1cd3a4ae3 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -30,17 +30,21 @@ module ActiveRecord # option references an association's column), it will fallback to the table # join strategy. class Preloader #:nodoc: - autoload :Association, 'active_record/associations/preloader/association' - autoload :SingularAssociation, 'active_record/associations/preloader/singular_association' - autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association' - autoload :ThroughAssociation, 'active_record/associations/preloader/through_association' + extend ActiveSupport::Autoload - autoload :HasMany, 'active_record/associations/preloader/has_many' - autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through' - autoload :HasOne, 'active_record/associations/preloader/has_one' - autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through' - autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many' - autoload :BelongsTo, 'active_record/associations/preloader/belongs_to' + eager_autoload do + autoload :Association, 'active_record/associations/preloader/association' + autoload :SingularAssociation, 'active_record/associations/preloader/singular_association' + autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association' + autoload :ThroughAssociation, 'active_record/associations/preloader/through_association' + + autoload :HasMany, 'active_record/associations/preloader/has_many' + autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through' + autoload :HasOne, 'active_record/associations/preloader/has_one' + autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through' + autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many' + autoload :BelongsTo, 'active_record/associations/preloader/belongs_to' + end attr_reader :records, :associations, :preload_scope, :model diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 6213b5dcd5..46fd6ebfb3 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -35,21 +35,36 @@ module ActiveRecord protected - # We want to generate the methods via module_eval rather than define_method, - # because define_method is slower on dispatch and uses more memory (because it - # creates a closure). + # We want to generate the methods via module_eval rather than + # define_method, because define_method is slower on dispatch and + # uses more memory (because it creates a closure). # - # But sometimes the database might return columns with characters that are not - # allowed in normal method names (like 'my_column(omg)'. So to work around this - # we first define with the __temp__ identifier, and then use alias method to - # rename it to what we want. - def define_method_attribute(attr_name) + # But sometimes the database might return columns with + # characters that are not allowed in normal method names (like + # 'my_column(omg)'. So to work around this we first define with + # the __temp__ identifier, and then use alias method to rename + # it to what we want. + # + # We are also defining a constant to hold the frozen string of + # the attribute name. Using a constant means that we do not have + # to allocate an object on each call to the attribute method. + # Making it frozen means that it doesn't get duped when used to + # key the @attributes_cache in read_attribute. + def define_method_attribute(name) + safe_name = name.unpack('h*').first generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - def __temp__ - read_attribute(:'#{attr_name}') { |n| missing_attribute(n, caller) } + module AttrNames + unless defined? ATTR_#{safe_name} + ATTR_#{safe_name} = #{name.inspect}.freeze + end + end + + def __temp__#{safe_name} + read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) } end - alias_method '#{attr_name}', :__temp__ - undef_method :__temp__ + + alias_method #{name.inspect}, :__temp__#{safe_name} + undef_method :__temp__#{safe_name} STR end @@ -70,17 +85,13 @@ module ActiveRecord # it has been typecast (for example, "2004-12-12" in a data column is cast # to a date object, like Date.new(2004, 12, 12)). def read_attribute(attr_name) - return unless attr_name - name_sym = attr_name.to_sym - # If it's cached, just return it # We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/3552829. - @attributes_cache[name_sym] || @attributes_cache.fetch(name_sym) { - name = attr_name.to_s - + name = attr_name.to_s + @attributes_cache[name] || @attributes_cache.fetch(name) { column = @columns_hash.fetch(name) { return @attributes.fetch(name) { - if name_sym == :id && self.class.primary_key != name + if name == 'id' && self.class.primary_key != name read_attribute(self.class.primary_key) end } @@ -91,7 +102,7 @@ module ActiveRecord } if self.class.cache_attribute?(name) - @attributes_cache[name_sym] = column.type_cast(value) + @attributes_cache[name] = column.type_cast(value) else column.type_cast value end diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index b9a69cdb0a..f36a5806a9 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -50,7 +50,7 @@ module ActiveRecord if (rounded_value != rounded_time) || (!rounded_value && original_time) write_attribute("#{attr_name}", original_time) #{attr_name}_will_change! - @attributes_cache[:"#{attr_name}"] = zoned_time + @attributes_cache["#{attr_name}"] = zoned_time end end EOV diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 6eb9e25fd9..cd33494cc3 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -9,15 +9,19 @@ module ActiveRecord module ClassMethods protected - def define_method_attribute=(attr_name) - if attr_name =~ ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP - generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__) - else - generated_attribute_methods.send(:define_method, "#{attr_name}=") do |new_value| - write_attribute(attr_name, new_value) - end + + # See define_method_attribute in read.rb for an explanation of + # this code. + def define_method_attribute=(name) + safe_name = name.unpack('h*').first + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 + def __temp__#{safe_name}=(value) + write_attribute(AttrNames::ATTR_#{safe_name}, value) end - end + alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= + undef_method :__temp__#{safe_name}= + STR + end end # Updates the attribute identified by <tt>attr_name</tt> with the @@ -26,13 +30,13 @@ module ActiveRecord def write_attribute(attr_name, value) attr_name = attr_name.to_s attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key - @attributes_cache.delete(attr_name.to_sym) + @attributes_cache.delete(attr_name) column = column_for_attribute(attr_name) # If we're dealing with a binary column, write the data to the cache # so we don't attempt to typecast multiple times. if column && column.binary? - @attributes_cache[attr_name.to_sym] = value + @attributes_cache[attr_name] = value end if column || @attributes.has_key?(attr_name) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 37d43d891d..9d3fa18e3a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -90,7 +90,7 @@ module ActiveRecord else super(value, column) end when IPAddr - return super(value, column) unless ['inet','cidr'].includes? column.sql_type + return super(value, column) unless ['inet','cidr'].include? column.sql_type PostgreSQLColumn.cidr_to_string(value) else super(value, column) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 2264595751..7cad8f94cf 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -280,16 +280,13 @@ module ActiveRecord end_sql if result.nil? or result.empty? - # If that fails, try parsing the primary key's default value. - # Support the 7.x and 8.0 nextval('foo'::text) as well as - # the 8.1+ nextval('foo'::regclass). result = query(<<-end_sql, 'SCHEMA')[0] SELECT attr.attname, CASE - WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN - substr(split_part(def.adsrc, '''', 2), - strpos(split_part(def.adsrc, '''', 2), '.')+1) - ELSE split_part(def.adsrc, '''', 2) + WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN + substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), + strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1) + ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) END FROM pg_class t JOIN pg_attribute attr ON (t.oid = attrelid) @@ -297,7 +294,7 @@ module ActiveRecord JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1]) WHERE t.oid = '#{quote_table_name(table)}'::regclass AND cons.contype = 'p' - AND def.adsrc ~* 'nextval' + AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval' end_sql end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 5e35f472c7..e18464fa35 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -78,11 +78,8 @@ module ActiveRecord when /\A\(?(-?\d+(\.\d*)?\)?)\z/ $1 # Character types - when /\A'(.*)'::(?:character varying|bpchar|text)\z/m + when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m $1 - # Character types (8.1 formatting) - when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m - $1.gsub(/\\(\d\d\d)/) { $1.oct.chr } # Binary data types when /\A'(.*)'::bytea\z/m $1 @@ -241,7 +238,7 @@ module ActiveRecord # <encoding></tt> call on the connection. # * <tt>:min_messages</tt> - An optional client min messages that is used in a # <tt>SET client_min_messages TO <min_messages></tt> call on the connection. - # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT<tt> statements + # * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT</tt> statements # defaults to true. # # Any further options are used as connection parameters to libpq. See @@ -763,7 +760,8 @@ module ActiveRecord # - ::regclass is a function that gives the id for a table name def column_definitions(table_name) #:nodoc: exec_query(<<-end_sql, 'SCHEMA').rows - SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod + SELECT a.attname, format_type(a.atttypid, a.atttypmod), + pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 899e89a6f5..413bd147de 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -657,7 +657,7 @@ module ActiveRecord #-- # Deprecate 'Fixtures' in favor of 'FixtureSet'. #++ - Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', '::ActiveRecord::FixtureSet') + Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet') class Fixture #:nodoc: include Enumerable diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index c1d57855a9..d5ee98382d 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -50,7 +50,7 @@ module ActiveRecord # # class AddSsl < ActiveRecord::Migration # def up - # add_column :accounts, :ssl_enabled, :boolean, :default => true + # add_column :accounts, :ssl_enabled, :boolean, default: true # end # # def down @@ -62,7 +62,7 @@ module ActiveRecord # if you're backing out of the migration. It shows how all migrations have # two methods +up+ and +down+ that describes the transformations # required to implement or remove the migration. These methods can consist - # of both the migration specific methods like add_column and remove_column, + # of both the migration specific methods like +add_column+ and +remove_column+, # but may also contain regular Ruby code for generating data needed for the # transformations. # @@ -78,9 +78,9 @@ module ActiveRecord # t.integer :position # end # - # SystemSetting.create :name => "notice", - # :label => "Use notice?", - # :value => 1 + # SystemSetting.create name: 'notice', + # label: 'Use notice?', + # value: 1 # end # # def down @@ -88,19 +88,22 @@ module ActiveRecord # end # end # - # This migration first adds the system_settings table, then creates the very + # This migration first adds the +system_settings+ table, then creates the very # first row in it using the Active Record model that relies on the table. It - # also uses the more advanced create_table syntax where you can specify a + # also uses the more advanced +create_table+ syntax where you can specify a # complete table schema in one block call. # # == Available transformations # - # * <tt>create_table(name, options)</tt> Creates a table called +name+ and + # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and # makes the table object available to a block that can then add columns to it, - # following the same format as add_column. See example above. The options hash + # following the same format as +add_column+. See example above. The options hash # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create # table definition. # * <tt>drop_table(name)</tt>: Drops the table called +name+. + # * <tt>change_table(name, options)</tt>: Allows to make column alterations to + # the table called +name+. It makes the table object availabe to a block that + # can then add/remove columns, indexes or foreign keys to it. # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ # to +new_name+. # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column @@ -109,9 +112,9 @@ module ActiveRecord # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, # <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>, # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be - # specified by passing an +options+ hash like <tt>{ :default => 11 }</tt>. + # specified by passing an +options+ hash like <tt>{ default: 11 }</tt>. # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g. - # <tt>{ :limit => 50, :null => false }</tt>) -- see + # <tt>{ limit: 50, null: false }</tt>) -- see # ActiveRecord::ConnectionAdapters::TableDefinition#column for details. # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames # a column but keeps the type and content. @@ -122,11 +125,11 @@ module ActiveRecord # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index # with the name of the column. Other options include # <tt>:name</tt>, <tt>:unique</tt> (e.g. - # <tt>{ :name => "users_name_index", :unique => true }</tt>) and <tt>:order</tt> - # (e.g. { :order => {:name => :desc} }</tt>). - # * <tt>remove_index(table_name, :column => column_name)</tt>: Removes the index + # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt> + # (e.g. <tt>{ order: { name: :desc } }</tt>). + # * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index # specified by +column_name+. - # * <tt>remove_index(table_name, :name => index_name)</tt>: Removes the index + # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index # specified by +index_name+. # # == Irreversible transformations diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 0107667fbe..611d3d97c3 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -197,7 +197,7 @@ module ActiveRecord end end - # Updates a single attribute of an object, without having to call save on that object. + # Updates a single attribute of an object, without having to explicitly call save on that object. # # * Validation is skipped. # * Callbacks are skipped. @@ -209,7 +209,7 @@ module ActiveRecord update_columns(name => value) end - # Updates the attributes from the passed-in hash, without having to call save on that object. + # Updates the attributes from the passed-in hash, without having to explicitly call save on that object. # # * Validation is skipped. # * Callbacks are skipped. diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index ed80422336..ecce7c703b 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -91,8 +91,10 @@ module ActiveRecord end def initialize_copy(other) - @values = @values.dup - @values[:bind] = @values[:bind].dup if @values[:bind] + # This method is a hot spot, so for now, use Hash[] to dup the hash. + # https://bugs.ruby-lang.org/issues/7166 + @values = Hash[@values] + @values[:bind] = @values[:bind].dup if @values.key? :bind reset end @@ -540,7 +542,7 @@ module ActiveRecord end def values - @values.dup + Hash[@values] end def inspect diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 28aab6d92b..8af0c6a8ef 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -40,7 +40,7 @@ module ActiveRecord # # It's not possible to set the order. That is automatically set to # ascending on the primary key ("id ASC") to make the batch ordering - # work. This also mean that this method only works with integer-based + # work. This also means that this method only works with integer-based # primary keys. You can't set the limit either, that's used to control # the batch sizes. # diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 7c43d844d0..6317004631 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -349,7 +349,7 @@ module ActiveRecord def type_cast_calculated_value(value, column, operation = nil) case operation when 'count' then value.to_i - when 'sum' then type_cast_using_column(value || '0', column) + when 'sum' then type_cast_using_column(value || 0, column) when 'average' then value.respond_to?(:to_d) ? value.to_d : value else type_cast_using_column(value, column) end diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index e5b50673da..59226d316e 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -22,7 +22,17 @@ module ActiveRecord # the values. def other other = Relation.new(relation.klass, relation.table) - hash.each { |k, v| other.send("#{k}!", v) } + hash.each { |k, v| + if k == :joins + if Hash === v + other.joins!(v) + else + other.joins!(*v) + end + else + other.send("#{k}!", v) + end + } other end end @@ -39,16 +49,18 @@ module ActiveRecord @values = other.values end + NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS + + Relation::MULTI_VALUE_METHODS - + [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc: + def normal_values - Relation::SINGLE_VALUE_METHODS + - Relation::MULTI_VALUE_METHODS - - [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] + NORMAL_VALUES end def merge normal_values.each do |name| value = values[name] - relation.send("#{name}!", value) unless value.blank? + relation.send("#{name}!", *value) unless value.blank? end merge_multi_values diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 3c59bd8a68..14bcb337e9 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -202,6 +202,15 @@ module ActiveRecord # # User.order('name DESC, email') # => SELECT "users".* FROM "users" ORDER BY name DESC, email + # + # User.order(:name) + # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC + # + # User.order(email: :desc) + # => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC + # + # User.order(:name, email: :desc) + # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC def order(*args) args.blank? ? self : spawn.order!(*args) end @@ -210,6 +219,8 @@ module ActiveRecord def order!(*args) args.flatten! + validate_order_args args + references = args.reject { |arg| Arel::Node === arg } references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact! references!(references) if references.any? @@ -235,6 +246,8 @@ module ActiveRecord def reorder!(*args) args.flatten! + validate_order_args args + self.reordering_value = true self.order_values = args self @@ -245,13 +258,11 @@ module ActiveRecord # User.joins(:posts) # => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" def joins(*args) - args.compact.blank? ? self : spawn.joins!(*args) + args.compact.blank? ? self : spawn.joins!(*args.flatten) end # Like #joins, but modifies relation in place. def joins!(*args) - args.flatten! - self.joins_values += args self end @@ -658,9 +669,7 @@ module ActiveRecord arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty? - order = order_values - order = reverse_sql_order(order) if reverse_order_value - arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty? + build_order(arel) build_select(arel, select_values.uniq) @@ -729,22 +738,22 @@ module ActiveRecord buckets = joins.group_by do |join| case join when String - 'string_join' + :string_join when Hash, Symbol, Array - 'association_join' + :association_join when ActiveRecord::Associations::JoinDependency::JoinAssociation - 'stashed_join' + :stashed_join when Arel::Nodes::Join - 'join_node' + :join_node else raise 'unknown class: %s' % join.class.name end end - association_joins = buckets['association_join'] || [] - stashed_association_joins = buckets['stashed_join'] || [] - join_nodes = (buckets['join_node'] || []).uniq - string_joins = (buckets['string_join'] || []).map { |x| + association_joins = buckets[:association_join] || [] + stashed_association_joins = buckets[:stashed_join] || [] + join_nodes = (buckets[:join_node] || []).uniq + string_joins = (buckets[:string_join] || []).map { |x| x.strip }.uniq @@ -786,11 +795,17 @@ module ActiveRecord case o when Arel::Nodes::Ordering o.reverse - when String, Symbol + when String o.to_s.split(',').collect do |s| s.strip! s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') end + when Symbol + { o => :desc } + when Hash + o.each_with_object({}) do |(field, dir), memo| + memo[field] = (dir == :asc ? :desc : :asc ) + end else o end @@ -801,5 +816,31 @@ module ActiveRecord o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)} end + def build_order(arel) + orders = order_values + orders = reverse_sql_order(orders) if reverse_order_value + + orders = orders.uniq.reject(&:blank?).map do |order| + case order + when Symbol + table[order].asc + when Hash + order.map { |field, dir| table[field].send(dir) } + else + order + end + end.flatten + + arel.order(*orders) unless orders.empty? + end + + def validate_order_args(args) + args.select { |a| Hash === a }.each do |h| + unless (h.values - [:asc, :desc]).empty? + raise ArgumentError, 'Direction should be :asc or :desc' + end + end + end + end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 5dece1cb36..5fa6a0b892 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -26,11 +26,12 @@ module ActiveRecord relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted? Array(options[:scope]).each do |scope_item| - scope_value = record.read_attribute(scope_item) reflection = record.class.reflect_on_association(scope_item) if reflection scope_value = record.send(reflection.foreign_key) scope_item = reflection.foreign_key + else + scope_value = record.read_attribute(scope_item) end relation = relation.and(table[scope_item].eq(scope_value)) end diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index f8a605b67c..685f0ea74f 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'ipaddr' module ActiveRecord module ConnectionAdapters @@ -20,6 +21,18 @@ module ActiveRecord assert_equal 'f', @conn.type_cast(false, c) end + def test_type_cast_cidr + ip = IPAddr.new('255.0.0.0/8') + c = Column.new(nil, ip, 'cidr') + assert_equal ip, @conn.type_cast(ip, c) + end + + def test_type_cast_inet + ip = IPAddr.new('255.1.0.0/8') + c = Column.new(nil, ip, 'inet') + assert_equal ip, @conn.type_cast(ip, c) + end + def test_quote_float_nan nan = 0.0/0 c = Column.new(nil, 1, 'float') diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 9208f53997..cd31900d4e 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -72,7 +72,7 @@ class SchemaTest < ActiveRecord::TestCase end def test_schema_names - assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names + assert_equal ["public", "schema_1", "test_schema", "test_schema2"], @connection.schema_names end def test_create_schema @@ -97,7 +97,7 @@ class SchemaTest < ActiveRecord::TestCase def test_drop_schema begin - @connection.create_schema "test_schema3" + @connection.create_schema "test_schema3" ensure @connection.drop_schema "test_schema3" end diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb index 7eef4ace81..74288a98d1 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -59,7 +59,7 @@ class CopyTableTest < ActiveRecord::TestCase def test_copy_table_with_unconventional_primary_key test_copy_table('owners', 'owners_unconventional') do |from, to, options| - original_pk = @connection.primary_key('owners') + original_pk = @connection.primary_key('owners') copied_pk = @connection.primary_key('owners_unconventional') assert_equal original_pk, copied_pk end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index f0582a3090..b2a5d9d6f7 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -19,7 +19,6 @@ require 'models/book' require 'models/subscription' require 'models/essay' require 'models/category' -require 'models/owner' require 'models/categorization' require 'models/member' require 'models/membership' diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index d08b157011..c2b58fd7d1 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -542,10 +542,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase val = t.send attr_name unless attr_name == "type" if attribute_gets_cached assert cached_columns.include?(attr_name) - assert_equal val, cache[attr_name.to_sym] + assert_equal val, cache[attr_name] else assert uncached_columns.include?(attr_name) - assert !cache.include?(attr_name.to_sym) + assert !cache.include?(attr_name) end end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index fd4f09ab36..4afd33f273 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -16,7 +16,6 @@ require 'models/ship_part' require 'models/tag' require 'models/tagging' require 'models/treasure' -require 'models/company' require 'models/eye' class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 6cb6c469d2..de4902f89a 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -378,6 +378,10 @@ class CalculationsTest < ActiveRecord::TestCase end end + def test_sum_expression_returns_zero_when_no_records_to_sum + assert_equal 0, Account.where('1 = 2').sum("2 * credit_limit") + end + def test_count_with_from_option assert_equal Company.count(:all), Company.from('companies').count(:all) assert_equal Account.where("credit_limit = 50").count(:all), diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index deaf5252db..72f1c99ca0 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -109,3 +109,43 @@ if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter) end end end + +if current_adapter?(:PostgreSQLAdapter) + class DefaultsUsingMultipleSchemasAndDomainTest < ActiveSupport::TestCase + def setup + @connection = ActiveRecord::Base.connection + + @old_search_path = @connection.schema_search_path + @connection.schema_search_path = "schema_1, pg_catalog" + @connection.create_table "defaults" do |t| + t.text "text_col", :default => "some value" + t.string "string_col", :default => "some value" + end + Default.reset_column_information + end + + def test_text_defaults_in_new_schema_when_overriding_domain + assert_equal "some value", Default.new.text_col, "Default of text column was not correctly parse" + end + + def test_string_defaults_in_new_schema_when_overriding_domain + assert_equal "some value", Default.new.string_col, "Default of string column was not correctly parse" + end + + def test_bpchar_defaults_in_new_schema_when_overriding_domain + @connection.execute "ALTER TABLE defaults ADD bpchar_col bpchar DEFAULT 'some value'" + Default.reset_column_information + assert_equal "some value", Default.new.bpchar_col, "Default of bpchar column was not correctly parse" + end + + def test_text_defaults_after_updating_column_default + @connection.execute "ALTER TABLE defaults ALTER COLUMN text_col SET DEFAULT 'some text'::schema_1.text" + assert_equal "some text", Default.new.text_col, "Default of text column was not correctly parse after updating default using '::text' since postgreSQL will add parens to the default in db" + end + + def teardown + @connection.schema_search_path = @old_search_path + Default.reset_column_information + end + end +end diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index ec4c554abb..17c1634444 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -293,7 +293,7 @@ module ActiveRecord connection.create_table :testings do |t| t.column :foo, :string, limit: 100 t.column :bar, :decimal, precision: 8, scale: 2 - t.column :taggable_id, :integer, null: false + t.column :taggable_id, :integer, null: false t.column :taggable_type, :string, default: 'Photo' end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 9120083eca..fe9eddbdec 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -156,7 +156,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_reject_if_with_blank_nested_attributes_id - # When using a select list to choose an existing 'ship' id, with :include_blank => true + # When using a select list to choose an existing 'ship' id, with include_blank: true Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? } pirate = Pirate.new(:catchphrase => "Stop wastin' me time") diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 2d778e9e90..51a285a2b4 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -48,7 +48,7 @@ class QueryCacheTest < ActiveRecord::TestCase } assert_raises(RuntimeError) { mw.call({}) } - assert_equal connection_id, ActiveRecord::Base.connection_id + assert_equal connection_id, ActiveRecord::Base.connection_id end def test_middleware_delegates diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 588da68ec1..a9d46f4fba 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -3,7 +3,6 @@ require 'models/topic' require 'models/customer' require 'models/company' require 'models/company_in_module' -require 'models/subscriber' require 'models/ship' require 'models/pirate' require 'models/price_estimate' diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index b91423351e..fdbc0a3fdb 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -5,7 +5,6 @@ require 'models/post' require 'models/topic' require 'models/comment' require 'models/author' -require 'models/comment' require 'models/entrant' require 'models/developer' require 'models/reply' @@ -158,6 +157,22 @@ class RelationTest < ActiveRecord::TestCase assert_equal 4, topics.to_a.size assert_equal topics(:first).title, topics.first.title end + + def test_finding_with_assoc_order + topics = Topic.order(:id => :desc) + assert_equal 4, topics.to_a.size + assert_equal topics(:fourth).title, topics.first.title + end + + def test_finding_with_reverted_assoc_order + topics = Topic.order(:id => :asc).reverse_order + assert_equal 4, topics.to_a.size + assert_equal topics(:fourth).title, topics.first.title + end + + def test_raising_exception_on_invalid_hash_params + assert_raise(ArgumentError) { Topic.order(:name, "id DESC", :id => :DeSc) } + end def test_finding_last_with_arel_order topics = Topic.order(Topic.arel_table[:id].asc) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 80f46c6b08..5f13124e5b 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -2,13 +2,9 @@ require "cases/helper" class SchemaDumperTest < ActiveRecord::TestCase - def initialize(*) - super - ActiveRecord::SchemaMigration.create_table - end - def setup super + ActiveRecord::SchemaMigration.create_table @stream = StringIO.new end diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb index a8e513d81f..2f5ee32538 100644 --- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb @@ -13,7 +13,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new yield - ensure + ensure I18n.load_path.replace @old_load_path I18n.backend = @old_backend end diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 15b97c02c8..efa0c9b934 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -43,7 +43,7 @@ class I18nValidationTest < ActiveRecord::TestCase [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }] # TODO Add :on case, but below doesn't work, because then the validation isn't run for some reason # even when using .save instead .valid? - # [ "given on condition", {:on => :save}, {}] + # [ "given on condition", {on: :save}, {}] ] # validates_uniqueness_of w/ mocha diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index 2cd9f30b59..d0e7338f15 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -12,6 +12,8 @@ ActiveRecord::Schema.define do execute 'DROP FUNCTION IF EXISTS partitioned_insert_trigger()' + execute "DROP SCHEMA IF EXISTS schema_1 CASCADE" + %w(accounts_id_seq developers_id_seq projects_id_seq topics_id_seq customers_id_seq orders_id_seq).each do |seq_name| execute "SELECT setval('#{seq_name}', 100)" end @@ -37,7 +39,12 @@ ActiveRecord::Schema.define do ); _SQL - execute <<_SQL + execute "CREATE SCHEMA schema_1" + execute "CREATE DOMAIN schema_1.text AS text" + execute "CREATE DOMAIN schema_1.varchar AS varchar" + execute "CREATE DOMAIN schema_1.bpchar AS bpchar" + + execute <<_SQL CREATE TABLE geometrics ( id serial primary key, a_point point, diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 0a12ba6cdd..23e2ce0b03 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,16 @@ ## Rails 4.0.0 (unreleased) ## +* Hash#extract! returns only those keys that present in the receiver. + + {:a => 1, :b => 2}.extract!(:a, :x) # => {:a => 1} + + *Mikhail Dieterle* + +* Hash#extract! returns the same subclass, that the receiver is. I.e. + HashWithIndifferentAccess#extract! returns HashWithIndifferentAccess instance. + + *Mikhail Dieterle* + * Optimize ActiveSupport::Cache::Entry to reduce memory and processing overhead. *Brian Durand* * Tests tag the Rails log with the current test class and test case: diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 690e5ce194..732ab4b7df 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -644,7 +644,7 @@ module ActiveSupport @c = @compressed remove_instance_variable(:@compressed) end - if defined?(@expires_in) && defined?(@created_at) + if defined?(@expires_in) && defined?(@created_at) && @expires_in && @created_at @x = (@created_at + @expires_in).to_i remove_instance_variable(:@created_at) remove_instance_variable(:@expires_in) diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 5aa78cc9f3..17450fe4d0 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -132,6 +132,10 @@ module ActiveSupport method = options && options[:unless_exist] ? :add : :set value = options[:raw] ? entry.value.to_s : entry expires_in = options[:expires_in].to_i + if expires_in > 0 && !options[:raw] + # Set the memcache expire a few minutes in the future to support race condition ttls on read + expires_in += 5.minutes + end @data.send(method, escape_key(key), value, expires_in, options) rescue Dalli::DalliError => e logger.error("DalliError (#{e}): #{e.message}") if logger diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 45fec57009..de09f26f3d 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -32,9 +32,9 @@ class Hash # Removes and returns the key/value pairs matching the given keys. # - # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) - # # => {:a => 1, :b => 2} + # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => { a: 1, b: 2 } + # { a: 1, b: 2 }.extract!(:a, :x) # => { a: 1 } def extract!(*keys) - keys.each_with_object({}) { |key, result| result[key] = delete(key) } + keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) } end end diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index ab01d7787a..ec2157221f 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -1,11 +1,14 @@ require 'active_support/core_ext/object/acts_like' require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/deep_dup' require 'active_support/core_ext/object/duplicable' +require 'active_support/core_ext/object/deep_dup' +require 'active_support/core_ext/object/try' require 'active_support/core_ext/object/inclusion' + +require 'active_support/core_ext/object/conversions' require 'active_support/core_ext/object/instance_variables' + require 'active_support/core_ext/object/to_json' require 'active_support/core_ext/object/to_param' require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/object/try' require 'active_support/core_ext/object/with_options' diff --git a/activesupport/lib/active_support/core_ext/object/conversions.rb b/activesupport/lib/active_support/core_ext/object/conversions.rb new file mode 100644 index 0000000000..540f7aadb0 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/object/conversions.rb @@ -0,0 +1,4 @@ +require 'active_support/core_ext/object/to_param' +require 'active_support/core_ext/object/to_query' +require 'active_support/core_ext/array/conversions' +require 'active_support/core_ext/hash/conversions' diff --git a/activesupport/lib/active_support/queueing.rb b/activesupport/lib/active_support/queueing.rb index 7c352886f3..c8ba28021d 100644 --- a/activesupport/lib/active_support/queueing.rb +++ b/activesupport/lib/active_support/queueing.rb @@ -56,32 +56,6 @@ module ActiveSupport end end - # A container for multiple queues. This class delegates to a default Queue - # so that <tt>Rails.queue.push</tt> and friends will Just Work. To use this class - # with multiple queues: - # - # # In your configuration: - # Rails.queue[:image_queue] = SomeQueue.new - # Rails.queue[:mail_queue] = SomeQueue.new - # - # # In your app code: - # Rails.queue[:mail_queue].push SomeJob.new - # - class QueueContainer < DelegateClass(::Queue) - def initialize(default_queue) - @queues = { :default => default_queue } - super(default_queue) - end - - def [](queue_name) - @queues[queue_name] - end - - def []=(queue_name, queue) - @queues[queue_name] = queue - end - end - # The threaded consumer will run jobs in a background thread in # development mode or in a VM where running jobs on a thread in # production mode makes sense. @@ -90,10 +64,6 @@ module ActiveSupport # queue and joins the thread, which will ensure that all jobs # are executed before the process finally dies. class ThreadedQueueConsumer - def self.start(*args) - new(*args).start - end - def initialize(queue, options = {}) @queue = queue @logger = options[:logger] diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index febf0eeeff..9f76f4c90b 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -3,6 +3,20 @@ require 'abstract_unit' require 'active_support/cache' class CacheKeyTest < ActiveSupport::TestCase + def test_entry_legacy_optional_ivars + legacy = Class.new(ActiveSupport::Cache::Entry) do + def initialize(value, options = {}) + @value = value + @expires_in = nil + @created_at = nil + super + end + end + + entry = legacy.new 'foo' + assert_equal 'foo', entry.value + end + def test_expand_cache_key assert_equal '1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true]) assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name) diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index b7c3b130c3..8810302f40 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -120,7 +120,7 @@ module CallbacksTest end class Child < ParentController - skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update} + skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update} skip_callback :dispatch, :after, :log2 end diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index 0b33a63460..9dfa2cbf11 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -1,6 +1,7 @@ require 'abstract_unit' require 'active_support/core_ext/array' require 'active_support/core_ext/big_decimal' +require 'active_support/core_ext/object/conversions' require 'active_support/core_ext' # FIXME: pulling in all to_xml extensions require 'active_support/hash_with_indifferent_access' diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 53ea2aad16..7cfe7b0ea7 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -3,6 +3,7 @@ require 'active_support/core_ext/hash' require 'bigdecimal' require 'active_support/core_ext/string/access' require 'active_support/ordered_hash' +require 'active_support/core_ext/object/conversions' require 'active_support/core_ext/object/deep_dup' require 'active_support/inflections' @@ -723,8 +724,32 @@ class HashExtTest < ActiveSupport::TestCase def test_extract original = {:a => 1, :b => 2, :c => 3, :d => 4} expected = {:a => 1, :b => 2} + remaining = {:c => 3, :d => 4} - assert_equal expected, original.extract!(:a, :b) + assert_equal expected, original.extract!(:a, :b, :x) + assert_equal remaining, original + end + + def test_extract_nils + original = {:a => nil, :b => nil} + expected = {:a => nil} + extracted = original.extract!(:a, :x) + + assert_equal expected, extracted + assert_equal nil, extracted[:a] + assert_equal nil, extracted[:x] + end + + def test_indifferent_extract + original = {:a => 1, 'b' => 2, :c => 3, 'd' => 4}.with_indifferent_access + expected = {:a => 1, :b => 2}.with_indifferent_access + remaining = {:c => 3, :d => 4}.with_indifferent_access + + [['a', 'b'], [:a, :b]].each do |keys| + copy = original.dup + assert_equal expected, copy.extract!(*keys) + assert_equal remaining, copy + end end def test_except diff --git a/activesupport/test/queueing/container_test.rb b/activesupport/test/queueing/container_test.rb deleted file mode 100644 index 7afc11e7a9..0000000000 --- a/activesupport/test/queueing/container_test.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'abstract_unit' -require 'active_support/queueing' - -module ActiveSupport - class ContainerTest < ActiveSupport::TestCase - def test_delegates_to_default - q = Queue.new - container = QueueContainer.new q - job = Object.new - - container.push job - assert_equal job, q.pop - end - - def test_access_default - q = Queue.new - container = QueueContainer.new q - assert_equal q, container[:default] - end - - def test_assign_queue - container = QueueContainer.new Object.new - q = Object.new - container[:foo] = q - assert_equal q, container[:foo] - end - end -end diff --git a/activesupport/test/queueing/test_queue_test.rb b/activesupport/test/queueing/test_queue_test.rb index e398a48bea..451fb68d3e 100644 --- a/activesupport/test/queueing/test_queue_test.rb +++ b/activesupport/test/queueing/test_queue_test.rb @@ -99,4 +99,48 @@ class TestQueueTest < ActiveSupport::TestCase assert job.ran?, "The job runs synchronously when the queue is drained" assert_equal job.thread_id, Thread.current.object_id end + + class IdentifiableJob + def initialize(id) + @id = id + end + + def ==(other) + other.same_id?(@id) + end + + def same_id?(other_id) + other_id == @id + end + + def run + end + end + + def test_queue_can_be_observed + jobs = (1..10).map do |id| + IdentifiableJob.new(id) + end + + jobs.each do |job| + @queue.push job + end + + assert_equal jobs, @queue.jobs + end + + def test_adding_an_unmarshallable_job + anonymous_class_instance = Struct.new(:run).new + + assert_raises TypeError do + @queue.push anonymous_class_instance + end + end + + def test_attempting_to_add_a_reference_to_itself + job = {reference: @queue} + assert_raises TypeError do + @queue.push job + end + end end diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index cce5bc5331..6b3680aa2d 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -95,9 +95,9 @@ Railties * Load all environments available in `config.paths["config/environments"]`. -* Add `config.queue_consumer` to allow the default consumer to be configurable. +* Add `config.queue_consumer` to change the job queue consumer from the default `ActiveSupport::ThreadedQueueConsumer`. -* Add `Rails.queue` as an interface with a default implementation that consumes jobs in a separate thread. +* Add `Rails.queue` for processing jobs in the background. * Remove `Rack::SSL` in favour of `ActionDispatch::SSL`. @@ -141,6 +141,8 @@ Action Mailer end ``` +* Allow for callbacks in mailers similar to ActionController::Base. You can now set up headers/attachments using `before_filter` or `after_filter`. You could also change delivery settings or prevent delivery in an after filter based on instance variables set in your mailer action. You have access to `ActionMailer::Base` instance methods like `message`, `attachments`, `headers`. + Action Pack ----------- @@ -808,6 +810,10 @@ Active Support * Add `Time#prev_quarter` and `Time#next_quarter` short-hands for `months_ago(3)` and `months_since(3)`. +* Add `Time#last_week`, `Time#last_month`, `Time#last_year` as aliases for `Time#prev_week`, `Time#prev_month`, and `Time#prev_year`. + +* Add `Date#last_week`, `Date#last_month`, `Date#last_year` as aliases for `Date#prev_week`, `Date#prev_month`, and `Date#prev_year`. + * Remove obsolete and unused `require_association` method from dependencies. * Add `:instance_accessor` option for `config_accessor`. diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index b992defa6d..a938db6265 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -476,7 +476,7 @@ The following configuration options are best made in one of the environment file |`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.| |`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default "localhost" setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>| |`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>| -|`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered.| +|`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.| |`delivery_method`|Defines a delivery method. Possible values are `:smtp` (default), `:sendmail`, `:file` and `:test`.| |`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| |`deliveries`|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 1ae6a1f204..66e6390f67 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -375,8 +375,6 @@ end Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:start` option on each worker. -NOTE: The `:include` option allows you to name associations that should be loaded alongside with the models. - #### `find_in_batches` The `find_in_batches` method is similar to `find_each`, since both retrieve batches of records. The difference is that `find_in_batches` yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices: diff --git a/guides/source/active_record_validations_callbacks.md b/guides/source/active_record_validations_callbacks.md index f32c1050ce..333cbdd90b 100644 --- a/guides/source/active_record_validations_callbacks.md +++ b/guides/source/active_record_validations_callbacks.md @@ -50,6 +50,7 @@ end We can see how it works by looking at some `rails console` output: ```ruby +$ rails console >> p = Person.new(:name => "John Doe") => #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil> >> p.new_record? @@ -60,6 +61,8 @@ We can see how it works by looking at some `rails console` output: => false ``` +TIP: All lines starting with a dollar sign `$` are intended to be run on the command line. + Creating and saving a new record will send an SQL `INSERT` operation to the database. Updating an existing record will send an SQL `UPDATE` operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the `INSERT` or `UPDATE` operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. CAUTION: There are many ways to change the state of an object in the database. Some methods will trigger validations, but some will not. This means that it's possible to save an object in the database in an invalid state if you aren't careful. diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 645498437d..f990b4f79f 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2867,8 +2867,16 @@ The method `extract!` removes and returns the key/value pairs matching the given ```ruby hash = {:a => 1, :b => 2} -rest = hash.extract!(:a) # => {:a => 1} -hash # => {:b => 2} +rest = hash.extract!(:a, :x) # => {:a => 1} # non-existing keys are ignored +hash # => {:b => 2} +``` + +The method `extract!` returns the same subclass of Hash, that the receiver is. + +```ruby +hash = {:a => 1, :b => 2}.with_indifferent_access +rest = hash.extract!(:a).class +# => ActiveSupport::HashWithIndifferentAccess ``` NOTE: Defined in `active_support/core_ext/hash/slice.rb`. diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index dbf18b511c..42c7c07745 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -1130,6 +1130,7 @@ When you declare a `has_many` association, the declaring class automatically gai * `collection(force_reload = false)` * `collection<<(object, ...)` * `collection.delete(object, ...)` +* `collection.destroy(object, ...)` * `collection=objects` * `collection_singular_ids` * `collection_singular_ids=ids` @@ -1156,6 +1157,7 @@ Each instance of the customer model will have these methods: orders(force_reload = false) orders<<(object, ...) orders.delete(object, ...) +orders.destroy(object, ...) orders=objects order_ids order_ids=ids @@ -1195,6 +1197,15 @@ The `collection.delete` method removes one or more objects from the collection b WARNING: Additionally, objects will be destroyed if they're associated with `:dependent => :destroy`, and deleted if they're associated with `:dependent => :delete_all`. +##### `collection.destroy(object, ...)` + +The `collection.destroy` method removes one or more objects from the collection by running `destroy` on each object. + +```ruby +@customer.orders.destroy(@order1) +``` + +WARNING: Objects will _always_ be removed from the database, ignoring the `:dependent` option. ##### `collection=objects` @@ -1564,6 +1575,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au * `collection(force_reload = false)` * `collection<<(object, ...)` * `collection.delete(object, ...)` +* `collection.destroy(object, ...)` * `collection=objects` * `collection_singular_ids` * `collection_singular_ids=ids` @@ -1590,6 +1602,7 @@ Each instance of the part model will have these methods: assemblies(force_reload = false) assemblies<<(object, ...) assemblies.delete(object, ...) +assemblies.destroy(object, ...) assemblies=objects assembly_ids assembly_ids=ids @@ -1636,6 +1649,16 @@ The `collection.delete` method removes one or more objects from the collection b @part.assemblies.delete(@assembly1) ``` +WARNING: This does not trigger callbacks on the join records. + +##### `collection.destroy(object, ...)` + +The `collection.destroy` method removes one or more objects from the collection by running `destroy` on each record in the join table, including running callbacks. This does not destroy the objects. + +```ruby +@part.assemblies.destroy(@assembly1) +``` + ##### `collection=objects` The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index ce1a01d313..e4d2ecaba1 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -5,17 +5,20 @@ This guide will teach you what you need to know about avoiding that expensive ro After reading this guide, you should be able to use and configure: -* Page, action, and fragment caching -* Sweepers -* Alternative cache stores -* Conditional GET support +* Page, action, and fragment caching. +* Sweepers. +* Alternative cache stores. +* Conditional GET support. -------------------------------------------------------------------------------- Basic Caching ------------- -This is an introduction to the three types of caching techniques that Rails provides by default without the use of any third party plugins. +This is an introduction to three types of caching techniques: page, action and +fragment caching. Rails provides by default fragment caching. In order to use +page and action caching, you will need to add `actionpack-page_caching` and +`actionpack-action_caching` to your Gemfile. To start playing with caching you'll want to ensure that `config.action_controller.perform_caching` is set to `true`, if you're running in development mode. This flag is normally set in the corresponding `config/environments/*.rb` and caching is disabled by default for development and test, and enabled for production. @@ -44,7 +47,7 @@ Let's say you have a controller called `ProductsController` and an `index` actio By default, the page cache directory is set to `Rails.public_path` (which is usually set to the `public` folder) and this can be configured by changing the configuration setting `config.action_controller.page_cache_directory`. Changing the default from `public` helps avoid naming conflicts, since you may want to put other static html in `public`, but changing this will require web server reconfiguration to let the web server know where to serve the cached files from. -The Page Caching mechanism will automatically add a `.html` extension to requests for pages that do not have an extension to make it easy for the webserver to find those pages and this can be configured by changing the configuration setting `config.action_controller.page_cache_extension`. +The Page Caching mechanism will automatically add a `.html` extension to requests for pages that do not have an extension to make it easy for the webserver to find those pages and this can be configured by changing the configuration setting `config.action_controller.default_static_extension`. In order to expire this page when a new product is added we could extend our example controller like this: diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 8efc1f655f..26c7976c6b 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -115,9 +115,9 @@ NOTE. The `config.asset_path` configuration is ignored if the asset pipeline is * `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below. -* `config.queue` configures a different queue implementation for the application. Defaults to `ActiveSupport::SynchronousQueue`. Note that, if the default queue is changed, the default `queue_consumer` is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s). +* `config.queue` configures the default job queue for the application. Defaults to `ActiveSupport::Queue.new` which processes jobs in a background thread. If you change the queue, you're responsible for running the jobs as well. -* `config.queue_consumer` configures a different consumer implementation for the default queue. Defaults to `ActiveSupport::ThreadedQueueConsumer`. +* `config.queue_consumer` configures a different job consumer for the default queue. Defaults to `ActiveSupport::ThreadedQueueConsumer`. The job consumer must respond to `start`. * `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If `config.cache_classes` is true, this option is ignored. @@ -282,12 +282,8 @@ config.middleware.delete ActionDispatch::BestStandardsSupport * `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default. -* `config.active_record.whitelist_attributes` will create an empty whitelist of attributes available for mass-assignment security for all models in your app. - * `config.active_record.auto_explain_threshold_in_seconds` configures the threshold for automatic EXPLAINs (`nil` disables this feature). Queries exceeding the threshold get their query plan logged. Default is 0.5 in development mode. -* `config.active_record.mass_assignment_sanitizer` will determine the strictness of the mass assignment sanitization within Rails. Defaults to `:strict`. In this mode, mass assigning any non-`attr_accessible` attribute in a `create` or `update_attributes` call will raise an exception. Setting this option to `:logger` will only print to the log file when an attribute is being assigned and will not raise an exception. - The MySQL adapter adds one additional configuration option: * `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default. @@ -304,27 +300,21 @@ The schema dumper adds one additional configuration option: * `config.action_controller.asset_path` takes a block which configures where assets can be found. Shorter version of `config.action_controller.asset_path`. -* `config.action_controller.page_cache_directory` should be the document root for the web server and is set using `Base.page_cache_directory = "/document/root"`. For Rails, this directory has already been set to `Rails.public_path` (which is usually set to `Rails.root ` "/public"`). Changing this setting can be useful to avoid naming conflicts with files in `public/`, but doing so will likely require configuring your web server to look in the new location for cached files. - -* `config.action_controller.page_cache_extension` configures the extension used for cached pages saved to `page_cache_directory`. Defaults to `.html`. - * `config.action_controller.perform_caching` configures whether the application should perform caching or not. Set to false in development mode, true in production. +* `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`. + * `config.action_controller.default_charset` specifies the default character set for all renders. The default is "utf-8". * `config.action_controller.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to `nil` to disable logging. * `config.action_controller.request_forgery_protection_token` sets the token parameter name for RequestForgery. Calling `protect_from_forgery` sets it to `:authenticity_token` by default. -* `config.action_controller.allow_forgery_protection` enables or disables CSRF protection. By default this is false in test mode and true in all other modes. +* `config.action_controller.allow_forgery_protection` enables or disables CSRF protection. By default this is `false` in test mode and `true` in all other modes. * `config.action_controller.relative_url_root` can be used to tell Rails that you are deploying to a subdirectory. The default is `ENV['RAILS_RELATIVE_URL_ROOT']`. -The caching code adds two additional settings: - -* `ActionController::Base.page_cache_directory` sets the directory where Rails will create cached pages for your web server. The default is `Rails.public_path` (which is usually set to `Rails.root + "/public"`). - -* `ActionController::Base.page_cache_extension` sets the extension to be used when generating pages for the cache (this is ignored if the incoming request already has an extension). The default is `.html`. +* `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`. ### Configuring Action Dispatch diff --git a/guides/source/engines.md b/guides/source/engines.md index 7aef0f150f..97af423f3e 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -33,10 +33,10 @@ Finally, engines would not have been possible without the work of James Adam, Pi Generating an engine -------------------- -To generate an engine with Rails 3.1, you will need to run the plugin generator and pass it the `--full` and `--mountable` options. To generate the beginnings of the "blorgh" engine you will need to run this command in a terminal: +To generate an engine with Rails 3.2, you will need to run the plugin generator and pass it options as appropriate to the need. For the "blorgh" example, you will need to create a "mountable" engine, running this command in a terminal: ```bash -$ rails plugin new blorgh --full --mountable +$ rails plugin new blorgh --mountable ``` The full list of options for the plugin generator may be seen by typing: @@ -45,9 +45,48 @@ The full list of options for the plugin generator may be seen by typing: $ rails plugin --help ``` -The `--full` option tells the plugin generator that you want to create an engine, creating the basic directory structure of an engine by providing things such as an `app` directory and a `config/routes.rb` file. This generator also provides a file at `lib/blorgh/engine.rb` which is identical in function to a standard Rails application's `config/application.rb` file. +The `--full` option tells the generator that you want to create an engine, including a skeleton structure by providing the following: -The `--mountable` option tells the generator to mount the engine inside the dummy testing application located at `test/dummy`. It does this by placing this line into the dummy application's routes file at `test/dummy/config/routes.rb`: + * An `app` directory tree + * A `config/routes.rb` file: + + ```ruby + Rails.application.routes.draw do + end + ``` + * A file at `lib/blorgh/engine.rb` which is identical in function to a standard Rails application's `config/application.rb` file: + + ```ruby + module Blorgh + class Engine < ::Rails::Engine + end + end + ``` + +The `--mountable` option tells the generator that you want to create a "mountable" and namespace-isolated engine. This generator will provide the same skeleton structure as would the `--full` option, and will add: + + * Asset manifest files (`application.js` and `application.css`) + * A namespaced `ApplicationController` stub + * A namespaced `ApplicationHelper` stub + * A layout view template for the engine + * Namespace isolation to `config/routes.rb`: + + ```ruby + Blorgh::Engine.routes.draw do + end + ``` + + * Namespace isolation to `lib/blorgh/engine.rb`: + + ```ruby + module Blorgh + class Engine < ::Rails::Engine + isolate_namespace Blorgh + end + end + ``` + +Additionally, the `--mountable` option tells the generator to mount the engine inside the dummy testing application located at `test/dummy` by adding the following to the dummy application's routes file at `test/dummy/config/routes.rb`: ```ruby mount Blorgh::Engine, :at => "blorgh" diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 3fbe64c4a7..9f23f9fc42 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -77,10 +77,17 @@ TIP: The examples below use # and $ to denote superuser and regular user termina ### Installing Rails +Open up a command line prompt. On a mac this is called terminal, on windows it is called command prompt. Any commands prefaced with a dollar sign `$` should be run in the command line. Verify sure you have a current version of Ruby installed: + +```bash +$ ruby -v +ruby 1.9.3p194 +``` + To install Rails, use the `gem install` command provided by RubyGems: ```bash -# gem install rails +$ gem install rails ``` TIP. A number of tools exist to help you quickly install Ruby and Ruby @@ -154,11 +161,11 @@ $ rails server TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the absence of a runtime will give you an `execjs` error. Usually Mac OS X and Windows come with a JavaScript runtime installed. Rails adds the `therubyracer` gem to Gemfile in a commented line for new apps and you can uncomment if you need it. `therubyrhino` is the recommended runtime for JRuby users and is added by default to Gemfile in apps generated under JRuby. You can investigate about all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme). -This will fire up WEBrick, a webserver built into Ruby by default. To see your application in action, open a browser window and navigate to [http://localhost:3000](http://localhost:3000). You should see the Rails default information page: +This will fire up WEBrick, a webserver built into Ruby by default. To see your application in action, open a browser window and navigate to <http://localhost:3000>. You should see the Rails default information page:  -TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server. +TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. To verify the server has stopped you should see your command prompt cursor again. For most unix like systems including mac this will be a dollar sign `$`. In development mode, Rails does not generally require you to restart the server; changes you make in files will be automatically picked up by the server. The "Welcome Aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a page. You can also click on the _About your application’s environment_ link to see a summary of your application's environment. @@ -207,11 +214,11 @@ Open the `app/views/welcome/index.html.erb` file in your text editor and edit it ### Setting the Application Home Page -Now that we have made the controller and view, we need to tell Rails when we want Hello Rails! to show up. In our case, we want it to show up when we navigate to the root URL of our site, [http://localhost:3000](http://localhost:3000). At the moment, however, the "Welcome Aboard" smoke test is occupying that spot. +Now that we have made the controller and view, we need to tell Rails when we want Hello Rails! to show up. In our case, we want it to show up when we navigate to the root URL of our site, <http://localhost:3000>. At the moment, however, the "Welcome Aboard" smoke test is occupying that spot. To fix this, delete the `index.html` file located inside the `public` directory of the application. -You need to do this because Rails will serve any static file in the `public` directory that matches a route in preference to any dynamic content you generate from the controllers. The `index.html` file is special: it will be served if a request comes in at the root route, e.g. [http://localhost:3000](http://localhost:3000). If another request such as [http://localhost:3000/welcome](http://localhost:3000/welcome) happened, a static file at `public/welcome.html` would be served first, but only if it existed. +You need to do this because Rails will serve any static file in the `public` directory that matches a route in preference to any dynamic content you generate from the controllers. The `index.html` file is special: it will be served if a request comes in at the root route, e.g. <http://localhost:3000>. If another request such as <http://localhost:3000/welcome> happened, a static file at `public/welcome.html` would be served first, but only if it existed. Next, you have to tell Rails where your actual home page is located. @@ -235,9 +242,9 @@ This is your application's _routing file_ which holds entries in a special DSL ( root :to => "welcome#index" ``` -The `root :to => "welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to [http://localhost:3000/welcome/index](http://localhost:3000/welcome/index) to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`). +The `root :to => "welcome#index"` tells Rails to map requests to the root of the application to the welcome controller's index action and `get "welcome/index"` tells Rails to map requests to <http://localhost:3000/welcome/index> to the welcome controller's index action. This was created earlier when you ran the controller generator (`rails generate controller welcome index`). -If you navigate to [http://localhost:3000](http://localhost:3000) in your browser, you'll see the `Hello, Rails!` message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` action and is rendering the view correctly. +If you navigate to <http://localhost:3000> in your browser, you'll see the `Hello, Rails!` message you put into `app/views/welcome/index.html.erb`, indicating that this new route is indeed going to `WelcomeController`'s `index` action and is rendering the view correctly. NOTE. For more information about routing, refer to [Rails Routing from the Outside In](routing.html). @@ -256,7 +263,7 @@ It will look a little basic for now, but that's ok. We'll look at improving the ### Laying down the ground work -The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. If you attempt to navigate to that now -- by visiting [http://localhost:3000/posts/new](http://localhost:3000/posts/new) -- Rails will give you a routing error: +The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at `/posts/new`. If you attempt to navigate to that now -- by visiting <http://localhost:3000/posts/new> -- Rails will give you a routing error:  @@ -270,7 +277,7 @@ get "posts/new" This route is a super-simple route: it defines a new route that only responds to `GET` requests, and that the route is at `posts/new`. But how does it know where to go without the use of the `:to` option? Well, Rails uses a sensible default here: Rails will assume that you want this route to go to the new action inside the posts controller. -With the route defined, requests can now be made to `/posts/new` in the application. Navigate to [http://localhost:3000/posts/new](http://localhost:3000/posts/new) and you'll see another routing error: +With the route defined, requests can now be made to `/posts/new` in the application. Navigate to <http://localhost:3000/posts/new> and you'll see another routing error:  @@ -289,7 +296,7 @@ end A controller is simply a class that is defined to inherit from `ApplicationController`. It's inside this class that you'll define methods that will become the actions for this controller. These actions will perform CRUD operations on the posts within our system. -If you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) now, you'll get a new error: +If you refresh <http://localhost:3000/posts/new> now, you'll get a new error:  @@ -302,7 +309,7 @@ def new end ``` -With the `new` method defined in `PostsController`, if you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll see another error: +With the `new` method defined in `PostsController`, if you refresh <http://localhost:3000/posts/new> you'll see another error:  @@ -330,7 +337,7 @@ Go ahead now and create a new file at `app/views/posts/new.html.erb` and write t <h1>New Post</h1> ``` -When you refresh [http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll now see that the page has a title. The route, controller, action and view are now working harmoniously! It's time to create the form for a new post. +When you refresh <http://localhost:3000/posts/new> you'll now see that the page has a title. The route, controller, action and view are now working harmoniously! It's time to create the form for a new post. ### The first form @@ -579,7 +586,7 @@ content: ``` Finally, if you now go to -[http://localhost:3000/posts/new](http://localhost:3000/posts/new) you'll +<http://localhost:3000/posts/new> you'll be able to create a post. Try it!  @@ -756,7 +763,7 @@ Notice that inside the `create` action we use `render` instead of `redirect_to` returns `false`. The `render` method is used so that the `@post` object is passed back to the `new` template when it is rendered. This rendering is done within the same request as the form submission, whereas the `redirect_to` will tell the browser to issue another request. If you reload -[http://localhost:3000/posts/new](http://localhost:3000/posts/new) and +<http://localhost:3000/posts/new> and try to save a post without a title, Rails will send you back to the form, but that's not very useful. You need to tell the user that something went wrong. To do that, you'll modify @@ -1037,7 +1044,7 @@ Then do the same for the `app/views/posts/edit.html.erb` view: <%= link_to 'Back', :action => :index %> ``` -Point your browser to [http://localhost:3000/posts/new](http://localhost:3000/posts/new) and +Point your browser to <http://localhost:3000/posts/new> and try creating a new post. Everything still works. Now try editing the post and you'll receive the following error: @@ -1057,10 +1064,10 @@ If you run `rake routes` from the console you'll see that we already have a `posts_path` route, which was created automatically by Rails when we defined the route for the index action. However, we don't have a `post_path` yet, which is the reason why we -received an error before. +received an error before. With your server running you can view your routes by visiting [localhost:3000/rails/info/routes](http://localhost:3000/rails/info/routes), or you can generate them from the command line by running `rake routes`: ```bash -# rake routes +$ rake routes posts GET /posts(.:format) posts#index posts_new GET /posts/new(.:format) posts#new @@ -1198,7 +1205,7 @@ If you run `rake routes`, you'll see that all the routes that we declared before are still available: ```bash -# rake routes +$ rake routes posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new diff --git a/guides/source/i18n.md b/guides/source/i18n.md index a3c6b514a4..eda1881e73 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -94,13 +94,13 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations. -NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](ht) +NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize2](https://github.com/joshmh/globalize2/tree/master) may help you implement it. The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you. NOTE: The backend will lazy-load these translations when a translation is looked up for the first time. This makes it possible to just swap the backend with something else even after translations have already been announced. -The default `application.rb` files has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines. +The default initializer `locale.rb` file has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines. ```ruby # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. diff --git a/guides/source/migrations.md b/guides/source/migrations.md index 705b65ee8b..57db14f30c 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -85,7 +85,7 @@ existing users. ### Using the change method -Rails 3.1 makes migrations smarter by providing a new `change` method. +Rails 3.1 and up makes migrations smarter by providing a `change` method. This method is preferred for writing constructive migrations (adding columns or tables). The migration knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate `down` method. @@ -235,6 +235,8 @@ adding these columns will also be created. For example, running $ rails generate model Product name:string description:text ``` +TIP: All lines starting with a dollar sign `$` are intended to be run on the command line. + will create a migration that looks like this ```ruby @@ -544,7 +546,7 @@ support](#active-record-and-referential-integrity). If the helpers provided by Active Record aren't enough you can use the `execute` method to execute arbitrary SQL. -For more details and examples of individual methods, check the API documentation. +For more details and examples of individual methods, check the API documentation. In particular the documentation for [`ActiveRecord::ConnectionAdapters::SchemaStatements`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html) (which provides the methods available in the `up` and `down` methods), @@ -700,6 +702,14 @@ will run the `up` method from the 20080906120000 migration. This task will first check whether the migration is already performed and will do nothing if Active Record believes that it has already been run. +### Running Migrations in Different Environments + +By default running `rake db:migrate` will run in the `development` environment. To run migrations against another environment you can specify it using the `RAILS_ENV` environment variable while running the command. For example to run migrations against the `test` environment you could run: + +```bash +$ rake db:migrate RAILS_ENV=test +``` + ### Changing the Output of Running Migrations By default migrations tell you exactly what they're doing and how long it took. @@ -879,6 +889,27 @@ class AddFuzzToProduct < ActiveRecord::Migration end ``` +There are other ways in which the above example could have gone badly. + +For example, imagine that Alice creates a migration that selectively +updates the +description+ field on certain products. She runs the +migration, commits the code, and then begins working on the next feature, +which is to add a new column +fuzz+ to the products table. + +She creates two migrations for this new feature, one which adds the new +column, and a second which selectively updates the +fuzz+ column based on +other product attributes. + +These migrations run just fine, but when Bob comes back from his vacation +and calls `rake db:migrate` to run all the outstanding migrations, he gets a +subtle bug: The descriptions have defaults, and the +fuzz+ column is present, +but +fuzz+ is nil on all products. + +The solution is again to use +Product.reset_column_information+ before +referencing the Product model in a migration, ensuring the Active Record's +knowledge of the table structure is current before manipulating data in those +records. + Schema Dumping and You ---------------------- diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 0e59395c8a..ba96c0c0a9 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -162,8 +162,8 @@ You can add a new middleware to the middleware stack using any of the following config.middleware.use Rack::BounceFavicon # Add Lifo::Cache after ActiveRecord::QueryCache. -# Pass { :page_cache => false } argument to Lifo::Cache. -config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, :page_cache => false +# Pass { page_cache: false } argument to Lifo::Cache. +config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, page_cache: false ``` #### Swapping a Middleware diff --git a/guides/source/routing.md b/guides/source/routing.md index 3acb7fa0e5..469fcf49fb 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -30,14 +30,14 @@ it asks the router to match it to a controller action. If the first matching rou get "/patients/:id" => "patients#show" ``` -the request is dispatched to the `patients` controller's `show` action with `{ :id => "17" }` in `params`. +the request is dispatched to the `patients` controller's `show` action with `{ id: "17" }` in `params`. ### Generating Paths and URLs from Code You can also generate paths and URLs. If the route above is modified to be ```ruby -get "/patients/:id" => "patients#show", :as => "patient" +get "/patients/:id" => "patients#show", as: "patient" ``` If your application contains this code: @@ -73,7 +73,7 @@ it asks the router to map it to a controller action. If the first matching route resources :photos ``` -Rails would dispatch that request to the `destroy` method on the `photos` controller with `{ :id => "17" }` in `params`. +Rails would dispatch that request to the `destroy` method on the `photos` controller with `{ id: "17" }` in `params`. ### CRUD, Verbs, and Actions @@ -186,7 +186,7 @@ This will create a number of routes for each of the `posts` and `comments` contr If you want to route `/posts` (without the prefix `/admin`) to `Admin::PostsController`, you could use ```ruby -scope :module => "admin" do +scope module: "admin" do resources :posts, :comments end ``` @@ -194,7 +194,7 @@ end or, for a single case ```ruby -resources :posts, :module => "admin" +resources :posts, module: "admin" ``` If you want to route `/admin/posts` to `PostsController` (without the `Admin::` module prefix), you could use @@ -208,7 +208,7 @@ end or, for a single case ```ruby -resources :posts, :path => "/admin/posts" +resources :posts, path: "/admin/posts" ``` In each of these cases, the named routes remain the same as if you did not use `scope`. In the last case, the following paths map to `PostsController`: @@ -375,7 +375,7 @@ Within the block of member routes, each route name specifies the HTTP verb that ```ruby resources :photos do - get 'preview', :on => :member + get 'preview', on: :member end ``` @@ -397,7 +397,7 @@ Just as with member routes, you can pass `:on` to a route: ```ruby resources :photos do - get 'search', :on => :collection + get 'search', on: :collection end ``` @@ -407,7 +407,7 @@ To add an alternate new action using the `:on` shortcut: ```ruby resources :comments do - get 'preview', :on => :new + get 'preview', on: :new end ``` @@ -449,10 +449,10 @@ An incoming path of `/photos/show/1/2` will be dispatched to the `show` action o NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g: ```ruby -get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/ +get ':controller(/:action(/:id))', controller: /admin\/[^\/]+/ ``` -TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `:id => /[^\/]+/` allows anything except a slash. +TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `id: /[^\/]+/` allows anything except a slash. ### Static Segments @@ -462,7 +462,7 @@ You can specify static segments when creating a route: get ':controller/:action/:id/with_user/:user_id' ``` -This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }`. +This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ controller: "photos", action: "show", id: "1", user_id: "2" }`. ### The Query String @@ -472,7 +472,7 @@ The `params` will also include any parameters from the query string. For example get ':controller/:action/:id' ``` -An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ :controller => "photos", :action => "show", :id => "1", :user_id => "2" }`. +An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: "photos", action: "show", id: "1", user_id: "2" }`. ### Defining Defaults @@ -487,7 +487,7 @@ With this route, Rails will match an incoming path of `/photos/12` to the `show` You can also define other defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example: ```ruby -get 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' } +get 'photos/:id' => 'photos#show', defaults: { format: 'jpg' } ``` Rails would match `photos/12` to the `show` action of `PhotosController`, and set `params[:format]` to `"jpg"`. @@ -497,7 +497,7 @@ Rails would match `photos/12` to the `show` action of `PhotosController`, and se You can specify a name for any route using the `:as` option. ```ruby -get 'exit' => 'sessions#destroy', :as => :logout +get 'exit' => 'sessions#destroy', as: :logout ``` This will create `logout_path` and `logout_url` as named helpers in your application. Calling `logout_path` will return `/exit` @@ -505,7 +505,7 @@ This will create `logout_path` and `logout_url` as named helpers in your applica You can also use this to override routing methods defined by resources, like this: ```ruby -get ':username', :to => "users#show", :as => :user +get ':username', to: "users#show", as: :user ``` This will define a `user_path` method that will be available in controllers, helpers and views that will go to a route such as `/bob`. Inside the `show` action of `UsersController`, `params[:username]` will contain the username for the user. Change `:username` in the route definition if you do not want your parameter name to be `:username`. @@ -515,13 +515,13 @@ This will define a `user_path` method that will be available in controllers, hel In general, you should use the `get`, `post`, `put` and `delete` methods to constrain a route to a particular verb. You can use the `match` method with the `:via` option to match multiple verbs at once: ```ruby -match 'photos' => 'photos#show', :via => [:get, :post] +match 'photos' => 'photos#show', via: [:get, :post] ``` -You can match all verbs to a particular route using `:via => :all`: +You can match all verbs to a particular route using `via: :all`: ```ruby -match 'photos' => 'photos#show', :via => :all +match 'photos' => 'photos#show', via: :all ``` You should avoid routing all verbs to an action unless you have a good reason to, as routing both `GET` requests and `POST` requests to a single action has security implications. @@ -531,19 +531,19 @@ You should avoid routing all verbs to an action unless you have a good reason to You can use the `:constraints` option to enforce a format for a dynamic segment: ```ruby -get 'photos/:id' => 'photos#show', :constraints => { :id => /[A-Z]\d{5}/ } +get 'photos/:id' => 'photos#show', constraints: { id: /[A-Z]\d{5}/ } ``` This route would match paths such as `/photos/A12345`. You can more succinctly express the same route this way: ```ruby -get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ +get 'photos/:id' => 'photos#show', id: /[A-Z]\d{5}/ ``` `:constraints` takes regular expressions with the restriction that regexp anchors can't be used. For example, the following route will not work: ```ruby -get '/:id' => 'posts#show', :constraints => {:id => /^\d/} +get '/:id' => 'posts#show', constraints: {id: /^\d/} ``` However, note that you don't need to use anchors because all routes are anchored at the start. @@ -551,7 +551,7 @@ However, note that you don't need to use anchors because all routes are anchored For example, the following routes would allow for `posts` with `to_param` values like `1-hello-world` that always begin with a number and `users` with `to_param` values like `david` that never begin with a number to share the root namespace: ```ruby -get '/:id' => 'posts#show', :constraints => { :id => /\d.+/ } +get '/:id' => 'posts#show', constraints: { id: /\d.+/ } get '/:username' => 'users#show' ``` @@ -562,14 +562,14 @@ You can also constrain a route based on any method on the <a href="action_contro You specify a request-based constraint the same way that you specify a segment constraint: ```ruby -get "photos", :constraints => {:subdomain => "admin"} +get "photos", constraints: {subdomain: "admin"} ``` You can also specify constraints in a block form: ```ruby namespace :admin do - constraints :subdomain => "admin" do + constraints subdomain: "admin" do resources :photos end end @@ -592,7 +592,7 @@ end TwitterClone::Application.routes.draw do get "*path" => "blacklist#index", - :constraints => BlacklistConstraint.new + constraints: BlacklistConstraint.new end ``` @@ -601,7 +601,7 @@ You can also specify constraints as a lambda: ```ruby TwitterClone::Application.routes.draw do get "*path" => "blacklist#index", - :constraints => lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) } + constraints: lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) } end ``` @@ -639,16 +639,16 @@ NOTE: Starting from Rails 3.1, wildcard routes will always match the optional fo get '*pages' => 'pages#show' ``` -NOTE: By requesting `"/foo/bar.json"`, your `params[:pages]` will be equals to `"foo/bar"` with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `:format => false` like this: +NOTE: By requesting `"/foo/bar.json"`, your `params[:pages]` will be equals to `"foo/bar"` with the request format of JSON. If you want the old 3.0.x behavior back, you could supply `format: false` like this: ```ruby -get '*pages' => 'pages#show', :format => false +get '*pages' => 'pages#show', format: false ``` -NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply `:format => true` like this: +NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply `format: true` like this: ```ruby -get '*pages' => 'pages#show', :format => true +get '*pages' => 'pages#show', format: true ``` ### Redirection @@ -681,10 +681,10 @@ In all of these cases, if you don't provide the leading host (`http://www.exampl Instead of a String, like `"posts#index"`, which corresponds to the `index` action in the `PostsController`, you can specify any <a href="rails_on_rack.html">Rack application</a> as the endpoint for a matcher. ```ruby -match "/application.js" => Sprockets, :via => :all +match "/application.js" => Sprockets, via: :all ``` -As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `:via => :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate. +As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate. NOTE: For the curious, `"posts#index"` actually expands out to `PostsController.action(:index)`, which returns a valid Rack application. @@ -693,7 +693,7 @@ NOTE: For the curious, `"posts#index"` actually expands out to `PostsController. You can specify what Rails should route `"/"` to with the `root` method: ```ruby -root :to => 'pages#main' +root to: 'pages#main' root 'pages#main' # shortcut for the above ``` @@ -719,7 +719,7 @@ While the default routes and helpers generated by `resources :posts` will usuall The `:controller` option lets you explicitly specify a controller to use for the resource. For example: ```ruby -resources :photos, :controller => "images" +resources :photos, controller: "images" ``` will recognize incoming paths beginning with `/photos` but route to the `Images` controller: @@ -741,7 +741,7 @@ NOTE: Use `photos_path`, `new_photo_path`, etc. to generate paths for this resou You can use the `:constraints` option to specify a required format on the implicit `id`. For example: ```ruby -resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/} +resources :photos, constraints: {id: /[A-Z][A-Z][0-9]+/} ``` This declaration constrains the `:id` parameter to match the supplied regular expression. So, in this case, the router would no longer match `/photos/1` to this route. Instead, `/photos/RR27` would match. @@ -749,7 +749,7 @@ This declaration constrains the `:id` parameter to match the supplied regular ex You can specify a single constraint to apply to a number of routes by using the block form: ```ruby -constraints(:id => /[A-Z][A-Z][0-9]+/) do +constraints(id: /[A-Z][A-Z][0-9]+/) do resources :photos resources :accounts end @@ -757,14 +757,14 @@ end NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context. -TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `:id => /[^\/]+/` allows anything except a slash. +TIP: By default the `:id` parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an `:id` add a constraint which overrides this - for example `id: /[^\/]+/` allows anything except a slash. ### Overriding the Named Helpers The `:as` option lets you override the normal naming for the named route helpers. For example: ```ruby -resources :photos, :as => "images" +resources :photos, as: "images" ``` will recognize incoming paths beginning with `/photos` and route the requests to `PhotosController`, but use the value of the :as option to name the helpers. @@ -784,7 +784,7 @@ will recognize incoming paths beginning with `/photos` and route the requests to The `:path_names` option lets you override the automatically-generated "new" and "edit" segments in paths: ```ruby -resources :photos, :path_names => { :new => 'make', :edit => 'change' } +resources :photos, path_names: { new: 'make', edit: 'change' } ``` This would cause the routing to recognize paths such as @@ -799,7 +799,7 @@ NOTE: The actual action names aren't changed by this option. The two paths shown TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope. ```ruby -scope :path_names => { :new => "make" } do +scope path_names: { new: "make" } do # rest of your routes end ``` @@ -810,7 +810,7 @@ You can use the `:as` option to prefix the named route helpers that Rails genera ```ruby scope "admin" do - resources :photos, :as => "admin_photos" + resources :photos, as: "admin_photos" end resources :photos @@ -821,7 +821,7 @@ This will provide route helpers such as `admin_photos_path`, `new_admin_photo_pa To prefix a group of route helpers, use `:as` with `scope`: ```ruby -scope "admin", :as => "admin" do +scope "admin", as: "admin" do resources :photos, :accounts end @@ -847,7 +847,7 @@ This will provide you with URLs such as `/bob/posts/1` and will allow you to ref By default, Rails creates routes for the seven default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the `:only` and `:except` options to fine-tune this behavior. The `:only` option tells Rails to create only the specified routes: ```ruby -resources :photos, :only => [:index, :show] +resources :photos, only: [:index, :show] ``` Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photos` (which would ordinarily be routed to the `create` action) will fail. @@ -855,7 +855,7 @@ Now, a `GET` request to `/photos` would succeed, but a `POST` request to `/photo The `:except` option specifies a route or list of routes that Rails should _not_ create: ```ruby -resources :photos, :except => :destroy +resources :photos, except: :destroy ``` In this case, Rails will create all of the normal routes except the route for `destroy` (a `DELETE` request to `/photos/:id`). @@ -867,8 +867,8 @@ TIP: If your application has many RESTful routes, using `:only` and `:except` to Using `scope`, we can alter path names generated by resources: ```ruby -scope(:path_names => { :new => "neu", :edit => "bearbeiten" }) do - resources :categories, :path => "kategorien" +scope(path_names: { new: "neu", edit: "bearbeiten" }) do + resources :categories, path: "kategorien" end ``` @@ -900,7 +900,7 @@ The `:as` option overrides the automatically-generated name for the resource in ```ruby resources :magazines do - resources :ads, :as => 'periodical_ads' + resources :ads, as: 'periodical_ads' end ``` @@ -952,8 +952,8 @@ Routes should be included in your testing strategy (just like the rest of your a `assert_generates` asserts that a particular set of options generate a particular path and can be used with default routes or custom routes. ```ruby -assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" } -assert_generates "/about", :controller => "pages", :action => "about" +assert_generates "/photos/1", { controller: "photos", action: "show", id: "1" } +assert_generates "/about", controller: "pages", action: "about" ``` #### The `assert_recognizes` Assertion @@ -961,13 +961,13 @@ assert_generates "/about", :controller => "pages", :action => "about" `assert_recognizes` is the inverse of `assert_generates`. It asserts that a given path is recognized and routes it to a particular spot in your application. ```ruby -assert_recognizes({ :controller => "photos", :action => "show", :id => "1" }, "/photos/1") +assert_recognizes({ controller: "photos", action: "show", id: "1" }, "/photos/1") ``` You can supply a `:method` argument to specify the HTTP verb: ```ruby -assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }) +assert_recognizes({ controller: "photos", action: "create" }, { path: "photos", method: :post }) ``` #### The `assert_routing` Assertion @@ -975,5 +975,5 @@ assert_recognizes({ :controller => "photos", :action => "create" }, { :path => " The `assert_routing` assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of `assert_generates` and `assert_recognizes`. ```ruby -assert_routing({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }) +assert_routing({ path: "photos", method: :post }, { controller: "photos", action: "create" }) ``` diff --git a/guides/source/security.md b/guides/source/security.md index 0186386059..5ef68d2272 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -96,8 +96,8 @@ That means the security of this storage depends on this secret (and on the diges ```ruby config.action_dispatch.session = { - :key => '_app_session', - :secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...' + key: '_app_session', + secret: '0x0dkfj3927dkc7djdh36rkckdfzsg...' } ``` @@ -233,7 +233,7 @@ Or the attacker places the code into the onmouseover event handler of an image: There are many other possibilities, including Ajax to attack the victim in the background.
The _solution to this is including a security token in non-GET requests_ which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller: ```ruby -protect_from_forgery :secret => "123456789012345678901234567890..." +protect_from_forgery secret: "123456789012345678901234567890..." ``` This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. **Note:** In Rails versions prior to 3.0.4, this raised an `ActionController::InvalidAuthenticityToken` error. @@ -264,7 +264,7 @@ Whenever the user is allowed to pass (parts of) the URL for redirection, it is p ```ruby def legacy - redirect_to(params.update(:action=>'main')) + redirect_to(params.update(action:'main')) end ``` @@ -334,7 +334,7 @@ basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files')) filename = File.expand_path(File.join(basename, @file.public_filename)) raise if basename != File.expand_path(File.join(File.dirname(filename), '../../../')) -send_file filename, :disposition => 'inline' +send_file filename, disposition: 'inline' ``` Another (additional) approach is to store the file names in the database and name the files on the disk after the ids in the database. This is also a good approach to avoid possible code in an uploaded file to be executed. The attachment_fu plugin does this in a similar way. @@ -383,7 +383,7 @@ any model's attributes by manipulating the hash passed to a model's `new()` meth ```ruby def signup - params[:user] # => {:name=>"ow3ned", :admin=>true} + params[:user] # => {name:"ow3ned", admin:true} @user = User.new(params[:user]) end ``` @@ -402,7 +402,7 @@ http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1 This will set the following parameters in the controller: ```ruby -params[:user] # => {:name=>"ow3ned", :admin=>true} +params[:user] # => {name:"ow3ned", admin:true} ``` So if you create a new user using mass-assignment, it may be too easy to become @@ -459,9 +459,9 @@ should be allowed for mass updating using the slice pattern. For example: ```ruby def signup params[:user] - # => {:name=>"ow3ned", :admin=>true} + # => {name:"ow3ned", admin:true} permitted_params = params.require(:user).permit(:name) - # => {:name=>"ow3ned"} + # => {name:"ow3ned"} @user = User.new(permitted_params) end @@ -499,10 +499,11 @@ attributes. ```ruby def user_params - filters = [:name] - filters << :admin if current_user.try(:admin?) - - params.require(:user).permit(*filters) + if current_user.admin? + params.require(:user).permit(:name, :admin) + else + params.require(:user).permit(:name) + end end ``` @@ -647,7 +648,7 @@ Since this is a frequent mistake, the format validator (validates_format_of) now ```ruby # content should include a line "Meanwhile" anywhere in the string - validates :content, :format => { :with => /^Meanwhile$/, :multiline => true } + validates :content, format: { with: /^Meanwhile$/, multiline: true } ``` Note that this only protects you against the most common mistake when using the format validator - you always need to keep in mind that ^ and $ match the **line** beginning and line end in Ruby, and not the beginning and end of a string. @@ -685,7 +686,7 @@ NOTE: _When sanitizing, protecting or verifying something, whitelists over black A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _prefer to use whitelist approaches_: -* Use before_filter :only => [...] instead of :except => [...]. This way you don't forget to turn it off for newly added actions. +* Use before_filter only: [...] instead of except: [...]. This way you don't forget to turn it off for newly added actions. * Use attr_accessible instead of attr_protected. See the mass-assignment section for details * Allow <strong> instead of removing <script> against Cross-Site Scripting (XSS). See below for details. * Don't try to correct user input by blacklists: @@ -768,7 +769,7 @@ Model.where("login = ? AND password = ?", entered_user_name, entered_password).f As you can see, the first part of the array is an SQL fragment with question marks. The sanitized versions of the variables in the second part of the array replace the question marks. Or you can pass a hash for the same result: ```ruby -Model.where(:login => entered_user_name, :password => entered_password).first +Model.where(login: entered_user_name, password: entered_password).first ``` The array or hash form is only available in model instances. You can try `sanitize_sql()` elsewhere. _Make it a habit to think about the security consequences when using an external string in SQL_. @@ -863,7 +864,7 @@ This returned "some<script>alert('hello')</script>", which makes an ```ruby tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) -s = sanitize(user_input, :tags => tags, :attributes => %w(href title)) +s = sanitize(user_input, tags: tags, attributes: %w(href title)) ``` This allows only the given tags and does a good job, even against all kinds of tricks and malformed tags. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 0ae0e30ab7..148316d170 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -255,7 +255,7 @@ ActiveSupport.on_load(:active_record) do end ``` -h4(#config_session3_1). config/initializers/session_store.rb +### config/initializers/session_store.rb You need to change your session key to something new, or remove all sessions: @@ -266,4 +266,6 @@ AppName::Application.config.session_store :cookie_store, :key => 'SOMETHINGNEW' or -<tt>$ rake db:sessions:clear</tt> +```bash +$ rake db:sessions:clear +``` diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index c9fa541db8..ba9b24c6c6 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `.rake` to list of file extensions included by `rake notes` and `rake notes:custom`. *Brent J. Nordquist* + * New test locations `test/models`, `test/helpers`, `test/controllers`, and `test/mailers`. Corresponding rake tasks added as well. *Mike Moore* @@ -79,9 +81,9 @@ * Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki* -* Add `config.queue_consumer` to allow the default consumer to be configurable. *Carlos Antonio da Silva* +* Add `config.queue_consumer` to change the job queue consumer from the default `ActiveSupport::ThreadedQueueConsumer`. *Carlos Antonio da Silva* -* Add Rails.queue as an interface with a default implementation that consumes jobs in a separate thread. *Yehuda Katz* +* Add `Rails.queue` for processing jobs in the background. *Yehuda Katz* * Remove Rack::SSL in favour of ActionDispatch::SSL. *Rafael Mendonça França* diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index d7e22cc839..dd51a6fb01 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -106,7 +106,7 @@ module Rails # * The environment variable RAILS_GROUPS; # * The optional envs given as argument and the hash with group dependencies; # - # groups :assets => [:development, :test] + # groups assets: [:development, :test] # # # Returns # # => [:default, :development, :assets] for Rails.env == "development" diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index b30e6ff615..eff5bbbdd6 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -71,7 +71,7 @@ module Rails attr_reader :reloaders attr_writer :queue - delegate :default_url_options, :default_url_options=, :to => :routes + delegate :default_url_options, :default_url_options=, to: :routes def initialize super @@ -106,7 +106,7 @@ module Rails 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) + @key_generator ||= ActiveSupport::KeyGenerator.new(config.secret_token, iterations: 1000) end # Stores some of the Rails initial environment parameters which @@ -198,11 +198,7 @@ module Rails end def queue #:nodoc: - @queue ||= ActiveSupport::QueueContainer.new(build_queue) - end - - def build_queue #:nodoc: - config.queue.new + @queue ||= config.queue || ActiveSupport::Queue.new end def to_app #:nodoc: @@ -300,9 +296,9 @@ module Rails if rack_cache == true rack_cache = { - :metastore => "rails:/", - :entitystore => "rails:/", - :verbose => false + metastore: "rails:/", + entitystore: "rails:/", + verbose: false } end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index a1bc95550b..62d57c0cc6 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -7,13 +7,13 @@ module Rails module Bootstrap include Initializable - initializer :load_environment_hook, :group => :all do end + initializer :load_environment_hook, group: :all do end - initializer :load_active_support, :group => :all do + initializer :load_active_support, group: :all do require "active_support/all" unless config.active_support.bare end - initializer :set_eager_load, :group => :all do + initializer :set_eager_load, group: :all do if config.eager_load.nil? warn <<-INFO config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: @@ -28,7 +28,7 @@ INFO end # Initialize the logger early in the stack in case we need to log some deprecation. - initializer :initialize_logger, :group => :all do + initializer :initialize_logger, group: :all do Rails.logger ||= config.logger || begin path = config.paths["log"].first unless File.exist? File.dirname path @@ -56,7 +56,7 @@ INFO end # Initialize cache early in the stack so railties can make use of it. - initializer :initialize_cache, :group => :all do + initializer :initialize_cache, group: :all do unless Rails.cache Rails.cache = ActiveSupport::Cache.lookup_store(config.cache_store) @@ -67,11 +67,11 @@ INFO end # Sets the dependency loading mechanism. - initializer :initialize_dependency_mechanism, :group => :all do + initializer :initialize_dependency_mechanism, group: :all do ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end - initializer :bootstrap_hook, :group => :all do |app| + initializer :bootstrap_hook, group: :all do |app| ActiveSupport.run_load_hooks(:before_initialize, app) end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index a7a35c2685..9ada195dd3 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -6,7 +6,7 @@ require 'rails/engine/configuration' module Rails class Application class Configuration < ::Rails::Engine::Configuration - attr_accessor :asset_host, :asset_path, :assets, :autoflush_log, + attr_accessor :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, @@ -43,8 +43,8 @@ module Rails @exceptions_app = nil @autoflush_log = true @log_formatter = ActiveSupport::Logger::SimpleFormatter.new - @queue = ActiveSupport::SynchronousQueue - @queue_consumer = ActiveSupport::ThreadedQueueConsumer + @queue = ActiveSupport::SynchronousQueue.new + @queue_consumer = nil @eager_load = nil @assets = ActiveSupport::OrderedOptions.new @@ -64,10 +64,6 @@ module Rails @assets.logger = nil end - def compiled_asset_path - "/" - end - def encoding=(value) @encoding = value silence_warnings do @@ -79,10 +75,10 @@ module Rails def paths @paths ||= begin paths = super - paths.add "config/database", :with => "config/database.yml" - paths.add "config/environment", :with => "config/environment.rb" + paths.add "config/database", with: "config/database.yml" + paths.add "config/environment", with: "config/environment.rb" paths.add "lib/templates" - paths.add "log", :with => "log/#{Rails.env}.log" + paths.add "log", with: "log/#{Rails.env}.log" paths.add "public" paths.add "public/javascripts" paths.add "public/stylesheets" diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index d2a402aa51..c520f7af9d 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -72,7 +72,7 @@ module Rails # Set app reload just after the finisher hook to ensure # paths added in the hook are still loaded. - initializer :set_clear_dependencies_hook, :group => :all do + initializer :set_clear_dependencies_hook, group: :all do callback = lambda do ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear @@ -83,7 +83,7 @@ module Rails 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 } + ActionDispatch::Reloader.to_prepare(prepend: true){ reloader.execute } else ActionDispatch::Reloader.to_cleanup(&callback) end @@ -97,8 +97,9 @@ module Rails end initializer :activate_queue_consumer do |app| - if config.queue == ActiveSupport::Queue - app.queue_consumer = config.queue_consumer.start(app.queue, {logger: Rails.logger}) + 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 diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 6f9a200aa9..737977adf9 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -4,7 +4,7 @@ module Rails class Application class RoutesReloader attr_reader :route_sets, :paths - delegate :execute_if_updated, :execute, :updated?, :to => :updater + delegate :execute_if_updated, :execute, :updated?, to: :updater def initialize @paths = [] diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index 9c5dc8f188..b0fae13192 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -9,6 +9,30 @@ 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 @@ -81,29 +105,14 @@ when '--version', '-v' ARGV.unshift '--version' require 'rails/commands/application' -else - puts "Error: Command not recognized" unless %w(-h --help).include?(command) - puts <<-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" +when '-h', '--help' + puts help_message -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 +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 diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index 2cb6d5ca2e..ff0eda3413 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -24,7 +24,7 @@ require 'rails/generators/rails/app/app_generator' module Rails module Generators - class AppGenerator + class AppGenerator # :nodoc: # We want to exit on failure to be kind to other libraries # This is only when accessing via CLI def self.exit_on_failure? diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb index 9023c61bf2..5479da86a0 100644 --- a/railties/lib/rails/commands/destroy.rb +++ b/railties/lib/rails/commands/destroy.rb @@ -6,4 +6,4 @@ if [nil, "-h", "--help"].include?(ARGV.first) end name = ARGV.shift -Rails::Generators.invoke name, ARGV, :behavior => :revoke, :destination_root => Rails.root +Rails::Generators.invoke name, ARGV, behavior: :revoke, destination_root: Rails.root diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb index 9f13cb0513..351c59c645 100644 --- a/railties/lib/rails/commands/generate.rb +++ b/railties/lib/rails/commands/generate.rb @@ -8,4 +8,4 @@ end name = ARGV.shift root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root -Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => root +Rails::Generators.invoke name, ARGV, behavior: :invoke, destination_root: root diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index a672258aa6..0cc672e01c 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'] || "development").dup } code_or_file = nil if ARGV.first.nil? diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index a684129353..80fdc06cd2 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -105,13 +105,13 @@ module Rails def default_options super.merge({ - :Port => 3000, - :DoNotReverseLookup => true, - :environment => (ENV['RAILS_ENV'] || "development").dup, - :daemonize => false, - :debugger => false, - :pid => File.expand_path("tmp/pids/server.pid"), - :config => File.expand_path("config.ru") + Port: 3000, + DoNotReverseLookup: true, + environment: (ENV['RAILS_ENV'] || "development").dup, + daemonize: false, + debugger: false, + pid: File.expand_path("tmp/pids/server.pid"), + config: File.expand_path("config.ru") }) end end diff --git a/railties/lib/rails/commands/update.rb b/railties/lib/rails/commands/update.rb index 85a81cddf0..59fae5c337 100644 --- a/railties/lib/rails/commands/update.rb +++ b/railties/lib/rails/commands/update.rb @@ -6,4 +6,4 @@ if ARGV.size == 0 end name = ARGV.shift -Rails::Generators.invoke name, ARGV, :behavior => :skip +Rails::Generators.invoke name, ARGV, behavior: :skip diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 7afb599910..2c2bb1c714 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -251,7 +251,7 @@ module Rails # # # config/routes.rb # MyApplication::Application.routes.draw do - # mount MyEngine::Engine => "/my_engine", :as => "my_engine" + # mount MyEngine::Engine => "/my_engine", as: "my_engine" # get "/foo" => "foo#index" # end # @@ -368,7 +368,7 @@ module Rails def isolate_namespace(mod) engine_name(generate_railtie_name(mod)) - self.routes.default_scope = { :module => ActiveSupport::Inflector.underscore(mod.name) } + self.routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) } self.isolated = true unless mod.respond_to?(:railtie_namespace) @@ -407,8 +407,8 @@ module Rails end end - delegate :middleware, :root, :paths, :to => :config - delegate :engine_name, :isolated?, :to => "self.class" + delegate :middleware, :root, :paths, to: :config + delegate :engine_name, :isolated?, to: "self.class" def initialize @_all_autoload_paths = nil @@ -536,7 +536,7 @@ module Rails end # Add configured load paths to ruby load paths and remove duplicates. - initializer :set_load_path, :before => :bootstrap_hook do + initializer :set_load_path, before: :bootstrap_hook do _all_load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end @@ -548,7 +548,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 |app| ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths) ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths) @@ -581,13 +581,13 @@ module Rails end end - initializer :load_environment_config, :before => :load_environment_hook, :group => :all do + initializer :load_environment_config, before: :load_environment_hook, group: :all do paths["config/environments"].existent.each do |environment| require environment end end - initializer :append_assets_path, :group => :all do |app| + initializer :append_assets_path, group: :all do |app| app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories) app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories) app.config.assets.paths.unshift(*paths["app/assets"].existent_directories) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 6b18b1e249..22e885a3a6 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -20,7 +20,7 @@ module Rails # Holds generators configuration: # # config.generators do |g| - # g.orm :data_mapper, :migration => true + # g.orm :data_mapper, migration: true # g.template_engine :haml # g.test_framework :rspec # end @@ -38,26 +38,26 @@ 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 - paths.add "app/helpers", :eager_load => true - paths.add "app/models", :eager_load => true - paths.add "app/mailers", :eager_load => true + paths.add "app", eager_load: true, glob: "*" + paths.add "app/assets", glob: "*" + paths.add "app/controllers", eager_load: true + paths.add "app/helpers", eager_load: true + paths.add "app/models", eager_load: true + paths.add "app/mailers", eager_load: true paths.add "app/views" - paths.add "lib", :load_path => true - paths.add "lib/assets", :glob => "*" - paths.add "lib/tasks", :glob => "**/*.rake" + 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/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.add "vendor", load_path: true + paths.add "vendor/assets", glob: "*" paths end end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index a8c0626a41..367f9288b8 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -23,41 +23,41 @@ module Rails mattr_accessor :namespace DEFAULT_ALIASES = { - :rails => { - :actions => '-a', - :orm => '-o', - :javascripts => '-j', - :javascript_engine => '-je', - :resource_controller => '-c', - :scaffold_controller => '-c', - :stylesheets => '-y', - :stylesheet_engine => '-se', - :template_engine => '-e', - :test_framework => '-t' + rails: { + actions: '-a', + orm: '-o', + javascripts: '-j', + javascript_engine: '-je', + resource_controller: '-c', + scaffold_controller: '-c', + stylesheets: '-y', + stylesheet_engine: '-se', + template_engine: '-e', + test_framework: '-t' }, - :test_unit => { - :fixture_replacement => '-r', + test_unit: { + fixture_replacement: '-r', } } DEFAULT_OPTIONS = { - :rails => { - :assets => true, - :force_plural => false, - :helper => true, - :integration_tool => nil, - :javascripts => true, - :javascript_engine => :js, - :orm => false, - :performance_tool => nil, - :resource_controller => :controller, - :resource_route => true, - :scaffold_controller => :scaffold_controller, - :stylesheets => true, - :stylesheet_engine => :css, - :test_framework => false, - :template_engine => :erb + rails: { + assets: true, + force_plural: false, + helper: true, + integration_tool: nil, + javascripts: true, + javascript_engine: :js, + orm: false, + performance_tool: nil, + resource_controller: :controller, + resource_route: true, + scaffold_controller: :scaffold_controller, + stylesheets: true, + stylesheet_engine: :css, + test_framework: false, + template_engine: :erb } } diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index c41acc7841..5c4e81431c 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -7,9 +7,9 @@ module Rails # Adds an entry into Gemfile for the supplied gem. # - # gem "rspec", :group => :test - # gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/" - # gem "rails", "3.0", :git => "git://github.com/rails/rails" + # gem "rspec", group: :test + # gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/" + # gem "rails", "3.0", git: "git://github.com/rails/rails" def gem(*args) options = args.extract_options! name, version = args @@ -33,7 +33,7 @@ module Rails str = "gem #{parts.join(", ")}" str = " " + str if @in_group str = "\n" + str - append_file "Gemfile", str, :verbose => false + append_file "Gemfile", str, verbose: false end end @@ -47,13 +47,13 @@ module Rails log :gemfile, "group #{name}" in_root do - append_file "Gemfile", "\ngroup #{name} do", :force => true + append_file "Gemfile", "\ngroup #{name} do", force: true @in_group = true instance_eval(&block) @in_group = false - append_file "Gemfile", "\nend\n", :force => true + append_file "Gemfile", "\nend\n", force: true end end @@ -64,7 +64,7 @@ module Rails log :source, source in_root do - prepend_file "Gemfile", "source #{source.inspect}\n", :verbose => false + prepend_file "Gemfile", "source #{source.inspect}\n", verbose: false end end @@ -77,7 +77,7 @@ module Rails # "config.autoload_paths += %W(#{config.root}/extras)" # end # - # environment(nil, :env => "development") do + # environment(nil, env: "development") do # "config.active_record.observers = :cacher" # end def environment(data=nil, options={}, &block) @@ -87,10 +87,10 @@ module Rails in_root do if options[:env].nil? - inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false + inject_into_file 'config/application.rb', "\n #{data}", after: sentinel, verbose: false else Array(options[:env]).each do |env| - inject_into_file "config/environments/#{env}.rb", "\n #{data}", :after => env_file_sentinel, :verbose => false + inject_into_file "config/environments/#{env}.rb", "\n #{data}", after: env_file_sentinel, verbose: false end end end @@ -100,8 +100,8 @@ module Rails # Run a command in git. # # git :init - # git :add => "this.file that.rb" - # git :add => "onefile.rb", :rm => "badfile.cxx" + # git add: "this.file that.rb" + # git add: "onefile.rb", rm: "badfile.cxx" def git(commands={}) if commands.is_a?(Symbol) run "git #{commands}" @@ -123,7 +123,7 @@ module Rails # vendor("foreign.rb", "# Foreign code is fun") def vendor(filename, data=nil, &block) log :vendor, filename - create_file("vendor/#{filename}", data, :verbose => false, &block) + create_file("vendor/#{filename}", data, verbose: false, &block) end # Create a new file in the lib/ directory. Code can be specified @@ -136,7 +136,7 @@ module Rails # lib("foreign.rb", "# Foreign code is fun") def lib(filename, data=nil, &block) log :lib, filename - create_file("lib/#{filename}", data, :verbose => false, &block) + create_file("lib/#{filename}", data, verbose: false, &block) end # Create a new Rakefile with the provided code (either in a block or a string). @@ -156,7 +156,7 @@ module Rails # rakefile('seed.rake', 'puts "Planting seeds"') def rakefile(filename, data=nil, &block) log :rakefile, filename - create_file("lib/tasks/#{filename}", data, :verbose => false, &block) + create_file("lib/tasks/#{filename}", data, verbose: false, &block) end # Create a new initializer with the provided code (either in a block or a string). @@ -174,7 +174,7 @@ module Rails # initializer("api.rb", "API_KEY = '123456'") def initializer(filename, data=nil, &block) log :initializer, filename - create_file("config/initializers/#{filename}", data, :verbose => false, &block) + create_file("config/initializers/#{filename}", data, verbose: false, &block) end # Generate something using a generator from Rails or a plugin. @@ -186,19 +186,19 @@ 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("script/rails generate #{what} #{argument}", verbose: false) } end # Runs the supplied rake task # # rake("db:migrate") - # rake("db:migrate", :env => "production") - # rake("gems:install", :sudo => true) + # rake("db:migrate", env: "production") + # rake("gems:install", sudo: true) def rake(command, options={}) log :rake, command env = options[:env] || ENV["RAILS_ENV"] || 'development' sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' - in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) } + in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) } end # Just run the capify command in root @@ -206,7 +206,7 @@ module Rails # capify! def capify! log :capify, "" - in_root { run("#{extify(:capify)} .", :verbose => false) } + in_root { run("#{extify(:capify)} .", verbose: false) } end # Make an entry in Rails routing file config/routes.rb @@ -217,7 +217,7 @@ module Rails sentinel = /\.routes\.draw do\s*$/ in_root do - inject_into_file 'config/routes.rb', "\n #{routing_code}", { :after => sentinel, :verbose => false } + inject_into_file 'config/routes.rb', "\n #{routing_code}", { after: sentinel, verbose: false } end end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 44c6507b08..e761e26b04 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -8,7 +8,7 @@ require 'uri' module Rails module Generators - class AppBase < Base + class AppBase < Base # :nodoc: DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver ) JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) DATABASES.concat(JDBC_DATABASES) diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index c2accf0387..7e938fab47 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -11,7 +11,7 @@ require 'rails/generators/actions' module Rails module Generators - class Error < Thor::Error + class Error < Thor::Error # :nodoc: end class Base < Thor::Group @@ -61,7 +61,7 @@ module Rails # # module Rails::Generators # class ControllerGenerator < Base - # hook_for :test_framework, :aliases => "-t" + # hook_for :test_framework, aliases: "-t" # end # end # @@ -102,7 +102,7 @@ module Rails # :as option: # # class AwesomeGenerator < Rails::Generators::Base - # hook_for :test_framework, :as => :controller + # hook_for :test_framework, as: :controller # end # # And now it will lookup at: @@ -113,7 +113,7 @@ module Rails # need to provide the :base value: # # class AwesomeGenerator < Rails::Generators::Base - # hook_for :test_framework, :in => :rails, :as => :controller + # hook_for :test_framework, in: :rails, as: :controller # end # # And the lookup is exactly the same as previously: @@ -137,7 +137,7 @@ module Rails # developers might want to have webrat available on controller generator. # This can be achieved as: # - # Rails::Generators::ControllerGenerator.hook_for :webrat, :type => :boolean + # Rails::Generators::ControllerGenerator.hook_for :webrat, type: :boolean # # Then, if you want webrat to be invoked, just supply: # @@ -171,9 +171,9 @@ module Rails defaults = if options[:type] == :boolean { } elsif [true, false].include?(default_value_for_option(name, options)) - { :banner => "" } + { banner: "" } else - { :desc => "#{name.to_s.humanize} to be invoked", :banner => "NAME" } + { desc: "#{name.to_s.humanize} to be invoked", banner: "NAME" } end unless class_options.key?(name) @@ -343,8 +343,8 @@ module Rails # Small macro to add ruby as an option to the generator with proper # default value plus an instance helper method called shebang. def self.add_shebang_option! - class_option :ruby, :type => :string, :aliases => "-r", :default => Thor::Util.ruby_command, - :desc => "Path to the Ruby binary of your choice", :banner => "PATH" + class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command, + desc: "Path to the Ruby binary of your choice", banner: "PATH" no_tasks { define_method :shebang do diff --git a/railties/lib/rails/generators/css/assets/assets_generator.rb b/railties/lib/rails/generators/css/assets/assets_generator.rb index 492177ca2e..e4a305f4b3 100644 --- a/railties/lib/rails/generators/css/assets/assets_generator.rb +++ b/railties/lib/rails/generators/css/assets/assets_generator.rb @@ -1,8 +1,8 @@ require "rails/generators/named_base" -module Css - module Generators - class AssetsGenerator < Rails::Generators::NamedBase +module Css # :nodoc: + module Generators # :nodoc: + class AssetsGenerator < Rails::Generators::NamedBase # :nodoc: source_root File.expand_path("../templates", __FILE__) def copy_stylesheet diff --git a/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb index 1d7fe9fac0..cf534030f9 100644 --- a/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb @@ -1,8 +1,8 @@ require "rails/generators/named_base" -module Css - module Generators - class ScaffoldGenerator < Rails::Generators::NamedBase +module Css # :nodoc: + module Generators # :nodoc: + class ScaffoldGenerator < Rails::Generators::NamedBase # :nodoc: # In order to allow the Sass generators to pick up the default Rails CSS and # transform it, we leave it in a standard location for the CSS stylesheet # generators to handle. For the simple, default case, just copy it over. diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index 3e6371268f..73e986ee7f 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -1,7 +1,7 @@ require 'rails/generators/named_base' -module Erb - module Generators +module Erb # :nodoc: + module Generators # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: protected diff --git a/railties/lib/rails/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb index ac57140c23..5f06734ab8 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/erb' -module Erb - module Generators - class ControllerGenerator < Base - argument :actions, :type => :array, :default => [], :banner => "action action" +module Erb # :nodoc: + module Generators # :nodoc: + class ControllerGenerator < Base # :nodoc: + argument :actions, type: :array, default: [], banner: "action action" def copy_view_files base_path = File.join("app/views", class_path, file_name) diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 943d0c9f8d..7bcac30dde 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -1,8 +1,8 @@ require 'rails/generators/erb/controller/controller_generator' -module Erb - module Generators - class MailerGenerator < ControllerGenerator +module Erb # :nodoc: + module Generators # :nodoc: + class MailerGenerator < ControllerGenerator # :nodoc: protected def format diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index b2c8d7051b..bacbc2d280 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -1,12 +1,12 @@ require 'rails/generators/erb' require 'rails/generators/resource_helpers' -module Erb - module Generators - class ScaffoldGenerator < Base +module Erb # :nodoc: + module Generators # :nodoc: + class ScaffoldGenerator < Base # :nodoc: include Rails::Generators::ResourceHelpers - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + argument :attributes, type: :array, default: [], banner: "field:type field:type" def create_root_folder empty_directory File.join("app/views", controller_file_path) diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index d2c2abf40c..d8a4f15b4b 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -2,7 +2,7 @@ require 'active_support/time' module Rails module Generators - class GeneratedAttribute + class GeneratedAttribute # :nodoc: INDEX_OPTIONS = %w(index uniq) UNIQ_INDEX_OPTIONS = %w(uniq) @@ -23,7 +23,7 @@ module Rails type = type.to_sym if type if type && reference?(type) - references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { :unique => true } : true + references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { unique: true } : true attr_options[:index] = references_index end @@ -41,11 +41,11 @@ module Rails def parse_type_and_options(type) case type when /(string|text|binary|integer)\{(\d+)\}/ - return $1, :limit => $2.to_i + return $1, limit: $2.to_i when /decimal\{(\d+)[,.-](\d+)\}/ - return :decimal, :precision => $1.to_i, :scale => $2.to_i + return :decimal, precision: $1.to_i, scale: $2.to_i when /(references|belongs_to)\{polymorphic\}/ - return $1, :polymorphic => true + return $1, polymorphic: true else return type, {} end diff --git a/railties/lib/rails/generators/js/assets/assets_generator.rb b/railties/lib/rails/generators/js/assets/assets_generator.rb index d134a9e392..1e925b2cd2 100644 --- a/railties/lib/rails/generators/js/assets/assets_generator.rb +++ b/railties/lib/rails/generators/js/assets/assets_generator.rb @@ -1,8 +1,8 @@ require "rails/generators/named_base" -module Js - module Generators - class AssetsGenerator < Rails::Generators::NamedBase +module Js # :nodoc: + module Generators # :nodoc: + class AssetsGenerator < Rails::Generators::NamedBase # :nodoc: source_root File.expand_path("../templates", __FILE__) def copy_javascript diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index b61a5fc69d..84f8f76838 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -5,9 +5,9 @@ require 'rails/generators/generated_attribute' module Rails module Generators class NamedBase < Base - argument :name, :type => :string - class_option :skip_namespace, :type => :boolean, :default => false, - :desc => "Skip namespace (affects only isolated applications)" + argument :name, type: :string + class_option :skip_namespace, type: :boolean, default: false, + desc: "Skip namespace (affects only isolated applications)" def initialize(args, *options) #:nodoc: @inside_template = nil @@ -169,7 +169,7 @@ module Rails # # ==== Examples # - # check_class_collision :suffix => "Observer" + # check_class_collision suffix: "Observer" # # If the generator is invoked with class name Admin, it will check for # the presence of "AdminObserver". diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 98997864de..18637451ac 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -1,7 +1,7 @@ require 'rails/generators/app_base' module Rails - module ActionMethods + module ActionMethods # :nodoc: attr_reader :options def initialize(generator) @@ -96,7 +96,7 @@ module Rails end def public_directory - directory "public", "public", :recursive => false + directory "public", "public", recursive: false if options[:skip_index_html] remove_file "public/index.html" remove_file 'app/assets/images/rails.png' @@ -108,7 +108,7 @@ module Rails directory "script" do |content| "#{shebang}\n" + content end - chmod "script", 0755, :verbose => false + chmod "script", 0755, verbose: false end def test @@ -148,12 +148,12 @@ module Rails RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) RESERVED_NAMES = %w[application destroy benchmarker profiler plugin runner test] - class AppGenerator < AppBase + class AppGenerator < AppBase # :nodoc: add_shared_options_for "application" # Add bin/rails options - class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, - :desc => "Show Rails version number and quit" + class_option :version, type: :boolean, aliases: "-v", group: :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? diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index e5aa153e29..30f8a5f75e 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -9,13 +9,10 @@ source 'https://rubygems.org' <%= assets_gemfile_entry %> <%= javascript_gemfile_entry %> -# Puts a simple HTTP cache in front of your app (and gets you ready for later upgrading to nginx/varnish/squid) -# gem 'rack-cache', '~> 1.2' - # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' -# Build JSON APIs with ease. Read more: http://github.com/rails/jbuilder +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # gem 'jbuilder' # Use unicorn as the app server 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 07223a71c9..22c9194fad 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 @@ -2,7 +2,9 @@ # # Install the pg driver: # gem install pg -# On Mac OS X with macports: +# On OS X with Homebrew: +# gem install pg -- --with-pg-config=/usr/local/bin/pg_config +# On OS X with MacPorts: # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config # On Windows: # gem install pg 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 3629920c30..8aaaba628c 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 @@ -60,7 +60,8 @@ # config.assets.precompile += %w( search.js ) <%- end -%> - # Disable delivery errors, bad email addresses will be ignored. + # 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. # config.action_mailer.raise_delivery_errors = false # Enable threaded mode. @@ -87,5 +88,5 @@ # 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 + # 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 202fc98adf..a5ef0cd9cd 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 @@ -34,6 +34,6 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Use the testing queue. - config.queue = ActiveSupport::TestQueue + # Use the synchronous queue to run jobs immediately. + config.queue = ActiveSupport::SynchronousQueue.new end diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb index 2e7f25a0b7..6f4b86e708 100644 --- a/railties/lib/rails/generators/rails/assets/assets_generator.rb +++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb @@ -1,11 +1,11 @@ module Rails module Generators - class AssetsGenerator < NamedBase - class_option :javascripts, :type => :boolean, :desc => "Generate JavaScripts" - class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets" + class AssetsGenerator < NamedBase # :nodoc: + class_option :javascripts, type: :boolean, desc: "Generate JavaScripts" + class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" - class_option :javascript_engine, :desc => "Engine for JavaScripts" - class_option :stylesheet_engine, :desc => "Engine for Stylesheets" + class_option :javascript_engine, desc: "Engine for JavaScripts" + class_option :stylesheet_engine, desc: "Engine for Stylesheets" protected diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 74aa0432a8..bae54623c6 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -1,8 +1,8 @@ module Rails module Generators - class ControllerGenerator < NamedBase - argument :actions, :type => :array, :default => [], :banner => "action action" - check_class_collision :suffix => "Controller" + class ControllerGenerator < NamedBase # :nodoc: + argument :actions, type: :array, default: [], banner: "action action" + check_class_collision suffix: "Controller" def create_controller_files template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb") diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 3e0a442bda..9a7a516b5b 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -1,10 +1,10 @@ module Rails module Generators - class GeneratorGenerator < NamedBase - check_class_collision :suffix => "Generator" + class GeneratorGenerator < NamedBase # :nodoc: + check_class_collision suffix: "Generator" - class_option :namespace, :type => :boolean, :default => true, - :desc => "Namespace generator under lib/generators/name" + class_option :namespace, type: :boolean, default: true, + desc: "Namespace generator under lib/generators/name" def create_generator_files directory '.', generator_dir diff --git a/railties/lib/rails/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb index ad66388591..5ff38e4111 100644 --- a/railties/lib/rails/generators/rails/helper/helper_generator.rb +++ b/railties/lib/rails/generators/rails/helper/helper_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators - class HelperGenerator < NamedBase - check_class_collision :suffix => "Helper" + class HelperGenerator < NamedBase # :nodoc: + check_class_collision suffix: "Helper" def create_helper_files template 'helper.rb', File.join('app/helpers', class_path, "#{file_name}_helper.rb") diff --git a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb index 363a327fcb..70770ddcb8 100644 --- a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb +++ b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators - class IntegrationTestGenerator < NamedBase - hook_for :integration_tool, :as => :integration + class IntegrationTestGenerator < NamedBase # :nodoc: + hook_for :integration_tool, as: :integration end end end diff --git a/railties/lib/rails/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb index f87dce1502..965c42db36 100644 --- a/railties/lib/rails/generators/rails/migration/migration_generator.rb +++ b/railties/lib/rails/generators/rails/migration/migration_generator.rb @@ -1,8 +1,8 @@ module Rails module Generators - class MigrationGenerator < NamedBase #metagenerator - argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" - hook_for :orm, :required => true + class MigrationGenerator < NamedBase # :nodoc: + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" + hook_for :orm, required: true end end end diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index 9bb29b784e..ea3d69d7c9 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,8 +1,8 @@ module Rails module Generators - class ModelGenerator < NamedBase #metagenerator - argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" - hook_for :orm, :required => true + class ModelGenerator < NamedBase # :nodoc: + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" + hook_for :orm, required: true end end end diff --git a/railties/lib/rails/generators/rails/observer/observer_generator.rb b/railties/lib/rails/generators/rails/observer/observer_generator.rb index f5cedee91f..7a4d701ac6 100644 --- a/railties/lib/rails/generators/rails/observer/observer_generator.rb +++ b/railties/lib/rails/generators/rails/observer/observer_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators - class ObserverGenerator < NamedBase #metagenerator - hook_for :orm, :required => true + class ObserverGenerator < NamedBase # :nodoc: + hook_for :orm, required: true end end end 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 index d1c71ab8ed..56cd562f3d 100644 --- a/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb +++ b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators - class PerformanceTestGenerator < NamedBase - hook_for :performance_tool, :as => :performance + class PerformanceTestGenerator < NamedBase # :nodoc: + hook_for :performance_tool, as: :performance end end end diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index c77b3450a3..4a0bcc35a4 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -3,6 +3,13 @@ require "rails/generators/rails/app/app_generator" require 'date' module Rails + # The plugin builder allows you to override elements of the plugin + # generator without being forced to reverse the operations of the default + # generator. + # + # This allows you to override entire operations, like the creation of the + # Gemfile, README, or JavaScript files, without needing to know exactly + # what those operations do so you can create another template action. class PluginBuilder def rakefile template "Rakefile" @@ -61,7 +68,7 @@ module Rails append_file "Rakefile", <<-EOF #{rakefile_test_tasks} -task :default => :test +task default: :test EOF if full? template "test/integration/navigation_test.rb" @@ -82,10 +89,10 @@ task :default => :test end def test_dummy_config - template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true - template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true + template "rails/boot.rb", "#{dummy_path}/config/boot.rb", force: true + template "rails/application.rb", "#{dummy_path}/config/application.rb", force: true if mountable? - template "rails/routes.rb", "#{dummy_path}/config/routes.rb", :force => true + template "rails/routes.rb", "#{dummy_path}/config/routes.rb", force: true end end @@ -128,10 +135,10 @@ task :default => :test def script(force = false) return unless full? - directory "script", :force => force do |content| + directory "script", force: force do |content| "#{shebang}\n" + content end - chmod "script", 0755, :verbose => false + chmod "script", 0755, verbose: false end def gemfile_entry @@ -146,25 +153,25 @@ task :default => :test end module Generators - class PluginNewGenerator < AppBase + class PluginNewGenerator < AppBase # :nodoc: add_shared_options_for "plugin" alias_method :plugin_path, :app_path - class_option :dummy_path, :type => :string, :default => "test/dummy", - :desc => "Create dummy application at given path" + class_option :dummy_path, type: :string, default: "test/dummy", + desc: "Create dummy application at given path" - class_option :full, :type => :boolean, :default => false, - :desc => "Generate a rails engine with bundled Rails application for testing" + class_option :full, type: :boolean, default: false, + desc: "Generate a rails engine with bundled Rails application for testing" - class_option :mountable, :type => :boolean, :default => false, - :desc => "Generate mountable isolated application" + class_option :mountable, type: :boolean, default: false, + desc: "Generate mountable isolated application" - class_option :skip_gemspec, :type => :boolean, :default => false, - :desc => "Skip gemspec file" + class_option :skip_gemspec, type: :boolean, default: false, + desc: "Skip gemspec file" - class_option :skip_gemfile_entry, :type => :boolean, :default => false, - :desc => "If creating plugin in application's directory " + + class_option :skip_gemfile_entry, type: :boolean, default: false, + desc: "If creating plugin in application's directory " + "skip adding entry to Gemfile" def initialize(*args) 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_new/templates/app/views/layouts/%name%/application.html.erb.tt index bd983fb90f..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_new/templates/app/views/layouts/%name%/application.html.erb.tt @@ -2,7 +2,7 @@ <html> <head> <title><%= camelized %></title> - <%%= stylesheet_link_tag "<%= name %>/application", :media => "all" %> + <%%= stylesheet_link_tag "<%= name %>/application", media: "all" %> <%%= javascript_include_tag "<%= name %>/application" %> <%%= csrf_meta_tags %> </head> diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 3a0586ee43..8014feb75f 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -4,17 +4,17 @@ require 'active_support/core_ext/object/blank' module Rails module Generators - class ResourceGenerator < ModelGenerator #metagenerator + class ResourceGenerator < ModelGenerator # :nodoc: include ResourceHelpers - hook_for :resource_controller, :required => true do |controller| + hook_for :resource_controller, required: true do |controller| invoke controller, [ controller_name, options[:actions] ] end - class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [], - :desc => "Actions for the resource controller" + class_option :actions, type: :array, banner: "ACTION ACTION", default: [], + desc: "Actions for the resource controller" - hook_for :resource_route, :required => true + hook_for :resource_route, required: true end end end 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 f33d56b564..121205b254 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 @@ -1,6 +1,6 @@ module Rails module Generators - class ResourceRouteGenerator < NamedBase + class ResourceRouteGenerator < NamedBase # :nodoc: # Properly nests namespaces passed into a generator # diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index 03a61a035e..b4f466fbd8 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -2,14 +2,14 @@ require 'rails/generators/rails/resource/resource_generator' module Rails module Generators - class ScaffoldGenerator < ResourceGenerator #metagenerator + 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 :stylesheets, type: :boolean, desc: "Generate Stylesheets" + class_option :stylesheet_engine, desc: "Engine for Stylesheets" - hook_for :scaffold_controller, :required => true + hook_for :scaffold_controller, required: true hook_for :assets do |assets| invoke assets, [controller_name] 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 f30ad6e20d..4f36b612ae 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 @@ -2,24 +2,24 @@ require 'rails/generators/resource_helpers' module Rails module Generators - class ScaffoldControllerGenerator < NamedBase + class ScaffoldControllerGenerator < NamedBase # :nodoc: include ResourceHelpers - check_class_collision :suffix => "Controller" + check_class_collision suffix: "Controller" - class_option :orm, :banner => "NAME", :type => :string, :required => true, - :desc => "ORM to generate the controller for" + class_option :orm, banner: "NAME", type: :string, required: true, + desc: "ORM to generate the controller for" - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + 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") end - hook_for :template_engine, :test_framework, :as => :scaffold + hook_for :template_engine, :test_framework, as: :scaffold # Invoke the helper using the controller name (pluralized) - hook_for :helper, :as => :scaffold do |invoked| + hook_for :helper, as: :scaffold do |invoked| invoke invoked, [ controller_name ] end end diff --git a/railties/lib/rails/generators/rails/task/task_generator.rb b/railties/lib/rails/generators/rails/task/task_generator.rb index 8a62d9e8eb..754824ca0c 100644 --- a/railties/lib/rails/generators/rails/task/task_generator.rb +++ b/railties/lib/rails/generators/rails/task/task_generator.rb @@ -1,7 +1,7 @@ module Rails module Generators - class TaskGenerator < NamedBase - argument :actions, :type => :array, :default => [], :banner => "action action" + class TaskGenerator < NamedBase # :nodoc: + argument :actions, type: :array, default: [], banner: "action action" def create_task_files template 'task.rb', File.join('lib/tasks', "#{file_name}.rake") diff --git a/railties/lib/rails/generators/rails/task/templates/task.rb b/railties/lib/rails/generators/rails/task/templates/task.rb index b7407bd6dc..1e3ed5f158 100644 --- a/railties/lib/rails/generators/rails/task/templates/task.rb +++ b/railties/lib/rails/generators/rails/task/templates/task.rb @@ -1,7 +1,7 @@ namespace :<%= file_name %> do <% actions.each do |action| -%> desc "TODO" - task :<%= action %> => :environment do + task <%= action %>: :environment do end <% end -%> diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 48833869e5..7fd5c00768 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -4,16 +4,14 @@ module Rails module Generators # Deal with controller names on scaffold and add some helpers to deal with # ActiveModel. - # - module ResourceHelpers + module ResourceHelpers # :nodoc: mattr_accessor :skip_warn def self.included(base) #:nodoc: - base.class_option :force_plural, :type => :boolean, :desc => "Forces the use of a plural ModelName" + base.class_option :force_plural, type: :boolean, desc: "Forces the use of a plural ModelName" end # Set controller variables on initialization. - # def initialize(*args) #:nodoc: super diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 2ff340755a..24308dcf6c 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -26,7 +26,6 @@ module Rails # destination File.expand_path("../tmp", File.dirname(__FILE__)) # setup :prepare_destination # end - # class TestCase < ActiveSupport::TestCase include FileUtils @@ -37,13 +36,13 @@ module Rails self.current_path = File.expand_path(Dir.pwd) self.default_arguments = [] - def setup + def setup # :nodoc: destination_root_is_set? ensure_current_path super end - def teardown + def teardown # :nodoc: ensure_current_path super end @@ -51,7 +50,6 @@ module Rails # Sets which generator should be tested: # # tests AppGenerator - # def self.tests(klass) self.generator_class = klass end @@ -60,7 +58,6 @@ module Rails # invoking it. # # arguments %w(app_name --skip-active-record) - # def self.arguments(array) self.default_arguments = array end @@ -68,7 +65,6 @@ module Rails # Sets the destination of generator files: # # destination File.expand_path("../tmp", File.dirname(__FILE__)) - # def self.destination(path) self.destination_root = path end @@ -91,7 +87,6 @@ module Rails # 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" @@ -114,7 +109,6 @@ module Rails # 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" @@ -132,7 +126,6 @@ module Rails # 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" @@ -143,7 +136,6 @@ module Rails # 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}" @@ -158,7 +150,6 @@ module Rails # assert_match(/create_table/, up) # end # end - # def assert_class_method(method, content, &block) assert_instance_method "self.#{method}", content, &block end @@ -171,7 +162,6 @@ module Rails # 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? @@ -182,7 +172,6 @@ module Rails # 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 @@ -190,7 +179,6 @@ module Rails # 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 @@ -212,39 +200,38 @@ module Rails # 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)) } + 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)) + @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: + 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: + def ensure_current_path # :nodoc: cd current_path end - def prepare_destination + def prepare_destination # :nodoc: rm_rf(destination_root) mkdir_p(destination_root) end - def migration_file_name(relative) #:nodoc: + 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 diff --git a/railties/lib/rails/generators/test_unit.rb b/railties/lib/rails/generators/test_unit.rb index 62b9afaa2c..fe45c9e15d 100644 --- a/railties/lib/rails/generators/test_unit.rb +++ b/railties/lib/rails/generators/test_unit.rb @@ -1,8 +1,8 @@ require 'rails/generators/named_base' -module TestUnit - module Generators - class Base < Rails::Generators::NamedBase #:nodoc: +module TestUnit # :nodoc: + module Generators # :nodoc: + class Base < Rails::Generators::NamedBase # :nodoc: end end end diff --git a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb index db99e55e9e..b5aa581769 100644 --- a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb +++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb @@ -1,10 +1,10 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class ControllerGenerator < Base - argument :actions, :type => :array, :default => [], :banner => "action action" - check_class_collision :suffix => "ControllerTest" +module TestUnit # :nodoc: + module Generators # :nodoc: + class ControllerGenerator < Base # :nodoc: + argument :actions, type: :array, default: [], banner: "action action" + check_class_collision suffix: "ControllerTest" def create_test_files template 'functional_test.rb', diff --git a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb index d4c287540c..0db76f9eaf 100644 --- a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb +++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class HelperGenerator < Base - check_class_collision :suffix => "HelperTest" +module TestUnit # :nodoc: + module Generators # :nodoc: + class HelperGenerator < Base # :nodoc: + check_class_collision suffix: "HelperTest" def create_helper_files template 'helper_test.rb', File.join('test/helpers', class_path, "#{file_name}_helper_test.rb") diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb index 32d0fac029..e004835bd5 100644 --- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb +++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class IntegrationGenerator < Base - check_class_collision :suffix => "Test" +module TestUnit # :nodoc: + module Generators # :nodoc: + class IntegrationGenerator < Base # :nodoc: + check_class_collision suffix: "Test" def create_test_files template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb") diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb index a404a13bd2..3334b189bf 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -1,10 +1,10 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class MailerGenerator < Base - argument :actions, :type => :array, :default => [], :banner => "method method" - check_class_collision :suffix => "Test" +module TestUnit # :nodoc: + module Generators # :nodoc: + class MailerGenerator < Base # :nodoc: + argument :actions, type: :array, default: [], banner: "method method" + check_class_collision suffix: "Test" def create_test_files template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_test.rb") 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 ffb51e437d..2801749ffe 100644 --- a/railties/lib/rails/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -1,12 +1,12 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class ModelGenerator < Base - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" - class_option :fixture, :type => :boolean +module TestUnit # :nodoc: + module Generators # :nodoc: + class ModelGenerator < Base # :nodoc: + argument :attributes, type: :array, default: [], banner: "field:type field:type" + class_option :fixture, type: :boolean - check_class_collision :suffix => "Test" + check_class_collision suffix: "Test" def create_test_file template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_test.rb") diff --git a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb index 658373d554..64fe694a8b 100644 --- a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb +++ b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class ObserverGenerator < Base - check_class_collision :suffix => "ObserverTest" +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") diff --git a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb index 99edda5461..5552edeee4 100644 --- a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb +++ b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class PerformanceGenerator < Base - check_class_collision :suffix => "Test" +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") 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 index 2f25dcf832..2bcb482d68 100644 --- a/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb +++ b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb @@ -3,8 +3,8 @@ 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] } + # self.profile_options = { runs: 5, metrics: [:wall_time, :memory], + # output: 'tmp/performance', formats: [:flat] } test "homepage" do get '/' diff --git a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb index 4d65cd7d89..b5d4f38444 100644 --- a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb @@ -1,9 +1,9 @@ require 'rails/generators/test_unit' -module TestUnit - module Generators - class PluginGenerator < Base - check_class_collision :suffix => "Test" +module TestUnit # :nodoc: + module Generators # :nodoc: + class PluginGenerator < Base # :nodoc: + check_class_collision suffix: "Test" def create_test_files directory '.', 'test' 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 e9de51ba72..3b4fec2e83 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -1,14 +1,14 @@ require 'rails/generators/test_unit' require 'rails/generators/resource_helpers' -module TestUnit - module Generators - class ScaffoldGenerator < Base +module TestUnit # :nodoc: + module Generators # :nodoc: + class ScaffoldGenerator < Base # :nodoc: include Rails::Generators::ResourceHelpers - check_class_collision :suffix => "ControllerTest" + check_class_collision suffix: "ControllerTest" - argument :attributes, :type => :array, :default => [], :banner => "field:type field:type" + argument :attributes, type: :array, default: [], banner: "field:type field:type" def create_test_files template "functional_test.rb", diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 512803aeac..e94c6a2030 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -23,7 +23,7 @@ class Rails::InfoController < ActionController::Base def require_local! unless local_request? - render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden + render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden end end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 9826aecb54..8af4130e87 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -5,7 +5,7 @@ module Rails # paths by a Hash like API. It requires you to give a physical path on initialization. # # root = Root.new "/rails" - # root.add "app/controllers", :eager_load => true + # root.add "app/controllers", eager_load: true # # The command above creates a new root object and add "app/controllers" as a path. # This means we can get a <tt>Rails::Paths::Path</tt> object back like below: @@ -26,7 +26,7 @@ module Rails # contains the path with the same path value given to +add+. In some situations, # you may not want this behavior, so you can give :with as option. # - # root.add "config/routes", :with => "config/routes.rb" + # root.add "config/routes", with: "config/routes.rb" # root["config/routes"].inspect # => ["config/routes.rb"] # # The +add+ method accepts the following options as arguments: @@ -52,7 +52,7 @@ module Rails def []=(path, value) glob = self[path] ? self[path].glob : nil - add(path, :with => value, :glob => glob) + add(path, with: value, glob: glob) end def add(path, options={}) diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index fba685c769..5b454e7f20 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -172,7 +172,7 @@ module Rails end end - delegate :railtie_name, :to => "self.class" + delegate :railtie_name, to: "self.class" def config @config ||= Railtie::Configuration.new diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb index 53796c74cf..1572af0b2a 100644 --- a/railties/lib/rails/railtie/configurable.rb +++ b/railties/lib/rails/railtie/configurable.rb @@ -6,7 +6,7 @@ module Rails extend ActiveSupport::Concern module ClassMethods - delegate :config, :to => :instance + delegate :config, to: :instance def inherited(base) raise "You cannot inherit from a #{self.superclass.name} child" diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 9dc8843887..0cbbf04da2 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -50,23 +50,23 @@ module Rails # First configurable block to run. Called before any initializers are run. def before_configuration(&block) - ActiveSupport.on_load(:before_configuration, :yield => true, &block) + ActiveSupport.on_load(:before_configuration, yield: true, &block) end # Third configurable block to run. Does not run if +config.cache_classes+ # set to false. def before_eager_load(&block) - ActiveSupport.on_load(:before_eager_load, :yield => true, &block) + ActiveSupport.on_load(:before_eager_load, yield: true, &block) end # Second configurable block to run. Called before frameworks initialize. def before_initialize(&block) - ActiveSupport.on_load(:before_initialize, :yield => true, &block) + ActiveSupport.on_load(:before_initialize, yield: true, &block) end # Last configurable block to run. Called after frameworks initialize. def after_initialize(&block) - ActiveSupport.on_load(:after_initialize, :yield => true, &block) + ActiveSupport.on_load(:after_initialize, yield: true, &block) end # Array of callbacks defined by #to_prepare. diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 31e34023c0..3474b02af4 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -32,9 +32,9 @@ class SourceAnnotationExtractor end # Prints all annotations with tag +tag+ under the root directories +app+, +config+, +lib+, - # +script+, and +test+ (recursively). Only filenames with extension - # +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, +.scss+, +.js+, and - # +.coffee+ are taken into account. The +options+ hash is passed to each + # +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+. # # This class method is the single entry point for the rake tasks. @@ -56,9 +56,9 @@ class SourceAnnotationExtractor end # Returns a hash that maps filenames under +dir+ (recursively) to arrays - # with their annotations. Only files with annotations are included, and only - # those with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, - # +.scss+, +.js+, and +.coffee+ + # with their annotations. Only files with annotations are included. Files + # with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, + # +.scss+, +.js+, +.coffee+, and +.rake+ # are taken into account. def find_in(dir) results = {} @@ -68,7 +68,7 @@ class SourceAnnotationExtractor if File.directory?(item) results.update(find_in(item)) - elsif item =~ /\.(builder|rb|coffee)$/ + 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*(.*)$/)) diff --git a/railties/lib/rails/tasks/annotations.rake b/railties/lib/rails/tasks/annotations.rake index 9067b03d00..386ecf44be 100644 --- a/railties/lib/rails/tasks/annotations.rake +++ b/railties/lib/rails/tasks/annotations.rake @@ -2,7 +2,7 @@ require 'rails/source_annotation_extractor' desc "Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)" task :notes do - SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true + SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", tag: true end namespace :notes do diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index f9cff5b627..50499304cb 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" ] + task update: [ "update:configs", "update:scripts", "update:application_controller" ] desc "Applies the template supplied by LOCATION=(/path/to/template) or URL" task :template do @@ -9,8 +9,8 @@ namespace :rails do template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} require 'rails/generators' require 'rails/generators/rails/app/app_generator' - generator = Rails::Generators::AppGenerator.new [Rails.root], {}, :destination_root => Rails.root - generator.apply template, :verbose => false + generator = Rails::Generators::AppGenerator.new [Rails.root], {}, destination_root: Rails.root + generator.apply template, verbose: false end namespace :templates do @@ -44,8 +44,8 @@ namespace :rails do @app_generator ||= begin require 'rails/generators' require 'rails/generators/rails/app/app_generator' - gen = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, - :destination_root => Rails.root + 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?) gen diff --git a/railties/lib/rails/tasks/middleware.rake b/railties/lib/rails/tasks/middleware.rake index cd35ffb19a..31e961b483 100644 --- a/railties/lib/rails/tasks/middleware.rake +++ b/railties/lib/rails/tasks/middleware.rake @@ -1,5 +1,5 @@ desc 'Prints out your Rack middleware stack' -task :middleware => :environment do +task middleware: :environment do Rails.configuration.middleware.each do |middleware| puts "use #{middleware.inspect}" end diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index 0a9b9ff4ff..4195106961 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -5,7 +5,7 @@ task :secret do end desc 'List versions of all Rails frameworks and the environment' -task :about => :environment do +task about: :environment do puts Rails::Info end @@ -26,7 +26,7 @@ namespace :time do require 'active_support' require 'active_support/time' jan_offset = Time.now.beginning_of_year.utc_offset - jul_offset = Time.now.beginning_of_year.change(:month => 7).utc_offset + jul_offset = Time.now.beginning_of_year.change(month: 7).utc_offset offset = jan_offset < jul_offset ? jan_offset : jul_offset build_time_zone_list(:all, offset) end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 95f47566ef..676b475640 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -1,5 +1,5 @@ desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.' -task :routes => :environment do +task routes: :environment do all_routes = Rails.application.routes.routes require 'action_dispatch/routing/inspector' inspector = ActionDispatch::Routing::RoutesInspector.new diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake index 0bb64ced95..116988665f 100644 --- a/railties/lib/rails/tasks/tmp.rake +++ b/railties/lib/rails/tasks/tmp.rake @@ -1,6 +1,6 @@ namespace :tmp do desc "Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)" - task :clear => [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"] + task clear: [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"] tmp_dirs = [ 'tmp/sessions', 'tmp/cache', @@ -13,7 +13,7 @@ namespace :tmp do tmp_dirs.each { |d| directory d } desc "Creates tmp directories for sessions, cache, sockets, and pids" - task :create => tmp_dirs + task create: tmp_dirs namespace :sessions do # desc "Clears all files in tmp/sessions" diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index 2b6170ebfb..ed89ce4128 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,8 +1,8 @@ module Rails class TestUnitRailtie < Rails::Railtie config.app_generators do |c| - c.test_framework :test_unit, :fixture => true, - :fixture_replacement => nil + c.test_framework :test_unit, fixture: true, + fixture_replacement: nil c.integration_tool :test_unit c.performance_tool :test_unit diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 63cb955d44..cd59fbe599 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -43,7 +43,7 @@ module Kernel end end -task :default => :test +task default: :test desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile)' task :test do @@ -61,7 +61,7 @@ namespace :test do Rake::Task[task].invoke nil rescue => e - { :task => task, :exception => e } + { task: task, exception: e } end end.compact @@ -71,7 +71,7 @@ namespace :test do end end - Rake::TestTask.new(:recent => "test:prepare") do |t| + 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) + @@ -84,7 +84,7 @@ namespace :test do end Rake::Task['test:recent'].comment = "Test recent changes" - Rake::TestTask.new(:uncommitted => "test:prepare") do |t| + 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] } @@ -108,52 +108,52 @@ namespace :test do end Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)" - Rake::TestTask.new(:single => "test:prepare") do |t| + Rake::TestTask.new(single: "test:prepare") do |t| t.libs << "test" end - Rails::SubTestTask.new(:models => "test:prepare") do |t| + 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| + Rails::SubTestTask.new(helpers: "test:prepare") do |t| t.libs << "test" t.pattern = 'test/helpers/**/*_test.rb' end - Rails::SubTestTask.new(:units => "test:prepare") do |t| + Rails::SubTestTask.new(units: "test:prepare") do |t| t.libs << "test" t.pattern = 'test/{models,helpers,unit}/**/*_test.rb' end - Rails::SubTestTask.new(:controllers => "test:prepare") do |t| + 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| + 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| + Rails::SubTestTask.new(functionals: "test:prepare") do |t| t.libs << "test" t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb' end - Rails::SubTestTask.new(:integration => "test:prepare") do |t| + 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| + 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| + Rails::SubTestTask.new(profile: 'test:prepare') do |t| t.libs << 'test' t.pattern = 'test/performance/**/*_test.rb' end diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb index ebafc7d670..1eddfac664 100644 --- a/railties/test/application/asset_debugging_test.rb +++ b/railties/test/application/asset_debugging_test.rb @@ -7,7 +7,7 @@ module ApplicationTests include Rack::Test::Methods def setup - build_app(:initializers => true) + build_app(initializers: true) app_file "app/assets/javascripts/application.js", "//= require_tree ." app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" @@ -15,7 +15,7 @@ module ApplicationTests app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do - get '/posts', :to => "posts#index" + get '/posts', to: "posts#index" end RUBY @@ -36,9 +36,8 @@ module ApplicationTests test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do # config.assets.debug and config.assets.compile are false for production environment ENV["RAILS_ENV"] = "production" - capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } - end + output = Dir.chdir(app_path){ `bundle exec rake assets:precompile --trace 2>&1` } + assert $?.success?, output require "#{app_path}/config/environment" class ::PostsController < ActionController::Base ; end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index be97855e1a..2506d19e6d 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -8,7 +8,7 @@ module ApplicationTests include Rack::Test::Methods def setup - build_app(:initializers => true) + build_app(initializers: true) boot_rails end @@ -18,7 +18,7 @@ module ApplicationTests def precompile!(env = nil) quietly do - precompile_task = "bundle exec rake assets:precompile #{env} 2>&1" + precompile_task = "bundle exec rake assets:precompile #{env} --trace 2>&1" output = Dir.chdir(app_path) { %x[ #{precompile_task} ] } assert $?.success?, output output @@ -44,7 +44,7 @@ module ApplicationTests app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get '*path', :to => lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] } + get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] } end RUBY @@ -353,7 +353,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index flash[:cool_story] = true - render :text => "ok" + render text: "ok" end end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 07d47dc67b..c4c1100f19 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -56,14 +56,6 @@ module ApplicationTests assert_match "ActiveRecord::PendingMigrationError", last_response.body end - test "multiple queue construction is possible" do - require 'rails' - require "#{app_path}/config/environment" - mail_queue = Rails.application.build_queue - image_processing_queue = Rails.application.build_queue - assert_not_equal mail_queue, image_processing_queue - end - test "Rails.groups returns available groups" do require "rails" @@ -162,11 +154,6 @@ module ApplicationTests 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 - end - test "the application can be eager loaded even when there are no frameworks" do FileUtils.rm_rf("#{app_path}/config/environments") add_to_config <<-RUBY @@ -247,7 +234,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index cookies.signed[:some_key] = "some_value" - render :text => env["action_dispatch.secret_token"] + render text: env["action_dispatch.secret_token"] end end @@ -260,7 +247,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index - render :inline => "<%= csrf_meta_tags %>" + render inline: "<%= csrf_meta_tags %>" end end @@ -280,11 +267,11 @@ module ApplicationTests app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ApplicationController def show - render :inline => "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>" + render inline: "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>" end def update - render :text => "update" + render text: "update" end end RUBY @@ -299,7 +286,7 @@ module ApplicationTests token = "cf50faa3fe97702ca1ae" PostsController.any_instance.stubs(:form_authenticity_token).returns(token) - params = {:authenticity_token => token} + params = {authenticity_token: token} get "/posts/1" assert_match(/patch/, last_response.body) @@ -324,7 +311,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index - render :inline => "<%= csrf_meta_tags %>" + render inline: "<%= csrf_meta_tags %>" end end @@ -441,21 +428,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" @@ -501,7 +473,7 @@ module ApplicationTests class ::OmgController < ActionController::Base def index - render :text => env["action_dispatch.show_exceptions"] + render text: env["action_dispatch.show_exceptions"] end end @@ -511,7 +483,7 @@ module ApplicationTests test "config.action_controller.wrap_parameters is set in ActionController::Base" do app_file 'config/initializers/wrap_parameters.rb', <<-RUBY - ActionController::Base.wrap_parameters :format => [:json] + ActionController::Base.wrap_parameters format: [:json] RUBY app_file 'app/models/post.rb', <<-RUBY @@ -531,7 +503,7 @@ module ApplicationTests app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ApplicationController def create - render :text => params[:post].inspect + render text: params[:post].inspect end end RUBY @@ -552,7 +524,7 @@ module ApplicationTests app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ActionController::Base def create - render :text => params[:post].permitted? ? "permitted" : "forbidden" + render text: params[:post].permitted? ? "permitted" : "forbidden" end end RUBY @@ -566,7 +538,7 @@ module ApplicationTests require "#{app_path}/config/environment" - post "/posts", {:post => {"title" =>"zomg"}} + post "/posts", {post: {"title" =>"zomg"}} assert_equal 'permitted', last_response.body end @@ -578,8 +550,8 @@ module ApplicationTests class ::OmgController < ActionController::Base def index respond_to do |format| - format.html { render :text => "HTML" } - format.xml { render :text => "XML" } + format.html { render text: "HTML" } + format.xml { render text: "XML" } end end end @@ -587,7 +559,7 @@ module ApplicationTests get "/", {}, "HTTP_ACCEPT" => "application/xml" assert_equal 'HTML', last_response.body - get "/", { :format => :xml }, "HTTP_ACCEPT" => "application/xml" + get "/", { format: :xml }, "HTTP_ACCEPT" => "application/xml" assert_equal 'XML', last_response.body end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index b80244f1d2..bc0af499c1 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -48,22 +48,22 @@ module ApplicationTests c.generators.orm = :data_mapper c.generators.test_framework = :rspec c.generators.helper = false - expected = { :rails => { :orm => :data_mapper, :test_framework => :rspec, :helper => false } } + expected = { rails: { orm: :data_mapper, test_framework: :rspec, helper: false } } assert_equal(expected, c.generators.options) end end test "generators set rails aliases" do with_config do |c| - c.generators.aliases = { :rails => { :test_framework => "-w" } } - expected = { :rails => { :test_framework => "-w" } } + c.generators.aliases = { rails: { test_framework: "-w" } } + expected = { rails: { test_framework: "-w" } } assert_equal expected, c.generators.aliases end end test "generators aliases, options, templates and fallbacks on initialization" do add_to_config <<-RUBY - config.generators.rails :aliases => { :test_framework => "-w" } + config.generators.rails aliases: { test_framework: "-w" } config.generators.orm :data_mapper config.generators.test_framework :rspec config.generators.fallbacks[:shoulda] = :test_unit @@ -76,7 +76,7 @@ module ApplicationTests assert_equal :rspec, Rails::Generators.options[:rails][:test_framework] assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework] - assert_equal Hash[:shoulda => :test_unit], Rails::Generators.fallbacks + assert_equal Hash[shoulda: :test_unit], Rails::Generators.fallbacks assert_equal ["some/where"], Rails::Generators.templates_path end @@ -95,31 +95,31 @@ module ApplicationTests test "generators with hashes for options and aliases" do with_bare_config do |c| c.generators do |g| - g.orm :data_mapper, :migration => false - g.plugin :aliases => { :generator => "-g" }, - :generator => true + g.orm :data_mapper, migration: false + g.plugin aliases: { generator: "-g" }, + generator: true end expected = { - :rails => { :orm => :data_mapper }, - :plugin => { :generator => true }, - :data_mapper => { :migration => false } + rails: { orm: :data_mapper }, + plugin: { generator: true }, + data_mapper: { migration: false } } assert_equal expected, c.generators.options - assert_equal({ :plugin => { :generator => "-g" } }, c.generators.aliases) + assert_equal({ plugin: { generator: "-g" } }, c.generators.aliases) end end test "generators with string and hash for options should generate symbol keys" do with_bare_config do |c| c.generators do |g| - g.orm 'data_mapper', :migration => false + g.orm 'data_mapper', migration: false end expected = { - :rails => { :orm => :data_mapper }, - :data_mapper => { :migration => false } + rails: { orm: :data_mapper }, + data_mapper: { migration: false } } assert_equal expected, c.generators.options diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 81f6096be8..528bec58ef 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -52,14 +52,13 @@ module ApplicationTests test "uses the default queue for ActionMailer" do require "#{app_path}/config/environment" - assert_kind_of ActiveSupport::QueueContainer, ActionMailer::Base.queue + 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 - Rails.queue[:mailer] = ActiveSupport::TestQueue.new - config.action_mailer.queue = Rails.queue[:mailer] + config.action_mailer.queue = ActiveSupport::TestQueue.new end RUBY diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 02d20bc150..489b7ddb92 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -143,7 +143,7 @@ en: I18n::Railtie.config.i18n.fallbacks = true load_app assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] + assert_fallbacks de: [:de, :en] end test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do @@ -151,37 +151,37 @@ en: I18n::Railtie.config.i18n.backend = Class.new(I18n::Backend::Simple).new load_app assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) - assert_fallbacks :de => [:de, :en] + assert_fallbacks de: [:de, :en] end test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US'] load_app - assert_fallbacks :de => [:de, :'en-US', :en] + assert_fallbacks de: [:de, :'en-US', :en] end test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + assert_fallbacks ca: [:ca, :"es-ES", :es, :en] end test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do I18n::Railtie.config.i18n.fallbacks = [:'en-US'] load_app - assert_fallbacks :de => [:de, :'en-US', :en] + assert_fallbacks de: [:de, :'en-US', :en] end test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :en] + assert_fallbacks ca: [:ca, :"es-ES", :es, :en] end test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] load_app - assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en] + assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en] end end end diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb index d866a63fe0..baae6fd928 100644 --- a/railties/test/application/initializers/notifications_test.rb +++ b/railties/test/application/initializers/notifications_test.rb @@ -33,7 +33,7 @@ module ApplicationTests ActiveRecord::Base.logger = logger # Mimic Active Record notifications - instrument "sql.active_record", :name => "SQL", :sql => "SHOW tables" + instrument "sql.active_record", name: "SQL", sql: "SHOW tables" wait assert_equal 1, logger.logged(:debug).size diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index fcbc3c048c..ad7172c514 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -19,14 +19,14 @@ class LoadingTest < ActiveSupport::TestCase test "constants in app are autoloaded" do app_file "app/models/post.rb", <<-MODEL class Post < ActiveRecord::Base - validates_acceptance_of :title, :accept => "omg" + validates_acceptance_of :title, accept: "omg" end MODEL require "#{rails_root}/config/environment" setup_ar! - p = Post.create(:title => 'omg') + p = Post.create(title: 'omg') assert_equal 1, Post.count assert_equal 'omg', p.title p = Post.first @@ -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 @@ -76,8 +76,8 @@ class LoadingTest < ActiveSupport::TestCase app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get '/load', :to => lambda { |env| [200, {}, Post.all] } - get '/unload', :to => lambda { |env| [200, {}, []] } + get '/load', to: lambda { |env| [200, {}, Post.all] } + get '/unload', to: lambda { |env| [200, {}, []] } end RUBY @@ -106,7 +106,7 @@ class LoadingTest < ActiveSupport::TestCase app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } + get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -145,7 +145,7 @@ class LoadingTest < ActiveSupport::TestCase app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } + get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end RUBY @@ -181,7 +181,7 @@ class LoadingTest < ActiveSupport::TestCase app_file 'config/routes.rb', <<-RUBY $counter = 0 AppTemplate::Application.routes.draw do - get '/c', :to => lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } + get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } end RUBY @@ -212,8 +212,8 @@ class LoadingTest < ActiveSupport::TestCase app_file 'config/routes.rb', <<-RUBY AppTemplate::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]] } + 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 RUBY @@ -229,7 +229,7 @@ class LoadingTest < ActiveSupport::TestCase class CreatePosts < ActiveRecord::Migration def change create_table :posts do |t| - t.string :title, :default => "TITLE" + t.string :title, default: "TITLE" end end end @@ -244,7 +244,7 @@ class LoadingTest < ActiveSupport::TestCase app_file "db/migrate/2_add_body_to_posts.rb", <<-MIGRATION class AddBodyToPosts < ActiveRecord::Migration def change - add_column :posts, :body, :text, :default => "BODY" + add_column :posts, :body, :text, default: "BODY" end end MIGRATION @@ -297,9 +297,9 @@ class LoadingTest < ActiveSupport::TestCase protected def setup_ar! - ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") + ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Migration.verbose = false - ActiveRecord::Schema.define(:version => 1) do + ActiveRecord::Schema.define(version: 1) do create_table :posts do |t| t.string :title end diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index fffe79f9cc..9b6c76e7aa 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -19,17 +19,17 @@ module ApplicationTests controller :expires, <<-RUBY class ExpiresController < ApplicationController def expires_header - expires_in 10, :public => !params[:private] - render :text => SecureRandom.hex(16) + expires_in 10, public: !params[:private] + render text: SecureRandom.hex(16) end def expires_etag - render_conditionally(:etag => "1") + render_conditionally(etag: "1") end def expires_last_modified $last_modified ||= Time.now.utc - render_conditionally(:last_modified => $last_modified) + render_conditionally(last_modified: $last_modified) end def keeps_if_modified_since @@ -37,8 +37,8 @@ module ApplicationTests end private def render_conditionally(headers) - if stale?(headers.merge(:public => !params[:private])) - render :text => SecureRandom.hex(16) + if stale?(headers.merge(public: !params[:private])) + render text: SecureRandom.hex(16) end end end @@ -96,13 +96,13 @@ module ApplicationTests def test_cache_works_with_expires_private simple_controller - get "/expires/expires_header", :private => 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"] body = last_response.body - get "/expires/expires_header", :private => true + get "/expires/expires_header", private: true assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end @@ -125,14 +125,14 @@ module ApplicationTests def test_cache_works_with_etags_private simple_controller - get "/expires/expires_etag", :private => 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"] body = last_response.body etag = last_response.headers["ETag"] - get "/expires/expires_etag", {:private => true}, "If-None-Match" => etag + get "/expires/expires_etag", {private: true}, "If-None-Match" => etag assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end @@ -155,14 +155,14 @@ module ApplicationTests def test_cache_works_with_last_modified_private simple_controller - get "/expires/expires_last_modified", :private => 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"] body = last_response.body last = last_response.headers["Last-Modified"] - get "/expires/expires_last_modified", {:private => true}, "If-Modified-Since" => last + get "/expires/expires_last_modified", {private: true}, "If-Modified-Since" => last assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 06dec81d40..5ce41caf61 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -36,7 +36,7 @@ module ApplicationTests flash[:notice] = "notice" end - render :nothing => true + render nothing: true end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index b2443e6503..c03d35e926 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -81,10 +81,10 @@ module ApplicationTests test "ActionDispatch::SSL is configured with options when given" do add_to_config "config.force_ssl = true" - add_to_config "config.ssl_options = { :host => 'example.com' }" + add_to_config "config.ssl_options = { host: 'example.com' }" boot! - assert_equal AppTemplate::Application.middleware.first.args, [{:host => 'example.com'}] + assert_equal AppTemplate::Application.middleware.first.args, [{host: 'example.com'}] end test "removing Active Record omits its middleware" do @@ -169,9 +169,9 @@ module ApplicationTests class ::OmgController < ActionController::Base def index if params[:nothing] - render :text => "" + render text: "" else - render :text => "OMG" + render text: "OMG" end end end diff --git a/railties/test/application/queue_test.rb b/railties/test/application/queue_test.rb index e67c6cc371..b0b3cf18e9 100644 --- a/railties/test/application/queue_test.rb +++ b/railties/test/application/queue_test.rb @@ -17,16 +17,16 @@ module ApplicationTests @app_const ||= Class.new(Rails::Application) end - test "the queue is a TestQueue in test mode" do + test "the queue is a SynchronousQueue in test mode" do app("test") - assert_kind_of ActiveSupport::TestQueue, Rails.application.queue[:default] - assert_kind_of ActiveSupport::TestQueue, Rails.queue[:default] + 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[:default] - assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue[:default] + assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue + assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue end class ThreadTrackingJob @@ -58,54 +58,26 @@ module ApplicationTests refute job.ran_in_different_thread?, "Expected job to run in the same thread" end - test "in test mode, explicitly draining the queue will process it in the same thread" do + test "in test mode, an enqueued job will be processed in the same thread" do app("test") - Rails.queue.push ThreadTrackingJob.new - job = Rails.queue.jobs.last - Rails.queue.drain + 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 - class IdentifiableJob - def initialize(id) - @id = id - end - - def ==(other) - other.same_id?(@id) - end - - def same_id?(other_id) - other_id == @id - end - - def run - end - end - - test "in test mode, the queue can be observed" do - app("test") - - jobs = (1..10).map do |id| - IdentifiableJob.new(id) - 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 - jobs.each do |job| - Rails.queue.push job - end + app("production") - assert_equal jobs, Rails.queue.jobs - end - - test "in test mode, adding an unmarshallable job will raise an exception" do - app("test") - anonymous_class_instance = Struct.new(:run).new - assert_raises TypeError do - Rails.queue.push anonymous_class_instance - end + 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 @@ -115,18 +87,10 @@ module ApplicationTests end end - test "attempting to add a reference to itself to the queue will raise an exception" do - app("test") - job = {reference: Rails.queue} - assert_raises TypeError do - Rails.queue.push job - end - end - def setup_custom_queue add_to_env_config "production", <<-RUBY require "my_queue" - config.queue = MyQueue + config.queue = MyQueue.new RUBY app_file "lib/my_queue.rb", <<-RUBY @@ -143,7 +107,7 @@ module ApplicationTests test "a custom queue implementation can be provided" do setup_custom_queue - assert_kind_of MyQueue, Rails.queue[:default] + assert_kind_of MyQueue, Rails.queue job = Struct.new(:id, :ran) do def run @@ -160,17 +124,16 @@ module ApplicationTests test "a custom consumer implementation can be provided" do add_to_env_config "production", <<-RUBY require "my_queue_consumer" - config.queue = ActiveSupport::Queue - config.queue_consumer = MyQueueConsumer + config.queue = ActiveSupport::Queue.new + config.queue_consumer = MyQueueConsumer.new RUBY app_file "lib/my_queue_consumer.rb", <<-RUBY - class MyQueueConsumer < ActiveSupport::ThreadedQueueConsumer + class MyQueueConsumer attr_reader :started def start @started = true - self end end RUBY diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 27de75b63b..7a227098ba 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -25,6 +25,7 @@ module ApplicationTests 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/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby" + app_file "lib/tasks/task.rake", "# TODO: note in rake" boot_rails require 'rake' @@ -45,8 +46,9 @@ module ApplicationTests assert_match(/note in js/, output) assert_match(/note in css/, output) assert_match(/note in scss/, output) + assert_match(/note in rake/, output) - assert_equal 8, lines.size + assert_equal 9, lines.size lines.each do |line| assert_equal 4, line[0].size diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 2e7426150c..c5a68a5152 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -46,7 +46,7 @@ module ApplicationTests end rake_tasks do - task :do_nothing => :environment do + task do_nothing: :environment do end end RUBY @@ -60,7 +60,7 @@ module ApplicationTests config.eager_load = true rake_tasks do - task :do_nothing => :environment do + task do_nothing: :environment do Hello.new.world end end @@ -109,7 +109,7 @@ module ApplicationTests def test_rake_routes_calls_the_route_inspector app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do - get '/cart', :to => 'cart#show' + get '/cart', to: 'cart#show' end RUBY assert_equal "cart GET /cart(.:format) cart#show\n", Dir.chdir(app_path){ `rake routes` } @@ -118,7 +118,7 @@ module ApplicationTests def test_logger_is_flushed_when_exiting_production_rake_tasks add_to_config <<-RUBY rake_tasks do - task :log_something => :environment do + task log_something: :environment do Rails.logger.error("Sample log message") end end @@ -233,7 +233,7 @@ module ApplicationTests app_file "lib/tasks/count_user.rake", <<-RUBY namespace :user do - task :count => :environment do + task count: :environment do puts User.count end end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 396b1849d8..ffcdeac7f0 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -50,7 +50,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render :inline => "<%= foo_or_bar? %>" + render inline: "<%= foo_or_bar? %>" end end RUBY @@ -76,7 +76,7 @@ module ApplicationTests test "mount rack app" do app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, :at => "/blog" + mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog" # The line below is required because mount sometimes # fails when a resource route is added. resource :user @@ -91,7 +91,7 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def index - render :text => "foo" + render text: "foo" end end RUBY @@ -99,7 +99,7 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ActionController::Base def index - render :text => "bar" + render text: "bar" end end RUBY @@ -121,7 +121,7 @@ module ApplicationTests controller 'foo', <<-RUBY class FooController < ApplicationController def index - render :text => "foo" + render text: "foo" end end RUBY @@ -130,7 +130,7 @@ module ApplicationTests module Admin class FooController < ApplicationController def index - render :text => "admin::foo" + render text: "admin::foo" end end end @@ -138,8 +138,8 @@ module ApplicationTests app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get 'admin/foo', :to => 'admin/foo#index' - get 'foo', :to => 'foo#index' + get 'admin/foo', to: 'admin/foo#index' + get 'foo', to: 'foo#index' end RUBY @@ -183,18 +183,18 @@ module ApplicationTests controller :foo, <<-RUBY class FooController < ApplicationController def bar - render :text => "bar" + render text: "bar" end def baz - render :text => "baz" + render text: "baz" end end RUBY app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get 'foo', :to => 'foo#bar' + get 'foo', to: 'foo#bar' end RUBY @@ -205,7 +205,7 @@ module ApplicationTests app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get 'foo', :to => 'foo#baz' + get 'foo', to: 'foo#baz' end RUBY @@ -226,7 +226,7 @@ module ApplicationTests app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do - get 'foo', :to => ::InitializeRackApp + get 'foo', to: ::InitializeRackApp end RUBY @@ -257,7 +257,7 @@ module ApplicationTests controller 'yazilar', <<-RUBY class YazilarController < ApplicationController def index - render :text => 'yazilar#index' + render text: 'yazilar#index' end end RUBY diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index f7e60749a7..4ecb94b65e 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -15,7 +15,7 @@ module ApplicationTests class MyApp < Rails::Application config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - config.session_store :cookie_store, :key => "_myapp_session" + config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log end @@ -26,12 +26,12 @@ module ApplicationTests class ::OmgController < ::ApplicationController def index - render :text => omg_path + render text: omg_path end end MyApp.routes.draw do - get "/" => "omg#index", :as => :omg + get "/" => "omg#index", as: :omg end require 'rack/test' diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index 91ede1cb68..e047d4882d 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -58,8 +58,8 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_defaults_to_IRB - config = mock("config", :console => nil) - app = mock("app", :config => config) + config = mock("config", console: nil) + app = mock("app", config: config) app.expects(:load_console).returns(nil) assert_equal IRB, Rails::Console.new(app).console @@ -68,40 +68,40 @@ class Rails::ConsoleTest < ActiveSupport::TestCase def test_default_environment_with_no_rails_env with_rails_env nil do start - assert_match /\sdevelopment\s/, output + assert_match(/\sdevelopment\s/, output) end end def test_default_environment_with_rails_env with_rails_env 'special-production' do start - assert_match /\sspecial-production\s/, output + assert_match(/\sspecial-production\s/, output) end end def test_e_option start ['-e', 'special-production'] - assert_match /\sspecial-production\s/, output + assert_match(/\sspecial-production\s/, output) end def test_environment_option start ['--environment=special-production'] - assert_match /\sspecial-production\s/, output + assert_match(/\sspecial-production\s/, output) end def test_rails_env_is_production_when_first_argument_is_p start ['p'] - assert_match /\sproduction\s/, output + assert_match(/\sproduction\s/, output) end def test_rails_env_is_test_when_first_argument_is_t start ['t'] - assert_match /\stest\s/, output + assert_match(/\stest\s/, output) end def test_rails_env_is_development_when_argument_is_d start ['d'] - assert_match /\sdevelopment\s/, output + assert_match(/\sdevelopment\s/, output) end private @@ -115,8 +115,8 @@ class Rails::ConsoleTest < ActiveSupport::TestCase def app @app ||= begin - config = mock("config", :console => FakeConsole) - app = mock("app", :config => config) + config = mock("config", console: FakeConsole) + app = mock("app", config: config) app.stubs(:sandbox=).returns(nil) app.expects(:load_console) app diff --git a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb index aa18c7ddaa..2721429599 100644 --- a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb +++ b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb @@ -4,7 +4,7 @@ class PluginBuilder < Rails::PluginBuilder append_file "Rakefile", <<-EOF # spec tasks in rakefile -task :default => :spec +task default: :spec EOF end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index bc086c5986..8af92479c3 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -99,7 +99,7 @@ class ActionsTest < Rails::Generators::TestCase def test_environment_should_include_data_in_environment_initializer_block_with_env_option run_generator autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' - action :environment, autoload_paths, :env => 'development' + action :environment, autoload_paths, env: 'development' assert_file "config/environments/development.rb", /Application\.configure do\n #{Regexp.escape(autoload_paths)}/ end @@ -124,7 +124,7 @@ class ActionsTest < Rails::Generators::TestCase def test_git_with_hash_should_run_each_command_using_git_scm generator.expects(:run).times(2) - action :git, :rm => 'README', :add => '.' + action :git, rm: 'README', add: '.' end def test_vendor_should_write_data_to_file_in_vendor @@ -138,8 +138,8 @@ class ActionsTest < Rails::Generators::TestCase end def test_rakefile_should_write_date_to_file_in_lib_tasks - action :rakefile, 'myapp.rake', 'task :run => [:environment]' - assert_file 'lib/tasks/myapp.rake', 'task :run => [:environment]' + action :rakefile, 'myapp.rake', 'task run: [:environment]' + assert_file 'lib/tasks/myapp.rake', 'task run: [:environment]' end def test_initializer_should_write_date_to_file_in_config_initializers @@ -148,12 +148,12 @@ 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('script/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) + 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 @@ -161,12 +161,12 @@ class ActionsTest < Rails::Generators::TestCase end def test_rake_with_env_option_should_run_rake_command_in_env - generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false) - action :rake, 'log:clear', :env => 'production' + generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false) + action :rake, 'log:clear', env: 'production' end 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) + 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 @@ -174,29 +174,29 @@ class ActionsTest < Rails::Generators::TestCase 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) + 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' + action :rake, 'log:clear', env: 'production' ensure ENV["RAILS_ENV"] = old_env 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) + 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 + action :rake, 'log:clear', sudo: true ensure ENV["RAILS_ENV"] = old_env end def test_capify_should_run_the_capify_command - generator.expects(:run).once.with('capify .', :verbose => false) + generator.expects(:run).once.with('capify .', verbose: false) action :capify! end def test_route_should_add_data_to_the_routes_block_in_config_routes run_generator - route_command = "route '/login', :controller => 'sessions', :action => 'new'" + route_command = "route '/login', controller: 'sessions', action: 'new'" action :route, route_command assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/ end @@ -208,7 +208,7 @@ class ActionsTest < Rails::Generators::TestCase end def test_readme_with_quiet - generator(default_arguments, :quiet => true) + 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")) @@ -223,12 +223,12 @@ class ActionsTest < Rails::Generators::TestCase end def test_log_with_quiet - generator(default_arguments, :quiet => true) + generator(default_arguments, quiet: true) assert_equal("", action(:log, "YES")) end def test_log_with_status_with_quiet - generator(default_arguments, :quiet => true) + generator(default_arguments, quiet: true) assert_equal("", action(:log, :yes, "YES")) end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 91575a38b6..e5397bf4f3 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -107,8 +107,8 @@ class AppGeneratorTest < Rails::Generators::TestCase FileUtils.mv(app_root, app_moved_root) - generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, - :destination_root => app_moved_root, :shell => @shell + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, + 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!/ @@ -123,7 +123,7 @@ class AppGeneratorTest < Rails::Generators::TestCase Rails.application.class.stubs(:name).returns("Myapp") Rails.application.stubs(:is_a?).returns(Rails::Application) - generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, :destination_root => app_root, :shell => @shell + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell generator.send(:app_const) quietly { generator.send(:create_config_files) } assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/ @@ -302,11 +302,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile", /# gem 'debugger'/ end - def test_inclusion_of_rack_cache - run_generator - assert_file "Gemfile", /gem 'rack-cache'/ - 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"])) diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index a90ad5cde0..0c7ff0ebe7 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -242,19 +242,19 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_migration_is_skipped_on_skip_behavior run_generator - output = run_generator ["Account"], :behavior => :skip + output = run_generator ["Account"], behavior: :skip assert_match %r{skip\s+db/migrate/\d+_create_accounts.rb}, output end def test_migration_error_is_not_shown_on_revoke run_generator - error = capture(:stderr){ run_generator ["Account"], :behavior => :revoke } + error = capture(:stderr){ run_generator ["Account"], behavior: :revoke } assert_no_match(/Another migration is already named create_accounts/, error) end def test_migration_is_removed_on_revoke run_generator - run_generator ["Account"], :behavior => :revoke + run_generator ["Account"], behavior: :revoke assert_no_migration "db/migrate/create_accounts.rb" end diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index d48712e51f..4b168ae110 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -263,7 +263,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase def test_scaffold_on_revoke run_generator - run_generator ["product_line"], :behavior => :revoke + run_generator ["product_line"], behavior: :revoke # Model assert_no_file "app/models/test_app/product_line.rb" @@ -335,7 +335,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase def test_scaffold_with_namespace_on_revoke run_generator [ "admin/role", "name:string", "description:string" ] - run_generator [ "admin/role" ], :behavior => :revoke + run_generator [ "admin/role" ], behavior: :revoke # Model assert_file "app/models/test_app/admin.rb" # ( should not be remove ) @@ -408,7 +408,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase def test_scaffold_with_nested_namespace_on_revoke run_generator [ "admin/user/special/role", "name:string", "description:string" ] - run_generator [ "admin/user/special/role" ], :behavior => :revoke + run_generator [ "admin/user/special/role" ], behavior: :revoke # Model assert_file "app/models/test_app/admin/user/special.rb" # ( should not be remove ) diff --git a/railties/test/generators/orm_test.rb b/railties/test/generators/orm_test.rb index 9dd3d3e0ec..88ae930554 100644 --- a/railties/test/generators/orm_test.rb +++ b/railties/test/generators/orm_test.rb @@ -20,12 +20,12 @@ class OrmTest < Rails::Generators::TestCase tests Rails::Generators::ScaffoldControllerGenerator def test_orm_class_returns_custom_generator_if_supported_custom_orm_set - g = generator ["Foo"], :orm => "ORMWithGenerators" + g = generator ["Foo"], orm: "ORMWithGenerators" assert_equal ORMWithGenerators::Generators::ActiveModel, g.send(:orm_class) end def test_orm_class_returns_rails_generator_if_unsupported_custom_orm_set - g = generator ["Foo"], :orm => "ORMWithoutGenerators" + g = generator ["Foo"], orm: "ORMWithoutGenerators" assert_equal Rails::Generators::ActiveModel, g.send(:orm_class) end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index dddbfa64b6..6974db5751 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -379,7 +379,7 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase 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', /task default: :spec/ assert_file 'Rakefile', /# spec tasks in rakefile/ end diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 0ae0841442..3d4e694361 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -80,7 +80,7 @@ class ResourceGeneratorTest < Rails::Generators::TestCase def test_route_is_removed_on_revoke run_generator - run_generator ["account"], :behavior => :revoke + run_generator ["account"], behavior: :revoke assert_file "config/routes.rb" do |route| assert_no_match(/resources :accounts$/, route) diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index dc825c7c99..efe47cdfcb 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -99,7 +99,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase def test_scaffold_on_revoke run_generator - run_generator ["product_line"], :behavior => :revoke + run_generator ["product_line"], behavior: :revoke # Model assert_no_file "app/models/product_line.rb" diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index a4bdfcf438..1e5a4545a1 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -87,7 +87,7 @@ module SharedGeneratorTests template = %{ say "It works!" } template.instance_eval "def read; self; end" # Make the string respond to read - generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) end @@ -96,31 +96,31 @@ module SharedGeneratorTests template = %{ say "It works!" } template.instance_eval "def read; self; end" # Make the string respond to read - generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) end def test_dev_option - generator([destination_root], :dev => true).expects(:bundle_command).with('install').once + generator([destination_root], dev: true).expects(:bundle_command).with('install').once quietly { generator.invoke_all } rails_path = File.expand_path('../../..', Rails.root) assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ end def test_edge_option - generator([destination_root], :edge => true).expects(:bundle_command).with('install').once + generator([destination_root], edge: true).expects(:bundle_command).with('install').once quietly { generator.invoke_all } assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} end def test_skip_gemfile - generator([destination_root], :skip_gemfile => true).expects(:bundle_command).never + generator([destination_root], skip_gemfile: true).expects(:bundle_command).never quietly { generator.invoke_all } assert_no_file 'Gemfile' end def test_skip_bundle - generator([destination_root], :skip_bundle => true).expects(:bundle_command).never + generator([destination_root], skip_bundle: true).expects(:bundle_command).never quietly { generator.invoke_all } # skip_bundle is only about running bundle install, ensure the Gemfile is still @@ -192,7 +192,7 @@ module SharedCustomGeneratorTests 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) + 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) } diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 027d8eb9b7..9953aa929b 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -43,8 +43,8 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_invoke_with_config_values - Rails::Generators::ModelGenerator.expects(:start).with(["Account"], :behavior => :skip) - Rails::Generators.invoke :model, ["Account"], :behavior => :skip + Rails::Generators::ModelGenerator.expects(:start).with(["Account"], behavior: :skip) + Rails::Generators.invoke :model, ["Account"], behavior: :skip end def test_find_by_namespace @@ -165,7 +165,7 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_developer_options_are_overwriten_by_user_options - Rails::Generators.options[:with_options] = { :generate => false } + Rails::Generators.options[:with_options] = { generate: false } self.class.class_eval(<<-end_eval, __FILE__, __LINE__ + 1) class WithOptionsGenerator < Rails::Generators::Base @@ -186,7 +186,7 @@ class GeneratorsTest < Rails::Generators::TestCase File.open(template, 'w'){ |f| f.write "empty" } capture(:stdout) do - Rails::Generators.invoke :model, ["user"], :destination_root => destination_root + Rails::Generators.invoke :model, ["user"], destination_root: destination_root end assert_file "app/models/user.rb" do |content| diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index c84c7f204c..16e259be5d 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -43,17 +43,17 @@ module InitializableTests class Child < Parent include Rails::Initializable - initializer :three, :before => :one do + initializer :three, before: :one do $arr << 3 end - initializer :four, :after => :one, :before => :two do + initializer :four, after: :one, before: :two do $arr << 4 end end class Parent - initializer :five, :before => :one do + initializer :five, before: :one do $arr << 5 end end @@ -61,7 +61,7 @@ module InitializableTests class Instance include Rails::Initializable - initializer :one, :group => :assets do + initializer :one, group: :assets do $arr << 1 end @@ -69,7 +69,7 @@ module InitializableTests $arr << 2 end - initializer :three, :group => :all do + initializer :three, group: :all do $arr << 3 end @@ -90,11 +90,11 @@ module InitializableTests class MoreInitializers include Rails::Initializable - initializer :startup, :before => :last do + initializer :startup, before: :last do $arr << 3 end - initializer :terminate, :after => :first, :before => :startup do + initializer :terminate, after: :first, before: :startup do $arr << two end @@ -134,11 +134,11 @@ module InitializableTests class PluginB include Rails::Initializable - initializer "plugin_b.startup", :after => "plugin_a.startup" do + initializer "plugin_b.startup", after: "plugin_a.startup" do $arr << 2 end - initializer "plugin_b.terminate", :before => "plugin_a.terminate" do + initializer "plugin_b.terminate", before: "plugin_a.terminate" do $arr << 3 end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 0f36eb67e5..e59488f97d 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -113,14 +113,14 @@ module TestHelpers routes = File.read("#{app_path}/config/routes.rb") if routes =~ /(\n\s*end\s*)\Z/ File.open("#{app_path}/config/routes.rb", 'w') do |f| - f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', :via => :all\n" + $1 + f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', via: :all\n" + $1 end end add_to_config <<-RUBY config.eager_load = false config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - config.session_store :cookie_store, :key => "_myapp_session" + config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log config.action_controller.allow_forgery_protection = false RUBY @@ -139,7 +139,7 @@ module TestHelpers app = Class.new(Rails::Application) app.config.eager_load = false app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - app.config.session_store :cookie_store, :key => "_myapp_session" + app.config.session_store :cookie_store, key: "_myapp_session" app.config.active_support.deprecation = :log yield app if block_given? @@ -157,7 +157,7 @@ module TestHelpers controller :foo, <<-RUBY class FooController < ApplicationController def index - render :text => "foo" + render text: "foo" end end RUBY diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 76ff3ec3e4..12f18b9dbf 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -32,7 +32,7 @@ class PathsTest < ActiveSupport::TestCase end test "creating a root level path with options" do - @root.add "app", :with => "/foo/bar" + @root.add "app", with: "/foo/bar" assert_equal ["/foo/bar"], @root["app"].to_a end @@ -52,18 +52,18 @@ class PathsTest < ActiveSupport::TestCase test "creating a child level path with option" do @root.add "app" - @root.add "app/models", :with => "/foo/bar/baz" + @root.add "app/models", with: "/foo/bar/baz" assert_equal ["/foo/bar/baz"], @root["app/models"].to_a end test "child level paths are relative from the root" do @root.add "app" - @root.add "app/models", :with => "baz" + @root.add "app/models", with: "baz" assert_equal ["/foo/bar/baz"], @root["app/models"].to_a end test "adding multiple physical paths as an array" do - @root.add "app", :with => ["/app", "/app2"] + @root.add "app", with: ["/app", "/app2"] assert_equal ["/app", "/app2"], @root["app"].to_a end @@ -92,7 +92,7 @@ class PathsTest < ActiveSupport::TestCase end test "it is possible to add a path that should be autoloaded only once" do - @root.add "app", :with => "/app" + @root.add "app", with: "/app" @root["app"].autoload_once! assert @root["app"].autoload_once? assert @root.autoload_once.include?(@root["app"].expanded.first) @@ -109,13 +109,13 @@ class PathsTest < ActiveSupport::TestCase end test "it is possible to add a path without assignment and specify it should be loaded only once" do - @root.add "app", :with => "/app", :autoload_once => true + @root.add "app", with: "/app", autoload_once: true assert @root["app"].autoload_once? assert @root.autoload_once.include?("/app") end test "it is possible to add multiple paths without assignment and specify it should be loaded only once" do - @root.add "app", :with => ["/app", "/app2"], :autoload_once => true + @root.add "app", with: ["/app", "/app2"], autoload_once: true assert @root["app"].autoload_once? assert @root.autoload_once.include?("/app") assert @root.autoload_once.include?("/app2") @@ -153,20 +153,20 @@ class PathsTest < ActiveSupport::TestCase end test "it is possible to add a path without assignment and mark it as eager" do - @root.add "app", :with => "/app", :eager_load => true + @root.add "app", with: "/app", eager_load: true assert @root["app"].eager_load? assert @root.eager_load.include?("/app") end test "it is possible to add multiple paths without assignment and mark them as eager" do - @root.add "app", :with => ["/app", "/app2"], :eager_load => true + @root.add "app", with: ["/app", "/app2"], eager_load: true assert @root["app"].eager_load? assert @root.eager_load.include?("/app") assert @root.eager_load.include?("/app2") end test "it is possible to create a path without assignment and mark it both as eager and load once" do - @root.add "app", :with => "/app", :eager_load => true, :autoload_once => true + @root.add "app", with: "/app", eager_load: true, autoload_once: true assert @root["app"].eager_load? assert @root["app"].autoload_once? assert @root.eager_load.include?("/app") @@ -194,12 +194,12 @@ class PathsTest < ActiveSupport::TestCase end test "it should be possible to override a path's default glob without assignment" do - @root.add "app", :with => "/app", :glob => "*.rb" + @root.add "app", with: "/app", glob: "*.rb" assert_equal "*.rb", @root["app"].glob end test "it should be possible to replace a path and persist the original paths glob" do - @root.add "app", :glob => "*.rb" + @root.add "app", glob: "*.rb" @root["app"] = "app2" assert_equal ["/foo/bar/app2"], @root["app"].to_a assert_equal "*.rb", @root["app"].glob @@ -213,7 +213,7 @@ class PathsTest < ActiveSupport::TestCase end test "a path can be added to the load path on creation" do - @root.add "app", :with => "/app", :load_path => true + @root.add "app", with: "/app", load_path: true assert @root["app"].load_path? assert_equal ["/app"], @root.load_paths end @@ -226,7 +226,7 @@ class PathsTest < ActiveSupport::TestCase end test "a path can be marked as autoload on creation" do - @root.add "app", :with => "/app", :autoload => true + @root.add "app", with: "/app", autoload: true assert @root["app"].autoload? assert_equal ["/app"], @root.autoload_paths end diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index cfb32b7d35..08fcddd4bf 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -21,19 +21,19 @@ class InfoControllerTest < ActionController::TestCase end test "info controller does not allow remote requests" do - @controller.stubs(:local_request? => false) + @controller.stubs(local_request?: false) get :properties assert_response :forbidden end test "info controller renders an error message when request was forbidden" do - @controller.stubs(:local_request? => false) + @controller.stubs(local_request?: false) get :properties assert_select 'p' end test "info controller allows requests when all requests are considered local" do - @controller.stubs(:local_request? => true) + @controller.stubs(local_request?: true) get :properties assert_response :success end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index e52b3efdab..fcbe7b6cda 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -285,8 +285,8 @@ module RailtiesTest @plugin.write "config/routes.rb", <<-RUBY Rails.application.routes.draw do - get 'foo', :to => 'bar#index' - get 'bar', :to => 'bar#index' + get 'foo', to: 'bar#index' + get 'bar', to: 'bar#index' end RUBY @@ -366,7 +366,7 @@ YAML Rails.application.routes.draw do namespace :admin do namespace :foo do - get "bar", :to => "bar#index" + get "bar", to: "bar#index" end end end @@ -375,7 +375,7 @@ YAML @plugin.write "app/controllers/admin/foo/bar_controller.rb", <<-RUBY class Admin::Foo::BarController < ApplicationController def index - render :text => "Rendered from namespace" + render text: "Rendered from namespace" end end RUBY @@ -487,14 +487,14 @@ YAML controller "foo", <<-RUBY class FooController < ActionController::Base def index - render :text => params[:username] + render text: params[:username] end end RUBY @plugin.write "config/routes.rb", <<-RUBY Bukkits::Engine.routes.draw do - root :to => "foo#index" + root to: "foo#index" end RUBY @@ -608,14 +608,14 @@ YAML app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do - get "/bar" => "bar#index", :as => "bar" - mount Bukkits::Engine => "/bukkits", :as => "bukkits" + get "/bar" => "bar#index", as: "bar" + mount Bukkits::Engine => "/bukkits", as: "bukkits" end RUBY @plugin.write "config/routes.rb", <<-RUBY Bukkits::Engine.routes.draw do - get "/foo" => "foo#index", :as => "foo" + get "/foo" => "foo#index", as: "foo" get "/foo/show" => "foo#show" get "/from_app" => "foo#from_app" get "/routes_helpers_in_view" => "foo#routes_helpers_in_view" @@ -643,23 +643,23 @@ YAML @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY class Bukkits::FooController < ActionController::Base def index - render :inline => "<%= help_the_engine %>" + render inline: "<%= help_the_engine %>" end def show - render :text => foo_path + render text: foo_path end def from_app - render :inline => "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" + render inline: "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" end def routes_helpers_in_view - render :inline => "<%= foo_path %>, <%= main_app.bar_path %>" + render inline: "<%= foo_path %>, <%= main_app.bar_path %>" end def polymorphic_path_without_namespace - render :text => polymorphic_path(Post.new) + render text: polymorphic_path(Post.new) end end RUBY @@ -726,7 +726,7 @@ YAML app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do - mount Bukkits::Engine => "/bukkits", :as => "bukkits" + mount Bukkits::Engine => "/bukkits", as: "bukkits" end RUBY @@ -1033,11 +1033,11 @@ YAML controller "main", <<-RUBY class MainController < ActionController::Base def foo - render :inline => '<%= render :partial => "shared/foo" %>' + render inline: '<%= render :partial => "shared/foo" %>' end def bar - render :inline => '<%= render :partial => "shared/bar" %>' + render inline: '<%= render :partial => "shared/bar" %>' end end RUBY @@ -1113,7 +1113,7 @@ YAML controller "main", <<-RUBY class MainController < ActionController::Base def foo - render :inline => '<%= render :partial => "shared/foo" %>' + render inline: '<%= render :partial => "shared/foo" %>' end end RUBY @@ -1167,7 +1167,7 @@ YAML fullpath: \#{request.fullpath} path: \#{request.path} TEXT - render :text => text + render text: text end end end @@ -1205,7 +1205,7 @@ YAML app_file "app/controllers/bar_controller.rb", <<-RUBY class BarController < ApplicationController def index - render :text => bukkits.bukkit_path + render text: bukkits.bukkit_path end end RUBY @@ -1227,7 +1227,7 @@ YAML @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY class Bukkits::BukkitController < ActionController::Base def index - render :text => main_app.bar_path + render text: main_app.bar_path end end RUBY diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index c90b795d59..0abb2b7578 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -46,7 +46,7 @@ module RailtiesTests f.write <<-GEMFILE.gsub(/^ {12}/, '') source "http://rubygems.org" - gem 'rails', :path => '#{RAILS_FRAMEWORK_ROOT}' + gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}' gem 'sqlite3' GEMFILE end diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index bd13c3aba3..a1c52f01dc 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -42,14 +42,14 @@ module ApplicationTests @simple_plugin.write "config/routes.rb", <<-RUBY Weblog::Engine.routes.draw do - get '/weblog' => "weblogs#index", :as => 'weblogs' + get '/weblog' => "weblogs#index", as: 'weblogs' end RUBY @simple_plugin.write "app/controllers/weblogs_controller.rb", <<-RUBY class WeblogsController < ActionController::Base def index - render :text => request.url + render text: request.url end end RUBY @@ -86,9 +86,9 @@ module ApplicationTests @plugin.write "config/routes.rb", <<-RUBY Blog::Engine.routes.draw do resources :posts - 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 '/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' end RUBY @@ -96,22 +96,22 @@ module ApplicationTests module Blog class PostsController < ActionController::Base def index - render :text => blog.post_path(1) + render text: blog.post_path(1) end def generate_application_route - path = main_app.url_for(:controller => "/main", - :action => "index", - :only_path => true) - render :text => path + path = main_app.url_for(controller: "/main", + action: "index", + only_path: true) + render text: path end def application_route_in_view - render :inline => "<%= main_app.root_path %>" + render inline: "<%= main_app.root_path %>" end def engine_polymorphic_path - render :text => polymorphic_path(Post.new) + render text: polymorphic_path(Post.new) end end end @@ -120,31 +120,31 @@ module ApplicationTests app_file "app/controllers/application_generating_controller.rb", <<-RUBY class ApplicationGeneratingController < ActionController::Base def engine_route - render :text => blog.posts_path + render text: blog.posts_path end def engine_route_in_view - render :inline => "<%= blog.posts_path %>" + render inline: "<%= blog.posts_path %>" end def weblog_engine_route - render :text => weblog.weblogs_path + render text: weblog.weblogs_path end def weblog_engine_route_in_view - render :inline => "<%= weblog.weblogs_path %>" + render inline: "<%= weblog.weblogs_path %>" end def url_for_engine_route - render :text => blog.url_for(:controller => "blog/posts", :action => "index", :user => "john", :only_path => true) + render text: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true) end def polymorphic_route - render :text => polymorphic_url([blog, Blog::Post.new]) + render text: polymorphic_url([blog, Blog::Post.new]) end def application_polymorphic_path - render :text => polymorphic_path(Blog::Post.new) + render text: polymorphic_path(Blog::Post.new) end end RUBY |