grape 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +15 -0
 - data/.travis.yml +2 -6
 - data/CHANGELOG.md +20 -0
 - data/README.md +43 -11
 - data/lib/grape.rb +6 -0
 - data/lib/grape/api.rb +27 -14
 - data/lib/grape/endpoint.rb +33 -34
 - data/lib/grape/exceptions/base.rb +4 -2
 - data/lib/grape/exceptions/validation.rb +13 -3
 - data/lib/grape/exceptions/validation_errors.rb +42 -0
 - data/lib/grape/http/request.rb +1 -1
 - data/lib/grape/locale/en.yml +4 -3
 - data/lib/grape/middleware/auth/base.rb +30 -0
 - data/lib/grape/middleware/auth/basic.rb +2 -19
 - data/lib/grape/middleware/auth/digest.rb +2 -19
 - data/lib/grape/middleware/error.rb +10 -1
 - data/lib/grape/middleware/formatter.rb +1 -1
 - data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
 - data/lib/grape/middleware/versioner/header.rb +2 -2
 - data/lib/grape/path.rb +72 -0
 - data/lib/grape/route.rb +6 -1
 - data/lib/grape/validations.rb +25 -8
 - data/lib/grape/validations/coerce.rb +1 -2
 - data/lib/grape/validations/presence.rb +6 -2
 - data/lib/grape/validations/regexp.rb +1 -2
 - data/lib/grape/version.rb +1 -1
 - data/spec/grape/api_spec.rb +71 -6
 - data/spec/grape/entity_spec.rb +5 -5
 - data/spec/grape/middleware/base_spec.rb +1 -1
 - data/spec/grape/middleware/formatter_spec.rb +3 -3
 - data/spec/grape/middleware/versioner/header_spec.rb +25 -0
 - data/spec/grape/path_spec.rb +219 -0
 - data/spec/grape/validations/coerce_spec.rb +31 -13
 - data/spec/grape/validations/presence_spec.rb +12 -12
 - data/spec/grape/validations/zh-CN.yml +4 -3
 - data/spec/grape/validations_spec.rb +154 -10
 - data/spec/support/versioned_helpers.rb +5 -2
 - metadata +10 -45
 
    
        data/lib/grape/http/request.rb
    CHANGED
    
    
    
        data/lib/grape/locale/en.yml
    CHANGED
    
    | 
         @@ -1,10 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            en:
         
     | 
| 
       2 
2 
     | 
    
         
             
              grape:
         
     | 
| 
       3 
3 
     | 
    
         
             
                errors:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  format: ! '%{attribute} %{message}'
         
     | 
| 
       4 
5 
     | 
    
         
             
                  messages:
         
     | 
| 
       5 
     | 
    
         
            -
                    coerce: 'invalid 
     | 
| 
       6 
     | 
    
         
            -
                    presence: 'missing 
     | 
| 
       7 
     | 
    
         
            -
                    regexp: 'invalid 
     | 
| 
      
 6 
     | 
    
         
            +
                    coerce: 'is invalid'
         
     | 
| 
      
 7 
     | 
    
         
            +
                    presence: 'is missing'
         
     | 
| 
      
 8 
     | 
    
         
            +
                    regexp: 'is invalid'
         
     | 
| 
       8 
9 
     | 
    
         
             
                    missing_vendor_option:
         
     | 
| 
       9 
10 
     | 
    
         
             
                      problem: 'missing :vendor option.'
         
     | 
| 
       10 
11 
     | 
    
         
             
                      summary: 'when version using header, you must specify :vendor option. '
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rack/auth/basic'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Grape
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Middleware
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Auth
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class Base < Grape::Middleware::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                    attr_reader :authenticator
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    def initialize(app, options = {}, &authenticator)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      super(app, options)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @authenticator = authenticator
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    def base_request
         
     | 
| 
      
 15 
     | 
    
         
            +
                      raise NotImplementedError.new("You must implement base_request.")
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    def credentials
         
     | 
| 
      
 19 
     | 
    
         
            +
                      base_request.provided?? base_request.credentials : [nil, nil]
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def before
         
     | 
| 
      
 23 
     | 
    
         
            +
                      unless authenticator.call(*credentials)
         
     | 
| 
      
 24 
     | 
    
         
            +
                        throw :error, :status => 401, :message => "API Authorization Failed."
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -3,27 +3,10 @@ require 'rack/auth/basic' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module Grape
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Middleware
         
     | 
| 
       5 
5 
     | 
    
         
             
                module Auth
         
     | 
