From 9d9cc4777be3787ed3645d704f02e5ba1228be13 Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Fri, 13 Feb 2015 23:41:19 -0500 Subject: Provide friendlier access to request variants Closes #18933. --- .../lib/action_dispatch/http/mime_negotiation.rb | 41 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'actionpack/lib/action_dispatch/http/mime_negotiation.rb') diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 53a98c5d0a..6544aff7d2 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -10,8 +10,6 @@ module ActionDispatch self.ignore_accept_header = false end - attr_reader :variant - # The MIME type of the HTTP request, such as Mime::XML. # # For backward compatibility, the post \format is extracted from the @@ -75,18 +73,22 @@ module ActionDispatch # Sets the \variant for template. def variant=(variant) - if variant.is_a?(Symbol) - @variant = [variant] - elsif variant.nil? || variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) } - @variant = variant + variant = Array(variant) + + if variant.all? { |v| v.is_a?(Symbol) } + @variant = VariantInquirer.new(variant) else - raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols, not a #{variant.class}. " \ + raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \ "For security reasons, never directly set the variant to a user-provided value, " \ "like params[:variant].to_sym. Check user-provided value against a whitelist first, " \ "then set the variant: request.variant = :tablet if params[:variant] == 'tablet'" end end + def variant + @variant ||= VariantInquirer.new + end + # Sets the \format by string extension, which can be used to force custom formats # that are not controlled by the extension. # @@ -139,6 +141,31 @@ module ActionDispatch order.include?(Mime::ALL) ? format : nil end + class VariantInquirer # :nodoc: + delegate :each, :empty?, to: :@variants + + def initialize(variants = []) + @variants = variants + end + + def any?(*candidates) + (@variants & candidates).any? + end + + def to_ary + @variants + end + + private + def method_missing(name, *args) + if name[-1] == '?' + any? name[0..-2].to_sym + else + super + end + end + end + protected BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ -- cgit v1.2.3 From c64b99ecc98341d504aced72448bee758f3cfdaf Mon Sep 17 00:00:00 2001 From: George Claghorn Date: Tue, 10 Mar 2015 01:00:37 -0400 Subject: Add ActiveSupport::ArrayInquirer and Array#inquiry Wrapping an array in an `ArrayInquirer` gives a friendlier way to check its string-like contents. For example, `request.variant` returns an `ArrayInquirer` object. To check a request's variants, you can call: request.variant.phone? request.variant.any?(:phone, :tablet) ...instead of: request.variant.include?(:phone) request.variant.any? { |v| v.in?([:phone, :tablet]) } `Array#inquiry` is a shortcut for wrapping the receiving array in an `ArrayInquirer`: pets = [:cat, :dog] pets.cat? # => true pets.ferret? # => false pets.any?(:cat, :ferret} # => true --- .../lib/action_dispatch/http/mime_negotiation.rb | 29 ++-------------------- 1 file changed, 2 insertions(+), 27 deletions(-) (limited to 'actionpack/lib/action_dispatch/http/mime_negotiation.rb') diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 6544aff7d2..ff336b7354 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -76,7 +76,7 @@ module ActionDispatch variant = Array(variant) if variant.all? { |v| v.is_a?(Symbol) } - @variant = VariantInquirer.new(variant) + @variant = ActiveSupport::ArrayInquirer.new(variant) else raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \ "For security reasons, never directly set the variant to a user-provided value, " \ @@ -86,7 +86,7 @@ module ActionDispatch end def variant - @variant ||= VariantInquirer.new + @variant ||= ActiveSupport::ArrayInquirer.new end # Sets the \format by string extension, which can be used to force custom formats @@ -141,31 +141,6 @@ module ActionDispatch order.include?(Mime::ALL) ? format : nil end - class VariantInquirer # :nodoc: - delegate :each, :empty?, to: :@variants - - def initialize(variants = []) - @variants = variants - end - - def any?(*candidates) - (@variants & candidates).any? - end - - def to_ary - @variants - end - - private - def method_missing(name, *args) - if name[-1] == '?' - any? name[0..-2].to_sym - else - super - end - end - end - protected BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ -- cgit v1.2.3