diff options
Diffstat (limited to 'actionpack/lib')
59 files changed, 301 insertions, 357 deletions
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index cc5878c88e..b95ea5f0b2 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -1,9 +1,5 @@ -activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__) -$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) - require 'action_pack' require 'active_support/concern' -require 'active_support/ruby/shim' require 'active_support/dependencies/autoload' require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/module/attr_internal' diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 520c210721..5705ab590c 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -14,7 +14,7 @@ module AbstractController # Override AbstractController::Base's process_action to run the # process_action callbacks around the normal behavior. def process_action(*args) - run_callbacks(:process_action, action_name) do + run_callbacks(:process_action) do super end end diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index 307594d54a..dd4eddbe9a 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -60,7 +60,8 @@ module ActionController #:nodoc: end module ClassMethods - # Expires the page that was cached with the +path+ as a key. Example: + # Expires the page that was cached with the +path+ as a key. + # # expire_page "/lists/show" def expire_page(path) return unless perform_caching @@ -72,7 +73,8 @@ module ActionController #:nodoc: end end - # Manually cache the +content+ in the key determined by +path+. Example: + # Manually cache the +content+ in the key determined by +path+. + # # cache_page "I'm the cached content", "/lists/show" def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION) return unless perform_caching @@ -93,8 +95,6 @@ module ActionController #:nodoc: # # You can also pass a :gzip option to override the class configuration one. # - # Usage: - # # # cache the index action # caches_page :index # @@ -142,7 +142,8 @@ module ActionController #:nodoc: end end - # Expires the page that was cached with the +options+ as a key. Example: + # Expires the page that was cached with the +options+ as a key. + # # expire_page :controller => "lists", :action => "show" def expire_page(options = {}) return unless self.class.perform_caching @@ -161,7 +162,8 @@ module ActionController #:nodoc: end # Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used. - # If no options are provided, the url of the current request being handled is used. Example: + # If no options are provided, the url of the current request being handled is used. + # # cache_page "I'm the cached content", :controller => "lists", :action => "show" def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION) return unless self.class.perform_caching && caching_allowed? diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index 4c76f4c43b..11aa393bf9 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -20,7 +20,7 @@ module ActionController status = payload[:status] if status.nil? && payload[:exception].present? - status = Rack::Utils.status_code(ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code) + status = ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code end message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration message << " (#{additions.join(" | ")})" unless additions.blank? diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index 5b25a0d303..2193dde667 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -108,7 +108,6 @@ module ActionController # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a <tt>private</tt> instruction, so that # intermediate caches must not cache the response. # - # Examples: # expires_in 20.minutes # expires_in 3.hours, :public => true # expires_in 3.hours, :public => true, :must_revalidate => true diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 1a4bca12d2..86d061e3b7 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -16,7 +16,6 @@ module ActionController # Additional helpers can be specified using the +helper+ class method in ActionController::Base or any # controller which inherits from it. # - # ==== Examples # The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if # a \Time object is blank: # diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 87225d74c1..57bb0e2a32 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -2,8 +2,9 @@ require 'base64' require 'active_support/core_ext/object/blank' module ActionController + # Makes it dead easy to do HTTP Basic, Digest and Token authentication. module HttpAuthentication - # Makes it dead easy to do HTTP \Basic and \Digest authentication. + # Makes it dead easy to do HTTP \Basic authentication. # # === Simple \Basic example # @@ -60,47 +61,6 @@ module ActionController # # assert_equal 200, status # end - # - # === Simple \Digest example - # - # require 'digest/md5' - # class PostsController < ApplicationController - # REALM = "SuperSecret" - # USERS = {"dhh" => "secret", #plain text password - # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password - # - # before_filter :authenticate, :except => [:index] - # - # def index - # render :text => "Everyone can see me!" - # end - # - # def edit - # render :text => "I'm only accessible if you know the password" - # end - # - # private - # def authenticate - # authenticate_or_request_with_http_digest(REALM) do |username| - # USERS[username] - # end - # end - # end - # - # === Notes - # - # The +authenticate_or_request_with_http_digest+ block must return the user's password - # or the ha1 digest hash so the framework can appropriately hash to check the user's - # credentials. Returning +nil+ will cause authentication to fail. - # - # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If - # the password file or database is compromised, the attacker would be able to use the ha1 hash to - # authenticate as the user at this +realm+, but would not have the user's password to try using at - # other sites. - # - # In rare instances, web servers or front proxies strip authorization headers before - # they reach your application. You can debug this situation by logging all environment - # variables, and check for HTTP_AUTHORIZATION, amongst others. module Basic extend self @@ -155,6 +115,48 @@ module ActionController end end + # Makes it dead easy to do HTTP \Digest authentication. + # + # === Simple \Digest example + # + # require 'digest/md5' + # class PostsController < ApplicationController + # REALM = "SuperSecret" + # USERS = {"dhh" => "secret", #plain text password + # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password + # + # before_filter :authenticate, :except => [:index] + # + # def index + # render :text => "Everyone can see me!" + # end + # + # def edit + # render :text => "I'm only accessible if you know the password" + # end + # + # private + # def authenticate + # authenticate_or_request_with_http_digest(REALM) do |username| + # USERS[username] + # end + # end + # end + # + # === Notes + # + # The +authenticate_or_request_with_http_digest+ block must return the user's password + # or the ha1 digest hash so the framework can appropriately hash to check the user's + # credentials. Returning +nil+ will cause authentication to fail. + # + # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If + # the password file or database is compromised, the attacker would be able to use the ha1 hash to + # authenticate as the user at this +realm+, but would not have the user's password to try using at + # other sites. + # + # In rare instances, web servers or front proxies strip authorization headers before + # they reach your application. You can debug this situation by logging all environment + # variables, and check for HTTP_AUTHORIZATION, amongst others. module Digest extend self diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 7917926978..0b800c3c62 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -16,8 +16,6 @@ module ActionController #:nodoc: # Defines mime types that are rendered by default when invoking # <tt>respond_with</tt>. # - # Examples: - # # respond_to :html, :xml, :json # # Specifies that all actions in the controller respond to requests @@ -185,7 +183,6 @@ module ActionController #:nodoc: # end # # Be sure to check respond_with and respond_to documentation for more examples. - # def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? @@ -323,7 +320,6 @@ module ActionController #:nodoc: # a successful html +post+ request. # 2. <tt>:action</tt> - overwrites the default render action used after an # unsuccessful html +post+ request. - # def respond_with(*resources, &block) raise "In order to use respond_with, first you need to declare the formats your " << "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? @@ -339,7 +335,6 @@ module ActionController #:nodoc: # Collect mimes declared in the class method respond_to valid for the # current action. - # def collect_mimes_from_class_level #:nodoc: action = action_name.to_s @@ -362,7 +357,6 @@ module ActionController #:nodoc: # # Sends :not_acceptable to the client and returns nil if no suitable format # is available. - # def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc: mimes ||= collect_mimes_from_class_level collector = Collector.new(mimes) @@ -401,7 +395,6 @@ module ActionController #:nodoc: # A subsequent call to #negotiate_format(request) will enable the Collector # to determine which specific mime-type it should respond with for the current # request, with this response then being accessible by calling #response. - # class Collector include AbstractController::Collector attr_accessor :order, :format diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 5e7bd44562..ee0e69d87c 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -24,7 +24,6 @@ module ActionController # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places. # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt> # - # Examples: # redirect_to :action => "show", :id => 5 # redirect_to post # redirect_to "http://www.rubyonrails.org" @@ -35,7 +34,6 @@ module ActionController # # The redirection happens as a "302 Moved" header unless otherwise specified. # - # Examples: # redirect_to post_url(@post), :status => :found # redirect_to :action=>'atom', :status => :moved_permanently # redirect_to post_url(@post), :status => 301 @@ -51,14 +49,12 @@ module ActionController # around this you can return a <tt>303 See Other</tt> status code which will be # followed using a GET request. # - # Examples: # redirect_to posts_url, :status => :see_other # redirect_to :action => 'index', :status => 303 # # It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names # +alert+ and +notice+ as well as a general purpose +flash+ bucket. # - # Examples: # redirect_to post_url(@post), :alert => "Watch it, mister!" # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road" # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id } @@ -69,6 +65,7 @@ module ActionController def redirect_to(options = {}, response_status = {}) #:doc: raise ActionControllerError.new("Cannot redirect to nil!") unless options raise AbstractController::DoubleRenderError if response_body + logger.debug { "Redirected by #{caller(1).first rescue "unknown"}" } if logger self.status = _extract_redirect_to_status(options, response_status) self.location = _compute_redirect_to_location(options) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 4a0c1c7dd7..1927c8bdc7 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -49,7 +49,6 @@ module ActionController # is the value paired with its key and the second is the remaining # hash of options passed to +render+. # - # === Example # Create a csv renderer: # # ActionController::Renderers.add :csv do |obj, options| diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 0bff1825d9..95b0e99ed5 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -51,8 +51,6 @@ module ActionController #:nodoc: module ClassMethods # Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked. # - # Example: - # # class FooController < ApplicationController # protect_from_forgery :except => :index # diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 8e7b56dbcc..e28c05cc2d 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -6,8 +6,6 @@ module ActionController # url options like the +host+. In order to do so, this module requires the host class # to implement +env+ and +request+, which need to be a Rack-compatible. # - # Example: - # # class RootUrl # include ActionController::UrlFor # include Rails.application.routes.url_helpers @@ -19,7 +17,6 @@ module ActionController # @url = root_path # named route from the application. # end # end - # module UrlFor extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index e7af3f5b8d..16a5decc62 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/module' module ActionController # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or # pretty much any other model type that has an id. These patterns are then used to try elevate the view actions to - # a higher logical level. Example: + # a higher logical level. # # # routes # resources :posts @@ -30,7 +30,7 @@ module ActionController JOIN = '_'.freeze NEW = 'new'.freeze - # The DOM class convention is to use the singular form of an object or class. Examples: + # The DOM class convention is to use the singular form of an object or class. # # dom_class(post) # => "post" # dom_class(Person) # => "person" @@ -45,7 +45,7 @@ module ActionController end # The DOM id convention is to use the singular form of an object or class with the id following an underscore. - # If no id is found, prefix with "new_" instead. Examples: + # If no id is found, prefix with "new_" instead. # # dom_id(Post.find(45)) # => "post_45" # dom_id(Post.new) # => "new_post" diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index ad02375f12..76d07891c9 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -56,8 +56,6 @@ module ActionController # Asserts that the request was rendered with the appropriate template file or partials. # - # ==== Examples - # # # assert that the "new" view template was rendered # assert_template "new" # @@ -84,7 +82,6 @@ module ActionController # # # assert that the "_customer" partial was rendered with a specific object # assert_template :partial => '_customer', :locals => { :customer => @customer } - # def assert_template(options = {}, message = nil) # Force body to be read in case the # template is being streamed @@ -350,7 +347,6 @@ module ActionController # == \Testing named routes # # If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case. - # Example: # # assert_redirected_to page_url(:title => 'foo') class TestCase < ActiveSupport::TestCase @@ -369,12 +365,11 @@ module ActionController module ClassMethods # Sets the controller class name. Useful if the name can't be inferred from test class. - # Normalizes +controller_class+ before using. Examples: + # Normalizes +controller_class+ before using. # # tests WidgetController # tests :widget # tests 'widget' - # def tests(controller_class) case controller_class when String, Symbol diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index 114b0e73c9..6b269e7a31 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -1,6 +1,7 @@ require 'set' require 'cgi' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/class/attribute_accessors' module HTML class Sanitizer diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index e3b04ac097..1e4ac70f3d 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -21,12 +21,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__) -$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) - -activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__) -$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path) - require 'active_support' require 'active_support/dependencies/autoload' require 'active_support/core_ext/module/attribute_accessors' diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 132b0c82bc..6413929be3 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -10,8 +10,6 @@ module ActionDispatch # value of the params hash and all subhashes is passed to it, the value # or key can be replaced using String#replace or similar method. # - # Examples: - # # env["action_dispatch.parameter_filter"] = [:password] # => replaces the value to all keys matching /password/i with "[FILTERED]" # @@ -22,7 +20,6 @@ module ActionDispatch # v.reverse! if k =~ /secret/i # end # => reverses the value to all keys matching /secret/i - # module FilterParameters extend ActiveSupport::Concern diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 9748956052..56908b5794 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -6,7 +6,6 @@ require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/string/access' require 'active_support/inflector' require 'action_dispatch/http/headers' -require 'action_dispatch/request/session' require 'action_controller/metal/exceptions' module ActionDispatch @@ -18,6 +17,8 @@ module ActionDispatch include ActionDispatch::Http::Upload include ActionDispatch::Http::URL + autoload :Session, 'action_dispatch/request/session' + LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/] ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 982f6641bf..a8f49bd3bd 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -1,5 +1,6 @@ require 'action_controller/metal/exceptions' require 'active_support/core_ext/exception' +require 'active_support/core_ext/class/attribute_accessors' module ActionDispatch class ExceptionWrapper @@ -76,4 +77,4 @@ module ActionDispatch @backtrace_cleaner ||= @env['action_dispatch.backtrace_cleaner'] end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 17776c2356..9928b7cc3a 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -11,7 +11,7 @@ module ActionDispatch # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create # action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can - # then expose the flash to its template. Actually, that exposure is automatically done. Example: + # then expose the flash to its template. Actually, that exposure is automatically done. # # class PostsController < ActionController::Base # def create diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index dbcf703ec3..7efc094f98 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -27,7 +27,7 @@ module ActionDispatch # CGI::Session instance as an argument. It's important that the secret # is not vulnerable to a dictionary attack. Therefore, you should choose # a secret consisting of random numbers and letters and more than 30 - # characters. Examples: + # characters. # # :secret => '449fe2e7daee471bffae2fd8dc02313d' # :secret => Proc.new { User.current_user.secret_key } diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 2a7d540517..67a208263b 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/reverse_merge' +require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/enumerable' require 'active_support/inflector' @@ -100,6 +101,10 @@ module ActionDispatch raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}" end end + + if @options[:constraints].is_a?(Hash) + (@options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(@options[:constraints])) + end end # match "account/overview" @@ -245,6 +250,11 @@ module ActionDispatch def default_action @options[:action] || @scope[:action] end + + def defaults_from_constraints(constraints) + url_keys = [:protocol, :subdomain, :domain, :host, :port] + constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) } + end end # Invokes Rack::Mount::Utils.normalize path and ensure that @@ -485,8 +495,6 @@ module ActionDispatch # Define a route that only recognizes HTTP GET. # For supported arguments, see <tt>Base#match</tt>. # - # Example: - # # get 'bacon', :to => 'food#bacon' def get(*args, &block) map_method(:get, args, &block) @@ -495,8 +503,6 @@ module ActionDispatch # Define a route that only recognizes HTTP POST. # For supported arguments, see <tt>Base#match</tt>. # - # Example: - # # post 'bacon', :to => 'food#bacon' def post(*args, &block) map_method(:post, args, &block) @@ -505,8 +511,6 @@ module ActionDispatch # Define a route that only recognizes HTTP PATCH. # For supported arguments, see <tt>Base#match</tt>. # - # Example: - # # patch 'bacon', :to => 'food#bacon' def patch(*args, &block) map_method(:patch, args, &block) @@ -515,8 +519,6 @@ module ActionDispatch # Define a route that only recognizes HTTP PUT. # For supported arguments, see <tt>Base#match</tt>. # - # Example: - # # put 'bacon', :to => 'food#bacon' def put(*args, &block) map_method(:put, args, &block) @@ -525,8 +527,6 @@ module ActionDispatch # Define a route that only recognizes HTTP DELETE. # For supported arguments, see <tt>Base#match</tt>. # - # Example: - # # delete 'broccoli', :to => 'food#broccoli' def delete(*args, &block) map_method(:delete, args, &block) @@ -641,6 +641,10 @@ module ActionDispatch block, options[:constraints] = options[:constraints], {} end + if options[:constraints].is_a?(Hash) + (options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(options[:constraints])) + end + scope_options.each do |option| if value = options.delete(option) recover[option] = @scope[option] @@ -667,7 +671,6 @@ module ActionDispatch # Scopes routes to a specific controller # - # Example: # controller "food" do # match "bacon", :action => "bacon" # end @@ -849,6 +852,11 @@ module ActionDispatch def override_keys(child) #:nodoc: child.key?(:only) || child.key?(:except) ? [:only, :except] : [] end + + def defaults_from_constraints(constraints) + url_keys = [:protocol, :subdomain, :domain, :host, :port] + constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) } + end end # Resource routing allows you to quickly declare all of the common routes @@ -1317,10 +1325,11 @@ module ActionDispatch msg = "Your router tried to #draw the external file #{name}.rb,\n" \ "but the file was not found in:\n\n" msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n") - raise msg + raise ArgumentError, msg end - - instance_eval(path.join("#{name}.rb").read) + + route_path = path.join("#{name}.rb") + instance_eval(route_path.read, route_path.to_s) end # match 'path' => 'controller#action' diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 8fc0f283fc..0ae668d42a 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -103,7 +103,7 @@ module ActionDispatch inner_options = args.extract_options! result = options.dup - if args.any? + if args.size > 0 keys = segment_keys if args.size < keys.size - 1 # take format into account keys -= self.url_options.keys if self.respond_to?(:url_options) @@ -460,12 +460,12 @@ module ActionDispatch normalize_options! normalize_controller_action_id! use_relative_controller! - controller.sub!(%r{^/}, '') if controller + normalize_controller! handle_nil_action! end def controller - @controller ||= @options[:controller] + @options[:controller] end def current_controller @@ -522,10 +522,15 @@ module ActionDispatch old_parts = current_controller.split('/') size = controller.count("/") + 1 parts = old_parts[0...-size] << controller - @controller = @options[:controller] = parts.join("/") + @options[:controller] = parts.join("/") end end + # Remove leading slashes from controllers + def normalize_controller! + @options[:controller] = controller.sub(%r{^/}, '') if controller + end + # This handles the case of :action => nil being explicitly passed. # It is identical to :action => "index" def handle_nil_action! diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index ee02f4b531..fd3bed7e8f 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -132,8 +132,6 @@ module ActionDispatch # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to # +url_for+ is forwarded to the Routes module. # - # Examples: - # # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' # # => 'http://somehost.org:8080/tasks/testing' # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index edea6dab39..7dc3d0f97c 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -5,11 +5,8 @@ module ActionDispatch module DomAssertions # \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) # - # ==== Examples - # # # assert that the referenced method generates the appropriate HTML string # assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com") - # def assert_dom_equal(expected, actual, message = "") expected_dom = HTML::Document.new(expected).root actual_dom = HTML::Document.new(actual).root @@ -18,11 +15,8 @@ module ActionDispatch # The negated form of +assert_dom_equivalent+. # - # ==== Examples - # # # assert that the referenced method does not generate the specified HTML string # assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com") - # def assert_dom_not_equal(expected, actual, message = "") expected_dom = HTML::Document.new(expected).root actual_dom = HTML::Document.new(actual).root diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 8f6fff5d32..3d121b6b9c 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -15,14 +15,11 @@ module ActionDispatch # or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>. # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list. # - # ==== Examples - # # # assert that the response was a redirection # assert_response :redirect # # # assert that the response code was status code 401 (unauthorized) # assert_response 401 - # def assert_response(type, message = nil) message ||= "Expected response to be a <#{type}>, but was <#{@response.response_code}>" @@ -42,8 +39,6 @@ module ActionDispatch # This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also # match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on. # - # ==== Examples - # # # assert that the redirection was to the "index" action on the WeblogController # assert_redirected_to :controller => "weblog", :action => "index" # @@ -55,7 +50,6 @@ module ActionDispatch # # # asserts that the redirection matches the regular expression # assert_redirected_to %r(\Ahttp://example.org) - # def assert_redirected_to(options = {}, message=nil) assert_response(:redirect, message) return true if options === @response.location diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 1f4b905d18..567ca0c392 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -26,7 +26,6 @@ module ActionDispatch # # The +message+ parameter allows you to pass in an error message that is displayed upon failure. # - # ==== Examples # # Check the default route (i.e., the index action) # assert_recognizes({:controller => 'items', :action => 'index'}, 'items') # @@ -57,7 +56,6 @@ module ActionDispatch # # The +defaults+ parameter is unused. # - # ==== Examples # # Asserts that the default action is generated for a route with no action # assert_generates "/items", :controller => "items", :action => "index" # @@ -100,7 +98,6 @@ module ActionDispatch # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The # +message+ parameter allows you to specify a custom error message to display upon failure. # - # ==== Examples # # Assert a basic route: a controller with the default action (index) # assert_routing '/home', :controller => 'home', :action => 'index' # diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index ea1ed20f3c..5f9c3bbf48 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -39,7 +39,6 @@ module ActionDispatch # The selector may be a CSS selector expression (String), an expression # with substitution values (Array) or an HTML::Selector object. # - # ==== Examples # # Selects all div tags # divs = css_select("div") # @@ -58,7 +57,6 @@ module ActionDispatch # inputs = css_select(form, "input") # ... # end - # def css_select(*args) # See assert_select to understand what's going on here. arg = args.shift @@ -340,7 +338,6 @@ module ActionDispatch # The content of each element is un-encoded, and wrapped in the root # element +encoded+. It then calls the block with all un-encoded elements. # - # ==== Examples # # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix) # assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do # # Select each entry item and then the title item @@ -401,8 +398,6 @@ module ActionDispatch # You must enable deliveries for this assertion to work, use: # ActionMailer::Base.perform_deliveries = true # - # ==== Examples - # # assert_select_email do # assert_select "h1", "Email alert" # end @@ -413,7 +408,6 @@ module ActionDispatch # # Work with items here... # end # end - # def assert_select_email(&block) deliveries = ActionMailer::Base.deliveries assert !deliveries.empty?, "No e-mail in delivery list" diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb index 5c735e61b2..68f1347e7c 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb @@ -48,8 +48,6 @@ module ActionDispatch # * if the condition is +true+, the value must not be +nil+. # * if the condition is +false+ or +nil+, the value must be +nil+. # - # === Examples - # # # Assert that there is a "span" tag # assert_tag :tag => "span" # @@ -104,7 +102,6 @@ module ActionDispatch # Identical to +assert_tag+, but asserts that a matching tag does _not_ # exist. (See +assert_tag+ for a full discussion of the syntax.) # - # === Examples # # Assert that there is not a "div" containing a "p" # assert_no_tag :tag => "div", :descendant => { :tag => "p" } # diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 69d54f6981..08fd28d72d 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -201,9 +201,16 @@ module ActionDispatch reset! end - remove_method :default_url_options - def default_url_options - { :host => host, :protocol => https? ? "https" : "http" } + def url_options + @url_options ||= default_url_options.dup.tap do |url_options| + url_options.reverse_merge!(controller.url_options) if controller + + if @app.respond_to?(:routes) && @app.routes.respond_to?(:default_url_options) + url_options.reverse_merge!(@app.routes.default_url_options) + end + + url_options.reverse_merge!(:host => host, :protocol => https? ? "https" : "http") + end end # Resets the instance. This can be used to reset the state information @@ -216,6 +223,7 @@ module ActionDispatch @controller = @request = @response = nil @_mock_session = nil @request_count = 0 + @url_options = nil self.host = DEFAULT_HOST self.remote_addr = "127.0.0.1" @@ -310,6 +318,7 @@ module ActionDispatch response = _mock_session.last_response @response = ActionDispatch::TestResponse.new(response.status, response.headers, response.body) @html_document = nil + @url_options = nil @controller = session.last_request.env['action_controller.instance'] @@ -367,12 +376,14 @@ module ActionDispatch end end - extend ActiveSupport::Concern - include ActionDispatch::Routing::UrlFor + def default_url_options + reset! unless integration_session + integration_session.default_url_options + end - def url_options + def default_url_options=(options) reset! unless integration_session - integration_session.url_options + integration_session.default_url_options = options end def respond_to?(method, include_private = false) @@ -476,6 +487,7 @@ module ActionDispatch class IntegrationTest < ActiveSupport::TestCase include Integration::Runner include ActionController::TemplateAssertions + include ActionDispatch::Routing::UrlFor @@app = nil @@ -495,5 +507,10 @@ module ActionDispatch def app super || self.class.app end + + def url_options + reset! unless integration_session + integration_session.url_options + end end end diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 349a3fcc6e..3823f87027 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -21,9 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support/ruby/shim' -require 'active_support/core_ext/class/attribute_accessors' - +require 'active_support' require 'action_pack' module ActionView @@ -78,7 +76,8 @@ module ActionView ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' end -require 'active_support/i18n' require 'active_support/core_ext/string/output_safety' -I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" +ActiveSupport.on_load(:i18n) do + I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" +end diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb index add8d94b70..4ce41d51f1 100644 --- a/actionpack/lib/action_view/asset_paths.rb +++ b/actionpack/lib/action_view/asset_paths.rb @@ -4,7 +4,7 @@ require 'action_controller/metal/exceptions' module ActionView class AssetPaths #:nodoc: - URI_REGEXP = %r{^[-a-z]+://|^cid:|^//} + URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//} attr_reader :config, :controller diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 5f81f24a2e..f98648d930 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/class/attribute_accessors' require 'active_support/ordered_options' require 'action_view/log_subscriber' diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb index 083856b2ca..245849d706 100644 --- a/actionpack/lib/action_view/context.rb +++ b/actionpack/lib/action_view/context.rb @@ -5,7 +5,7 @@ module ActionView # = Action View Context # - # Action View contexts are supplied to Action Controller to render template. + # Action View contexts are supplied to Action Controller to render a template. # The default Action View context is ActionView::Base. # # In order to work with ActionController, a Context must just include this module. @@ -25,7 +25,7 @@ module ActionView end # Encapsulates the interaction with the view flow so it - # returns the correct buffer on yield. This is usually + # returns the correct buffer on +yield+. This is usually # overwriten by helpers to add more behavior. # :api: plugin def _layout_for(name=nil) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index adc62ec6a9..a7a4ce21ff 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -252,7 +252,6 @@ module ActionView # The following call would generate such a tag: # # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %> - # def favicon_link_tag(source='favicon.ico', options={}) tag('link', { :rel => 'shortcut icon', @@ -261,13 +260,13 @@ module ActionView }.merge(options.symbolize_keys)) end - # Computes the path to an image asset in the public images directory. + # 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") # => "/images/edit" - # image_path("edit.png") # => "/images/edit.png" - # image_path("icons/edit.png") # => "/images/icons/edit.png" + # 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" # @@ -279,7 +278,7 @@ module ActionView 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 in the public images directory. + # 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 @@ -290,7 +289,6 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by +video_tag+ to build the video path. # - # ==== Examples # video_path("hd") # => /videos/hd # video_path("hd.avi") # => /videos/hd.avi # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi @@ -312,7 +310,6 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by +audio_tag+ to build the audio path. # - # ==== Examples # audio_path("horse") # => /audios/horse # audio_path("horse.wav") # => /audios/horse.wav # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav @@ -323,20 +320,19 @@ module ActionView end alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route - # Computes the full URL to a audio asset in the public audios directory. + # 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 in the public fonts directory. + # Computes the path to a font asset. # Full paths from the document root will be passed through. # - # ==== Examples - # font_path("font") # => /fonts/font - # font_path("font.ttf") # => /fonts/font.ttf - # font_path("dir/font.ttf") # => /fonts/dir/font.ttf + # 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) @@ -344,7 +340,7 @@ module ActionView 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 in the public fonts directory. + # 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 @@ -352,7 +348,7 @@ module ActionView 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 that exists in your public images directory. + # path or a file. # # ==== Options # You can add HTML attributes using the +options+. The +options+ supports @@ -363,33 +359,25 @@ module ActionView # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes # width="30" and height="45". <tt>:size</tt> will be ignored if the # value is not in the correct format. - # * <tt>:mouseover</tt> - Set an alternate image to be used when the onmouseover - # event is fired, and sets the original image to be replaced onmouseout. - # This can be used to implement an easy image toggle that fires on onmouseover. # - # ==== Examples # image_tag("icon") # => - # <img src="/images/icon" alt="Icon" /> + # <img src="/assets/icon" alt="Icon" /> # image_tag("icon.png") # => - # <img src="/images/icon.png" alt="Icon" /> + # <img src="/assets/icon.png" alt="Icon" /> # image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # => - # <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" /> + # <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" /> # image_tag("/icons/icon.gif", :size => "16x16") # => # <img src="/icons/icon.gif" width="16" height="16" alt="Icon" /> # image_tag("/icons/icon.gif", :height => '32', :width => '32') # => # <img alt="Icon" height="32" src="/icons/icon.gif" width="32" /> # image_tag("/icons/icon.gif", :class => "menu_icon") # => # <img alt="Icon" class="menu_icon" src="/icons/icon.gif" /> - # image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # => - # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" /> - # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # => - # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" /> def image_tag(source, options={}) options = options.symbolize_keys src = options[:src] = path_to_image(source) - unless src =~ /^cid:/ + unless src =~ /^(?:cid|data):/ options[:alt] = options.fetch(:alt){ image_alt(src) } end @@ -397,11 +385,6 @@ module ActionView options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} end - if mouseover = options.delete(:mouseover) - options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'" - options[:onmouseout] = "this.src='#{src}'" - end - tag("img", options) end @@ -425,7 +408,6 @@ module ActionView # width="30" and height="45". <tt>:size</tt> will be ignored if the # value is not in the correct format. # - # ==== Examples # video_tag("trailer") # => # <video src="/videos/trailer" /> # video_tag("trailer.ogg") # => @@ -433,7 +415,7 @@ module ActionView # video_tag("trailer.ogg", :controls => true, :autobuffer => true) # => # <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" /> # video_tag("trailer.m4v", :size => "16x10", :poster => "screenshot.png") # => - # <video src="/videos/trailer.m4v" width="16" height="10" poster="/images/screenshot.png" /> + # <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png" /> # video_tag("/trailers/hd.avi", :size => "16x16") # => # <video src="/trailers/hd.avi" width="16" height="16" /> # video_tag("/trailers/hd.avi", :height => '32', :width => '32') # => @@ -458,15 +440,14 @@ module ActionView # The +source+ can be full path or file that exists in # your public audios directory. # - # ==== Examples - # audio_tag("sound") # => - # <audio src="/audios/sound" /> - # audio_tag("sound.wav") # => - # <audio src="/audios/sound.wav" /> - # audio_tag("sound.wav", :autoplay => true, :controls => true) # => - # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" /> - # audio_tag("sound.wav", "sound.mid") # => - # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio> + # audio_tag("sound") # => + # <audio src="/audios/sound" /> + # audio_tag("sound.wav") # => + # <audio src="/audios/sound.wav" /> + # audio_tag("sound.wav", :autoplay => true, :controls => true) # => + # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" /> + # audio_tag("sound.wav", "sound.mid") # => + # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio> def audio_tag(*sources) multiple_sources_tag('audio', sources) 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 index 7bff0c1149..4292d29f60 100644 --- 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 @@ -76,7 +76,6 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by javascript_include_tag to build the script path. # - # ==== Examples # javascript_path "xmlhr" # => /javascripts/xmlhr.js # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js @@ -114,7 +113,6 @@ module ActionView # You can modify the HTML attributes of the script tag by passing a hash as the # last argument. # - # ==== Examples # javascript_include_tag "xmlhr" # # => <script src="/javascripts/xmlhr.js?1284139606"></script> # @@ -160,8 +158,6 @@ module ActionView # <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). # - # ==== Examples - # # # assuming config.perform_caching is false # javascript_include_tag :all, :cache => true # # => <script src="/javascripts/jquery.js?1284139606"></script> 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 index 4bcb8b9718..57b0627225 100644 --- 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 @@ -54,7 +54,6 @@ module ActionView # Full paths from the document root will be passed through. # Used internally by +stylesheet_link_tag+ to build the stylesheet path. # - # ==== Examples # stylesheet_path "style" # => /stylesheets/style.css # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css # stylesheet_path "/dir/style.css" # => /dir/style.css @@ -79,7 +78,6 @@ module ActionView # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to # apply to all media types. # - # ==== Examples # stylesheet_link_tag "style" # => # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" /> # @@ -117,7 +115,6 @@ module ActionView # is set to true (which is the case by default for the Rails production environment, but not for the development # environment). Examples: # - # ==== 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" /> diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index 850dd5f448..33799d7d71 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -10,7 +10,6 @@ module ActionView # # See ActionController::Caching::Fragments for usage instructions. # - # ==== Examples # If you want to cache a navigation menu, you can do following: # # <% cache do %> diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index d9d6f90211..397738dd98 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -13,7 +13,6 @@ module ActionView # The capture method allows you to extract part of a template into a # variable. You can then use this variable anywhere in your templates or layout. # - # ==== Examples # The capture method can be used in ERB templates... # # <% @greeting = capture do %> diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index f0a593d2c1..659aacf6d7 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -64,7 +64,6 @@ module ActionView # distance_of_time_in_words(from_time, to_time, :include_seconds => true) # => about 6 years # distance_of_time_in_words(to_time, from_time, :include_seconds => true) # => about 6 years # distance_of_time_in_words(Time.now, Time.now) # => less than a minute - # def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {}) if include_seconds_or_options.is_a?(Hash) options = include_seconds_or_options @@ -140,7 +139,6 @@ module ActionView # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>. # - # ==== Examples # time_ago_in_words(3.minutes.from_now) # => 3 minutes # time_ago_in_words(Time.now - 15.hours) # => about 15 hours # time_ago_in_words(Time.now) # => less than a minute @@ -148,7 +146,6 @@ module ActionView # # from_time = Time.now - 3.days - 14.minutes - 25.seconds # time_ago_in_words(from_time) # => 3 days - # def time_ago_in_words(from_time, include_seconds_or_options = {}) distance_of_time_in_words(from_time, Time.now, include_seconds_or_options) end @@ -197,7 +194,6 @@ module ActionView # # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. # - # ==== Examples # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute. # date_select("article", "written_on") # @@ -253,7 +249,6 @@ module ActionView # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # - # ==== Examples # # Creates a time select tag that, when POSTed, will be stored in the article variable in the sunrise attribute. # time_select("article", "sunrise") # @@ -286,7 +281,6 @@ module ActionView # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # - # ==== Examples # # Generates a datetime select that, when POSTed, will be stored in the article variable in the written_on # # attribute. # datetime_select("article", "written_on") @@ -325,7 +319,6 @@ module ActionView # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # - # ==== Examples # my_date_time = Time.now + 4.days # # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today). @@ -362,7 +355,6 @@ module ActionView # select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours # select_datetime(my_date_time, :prompt => true) # generic prompts for all - # def select_datetime(datetime = Time.current, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_datetime end @@ -374,7 +366,6 @@ module ActionView # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # - # ==== Examples # my_date = Time.now + 6.days # # # Generates a date select that defaults to the date in my_date (six days after today). @@ -403,7 +394,6 @@ module ActionView # select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours # select_date(my_date, :prompt => true) # generic prompts for all - # def select_date(date = Date.current, options = {}, html_options = {}) DateTimeSelector.new(date, options, html_options).select_date end @@ -414,7 +404,6 @@ module ActionView # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # - # ==== Examples # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds # # # Generates a time select that defaults to the time in my_time. @@ -442,7 +431,6 @@ module ActionView # select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) # select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours # select_time(my_time, :prompt => true) # generic prompts for all - # def select_time(datetime = Time.current, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_time end @@ -451,7 +439,6 @@ module ActionView # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'second' by default. # - # ==== Examples # my_time = Time.now + 16.minutes # # # Generates a select field for seconds that defaults to the seconds for the time in my_time. @@ -467,7 +454,6 @@ module ActionView # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_second(14, :prompt => 'Choose seconds') - # def select_second(datetime, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_second end @@ -477,7 +463,6 @@ module ActionView # selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'minute' by default. # - # ==== Examples # my_time = Time.now + 6.hours # # # Generates a select field for minutes that defaults to the minutes for the time in my_time. @@ -493,7 +478,6 @@ module ActionView # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_minute(14, :prompt => 'Choose minutes') - # def select_minute(datetime, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_minute end @@ -502,7 +486,6 @@ module ActionView # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'hour' by default. # - # ==== Examples # my_time = Time.now + 6.hours # # # Generates a select field for hours that defaults to the hour for the time in my_time. @@ -521,7 +504,6 @@ module ActionView # # # Generate a select field for hours in the AM/PM format # select_hour(my_time, :ampm => true) - # def select_hour(datetime, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_hour end @@ -531,7 +513,6 @@ module ActionView # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. # Override the field name using the <tt>:field_name</tt> option, 'day' by default. # - # ==== Examples # my_date = Time.now + 2.days # # # Generates a select field for days that defaults to the day for the date in my_date. @@ -550,7 +531,6 @@ module ActionView # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_day(5, :prompt => 'Choose day') - # def select_day(date, options = {}, html_options = {}) DateTimeSelector.new(date, options, html_options).select_day end @@ -565,7 +545,6 @@ module ActionView # If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. # Override the field name using the <tt>:field_name</tt> option, 'month' by default. # - # ==== Examples # # Generates a select field for months that defaults to the current month that # # will use keys like "January", "March". # select_month(Date.today) @@ -597,7 +576,6 @@ module ActionView # # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_month(14, :prompt => 'Choose month') - # def select_month(date, options = {}, html_options = {}) DateTimeSelector.new(date, options, html_options).select_month end @@ -608,7 +586,6 @@ module ActionView # greater than <tt>:end_year</tt>. The <tt>date</tt> can also be substituted for a year given as a number. # Override the field name using the <tt>:field_name</tt> option, 'year' by default. # - # ==== Examples # # Generates a select field for years that defaults to the current year that # # has ascending year values. # select_year(Date.today, :start_year => 1992, :end_year => 2007) @@ -628,14 +605,12 @@ module ActionView # # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. # select_year(14, :prompt => 'Choose year') - # def select_year(date, options = {}, html_options = {}) DateTimeSelector.new(date, options, html_options).select_year end # Returns an html time tag for the given date or time. # - # ==== Examples # time_tag Date.today # => # <time datetime="2010-11-04">November 04, 2010</time> # time_tag Time.now # => @@ -649,7 +624,6 @@ module ActionView # <span>Right now</span> # <% end %> # # => <time datetime="2010-11-04T17:55:45+01:00"><span>Right now</span></time> - # def time_tag(date_or_time, *args, &block) options = args.extract_options! format = options.delete(:format) || :long diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb index c0cc7d347c..878a8734a4 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionpack/lib/action_view/helpers/debug_helper.rb @@ -8,8 +8,6 @@ module ActionView # If the object cannot be converted to YAML using +to_yaml+, +inspect+ will be called instead. # Useful for inspecting an object at the time of rendering. # - # ==== Example - # # @user = User.new({ :username => 'testing', :password => 'xyz', :age => 42}) %> # debug(@user) # # => @@ -25,7 +23,6 @@ module ActionView # # new_record: true # </pre> - def debug(object) begin Marshal::dump(object) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 67f2abe509..cc1f133196 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -5,6 +5,7 @@ require 'action_view/helpers/form_tag_helper' require 'action_view/helpers/active_model_helper' require 'action_view/helpers/tags' require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/string/output_safety' @@ -899,7 +900,6 @@ module ActionView # In that case it is preferable to either use +check_box_tag+ or to use # hashes instead of arrays. # - # ==== Examples # # Let's say that @post.validated? is 1: # check_box("post", "validated") # # => <input name="post[validated]" type="hidden" value="0" /> @@ -925,7 +925,6 @@ module ActionView # To force the radio button to be checked pass <tt>:checked => true</tt> in the # +options+ hash. You may pass HTML options there as well. # - # ==== Examples # # Let's say that @post.category returns "rails": # radio_button("post", "category", "rails") # radio_button("post", "category", "java") @@ -944,8 +943,6 @@ module ActionView # assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by # some browsers. # - # ==== Examples - # # search_field(:user, :name) # # => <input id="user_name" name="user[name]" type="search" /> # search_field(:user, :name, :autosave => false) @@ -961,7 +958,6 @@ module ActionView # # => <input autosave="false" id="user_name" incremental="true" name="user[name]" onsearch="true" type="search" /> # search_field(:user, :name, :autosave => true, :onsearch => true) # # => <input autosave="com.example.www" id="user_name" incremental="true" name="user[name]" onsearch="true" results="10" type="search" /> - # def search_field(object_name, method, options = {}) Tags::SearchField.new(object_name, method, self, options).render end diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index cafcd93f58..52eb1aa447 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -264,7 +264,6 @@ module ActionView # Finally, this method supports a <tt>:default</tt> option, which selects # a default ActiveSupport::TimeZone if the object's time zone is +nil+. # - # Examples: # time_zone_select( "user", "time_zone", nil, :include_blank => true) # # time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" ) @@ -461,8 +460,11 @@ module ActionView # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags, # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>. - # * +prompt+ - set to true or a prompt string. When the select element doesn't have a value yet, this + # + # Options: + # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this # prepends an option with a generic prompt - "Please select" - or the given prompt string. + # * <tt>:divider</tt> - the divider for the options groups. # # Sample usage (Array): # grouped_options = [ @@ -491,15 +493,51 @@ module ActionView # <option value="Canada">Canada</option> # </optgroup> # + # Sample usage (divider): + # grouped_options = [ + # [['United States','US'], 'Canada'], + # ['Denmark','Germany','France'] + # ] + # grouped_options_for_select(grouped_options, divider: '---------') + # + # Possible output: + # <optgroup label="---------"> + # <option value="Denmark">Denmark</option> + # <option value="Germany">Germany</option> + # <option value="France">France</option> + # </optgroup> + # <optgroup label="---------"> + # <option value="US">United States</option> + # <option value="Canada">Canada</option> + # </optgroup> + # # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to # wrap the output in an appropriate <tt><select></tt> tag. - def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil) + def grouped_options_for_select(*args) + grouped_options = args.shift + options = args.extract_options! + selected_key = args.shift + if prompt = args.shift + ActiveSupport::Deprecation.warn 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please pass it in an options hash.' + else + prompt = options[:prompt] + divider = options[:divider] + end + body = "".html_safe - body.safe_concat content_tag(:option, prompt, :value => "") if prompt + + if prompt + body.safe_concat content_tag(:option, prompt_text(prompt), :value => "") + end grouped_options = grouped_options.sort if grouped_options.is_a?(Hash) - grouped_options.each do |label, container| + grouped_options.each do |container| + if divider + label, container = divider, container + else + label, container = container + end body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), :label => label) end @@ -715,6 +753,10 @@ module ActionView def value_for_collection(item, value) value.respond_to?(:call) ? value.call(item) : item.send(value) end + + def prompt_text(prompt) + prompt = prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', :default => 'Please select') + end end class FormBuilder diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 248cc2f6a3..9e5c66f4a9 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -386,9 +386,6 @@ module ActionView # drivers will provide a prompt with the question specified. If the user accepts, # the form is processed normally, otherwise no action is taken. # * <tt>:disabled</tt> - If true, the user will not be able to use this input. - # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a - # disabled version of the submit button when the form is submitted. This feature is - # provided by the unobtrusive JavaScript driver. # * Any other key creates standard HTML options for the tag. # # ==== Examples @@ -401,14 +398,14 @@ module ActionView # submit_tag "Save edits", :disabled => true # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" /> # - # submit_tag "Complete sale", :disable_with => "Please wait..." + # submit_tag "Complete sale", :data => { :disable_with => "Please wait..." } # # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" /> # # submit_tag nil, :class => "form_submit" # # => <input class="form_submit" name="commit" type="submit" /> # - # submit_tag "Edit", :disable_with => "Editing...", :class => "edit_button" - # # => <input class="edit_button" data-disable-with="Editing..." name="commit" type="submit" value="Edit" /> + # submit_tag "Edit", :class => "edit_button" + # # => <input class="edit_button" name="commit" type="submit" value="Edit" /> # # submit_tag "Save", :confirm => "Are you sure?" # # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" /> @@ -416,10 +413,6 @@ module ActionView def submit_tag(value = "Save changes", options = {}) options = options.stringify_keys - if disable_with = options.delete("disable_with") - options["data-disable-with"] = disable_with - end - if confirm = options.delete("confirm") options["data-confirm"] = confirm end @@ -441,10 +434,6 @@ module ActionView # processed normally, otherwise no action is taken. # * <tt>:disabled</tt> - If true, the user will not be able to # use this input. - # * <tt>:disable_with</tt> - Value of this parameter will be - # used as the value for a disabled version of the submit - # button when the form is submitted. This feature is provided - # by the unobtrusive JavaScript driver. # * Any other key creates standard HTML options for the tag. # # ==== Examples @@ -458,18 +447,11 @@ module ActionView # # <strong>Ask me!</strong> # # </button> # - # button_tag "Checkout", :disable_with => "Please wait..." - # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button> - # def button_tag(content_or_options = nil, options = nil, &block) options = content_or_options if block_given? && content_or_options.is_a?(Hash) options ||= {} options = options.stringify_keys - if disable_with = options.delete("disable_with") - options["data-disable-with"] = disable_with - end - if confirm = options.delete("confirm") options["data-confirm"] = confirm end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index dfc26acfad..62455b97f9 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -254,7 +254,7 @@ module ActionView parts = number.to_s.to_str.split('.') parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}") - safe_join(parts, options[:separator]) + parts.join(options[:separator]).html_safe end # Formats a +number+ with the specified level of diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 7768c8c151..a727b910e5 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -69,8 +69,6 @@ module ActionView # html-scanner tokenizer and so its HTML parsing ability is limited by # that of html-scanner. # - # ==== Examples - # # strip_tags("Strip <i>these</i> tags!") # # => Strip these tags! # @@ -85,7 +83,6 @@ module ActionView # Strips all link tags from +text+ leaving just the link text. # - # ==== Examples # strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>') # # => Ruby on Rails # diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index f7afa48256..d5cd60e8a1 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -103,7 +103,6 @@ module ActionView # otherwise be recognized as markup. CDATA sections begin with the string # <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>. # - # ==== Examples # cdata_section("<hello world>") # # => <![CDATA[<hello world>]]> # @@ -119,7 +118,6 @@ module ActionView # Returns an escaped version of +html+ without affecting existing escaped entities. # - # ==== Examples # escape_once("1 < 2 & 3") # # => "1 < 2 & 3" # diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb index e4f431a6d7..e077cd5b3c 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionpack/lib/action_view/helpers/tags/base.rb @@ -121,6 +121,7 @@ module ActionView def select_content_tag(option_tags, options, html_options) html_options = html_options.stringify_keys add_default_name_and_id(html_options) + options[:include_blank] ||= true unless options[:prompt] || select_not_required?(html_options) select = content_tag("select", add_options(option_tags, options, value(object)), html_options) if html_options["multiple"] && options.fetch(:include_hidden, true) @@ -130,13 +131,16 @@ module ActionView end end + def select_not_required?(html_options) + !html_options["required"] || html_options["multiple"] || html_options["size"].to_i > 1 + end + def add_options(option_tags, options, value = nil) if options[:include_blank] option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags end if value.blank? && options[:prompt] - prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select') - option_tags = content_tag('option', prompt, :value => '') + "\n" + option_tags + option_tags = content_tag('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags end option_tags end diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb index bb968e9f39..0e79609d52 100644 --- a/actionpack/lib/action_view/helpers/tags/date_field.rb +++ b/actionpack/lib/action_view/helpers/tags/date_field.rb @@ -5,7 +5,6 @@ module ActionView def render options = @options.stringify_keys options["value"] = @options.fetch("value") { value(object).try(:to_date) } - options["size"] = nil @options = options super end diff --git a/actionpack/lib/action_view/helpers/tags/file_field.rb b/actionpack/lib/action_view/helpers/tags/file_field.rb index 56442e1c14..59f2ff71b4 100644 --- a/actionpack/lib/action_view/helpers/tags/file_field.rb +++ b/actionpack/lib/action_view/helpers/tags/file_field.rb @@ -2,10 +2,6 @@ module ActionView module Helpers module Tags class FileField < TextField #:nodoc: - def render - @options.update(:size => nil) - super - end end end end diff --git a/actionpack/lib/action_view/helpers/tags/hidden_field.rb b/actionpack/lib/action_view/helpers/tags/hidden_field.rb index ea86596e0b..a8d13dc1b1 100644 --- a/actionpack/lib/action_view/helpers/tags/hidden_field.rb +++ b/actionpack/lib/action_view/helpers/tags/hidden_field.rb @@ -2,10 +2,6 @@ module ActionView module Helpers module Tags class HiddenField < TextField #:nodoc: - def render - @options.update(:size => nil) - super - end end end end diff --git a/actionpack/lib/action_view/helpers/tags/number_field.rb b/actionpack/lib/action_view/helpers/tags/number_field.rb index e89fdbec46..9cd04434f0 100644 --- a/actionpack/lib/action_view/helpers/tags/number_field.rb +++ b/actionpack/lib/action_view/helpers/tags/number_field.rb @@ -4,7 +4,6 @@ module ActionView class NumberField < TextField #:nodoc: def render options = @options.stringify_keys - options['size'] ||= nil if range = options.delete("in") || options.delete("within") options.update("min" => range.min, "max" => range.max) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index fffc37ce9e..67117077dc 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -37,7 +37,6 @@ module ActionView # do not operate as expected in an eRuby code block. If you absolutely must # output text within a non-output code block (i.e., <% %>), you can use the concat method. # - # ==== Examples # <% # concat "hello" # # is the equivalent of <%= "hello" %> @@ -67,8 +66,6 @@ module ActionView # used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags # or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags). # - # ==== Examples - # # truncate("Once upon a time in a world far far away") # # => "Once upon a time in a world..." # @@ -90,10 +87,9 @@ module ActionView # Highlights one or more +phrases+ everywhere in +text+ by inserting it into # a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt> - # as a single-quoted string with \1 where the phrase is to be inserted (defaults to + # as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to # '<mark>\1</mark>') # - # ==== Examples # highlight('You searched for: rails', 'rails') # # => You searched for: <mark>rails</mark> # @@ -108,7 +104,9 @@ module ActionView # # You can still use <tt>highlight</tt> with the old API that accepts the # +highlighter+ as its optional third parameter: - # highlight('You searched for: rails', 'rails', '<a href="search?q=\1">\1</a>') # => You searched for: <a href="search?q=rails">rails</a> + # + # highlight('You searched for: rails', 'rails', '<a href="search?q=\1">\1</a>') + # # => You searched for: <a href="search?q=rails">rails</a> def highlight(text, phrases, *args) options = args.extract_options! unless args.empty? @@ -131,7 +129,6 @@ module ActionView # then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string # will be stripped in any case. If the +phrase+ isn't found, nil is returned. # - # ==== Examples # excerpt('This is an example', 'an', :radius => 5) # # => ...s is an exam... # @@ -179,7 +176,6 @@ module ActionView # +plural+ is supplied, it will use that when count is > 1, otherwise # it will use the Inflector to determine the plural form # - # ==== Examples # pluralize(1, 'person') # # => 1 person # @@ -199,23 +195,23 @@ module ActionView # breaks on the first whitespace character that does not exceed +line_width+ # (which is 80 by default). # - # ==== Examples - # # word_wrap('Once upon a time') # # => Once upon a time # # word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...') - # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined... + # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined... # # word_wrap('Once upon a time', :line_width => 8) - # # => Once upon\na time + # # => Once\nupon a\ntime # # word_wrap('Once upon a time', :line_width => 1) # # => Once\nupon\na\ntime # # You can still use <tt>word_wrap</tt> with the old API that accepts the # +line_width+ as its optional second parameter: - # word_wrap('Once upon a time', 8) # => Once upon\na time + # + # word_wrap('Once upon a time', 8) + # # => Once\nupon a\ntime def word_wrap(text, *args) options = args.extract_options! unless args.blank? @@ -239,6 +235,7 @@ module ActionView # # ==== Options # * <tt>:sanitize</tt> - If +false+, does not sanitize +text+. + # * <tt>:wrapper_tag</tt> - String representing the tag wrapper, defaults to <tt>"p"</tt> # # ==== Examples # my_text = "Here is some basic text...\n...with a line break." @@ -257,16 +254,17 @@ module ActionView # simple_format("<span>I'm allowed!</span> It's true.", {}, :sanitize => false) # # => "<p><span>I'm allowed!</span> It's true.</p>" def simple_format(text, html_options={}, options={}) - text = '' if text.nil? - text = text.dup - start_tag = tag('p', html_options, true) text = sanitize(text) unless options[:sanitize] == false - text = text.to_str - text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n - text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph - text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br - text.insert 0, start_tag - text.html_safe.safe_concat("</p>") + wrapper_tag = options.fetch(:wrapper_tag, :p) + paragraphs = split_paragraphs(text) + + if paragraphs.empty? + content_tag(wrapper_tag, nil, html_options) + else + paragraphs.map { |paragraph| + content_tag(wrapper_tag, paragraph, html_options, options[:sanitize]) + }.join("\n\n").html_safe + end end # Creates a Cycle object whose _to_s_ method cycles through elements of an @@ -278,7 +276,6 @@ module ActionView # and passing the name of the cycle. The current cycle string can be obtained # anytime using the current_cycle method. # - # ==== Examples # # Alternate CSS classes for even and odd numbers... # @items = [1,2,3,4] # <table> @@ -324,7 +321,6 @@ module ActionView # for complex table highlighting or any other design need which requires # the current cycle string in more than one place. # - # ==== Example # # Alternate background colors # @items = [1,2,3,4] # <% @items.each do |item| %> @@ -340,7 +336,6 @@ module ActionView # Resets a cycle so that it starts from the first element the next time # it is called. Pass in +name+ to reset a named cycle. # - # ==== Example # # Alternate CSS classes for even and odd numbers... # @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]] # <table> @@ -411,6 +406,14 @@ module ActionView @_cycles = Hash.new unless defined?(@_cycles) @_cycles[name] = cycle_object end + + def split_paragraphs(text) + return [] if text.blank? + + text.to_str.gsub(/\r\n?/, "\n").split(/\n\n+/).map! do |t| + t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t + end + end end end end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 1145f348c2..7e69547dab 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -108,7 +108,7 @@ module ActionView options when nil, Hash options ||= {} - options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?) + options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys) super when :back controller.request.env["HTTP_REFERER"] || 'javascript:history.back()' @@ -322,11 +322,11 @@ module ActionView # # # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?', - # :method => "delete", :remote => true, :disable_with => 'loading...') %> + # :method => "delete", :remote => true) %> # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'> # # <div> # # <input name='_method' value='delete' type='hidden' /> - # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' /> + # # <input value='Destroy' type='submit' data-confirm='Are you sure?' /> # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/> # # </div> # # </form>" @@ -616,11 +616,9 @@ module ActionView html_options = html_options.stringify_keys html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options) - disable_with = html_options.delete("disable_with") confirm = html_options.delete('confirm') method = html_options.delete('method') - html_options["data-disable-with"] = disable_with if disable_with html_options["data-confirm"] = confirm if confirm add_method_to_attributes!(html_options, method) if method @@ -670,11 +668,11 @@ module ActionView end def token_tag(token=nil) - if token == false || !protect_against_forgery? - '' - else + if token != false && protect_against_forgery? token ||= form_authenticity_token tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token) + else + '' end end diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb index 52473cd222..72616b7463 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb @@ -14,12 +14,10 @@ module ActionView protected def extract_details(options) - details = {} - @lookup_context.registered_details.each do |key| + @lookup_context.registered_details.each_with_object({}) do |key, details| next unless value = options[key] details[key] = Array(value) end - details end def instrument(name, options={}) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 87609fd5ff..9100545718 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -283,7 +283,7 @@ module ActionView return nil if @collection.blank? if @options.key?(:spacer_template) - spacer = find_template(@options[:spacer_template]).render(@view, @locals) + spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals) end result = @template ? collection_with_template : collection_without_template @@ -291,11 +291,11 @@ module ActionView end def render_partial - locals, view, block = @locals, @view, @block + view, locals, block = @view, @locals, @block object, as = @object, @variable if !block && (layout = @options[:layout]) - layout = find_template(layout, @locals.keys + [@variable]) + layout = find_template(layout, @template_keys) end object ||= locals[as] @@ -337,6 +337,7 @@ module ActionView if @path @variable, @variable_counter = retrieve_variable(@path) + @template_keys = retrieve_template_keys else paths.map! { |path| retrieve_variable(path).unshift(path) } end @@ -358,62 +359,55 @@ module ActionView end def collection_from_object - if @object.respond_to?(:to_ary) - @object.to_ary - end + @object.to_ary if @object.respond_to?(:to_ary) end def find_partial if path = @path - locals = @locals.keys - locals << @variable - locals << @variable_counter if @collection - find_template(path, locals) + find_template(path, @template_keys) end end - def find_template(path=@path, locals=@locals.keys) + def find_template(path, locals) prefixes = path.include?(?/) ? [] : @lookup_context.prefixes @lookup_context.find_template(path, prefixes, true, locals, @details) end def collection_with_template - segments, locals, template = [], @locals, @template + view, locals, template = @view, @locals, @template as, counter = @variable, @variable_counter if layout = @options[:layout] - layout = find_template(layout, @locals.keys + [@variable, @variable_counter]) + layout = find_template(layout, @template_keys) end - locals[counter] = -1 - - @collection.each do |object| - locals[counter] += 1 - locals[as] = object + index = -1 + @collection.map do |object| + locals[as] = object + locals[counter] = (index += 1) - content = template.render(@view, locals) - content = layout.render(@view, locals) { content } if layout - segments << content + content = template.render(view, locals) + content = layout.render(view, locals) { content } if layout + content end - - segments end def collection_without_template - segments, locals, collection_data = [], @locals, @collection_data - index, template, cache = -1, nil, {} - keys = @locals.keys + view, locals, collection_data = @view, @locals, @collection_data + cache = {} + keys = @locals.keys - @collection.each_with_index do |object, i| - path, *data = collection_data[i] - template = (cache[path] ||= find_template(path, keys + data)) - locals[data[0]] = object - locals[data[1]] = (index += 1) - segments << template.render(@view, locals) - end + index = -1 + @collection.map do |object| + index += 1 + path, as, counter = collection_data[index] - @template = template - segments + locals[as] = object + locals[counter] = index + + template = (cache[path] ||= find_template(path, keys + [as, counter])) + template.render(view, locals) + end end def partial_path(object = @object) @@ -453,6 +447,13 @@ module ActionView end end + def retrieve_template_keys + keys = @locals.keys + keys << @variable + keys << @variable_counter if @collection + keys + end + def retrieve_variable(path) variable = @options.fetch(:as) { path[%r'_?(\w+)(\.\w+)*$', 1] }.try(:to_sym) variable_counter = :"#{variable}_counter" if @collection diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 4e22bec6cc..41b14373a3 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -4,10 +4,12 @@ module ActionView #:nodoc: module Handlers #:nodoc: autoload :ERB, 'action_view/template/handlers/erb' autoload :Builder, 'action_view/template/handlers/builder' + autoload :Raw, 'action_view/template/handlers/raw' def self.extended(base) base.register_default_template_handler :erb, ERB.new base.register_template_handler :builder, Builder.new + base.register_template_handler :raw, Raw.new end @@template_handlers = {} diff --git a/actionpack/lib/action_view/template/handlers/raw.rb b/actionpack/lib/action_view/template/handlers/raw.rb new file mode 100644 index 0000000000..0c0d1fffcb --- /dev/null +++ b/actionpack/lib/action_view/template/handlers/raw.rb @@ -0,0 +1,11 @@ +module ActionView + module Template::Handlers + class Raw + def call(template) + escaped = template.source.gsub(':', '\:') + + '%q:' + escaped + ':;' + end + end + end +end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 8ea2e5bfe4..fa2038f78d 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -1,5 +1,6 @@ require "pathname" require "active_support/core_ext/class" +require "active_support/core_ext/class/attribute_accessors" require "action_view/template" module ActionView @@ -170,7 +171,9 @@ module ActionView def extract_handler_and_format(path, default_formats) pieces = File.basename(path).split(".") pieces.shift - handler = Template.handler_for_extension(pieces.pop) + extension = pieces.pop + ActiveSupport::Deprecation.warn "The file #{path} did not specify a template handler. The default is currently ERB, but will change to RAW in the future." unless extension + handler = Template.handler_for_extension(extension) format = pieces.last && Mime[pieces.last] [handler, format] end |