| 
       6 
     | 
    
         
            -
                  class Basic < Grape::Middleware::Base
         
     | 
| 
       7 
     | 
    
         
            -
                     
     | 
| 
       8 
     | 
    
         
            -
                    
         
     | 
| 
       9 
     | 
    
         
            -
                    def initialize(app, options = {}, &authenticator)
         
     | 
| 
       10 
     | 
    
         
            -
                      super(app, options)
         
     | 
| 
       11 
     | 
    
         
            -
                      @authenticator = authenticator
         
     | 
| 
       12 
     | 
    
         
            -
                    end
         
     | 
| 
       13 
     | 
    
         
            -
                    
         
     | 
| 
       14 
     | 
    
         
            -
                    def basic_request
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class Basic < Grape::Middleware::Auth::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def base_request
         
     | 
| 
       15 
8 
     | 
    
         
             
                      Rack::Auth::Basic::Request.new(env)
         
     | 
| 
       16 
9 
     | 
    
         
             
                    end
         
     | 
| 
       17 
     | 
    
         
            -
                    
         
     | 
| 
       18 
     | 
    
         
            -
                    def credentials
         
     | 
| 
       19 
     | 
    
         
            -
                      basic_request.provided?? basic_request.credentials : [nil, nil]
         
     | 
| 
       20 
     | 
    
         
            -
                    end
         
     | 
| 
       21 
     | 
    
         
            -
                    
         
     | 
| 
       22 
     | 
    
         
            -
                    def before
         
     | 
| 
       23 
     | 
    
         
            -
                      unless authenticator.call(*credentials)
         
     | 
| 
       24 
     | 
    
         
            -
                        throw :error, :status => 401, :message => "API Authorization Failed."
         
     | 
| 
       25 
     | 
    
         
            -
                      end
         
     | 
| 
       26 
     | 
    
         
            -
                    end
         
     | 
| 
       27 
10 
     | 
    
         
             
                  end
         
     | 
| 
       28 
11 
     | 
    
         
             
                end
         
     | 
| 
       29 
12 
     | 
    
         
             
              end
         
     | 
| 
         @@ -3,27 +3,10 @@ require 'rack/auth/digest/md5' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module Grape
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Middleware
         
     | 
| 
       5 
5 
     | 
    
         
             
                module Auth
         
     | 
| 
       6 
     | 
    
         
            -
                  class Digest < Grape::Middleware::Base
         
     | 
| 
       7 
     | 
    
         
            -
                     
     | 
| 
       8 
     | 
    
         
            -
                    
         
     | 
| 
       9 
     | 
    
         
            -
                    def initialize(app, options = {}, &authenticator)
         
     | 
| 
       10 
     | 
    
         
            -
                      super(app, options)
         
     | 
| 
       11 
     | 
    
         
            -
                      @authenticator = authenticator
         
     | 
| 
       12 
     | 
    
         
            -
                    end
         
     | 
| 
       13 
     | 
    
         
            -
                    
         
     | 
| 
       14 
     | 
    
         
            -
                    def digest_request
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class Digest < Grape::Middleware::Auth::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def base_request
         
     | 
| 
       15 
8 
     | 
    
         
             
                      Rack::Auth::Digest::Request.new(env)
         
     | 
| 
       16 
9 
     | 
    
         
             
                    end
         
     | 
| 
       17 
     | 
    
         
            -
                    
         
     | 
| 
       18 
     | 
    
         
            -
                    def credentials
         
     | 
| 
       19 
     | 
    
         
            -
                      digest_request.provided?? digest_request.credentials : [nil, nil]
         
     | 
| 
       20 
     | 
    
         
            -
                    end
         
     | 
| 
       21 
     | 
    
         
            -
                    
         
     | 
| 
       22 
     | 
    
         
            -
                    def before
         
     | 
| 
       23 
     | 
    
         
            -
                      unless authenticator.call(*credentials)
         
     | 
| 
       24 
     | 
    
         
            -
                        throw :error, :status => 401, :message => "API Authorization Failed."
         
     | 
| 
       25 
     | 
    
         
            -
                      end
         
     | 
| 
       26 
     | 
    
         
            -
                    end
         
     | 
| 
       27 
10 
     | 
    
         
             
                  end
         
     | 
| 
       28 
11 
     | 
    
         
             
                end
         
     | 
| 
       29 
12 
     | 
    
         
             
              end
         
     | 
| 
         @@ -33,7 +33,8 @@ module Grape 
     | 
|
| 
       33 
33 
     | 
    
         
             
                        raise unless is_rescuable
         
     | 
| 
       34 
