lib/grape/dsl/inside_route.rb in grape-0.13.0 vs lib/grape/dsl/inside_route.rb in grape-0.14.0

- old
+ new

@@ -4,61 +4,78 @@ module DSL module InsideRoute extend ActiveSupport::Concern include Grape::DSL::Settings - # A filtering method that will return a hash - # consisting only of keys that have been declared by a - # `params` statement against the current/target endpoint or parent - # namespaces. - # - # @param params [Hash] The initial hash to filter. Usually this will just be `params` - # @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces` - # options. `:include_parent_namespaces` defaults to true, hence must be set to false if - # you want only to return params declared against the current/target endpoint. - def declared(params, options = {}, declared_params = nil) - options[:include_missing] = true unless options.key?(:include_missing) - options[:include_parent_namespaces] = true unless options.key?(:include_parent_namespaces) + # Denotes a situation where a DSL method has been invoked in a + # filter which it should not yet be available in + class MethodNotYetAvailable < StandardError; end - if declared_params.nil? - declared_params = (!options[:include_parent_namespaces] ? route_setting(:declared_params) : - (route_setting(:saved_declared_params) || [])).flatten(1) || [] - end + # @param type [Symbol] The type of filter for which evaluation has been + # completed + # @return [Module] A module containing method overrides suitable for the + # position in the filter evaluation sequence denoted by +type+. This + # defaults to an empty module if no overrides are defined for the given + # filter +type+. + def self.post_filter_methods(type) + @post_filter_modules ||= { before: PostBeforeFilter } + @post_filter_modules[type] + end - unless declared_params - fail ArgumentError, 'Tried to filter for declared parameters but none exist.' - end + # Methods which should not be available in filters until the before filter + # has completed + module PostBeforeFilter + def declared(params, options = {}, declared_params = nil) + options = options.reverse_merge(include_missing: true, include_parent_namespaces: true) - if params.is_a? Array - params.map do |param| - declared(param || {}, options, declared_params) - end - else - declared_params.inject(Hashie::Mash.new) do |hash, key| - key = { key => nil } unless key.is_a? Hash + declared_params ||= (!options[:include_parent_namespaces] ? route_setting(:declared_params) : (route_setting(:saved_declared_params) || [])).flatten(1) || [] - key.each_pair do |parent, children| - output_key = options[:stringify] ? parent.to_s : parent.to_sym + fail ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params - next unless options[:include_missing] || params.key?(parent) - - hash[output_key] = if children - children_params = params[parent] || (children.is_a?(Array) ? [] : {}) - declared(children_params, options, Array(children)) - else - params[parent] - end + if params.is_a? Array + params.map do |param| + declared(param || {}, options, declared_params) end + else + declared_params.each_with_object(Hashie::Mash.new) do |key, hash| + key = { key => nil } unless key.is_a? Hash - hash + key.each_pair do |parent, children| + output_key = options[:stringify] ? parent.to_s : parent.to_sym + + next unless options[:include_missing] || params.key?(parent) + + hash[output_key] = if children + children_params = params[parent] || (children.is_a?(Array) ? [] : {}) + declared(children_params, options, Array(children)) + else + params[parent] + end + end + end end end end + # A filtering method that will return a hash + # consisting only of keys that have been declared by a + # `params` statement against the current/target endpoint or parent + # namespaces. + # + # @see +PostBeforeFilter#declared+ + # + # @param params [Hash] The initial hash to filter. Usually this will just be `params` + # @param options [Hash] Can pass `:include_missing`, `:stringify` and `:include_parent_namespaces` + # options. `:include_parent_namespaces` defaults to true, hence must be set to false if + # you want only to return params declared against the current/target endpoint. + def declared(*) + fail MethodNotYetAvailable, '#declared is not available prior to parameter validation.' + end + # The API version as specified in the URL. def version - env['api.version'] + env[Grape::Env::API_VERSION] end # End the request and display an error to the # end user with the specified message. # @@ -72,23 +89,29 @@ # Redirect to a new url. # # @param url [String] The url to be redirect. # @param options [Hash] The options used when redirect. # :permanent, default false. + # :body, default a short message including the URL. def redirect(url, options = {}) - merged_options = { permanent: false }.merge(options) - if merged_options[:permanent] + permanent = options.fetch(:permanent, false) + body_message = options.fetch(:body, nil) + if permanent status 301 + body_message ||= "This resource has been moved permanently to #{url}." else if env[Grape::Http::Headers::HTTP_VERSION] == 'HTTP/1.1' && request.request_method.to_s.upcase != Grape::Http::Headers::GET status 303 + body_message ||= "An alternate resource is located at #{url}." else status 302 + body_message ||= "This resource has been moved temporarily to #{url}." end end header 'Location', url - body '' + content_type 'text/plain' + body body_message end # Set or retrieve the HTTP status code. # # @param status [Integer] The HTTP Status Code to return for this request. @@ -239,11 +262,11 @@ representation = { root => representation } if root if key representation = (@body || {}).merge(key => representation) elsif entity_class.present? && @body - fail ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?('merge') + fail ArgumentError, "Representation of type #{representation.class} cannot be merged." unless representation.respond_to?(:merge) representation = @body.merge(representation) end body representation end @@ -255,11 +278,11 @@ # desc "Returns the route description." # get '/' do # route.route_description # end def route - env['rack.routing_args'][:route_info] + env[Grape::Env::RACK_ROUTING_ARGS][:route_info] end # Attempt to locate the Entity class for a given object, if not given # explicitly. This is done by looking for the presence of Klass::Entity, # where Klass is the class of the `object` parameter, or one of its @@ -291,10 +314,10 @@ # @return the representation of the given object as done through # the given entity_class. def entity_representation_for(entity_class, object, options) embeds = { env: env } - embeds[:version] = env['api.version'] if env['api.version'] + embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION] entity_class.represent(object, embeds.merge(options)) end end end end