34 
     | 
    
         
             
                        handler = options[:rescue_handlers][e.class] || options[:rescue_handlers][:all]
         
     | 
| 
       35 
35 
     | 
    
         
             
                      end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      handler.nil? ? handle_error(e) : exec_handler(e, &handler)
         
     | 
| 
       37 
38 
     | 
    
         
             
                    end
         
     | 
| 
       38 
39 
     | 
    
         
             
                  end
         
     | 
| 
       39 
40 
     | 
    
         | 
| 
         @@ -41,6 +42,14 @@ module Grape 
     | 
|
| 
       41 
42 
     | 
    
         
             
                    options[:rescue_all] || (options[:rescued_errors] || []).include?(klass)
         
     | 
| 
       42 
43 
     | 
    
         
             
                  end
         
     | 
| 
       43 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  def exec_handler(e, &handler)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    if handler.lambda? && handler.arity == 0
         
     | 
| 
      
 47 
     | 
    
         
            +
                      self.instance_exec(&handler)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    else
         
     | 
| 
      
 49 
     | 
    
         
            +
                      self.instance_exec(e, &handler)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
       44 
53 
     | 
    
         
             
                  def handle_error(e)
         
     | 
| 
       45 
54 
     | 
    
         
             
                    error_response({ :message => e.message, :backtrace => e.backtrace })
         
     | 
| 
       46 
55 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -41,7 +41,7 @@ module Grape 
     | 
|
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
                    # store read input in env['api.request.input']
         
     | 
| 
       43 
43 
     | 
    
         
             
                    def read_body_input
         
     | 
| 
       44 
     | 
    
         
            -
                      if (request.post? || request.put? || request.patch?) &&
         
     | 
| 
      
 44 
     | 
    
         
            +
                      if (request.post? || request.put? || request.patch? || request.delete?) &&
         
     | 
| 
       45 
45 
     | 
    
         
             
                        (! request.form_data? || ! request.media_type) &&
         
     | 
| 
       46 
46 
     | 
    
         
             
                        (! request.parseable_data?) &&
         
     | 
| 
       47 
47 
     | 
    
         
             
                        (request.content_length.to_i > 0 || request.env['HTTP_TRANSFER_ENCODING'] == 'chunked')
         
     | 
| 
         @@ -11,7 +11,7 @@ module Grape 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  #
         
     | 
| 
       12 
12 
     | 
    
         
             
                  # The following rack env variables are set:
         
     | 
| 
       13 
13 
     | 
    
         
             
                  #
         
     | 
| 
       14 
     | 
    
         
            -
                  #    env['api.version]  => 'v1'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #    env['api.version']  => 'v1'
         
     | 
| 
       15 
15 
     | 
    
         
             
                  #
         
     | 
| 
       16 
16 
     | 
    
         
             
                  # If version does not match this route, then a 406 is raised with
         
     | 
| 
       17 
17 
     | 
    
         
             
                  # X-Cascade header to alert Rack::Mount to attempt the next matched
         
     | 
| 
         @@ -99,8 +99,8 @@ module Grape 
     | 
|
| 
       99 
99 
     | 
    
         
             
                    # of routes (see [Rack::Mount](https://github.com/josh/rack-mount) for more information). To prevent
         
     | 
| 
       100 
100 
     | 
    
         
             
                    # this behavior, and not add the `X-Cascade` header, one can set the `:cascade` option to `false`.
         
     | 
| 
       101 
101 
     | 
    
         
             
                    def cascade?
         
     | 
| 
       102 
     | 
    
         
            -
                      options[:version_options] && options[:version_options].has_key?(:cascade) ? 
     | 
| 
       103 
     | 
    
         
            -
                        !! options[:version_options][:cascade] : 
     | 
| 
      
 102 
     | 
    
         
            +
                      options[:version_options] && options[:version_options].has_key?(:cascade) ?
         
     | 
| 
      
 103 
     | 
    
         
            +
                        !! options[:version_options][:cascade] :
         
     | 
| 
       104 
104 
     | 
    
         
             
                        true
         
     | 
| 
       105 
105 
     | 
    
         
             
                    end
         
     | 
| 
       106 
106 
     | 
    
         | 
    
        data/lib/grape/path.rb
    ADDED
    
    | 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Grape
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Path
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                def self.prepare(raw_path, namespace, settings)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  Path.new(raw_path, namespace, settings).path_with_suffix
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :raw_path, :namespace, :settings
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(raw_path, namespace, settings)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @raw_path = raw_path
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @namespace = namespace
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @settings = settings
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def mount_path
         
     | 
| 
      
 17 
     | 
    
         
            +
                  split_setting(:mount_path, '/')
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def root_prefix
         
     | 
| 
      
 21 
     | 
    
         
            +
                  split_setting(:root_prefix, '/')
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def uses_path_versioning?
         
     | 
| 
      
 25 
     | 
    
         
            +
                  settings[:version] && settings[:version_options][:using] == :path
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def has_namespace?
         
     | 
| 
      
 29 
     | 
    
         
            +
                  namespace && namespace.to_s =~ /^\S/ && namespace != '/'
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def has_path?
         
     | 
| 
      
 33 
     | 
    
         
            +
                  raw_path && raw_path.to_s =~ /^\S/ && raw_path != '/'
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def suffix
         
     | 
| 
      
 37 
     | 
    
         
            +
                  if !uses_path_versioning? || (has_namespace? || has_path?)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    '(.:format)'
         
     | 
| 
      
 39 
     | 
    
         
            +
                  else
         
     | 
| 
      
 40 
     | 
    
         
            +
                    '(/.:format)'
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def path
         
     | 
| 
      
 45 
     | 
    
         
            +
                  Rack::Mount::Utils.normalize_path(parts.join('/'))
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def path_with_suffix
         
     | 
| 
      
 49 
     | 
    
         
            +
                  "#{path}#{suffix}"
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 53 
     | 
    
         
            +
                  path_with_suffix
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                private
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def parts
         
     | 
| 
      
 59 
     | 
    
         
            +
                  parts = [mount_path, root_prefix].compact
         
     | 
| 
      
 60 
     | 
    
         
            +
                  parts << ':version' if uses_path_versioning?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  parts << namespace.to_s
         
     | 
| 
      
 62 
     | 
    
         
            +
                  parts << raw_path.to_s
         
     | 
| 
      
 63 
     | 
    
         
            +
                  parts.flatten.reject { |part| part == '/' }
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
                
         
     | 
| 
      
 66 
     | 
    
         
            +
                def split_setting(key, delimiter)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  return if settings[key].nil?
         
     | 
| 
      
 68 
     | 
    
         
            +
                  settings[key].to_s.split("/")
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/grape/route.rb
    CHANGED
    
    
    
        data/lib/grape/validations.rb
    CHANGED
    
    | 
         @@ -89,10 +89,11 @@ module Grape 
     | 
|
| 
       89 
89 
     | 
    
         
             
                class ParamsScope
         
     | 
| 
       90 
90 
     | 
    
         
             
                  attr_accessor :element, :parent
         
     | 
| 
       91 
91 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
                  def initialize( 
     | 
| 
       93 
     | 
    
         
            -
                    @element 
     | 
| 
       94 
     | 
    
         
            -
                    @parent 
     | 
| 
       95 
     | 
    
         
            -
                    @api 
     | 
| 
      
 92 
     | 
    
         
            +
                  def initialize(opts, &block)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    @element  = opts[:element]
         
     | 
| 
      
 94 
     | 
    
         
            +
                    @parent   = opts[:parent]
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @api      = opts[:api]
         
     | 
| 
      
 96 
     | 
    
         
            +
                    @optional = opts[:optional] || false
         
     | 
| 
       96 
97 
     | 
    
         
             
                    @declared_params = []
         
     | 
| 
       97 
98 
     | 
    
         | 
| 
       98 
99 
     | 
    
         
             
                    instance_eval(&block)
         
     | 
| 
         @@ -100,7 +101,15 @@ module Grape 
     | 
|
| 
       100 
101 
     | 
    
         
             
                    configure_declared_params
         
     | 
| 
       101 
102 
     | 
    
         
             
                  end
         
     | 
| 
       102 
103 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                  def  
     | 
| 
      
 104 
     | 
    
         
            +
                  def should_validate?(parameters)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    return false if @optional && params(parameters).blank?
         
     | 
| 
      
 106 
     | 
    
         
            +
                    return true if parent.nil?
         
     | 
| 
      
 107 
     | 
    
         
            +
                    parent.should_validate?(parameters)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def requires(*attrs, &block)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    return new_scope(attrs, &block) if block_given?
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
       104 
113 
     | 
    
         
             
                    validations = {:presence => true}
         
     | 
| 
       105 
114 
     | 
    
         
             
                    if attrs.last.is_a?(Hash)
         
     | 
| 
       106 
115 
     | 
    
         
             
                      validations.merge!(attrs.pop)
         
     | 
| 
         @@ -110,7 +119,9 @@ module Grape 
     | 
|
| 
       110 
119 
     | 
    
         
             
                    validates(attrs, validations)
         
     | 
| 
       111 
120 
     | 
    
         
             
                  end
         
     | 
| 
       112 
121 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                  def optional(*attrs)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  def optional(*attrs, &block)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    return new_scope(attrs, true, &block) if block_given?
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       114 
125 
     | 
    
         
             
                    validations = {}
         
     | 
| 
       115 
126 
     | 
    
         
             
                    if attrs.last.is_a?(Hash)
         
     | 
| 
       116 
127 
     | 
    
         
             
                      validations.merge!(attrs.pop)
         
     | 
| 
         @@ -121,7 +132,7 @@ module Grape 
     | 
|
| 
       121 
132 
     | 
    
         
             
                  end
         
     | 
| 
       122 
133 
     | 
    
         | 
| 
       123 
134 
     | 
    
         
             
                  def group(element, &block)
         
     | 
| 
       124 
     | 
    
         
            -
                     
     | 
| 
      
 135 
     | 
    
         
            +
                    requires(element, &block)
         
     | 
| 
       125 
136 
     | 
    
         
             
                  end
         
     | 
| 
       126 
137 
     | 
    
         | 
| 
       127 
138 
     | 
    
         
             
                  def params(params)
         
     | 
| 
         @@ -143,6 +154,11 @@ module Grape 
     | 
|
| 
       143 
154 
     | 
    
         | 
| 
       144 
155 
     | 
    
         
             
                private
         
     | 
| 
       145 
156 
     | 
    
         | 
| 
      
 157 
     | 
    
         
            +
                  def new_scope(attrs, optional=false, &block)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    raise ArgumentError unless attrs.size == 1
         
     | 
| 
      
 159 
     | 
    
         
            +
                    ParamsScope.new(api: @api, element: attrs.first, parent: self, optional: optional, &block)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
       146 
162 
     | 
    
         
             
                  # Pushes declared params to parent or settings
         
     | 
| 
       147 
163 
     | 
    
         
             
                  def configure_declared_params
         
     | 
| 
       148 
164 
     | 
    
         
             
                    if @parent
         
     | 
| 
         @@ -179,6 +195,7 @@ module Grape 
     | 
|
| 
       179 
195 
     | 
    
         
             
                    # Validate for presence before any other validators
         
     | 
| 
       180 
196 
     | 
    
         
             
                    if validations.has_key?(:presence) && validations[:presence]
         
     | 
| 
       181 
197 
     | 
    
         
             
                      validate('presence', validations[:presence], attrs, doc_attrs)
         
     | 
| 
      
 198 
     | 
    
         
            +
                      validations.delete(:presence)
         
     | 
| 
       182 
199 
     | 
    
         
             
                    end
         
     | 
| 
       183 
200 
     | 
    
         | 
| 
       184 
201 
     | 
    
         
             
                    # Before we run the rest of the validators, lets handle
         
     | 
| 
         @@ -214,7 +231,7 @@ module Grape 
     | 
|
| 
       214 
231 
     | 
    
         
             
                  end
         
     | 
| 
       215 
232 
     | 
    
         | 
| 
       216 
233 
     | 
    
         
             
                  def params(&block)
         
     | 
| 
       217 
     | 
    
         
            -
                    ParamsScope.new(self,  
     | 
| 
      
 234 
     | 
    
         
            +
                    ParamsScope.new(api: self, &block)
         
     | 
| 
       218 
235 
     | 
    
         
             
                  end
         
     | 
| 
       219 
236 
     | 
    
         | 
| 
       220 
237 
     | 
    
         
             
                  def document_attribute(names, opts)
         
     | 
| 
         @@ -12,8 +12,7 @@ module Grape 
     | 
|
| 
       12 
12 
     | 
    
         
             
                    if valid_type?(new_value)
         
     | 
| 
       13 
13 
     | 
    
         
             
                      params[attr_name] = new_value
         
     | 
| 
       14 
14 
     | 
    
         
             
                    else
         
     | 
| 
       15 
     | 
    
         
            -
                      raise Grape::Exceptions::Validation, : 
     | 
| 
       16 
     | 
    
         
            -
                        :param => @scope.full_name(attr_name), :message_key => :coerce
         
     | 
| 
      
 15 
     | 
    
         
            +
                      raise Grape::Exceptions::Validation, :param => @scope.full_name(attr_name), :message_key => :coerce
         
     | 
| 
       17 
16 
     | 
    
         
             
                    end
         
     | 
| 
       18 
17 
     | 
    
         
             
                  end
         
     | 
| 
       19 
18 
     | 
    
         | 
| 
         @@ -1,10 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Grape
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Validations
         
     | 
| 
       3 
3 
     | 
    
         
             
                class PresenceValidator < Validator
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def validate!(params)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    return unless @scope.should_validate?(params)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    super
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       4 
9 
     | 
    
         
             
                  def validate_param!(attr_name, params)
         
     | 
| 
       5 
10 
     | 
    
         
             
                    unless params.has_key?(attr_name)
         
     | 
| 
       6 
     | 
    
         
            -
                      raise Grape::Exceptions::Validation, : 
     | 
| 
       7 
     | 
    
         
            -
                        :param => @scope.full_name(attr_name), :message_key => :presence
         
     | 
| 
      
 11 
     | 
    
         
            +
                      raise Grape::Exceptions::Validation, :param => @scope.full_name(attr_name), :message_key => :presence
         
     | 
| 
       8 
12 
     | 
    
         
             
                    end
         
     | 
| 
       9 
13 
     | 
    
         
             
                  end
         
     | 
| 
       10 
14 
     | 
    
         
             
                end
         
     | 
| 
         @@ -4,8 +4,7 @@ module Grape 
     | 
|
| 
       4 
4 
     | 
    
         
             
                class RegexpValidator < SingleOptionValidator
         
     | 
| 
       5 
5 
     | 
    
         
             
                  def validate_param!(attr_name, params)
         
     | 
| 
       6 
6 
     | 
    
         
             
                    if params[attr_name] && !( params[attr_name].to_s =~ @option )
         
     | 
| 
       7 
     | 
    
         
            -
                      raise Grape::Exceptions::Validation, : 
     | 
| 
       8 
     | 
    
         
            -
                        :param => @scope.full_name(attr_name), :message_key => :regexp
         
     | 
| 
      
 7 
     | 
    
         
            +
                      raise Grape::Exceptions::Validation, :param => @scope.full_name(attr_name), :message_key => :regexp
         
     | 
| 
       9 
8 
     | 
    
         
             
                    end
         
     | 
| 
       10 
9 
     | 
    
         
             
                  end
         
     | 
| 
       11 
10 
     | 
    
         
             
                end
         
     | 
    
        data/lib/grape/version.rb
    CHANGED
    
    
    
        data/spec/grape/api_spec.rb
    CHANGED
    
    | 
         @@ -275,7 +275,15 @@ describe Grape::API do 
     | 
|
| 
       275 
275 
     | 
    
         
             
                    subject.version 'v1', :using => :header, :vendor => 'test'
         
     | 
| 
       276 
276 
     | 
    
         
             
                    subject.enable_root_route!
         
     | 
| 
       277 
277 
     | 
    
         | 
| 
       278 
     | 
    
         
            -
                    versioned_get "/", "v1", :using => :header
         
     | 
| 
      
 278 
     | 
    
         
            +
                    versioned_get "/", "v1", :using => :header, :vendor => 'test'
         
     | 
| 
      
 279 
     | 
    
         
            +
                  end
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
                  it 'header versioned APIs with multiple headers' do
         
     | 
| 
      
 282 
     | 
    
         
            +
                    subject.version ['v1', 'v2'], :using => :header, :vendor => 'test'
         
     | 
| 
      
 283 
     | 
    
         
            +
                    subject.enable_root_route!
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
      
 285 
     | 
    
         
            +
                    versioned_get "/", "v1", :using => :header, :vendor => 'test'
         
     | 
| 
      
 286 
     | 
    
         
            +
                    versioned_get "/", "v2", :using => :header, :vendor => 'test'
         
     | 
| 
       279 
287 
     | 
    
         
             
                  end
         
     | 
| 
       280 
288 
     | 
    
         | 
| 
       281 
289 
     | 
    
         
             
                  it 'param versioned APIs' do
         
     | 
| 
         @@ -654,18 +662,18 @@ describe Grape::API do 
     | 
|
| 
       654 
662 
     | 
    
         
             
                describe '.middleware' do
         
     | 
| 
       655 
663 
     | 
    
         
             
                  it 'includes middleware arguments from settings' do
         
     | 
| 
       656 
664 
     | 
    
         
             
                    settings = Grape::Util::HashStack.new
         
     | 
| 
       657 
     | 
    
         
            -
                    settings.stub 
     | 
| 
       658 
     | 
    
         
            -
                    subject.stub 
     | 
| 
      
 665 
     | 
    
         
            +
                    settings.stub(:stack).and_return([{:middleware => [[ApiSpec::PhonyMiddleware, 'abc', 123]]}])
         
     | 
| 
      
 666 
     | 
    
         
            +
                    subject.stub(:settings).and_return(settings)
         
     | 
| 
       659 
667 
     | 
    
         
             
                    subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 'abc', 123]]
         
     | 
| 
       660 
668 
     | 
    
         
             
                  end
         
     | 
| 
       661 
669 
     | 
    
         | 
| 
       662 
670 
     | 
    
         
             
                  it 'includes all middleware from stacked settings' do
         
     | 
| 
       663 
671 
     | 
    
         
             
                    settings = Grape::Util::HashStack.new
         
     | 
| 
       664 
     | 
    
         
            -
                    settings.stub 
     | 
| 
      
 672 
     | 
    
         
            +
                    settings.stub(:stack).and_return [
         
     | 
| 
       665 
673 
     | 
    
         
             
                      {:middleware => [[ApiSpec::PhonyMiddleware, 123],[ApiSpec::PhonyMiddleware, 'abc']]},
         
     | 
| 
       666 
674 
     | 
    
         
             
                      {:middleware => [[ApiSpec::PhonyMiddleware, 'foo']]}
         
     | 
| 
       667 
675 
     | 
    
         
             
                    ]
         
     | 
| 
       668 
     | 
    
         
            -
                    subject.stub 
     | 
| 
      
 676 
     | 
    
         
            +
                    subject.stub(:settings).and_return(settings)
         
     | 
| 
       669 
677 
     | 
    
         | 
| 
       670 
678 
     | 
    
         
             
                    subject.middleware.should eql [
         
     | 
| 
       671 
679 
     | 
    
         
             
                      [ApiSpec::PhonyMiddleware, 123],
         
     | 
| 
         @@ -989,7 +997,7 @@ describe Grape::API do 
     | 
|
| 
       989 
997 
     | 
    
         
             
                end
         
     | 
| 
       990 
998 
     | 
    
         | 
| 
       991 
999 
     | 
    
         
             
                it 'can rescue exceptions raised in the formatter' do
         
     | 
| 
       992 
     | 
    
         
            -
                  formatter =  
     | 
| 
      
 1000 
     | 
    
         
            +
                  formatter = double(:formatter)
         
     | 
| 
       993 
1001 
     | 
    
         
             
                  formatter.stub(:call) { raise StandardError }
         
     | 
| 
       994 
1002 
     | 
    
         
             
                  Grape::Formatter::Base.stub(:formatter_for) { formatter }
         
     | 
| 
       995 
1003 
     | 
    
         | 
| 
         @@ -1074,6 +1082,42 @@ describe Grape::API do 
     | 
|
| 
       1074 
1082 
     | 
    
         
             
                end
         
     | 
| 
       1075 
1083 
     | 
    
         
             
              end
         
     | 
| 
       1076 
1084 
     | 
    
         | 
| 
      
 1085 
     | 
    
         
            +
              describe '.rescue_from klass, lambda' do
         
     | 
| 
      
 1086 
     | 
    
         
            +
                it 'rescues an error with the lambda' do
         
     | 
| 
      
 1087 
     | 
    
         
            +
                  subject.rescue_from ArgumentError, lambda {
         
     | 
| 
      
 1088 
     | 
    
         
            +
                    rack_response("rescued with a lambda", 400)
         
     | 
| 
      
 1089 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1090 
     | 
    
         
            +
                  subject.get('/rescue_lambda') { raise ArgumentError }
         
     | 
| 
      
 1091 
     | 
    
         
            +
             
     | 
| 
      
 1092 
     | 
    
         
            +
                  get '/rescue_lambda'
         
     | 
| 
      
 1093 
     | 
    
         
            +
                  last_response.status.should == 400
         
     | 
| 
      
 1094 
     | 
    
         
            +
                  last_response.body.should == "rescued with a lambda"
         
     | 
| 
      
 1095 
     | 
    
         
            +
                end
         
     | 
| 
      
 1096 
     | 
    
         
            +
             
     | 
| 
      
 1097 
     | 
    
         
            +
                it 'can execute the lambda with an argument' do
         
     | 
| 
      
 1098 
     | 
    
         
            +
                  subject.rescue_from ArgumentError, lambda {|e|
         
     | 
| 
      
 1099 
     | 
    
         
            +
                    rack_response(e.message, 400)
         
     | 
| 
      
 1100 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1101 
     | 
    
         
            +
                  subject.get('/rescue_lambda') { raise ArgumentError, 'lambda takes an argument' }
         
     | 
| 
      
 1102 
     | 
    
         
            +
             
     | 
| 
      
 1103 
     | 
    
         
            +
                  get '/rescue_lambda'
         
     | 
| 
      
 1104 
     | 
    
         
            +
                  last_response.status.should == 400
         
     | 
| 
      
 1105 
     | 
    
         
            +
                  last_response.body.should == 'lambda takes an argument'
         
     | 
| 
      
 1106 
     | 
    
         
            +
                end
         
     | 
| 
      
 1107 
     | 
    
         
            +
              end
         
     | 
| 
      
 1108 
     | 
    
         
            +
             
     | 
| 
      
 1109 
     | 
    
         
            +
              describe '.rescue_from klass, with: method' do
         
     | 
| 
      
 1110 
     | 
    
         
            +
                it 'rescues an error with the specified message' do
         
     | 
| 
      
 1111 
     | 
    
         
            +
                  def rescue_arg_error; Rack::Response.new('rescued with a method', 400); end
         
     | 
| 
      
 1112 
     | 
    
         
            +
                  subject.rescue_from ArgumentError, with: rescue_arg_error
         
     | 
| 
      
 1113 
     | 
    
         
            +
                  subject.get('/rescue_method') { raise ArgumentError }
         
     | 
| 
      
 1114 
     | 
    
         
            +
             
     | 
| 
      
 1115 
     | 
    
         
            +
                  get '/rescue_method'
         
     | 
| 
      
 1116 
     | 
    
         
            +
                  last_response.status.should == 400
         
     | 
| 
      
 1117 
     | 
    
         
            +
                  last_response.body.should == 'rescued with a method'
         
     | 
| 
      
 1118 
     | 
    
         
            +
                end
         
     | 
| 
      
 1119 
     | 
    
         
            +
              end
         
     | 
| 
      
 1120 
     | 
    
         
            +
             
     | 
| 
       1077 
1121 
     | 
    
         
             
              describe '.error_format' do
         
     | 
| 
       1078 
1122 
     | 
    
         
             
                it 'rescues all errors and return :txt' do
         
     | 
| 
       1079 
1123 
     | 
    
         
             
                  subject.rescue_from :all
         
     | 
| 
         @@ -1139,6 +1183,27 @@ describe Grape::API do 
     | 
|
| 
       1139 
1183 
     | 
    
         
             
                  end
         
     | 
| 
       1140 
1184 
     | 
    
         
             
                end
         
     | 
| 
       1141 
1185 
     | 
    
         | 
| 
      
 1186 
     | 
    
         
            +
                describe 'with' do
         
     | 
| 
      
 1187 
     | 
    
         
            +
                  context 'class' do
         
     | 
| 
      
 1188 
     | 
    
         
            +
                    before :each do
         
     | 
| 
      
 1189 
     | 
    
         
            +
                      class CustomErrorFormatter
         
     | 
| 
      
 1190 
     | 
    
         
            +
                        def self.call(message, backtrace, option, env)
         
     | 
| 
      
 1191 
     | 
    
         
            +
                          "message: #{message} @backtrace"
         
     | 
| 
      
 1192 
     | 
    
         
            +
                        end
         
     | 
| 
      
 1193 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1194 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1195 
     | 
    
         
            +
             
     | 
| 
      
 1196 
     | 
    
         
            +
                    it 'returns a custom error format' do
         
     | 
| 
      
 1197 
     | 
    
         
            +
                      subject.rescue_from :all, backtrace: true
         
     | 
| 
      
 1198 
     | 
    
         
            +
                      subject.error_formatter :txt, with: CustomErrorFormatter
         
     | 
| 
      
 1199 
     | 
    
         
            +
                      subject.get('/exception') { raise "rain!" }
         
     | 
| 
      
 1200 
     | 
    
         
            +
             
     | 
| 
      
 1201 
     | 
    
         
            +
                      get '/exception'
         
     | 
| 
      
 1202 
     | 
    
         
            +
                      last_response.body.should == 'message: rain! @backtrace'
         
     | 
| 
      
 1203 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1205 
     | 
    
         
            +
                end
         
     | 
| 
      
 1206 
     | 
    
         
            +
             
     | 
| 
       1142 
1207 
     | 
    
         
             
                it 'rescues all errors and return :json' do
         
     | 
| 
       1143 
1208 
     | 
    
         
             
                  subject.rescue_from :all
         
     | 
| 
       1144 
1209 
     | 
    
         
             
                  subject.format :json
         
     |