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
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            !binary "U0hBMQ==":
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: !binary |-
         
     | 
| 
      
 4 
     | 
    
         
            +
                Y2ZhNWZiZWQ4YjIwNmY5MDk1NmQxODgxM2FiZDA0NTE3ZDlmZmNiYQ==
         
     | 
| 
      
 5 
     | 
    
         
            +
              data.tar.gz: !binary |-
         
     | 
| 
      
 6 
     | 
    
         
            +
                MTE5MjU2MWY2MWZlNGI1ODQzNDExMDZjOTNmZjRiYzc3ZDY4ODZlMg==
         
     | 
| 
      
 7 
     | 
    
         
            +
            !binary "U0hBNTEy":
         
     | 
| 
      
 8 
     | 
    
         
            +
              metadata.gz: !binary |-
         
     | 
| 
      
 9 
     | 
    
         
            +
                MDlhYjA4YWQ1OThhMGFhNTc3ZjUwNzI4N2FiNmY2ZmNlOGM3MjQ5YjE2OWMy
         
     | 
| 
      
 10 
     | 
    
         
            +
                NzcxODEwZmY3Y2I5ZmVkOTk5ZWViMTNkZmE3NGM3MjMyOTAzZTdmMTg5MWZm
         
     | 
| 
      
 11 
     | 
    
         
            +
                ZmI1Njk0ZjRlMGIwOGFkY2EzZDJhZTMxMDQ0MzcyMDM4Y2UxMGY=
         
     | 
| 
      
 12 
     | 
    
         
            +
              data.tar.gz: !binary |-
         
     | 
| 
      
 13 
     | 
    
         
            +
                OWU4MGUxOGJkYzRjYzhkZmQyMzFkMWU1NTk3ZTllMTRkZDkyOTA0YjcwODg3
         
     | 
| 
      
 14 
     | 
    
         
            +
                YWNiNWY0ZDQzZWUxNmI4MmYxZGQzOWJmMTFiZDg0YTFiNzMyYzA5ODBhMDYz
         
     | 
| 
      
 15 
     | 
    
         
            +
                ZWRiN2FmY2FhM2FjNjQ1ZWM2NjMwNWI1YmU1Y2NhYjA1NGI2MDg=
         
     | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            0.6.0 (9/16/2013)
         
     | 
| 
      
 2 
     | 
    
         
            +
            =================
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            #### Features
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            * Grape is no longer tested against Ruby 1.8.7.
         
     | 
| 
      
 7 
     | 
    
         
            +
            * [#442](https://github.com/intridea/grape/issues/442): Enable incrementally building on top of a previous API version - [@dblock](https://github.com/dblock).
         
     | 
| 
      
 8 
     | 
    
         
            +
            * [#442](https://github.com/intridea/grape/issues/442): API `version` can now take an array of multiple versions - [@dblock](https://github.com/dblock).
         
     | 
| 
      
 9 
     | 
    
         
            +
            * [#444](https://github.com/intridea/grape/issues/444): Added `:en` as fallback locale for I18n - [@aew](https://github.com/aew).
         
     | 
| 
      
 10 
     | 
    
         
            +
            * [#448](https://github.com/intridea/grape/pull/448): Adding POST style parameters for DELETE requests - [@dquimper](https://github.com/dquimper).
         
     | 
| 
      
 11 
     | 
    
         
            +
            * [#450](https://github.com/intridea/grape/pull/450): Added option to pass an exception handler lambda as an argument to `rescue_from` - [@robertopedroso](https://github.com/robertopedroso).
         
     | 
| 
      
 12 
     | 
    
         
            +
            * [#443](https://github.com/intridea/grape/pull/443): Let `requires` and `optional` take blocks that initialize new scopes - [@asross](https://github.com/asross).
         
     | 
| 
      
 13 
     | 
    
         
            +
            * [#452](https://github.com/intridea/grape/pull/452): Added `with` as a hash option to specify handlers for `rescue_from` and `error_formatter` [@robertopedroso](https://github.com/robertopedroso).
         
     | 
| 
      
 14 
     | 
    
         
            +
            * [#433](https://github.com/intridea/grape/issues/433), [#462](https://github.com/intridea/grape/issues/462): API change: validation errors are now collected and `Grape::Exceptions::ValidationErrors` is raised - [@stevschmid](https://github.com/stevschmid).
         
     | 
| 
      
 15 
     | 
    
         
            +
            * Your contribution here.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            #### Fixes
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            * [#428](https://github.com/intridea/grape/issues/428): Removes memoization from `Grape::Request` params to prevent middleware from freezing parameter values before `Formatter` can get them - [@mbleigh](https://github.com/mbleigh).
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
       1 
21 
     | 
    
         
             
            0.5.0 (6/14/2013)
         
     | 
| 
       2 
22 
     | 
    
         
             
            =================
         
     | 
| 
       3 
23 
     | 
    
         | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -10,6 +10,10 @@ content negotiation, versioning and much more. 
     | 
|
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            [](http://travis-ci.org/intridea/grape) [](https://codeclimate.com/github/intridea/grape)
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
      
 13 
     | 
    
         
            +
            ## Stable Release
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            You're reading the documentation for the stable release of Grape, 0.6.0.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       13 
17 
     | 
    
         
             
            ## Project Resources
         
     | 
| 
       14 
18 
     | 
    
         | 
| 
       15 
19 
     | 
    
         
             
            * Need help? [Grape Google Group](http://groups.google.com/group/ruby-grape)
         
     | 
| 
         @@ -221,7 +225,7 @@ version 'v1', using: :header, vendor: 'twitter' 
     | 
|
| 
       221 
225 
     | 
    
         | 
| 
       222 
226 
     | 
    
         
             
            Using this versioning strategy, clients should pass the desired version in the HTTP `Accept` head.
         
     | 
| 
       223 
227 
     | 
    
         | 
| 
       224 
     | 
    
         
            -
                curl -H Accept 
     | 
| 
      
 228 
     | 
    
         
            +
                curl -H Accept:application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
         
     | 
| 
       225 
229 
     | 
    
         | 
| 
       226 
230 
     | 
    
         
             
            By default, the first matching version is used when no `Accept` header is
         
     | 
| 
       227 
231 
     | 
    
         
             
            supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
         
     | 
| 
         @@ -236,7 +240,7 @@ version 'v1', using: :accept_version_header 
     | 
|
| 
       236 
240 
     | 
    
         | 
| 
       237 
241 
     | 
    
         
             
            Using this versioning strategy, clients should pass the desired version in the HTTP `Accept-Version` header.
         
     | 
| 
       238 
242 
     | 
    
         | 
| 
       239 
     | 
    
         
            -
                curl -H "Accept-Version 
     | 
| 
      
 243 
     | 
    
         
            +
                curl -H "Accept-Version:v1" http://localhost:9292/statuses/public_timeline
         
     | 
| 
       240 
244 
     | 
    
         | 
| 
       241 
245 
     | 
    
         
             
            By default, the first matching version is used when no `Accept-Version` header is
         
     | 
| 
       242 
246 
     | 
    
         
             
            supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
         
     | 
| 
         @@ -329,6 +333,9 @@ params do 
     | 
|
| 
       329 
333 
     | 
    
         
             
              group :media do
         
     | 
| 
       330 
334 
     | 
    
         
             
                requires :url
         
     | 
| 
       331 
335 
     | 
    
         
             
              end
         
     | 
| 
      
 336 
     | 
    
         
            +
              optional :audio do
         
     | 
| 
      
 337 
     | 
    
         
            +
                requires :mp3
         
     | 
| 
      
 338 
     | 
    
         
            +
              end
         
     | 
| 
       332 
339 
     | 
    
         
             
            end
         
     | 
| 
       333 
340 
     | 
    
         
             
            put ':id' do
         
     | 
| 
       334 
341 
     | 
    
         
             
              # params[:id] is an Integer
         
     | 
| 
         @@ -346,8 +353,9 @@ params do 
     | 
|
| 
       346 
353 
     | 
    
         
             
            end
         
     | 
| 
       347 
354 
     | 
    
         
             
            ```
         
     | 
| 
       348 
355 
     | 
    
         | 
| 
       349 
     | 
    
         
            -
            Parameters can be nested using `group 
     | 
| 
       350 
     | 
    
         
            -
            `params[:media][:url]` is required along with `params[:id] 
     | 
| 
      
 356 
     | 
    
         
            +
            Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
         
     | 
| 
      
 357 
     | 
    
         
            +
            In the above example, this means `params[:media][:url]` is required along with `params[:id]`,
         
     | 
| 
      
 358 
     | 
    
         
            +
            and `params[:audio][:mp3]` is required only if `params[:audio]` is present.
         
     | 
| 
       351 
359 
     | 
    
         | 
| 
       352 
360 
     | 
    
         
             
            ### Namespace Validation and Coercion
         
     | 
| 
       353 
361 
     | 
    
         | 
| 
         @@ -379,7 +387,7 @@ The `namespace` method has a number of aliases, including: `group`, `resource`, 
     | 
|
| 
       379 
387 
     | 
    
         
             
            class AlphaNumeric < Grape::Validations::Validator
         
     | 
| 
       380 
388 
     | 
    
         
             
              def validate_param!(attr_name, params)
         
     | 
| 
       381 
389 
     | 
    
         
             
                unless params[attr_name] =~ /^[[:alnum:]]+$/
         
     | 
| 
       382 
     | 
    
         
            -
                   
     | 
| 
      
 390 
     | 
    
         
            +
                  raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message: "must consist of alpha-numeric characters"
         
     | 
| 
       383 
391 
     | 
    
         
             
                end
         
     | 
| 
       384 
392 
     | 
    
         
             
              end
         
     | 
| 
       385 
393 
     | 
    
         
             
            end
         
     | 
| 
         @@ -397,7 +405,7 @@ You can also create custom classes that take parameters. 
     | 
|
| 
       397 
405 
     | 
    
         
             
            class Length < Grape::Validations::SingleOptionValidator
         
     | 
| 
       398 
406 
     | 
    
         
             
              def validate_param!(attr_name, params)
         
     | 
| 
       399 
407 
     | 
    
         
             
                unless params[attr_name].length <= @option
         
     | 
| 
       400 
     | 
    
         
            -
                   
     | 
| 
      
 408 
     | 
    
         
            +
                  raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message: "must be at the most #{@option} characters long"
         
     | 
| 
       401 
409 
     | 
    
         
             
                end
         
     | 
| 
       402 
410 
     | 
    
         
             
              end
         
     | 
| 
       403 
411 
     | 
    
         
             
            end
         
     | 
| 
         @@ -411,20 +419,28 @@ end 
     | 
|
| 
       411 
419 
     | 
    
         | 
| 
       412 
420 
     | 
    
         
             
            ### Validation Errors
         
     | 
| 
       413 
421 
     | 
    
         | 
| 
       414 
     | 
    
         
            -
             
     | 
| 
      
 422 
     | 
    
         
            +
            Validation and coercion errors are collected and an exception of type `Grape::Exceptions::ValidationErrors` is raised.
         
     | 
| 
       415 
423 
     | 
    
         
             
            If the exception goes uncaught it will respond with a status of 400 and an error message.
         
     | 
| 
       416 
     | 
    
         
            -
            You can rescue a `Grape::Exceptions:: 
     | 
| 
      
 424 
     | 
    
         
            +
            You can rescue a `Grape::Exceptions::ValidationErrors` and respond with a custom response.
         
     | 
| 
       417 
425 
     | 
    
         | 
| 
       418 
426 
     | 
    
         
             
            ```ruby
         
     | 
| 
       419 
     | 
    
         
            -
            rescue_from Grape::Exceptions:: 
     | 
| 
      
 427 
     | 
    
         
            +
            rescue_from Grape::Exceptions::ValidationErrors do |e|
         
     | 
| 
       420 
428 
     | 
    
         
             
                Rack::Response.new({
         
     | 
| 
       421 
429 
     | 
    
         
             
                    'status' => e.status,
         
     | 
| 
       422 
430 
     | 
    
         
             
                    'message' => e.message,
         
     | 
| 
       423 
     | 
    
         
            -
                    ' 
     | 
| 
      
 431 
     | 
    
         
            +
                    'errors' => e.errors
         
     | 
| 
       424 
432 
     | 
    
         
             
                }.to_json, e.status)
         
     | 
| 
       425 
433 
     | 
    
         
             
            end
         
     | 
| 
       426 
434 
     | 
    
         
             
            ```
         
     | 
| 
       427 
435 
     | 
    
         | 
| 
      
 436 
     | 
    
         
            +
            The validation errors are grouped by parameter name and can be accessed via ``Grape::Exceptions::ValidationErrors#errors``.
         
     | 
| 
      
 437 
     | 
    
         
            +
             
     | 
| 
      
 438 
     | 
    
         
            +
            ### I18n
         
     | 
| 
      
 439 
     | 
    
         
            +
             
     | 
| 
      
 440 
     | 
    
         
            +
            Grape supports I18n for parameter-related error messages, but will fallback to English if
         
     | 
| 
      
 441 
     | 
    
         
            +
            translations for the default locale have not been provided. See [en.yml](lib/grape/locale/en.yml) for message keys.
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
       428 
444 
     | 
    
         
             
            ## Headers
         
     | 
| 
       429 
445 
     | 
    
         | 
| 
       430 
446 
     | 
    
         
             
            Request headers are available through the `headers` helper or from `env` in their original form.
         
     | 
| 
         @@ -629,9 +645,23 @@ You can also return JSON formatted objects by raising error! and passing a hash 
     | 
|
| 
       629 
645 
     | 
    
         
             
            instead of a message.
         
     | 
| 
       630 
646 
     | 
    
         | 
| 
       631 
647 
     | 
    
         
             
            ```ruby
         
     | 
| 
       632 
     | 
    
         
            -
            error! 
     | 
| 
      
 648 
     | 
    
         
            +
            error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
         
     | 
| 
       633 
649 
     | 
    
         
             
            ```
         
     | 
| 
       634 
650 
     | 
    
         | 
| 
      
 651 
     | 
    
         
            +
            ### Handling 404
         
     | 
| 
      
 652 
     | 
    
         
            +
             
     | 
| 
      
 653 
     | 
    
         
            +
            For Grape to handle all the 404s for your API, it can be useful to use a catch-all.
         
     | 
| 
      
 654 
     | 
    
         
            +
            In its simplest form, it can be like:
         
     | 
| 
      
 655 
     | 
    
         
            +
             
     | 
| 
      
 656 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 657 
     | 
    
         
            +
            route :any, '*path' do
         
     | 
| 
      
 658 
     | 
    
         
            +
              error! # or something else
         
     | 
| 
      
 659 
     | 
    
         
            +
            end
         
     | 
| 
      
 660 
     | 
    
         
            +
            ```
         
     | 
| 
      
 661 
     | 
    
         
            +
             
     | 
| 
      
 662 
     | 
    
         
            +
            It is very crucial to __define this endpoint at the very end of your API__, as it
         
     | 
| 
      
 663 
     | 
    
         
            +
            literally accepts every request.
         
     | 
| 
      
 664 
     | 
    
         
            +
             
     | 
| 
       635 
665 
     | 
    
         
             
            ## Exception Handling
         
     | 
| 
       636 
666 
     | 
    
         | 
| 
       637 
667 
     | 
    
         
             
            Grape can be told to rescue all exceptions and return them in the API format.
         
     | 
| 
         @@ -1045,6 +1075,8 @@ You can use any Hypermedia representer, including [Roar](https://github.com/apot 
     | 
|
| 
       1045 
1075 
     | 
    
         
             
            Roar renders JSON and works with the built-in Grape JSON formatter. Add `Roar::Representer::JSON`
         
     | 
| 
       1046 
1076 
     | 
    
         
             
            into your models or call `to_json` explicitly in your API implementation.
         
     | 
| 
       1047 
1077 
     | 
    
         | 
| 
      
 1078 
     | 
    
         
            +
            Other alternatives include `ActiveModel::Serializers` via [grape-active_model_serializers](https://github.com/jrhe/grape-active_model_serializers).
         
     | 
| 
      
 1079 
     | 
    
         
            +
             
     | 
| 
       1048 
1080 
     | 
    
         
             
            ### Rabl
         
     | 
| 
       1049 
1081 
     | 
    
         | 
| 
       1050 
1082 
     | 
    
         
             
            You can use [Rabl](https://github.com/nesquena/rabl) templates with the help of the
         
     | 
    
        data/lib/grape.rb
    CHANGED
    
    | 
         @@ -22,8 +22,12 @@ I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__) 
     | 
|
| 
       22 
22 
     | 
    
         
             
            module Grape
         
     | 
| 
       23 
23 
     | 
    
         
             
              autoload :API,                 'grape/api'
         
     | 
| 
       24 
24 
     | 
    
         
             
              autoload :Endpoint,            'grape/endpoint'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       25 
26 
     | 
    
         
             
              autoload :Route,               'grape/route'
         
     | 
| 
       26 
27 
     | 
    
         
             
              autoload :Namespace,           'grape/namespace'
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              autoload :Path,                'grape/path'
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       27 
31 
     | 
    
         
             
              autoload :Cookies,             'grape/cookies'
         
     | 
| 
       28 
32 
     | 
    
         
             
              autoload :Validations,         'grape/validations'
         
     | 
| 
       29 
33 
     | 
    
         
             
              autoload :Request,             'grape/http/request'
         
     | 
| 
         @@ -31,6 +35,7 @@ module Grape 
     | 
|
| 
       31 
35 
     | 
    
         
             
              module Exceptions
         
     | 
| 
       32 
36 
     | 
    
         
             
                autoload :Base,                           'grape/exceptions/base'
         
     | 
| 
       33 
37 
     | 
    
         
             
                autoload :Validation,                     'grape/exceptions/validation'
         
     | 
| 
      
 38 
     | 
    
         
            +
                autoload :ValidationErrors,               'grape/exceptions/validation_errors'
         
     | 
| 
       34 
39 
     | 
    
         
             
                autoload :MissingVendorOption,            'grape/exceptions/missing_vendor_option'
         
     | 
| 
       35 
40 
     | 
    
         
             
                autoload :MissingMimeType,                'grape/exceptions/missing_mime_type'
         
     | 
| 
       36 
41 
     | 
    
         
             
                autoload :MissingOption,                  'grape/exceptions/missing_option'
         
     | 
| 
         @@ -70,6 +75,7 @@ module Grape 
     | 
|
| 
       70 
75 
     | 
    
         | 
| 
       71 
76 
     | 
    
         
             
                module Auth
         
     | 
| 
       72 
77 
     | 
    
         
             
                  autoload :OAuth2,         'grape/middleware/auth/oauth2'
         
     | 
| 
      
 78 
     | 
    
         
            +
                  autoload :Base,	          'grape/middleware/auth/base'
         
     | 
| 
       73 
79 
     | 
    
         
             
                  autoload :Basic,          'grape/middleware/auth/basic'
         
     | 
| 
       74 
80 
     | 
    
         
             
                  autoload :Digest,	        'grape/middleware/auth/digest'
         
     | 
| 
       75 
81 
     | 
    
         
             
                end
         
     | 
    
        data/lib/grape/api.rb
    CHANGED
    
    | 
         @@ -6,14 +6,8 @@ module Grape 
     | 
|
| 
       6 
6 
     | 
    
         
             
                extend Validations::ClassMethods
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                class << self
         
     | 
| 
       9 
     | 
    
         
            -
                  attr_reader :route_set
         
     | 
| 
       10 
     | 
    
         
            -
                  attr_reader :versions
         
     | 
| 
       11 
     | 
    
         
            -
                  attr_reader :routes
         
     | 
| 
       12 
     | 
    
         
            -
                  attr_reader :settings
         
     | 
| 
      
 9 
     | 
    
         
            +
                  attr_reader :endpoints, :instance, :routes, :route_set, :settings, :versions
         
     | 
| 
       13 
10 
     | 
    
         
             
                  attr_writer :logger
         
     | 
| 
       14 
     | 
    
         
            -
                  attr_reader :endpoints
         
     | 
| 
       15 
     | 
    
         
            -
                  attr_reader :mountings
         
     | 
| 
       16 
     | 
    
         
            -
                  attr_reader :instance
         
     | 
| 
       17 
11 
     | 
    
         | 
| 
       18 
12 
     | 
    
         
             
                  def logger(logger = nil)
         
     | 
| 
       19 
13 
     | 
    
         
             
                    if logger
         
     | 
| 
         @@ -27,7 +21,6 @@ module Grape 
     | 
|
| 
       27 
21 
     | 
    
         
             
                    @settings  = Grape::Util::HashStack.new
         
     | 
| 
       28 
22 
     | 
    
         
             
                    @route_set = Rack::Mount::RouteSet.new
         
     | 
| 
       29 
23 
     | 
    
         
             
                    @endpoints = []
         
     | 
| 
       30 
     | 
    
         
            -
                    @mountings = []
         
     | 
| 
       31 
24 
     | 
    
         
             
                    @routes = nil
         
     | 
| 
       32 
25 
     | 
    
         
             
                    reset_validations!
         
     | 
| 
       33 
26 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -158,8 +151,14 @@ module Grape 
     | 
|
| 
       158 
151 
     | 
    
         
             
                    new_formatter ? set(:default_error_formatter, new_formatter) : settings[:default_error_formatter]
         
     | 
| 
       159 
152 
     | 
    
         
             
                  end
         
     | 
| 
       160 
153 
     | 
    
         | 
| 
       161 
     | 
    
         
            -
                  def error_formatter(format,  
     | 
| 
       162 
     | 
    
         
            -
                     
     | 
| 
      
 154 
     | 
    
         
            +
                  def error_formatter(format, options)
         
     | 
| 
      
 155 
     | 
    
         
            +
                    if options.is_a?(Hash) && options.has_key?(:with)
         
     | 
| 
      
 156 
     | 
    
         
            +
                      formatter = options[:with]
         
     | 
| 
      
 157 
     | 
    
         
            +
                    else
         
     | 
| 
      
 158 
     | 
    
         
            +
                      formatter = options
         
     | 
| 
      
 159 
     | 
    
         
            +
                    end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                    settings.imbue(:error_formatters, format.to_sym => formatter)
         
     | 
| 
       163 
162 
     | 
    
         
             
                  end
         
     | 
| 
       164 
163 
     | 
    
         | 
| 
       165 
164 
     | 
    
         
             
                  # Specify additional content-types, e.g.:
         
     | 
| 
         @@ -195,13 +194,27 @@ module Grape 
     | 
|
| 
       195 
194 
     | 
    
         
             
                  #   @param [Block] block Execution block to handle the given exception.
         
     | 
| 
       196 
195 
     | 
    
         
             
                  #   @param [Hash] options Options for the rescue usage.
         
     | 
| 
       197 
196 
     | 
    
         
             
                  #   @option options [Boolean] :backtrace Include a backtrace in the rescue response.
         
     | 
| 
      
 197 
     | 
    
         
            +
                  #   @param [Proc] handler Execution proc to handle the given exception as an
         
     | 
| 
      
 198 
     | 
    
         
            +
                  #     alternative to passing a block
         
     | 
| 
       198 
199 
     | 
    
         
             
                  def rescue_from(*args, &block)
         
     | 
| 
       199 
     | 
    
         
            -
                    if  
     | 
| 
      
 200 
     | 
    
         
            +
                    if args.last.is_a?(Proc)
         
     | 
| 
      
 201 
     | 
    
         
            +
                      handler = args.pop
         
     | 
| 
      
 202 
     | 
    
         
            +
                    elsif block_given?
         
     | 
| 
      
 203 
     | 
    
         
            +
                      handler = block
         
     | 
| 
      
 204 
     | 
    
         
            +
                    end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                    options = args.last.is_a?(Hash) ? args.pop : {}
         
     | 
| 
      
 207 
     | 
    
         
            +
                    if options.has_key?(:with)
         
     | 
| 
      
 208 
     | 
    
         
            +
                      handler ||= proc { options[:with] }
         
     | 
| 
      
 209 
     | 
    
         
            +
                    end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                    if handler
         
     | 
| 
       200 
212 
     | 
    
         
             
                      args.each do |arg|
         
     | 
| 
       201 
     | 
    
         
            -
                        imbue(:rescue_handlers, { arg =>  
     | 
| 
      
 213 
     | 
    
         
            +
                        imbue(:rescue_handlers, { arg => handler })
         
     | 
| 
       202 
214 
     | 
    
         
             
                      end
         
     | 
| 
       203 
215 
     | 
    
         
             
                    end
         
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                    imbue(:rescue_options, options)
         
     | 
| 
       205 
218 
     | 
    
         
             
                    set(:rescue_all, true) and return if args.include?(:all)
         
     | 
| 
       206 
219 
     | 
    
         
             
                    imbue(:rescued_errors, args)
         
     | 
| 
       207 
220 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -422,7 +435,7 @@ module Grape 
     | 
|
| 
       422 
435 
     | 
    
         
             
                  end
         
     | 
| 
       423 
436 
     | 
    
         | 
| 
       424 
437 
     | 
    
         
             
                  def cascade(value = nil)
         
     | 
| 
       425 
     | 
    
         
            -
                    value.nil? ? 
     | 
| 
      
 438 
     | 
    
         
            +
                    value.nil? ?
         
     | 
| 
       426 
439 
     | 
    
         
             
                      (settings.has_key?(:cascade) ? !! settings[:cascade] : true) :
         
     | 
| 
       427 
440 
     | 
    
         
             
                      set(:cascade, value)
         
     | 
| 
       428 
441 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/grape/endpoint.rb
    CHANGED
    
    | 
         @@ -33,27 +33,34 @@ module Grape 
     | 
|
| 
       33 
33 
     | 
    
         
             
                end
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
                def initialize(settings, options = {}, &block)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  require_option(options, :path)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  require_option(options, :method)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       36 
39 
     | 
    
         
             
                  @settings = settings
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @options = options
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  @options[:path] = Array(options[:path])
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @options[:path] << '/' if options[:path].empty?
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  @options[:method] = Array(options[:method])
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @options[:route_options] ||= {}
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       37 
48 
     | 
    
         
             
                  if block_given?
         
     | 
| 
       38 
     | 
    
         
            -
                    method_name = [
         
     | 
| 
       39 
     | 
    
         
            -
                      options[:method],
         
     | 
| 
       40 
     | 
    
         
            -
                      Namespace.joined_space(settings),
         
     | 
| 
       41 
     | 
    
         
            -
                      settings.gather(:mount_path).join("/"),
         
     | 
| 
       42 
     | 
    
         
            -
                      Array(options[:path]).join("/")
         
     | 
| 
       43 
     | 
    
         
            -
                    ].join(" ")
         
     | 
| 
       44 
49 
     | 
    
         
             
                    @source = block
         
     | 
| 
       45 
50 
     | 
    
         
             
                    @block = self.class.generate_api_method(method_name, &block)
         
     | 
| 
       46 
51 
     | 
    
         
             
                  end
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                  raise Grape::Exceptions::MissingOption.new(:path) unless options.key?(:path)
         
     | 
| 
       50 
     | 
    
         
            -
                  options[:path] = Array(options[:path])
         
     | 
| 
       51 
     | 
    
         
            -
                  options[:path] = ['/'] if options[:path].empty?
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
       52 
53 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                  options 
     | 
| 
      
 54 
     | 
    
         
            +
                def require_option(options, key)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  options.has_key?(key) or raise Grape::Exceptions::MissingOption.new(key)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
       55 
57 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
      
 58 
     | 
    
         
            +
                def method_name
         
     | 
| 
      
 59 
     | 
    
         
            +
                  [ options[:method],
         
     | 
| 
      
 60 
     | 
    
         
            +
                    Namespace.joined_space(settings),
         
     | 
| 
      
 61 
     | 
    
         
            +
                    settings.gather(:mount_path).join('/'),
         
     | 
| 
      
 62 
     | 
    
         
            +
                    options[:path].join('/')
         
     | 
| 
      
 63 
     | 
    
         
            +
                  ].join(" ")
         
     | 
| 
       57 
64 
     | 
    
         
             
                end
         
     | 
| 
       58 
65 
     | 
    
         | 
| 
       59 
66 
     | 
    
         
             
                def routes
         
     | 
| 
         @@ -120,24 +127,7 @@ module Grape 
     | 
|
| 
       120 
127 
     | 
    
         
             
                end
         
     | 
| 
       121 
128 
     | 
    
         | 
| 
       122 
129 
     | 
    
         
             
                def prepare_path(path)
         
     | 
| 
       123 
     | 
    
         
            -
                   
     | 
| 
       124 
     | 
    
         
            -
                  parts << settings[:mount_path].to_s.split("/") if settings[:mount_path]
         
     | 
| 
       125 
     | 
    
         
            -
                  parts << settings[:root_prefix].to_s.split("/") if settings[:root_prefix]
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                  uses_path_versioning = settings[:version] && settings[:version_options][:using] == :path
         
     | 
| 
       128 
     | 
    
         
            -
                  namespace_is_empty = namespace && (namespace.to_s =~ /^\s*$/ || namespace.to_s == '/')
         
     | 
| 
       129 
     | 
    
         
            -
                  path_is_empty = path && (path.to_s =~ /^\s*$/ || path.to_s == '/')
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                  parts << ':version' if uses_path_versioning
         
     | 
| 
       132 
     | 
    
         
            -
                  if ! uses_path_versioning || (! namespace_is_empty || ! path_is_empty)
         
     | 
| 
       133 
     | 
    
         
            -
                    parts << namespace.to_s if namespace
         
     | 
| 
       134 
     | 
    
         
            -
                    parts << path.to_s if path
         
     | 
| 
       135 
     | 
    
         
            -
                    format_suffix = '(.:format)'
         
     | 
| 
       136 
     | 
    
         
            -
                  else
         
     | 
| 
       137 
     | 
    
         
            -
                    format_suffix = '(/.:format)'
         
     | 
| 
       138 
     | 
    
         
            -
                  end
         
     | 
| 
       139 
     | 
    
         
            -
                  parts = parts.flatten.select { |part| part != '/' }
         
     | 
| 
       140 
     | 
    
         
            -
                  Rack::Mount::Utils.normalize_path(parts.join('/') + format_suffix)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  Path.prepare(path, namespace, settings)
         
     | 
| 
       141 
131 
     | 
    
         
             
                end
         
     | 
| 
       142 
132 
     | 
    
         | 
| 
       143 
133 
     | 
    
         
             
                def namespace
         
     | 
| 
         @@ -391,8 +381,17 @@ module Grape 
     | 
|
| 
       391 
381 
     | 
    
         
             
                  run_filters befores
         
     | 
| 
       392 
382 
     | 
    
         | 
| 
       393 
383 
     | 
    
         
             
                  # Retieve validations from this namespace and all parent namespaces.
         
     | 
| 
      
 384 
     | 
    
         
            +
                  validation_errors = []
         
     | 
| 
       394 
385 
     | 
    
         
             
                  settings.gather(:validations).each do |validator|
         
     | 
| 
       395 
     | 
    
         
            -
                     
     | 
| 
      
 386 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 387 
     | 
    
         
            +
                      validator.validate!(params)
         
     | 
| 
      
 388 
     | 
    
         
            +
                    rescue Grape::Exceptions::Validation => e
         
     | 
| 
      
 389 
     | 
    
         
            +
                      validation_errors << e
         
     | 
| 
      
 390 
     | 
    
         
            +
                    end
         
     | 
| 
      
 391 
     | 
    
         
            +
                  end
         
     | 
| 
      
 392 
     | 
    
         
            +
             
     | 
| 
      
 393 
     | 
    
         
            +
                  if validation_errors.any?
         
     | 
| 
      
 394 
     | 
    
         
            +
                    raise Grape::Exceptions::ValidationErrors, errors: validation_errors
         
     | 
| 
       396 
395 
     | 
    
         
             
                  end
         
     | 
| 
       397 
396 
     | 
    
         | 
| 
       398 
397 
     | 
    
         
             
                  run_filters after_validations
         
     | 
| 
         @@ -433,7 +432,7 @@ module Grape 
     | 
|
| 
       433 
432 
     | 
    
         | 
| 
       434 
433 
     | 
    
         
             
                  if settings[:version]
         
     | 
| 
       435 
434 
     | 
    
         
             
                    b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]), {
         
     | 
| 
       436 
     | 
    
         
            -
                      :versions        => settings[:version],
         
     | 
| 
      
 435 
     | 
    
         
            +
                      :versions        => settings[:version] ? settings[:version].flatten : nil,
         
     | 
| 
       437 
436 
     | 
    
         
             
                      :version_options => settings[:version_options],
         
     | 
| 
       438 
437 
     | 
    
         
             
                      :prefix          => settings[:root_prefix]
         
     | 
| 
       439 
438 
     | 
    
         
             
                    }
         
     | 
| 
         @@ -4,6 +4,7 @@ module Grape 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
                  BASE_MESSAGES_KEY = 'grape.errors.messages'
         
     | 
| 
       6 
6 
     | 
    
         
             
                  BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
         
     | 
| 
      
 7 
     | 
    
         
            +
                  FALLBACK_LOCALE = :en
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
                  attr_reader :status, :message, :headers
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
         @@ -54,11 +55,12 @@ module Grape 
     | 
|
| 
       54 
55 
     | 
    
         
             
                  end
         
     | 
| 
       55 
56 
     | 
    
         | 
| 
       56 
57 
     | 
    
         
             
                  def translate_message(key, options = {})
         
     | 
| 
       57 
     | 
    
         
            -
                    translate("#{BASE_MESSAGES_KEY}.#{key}", {:default => '' }.merge(options))
         
     | 
| 
      
 58 
     | 
    
         
            +
                    translate("#{BASE_MESSAGES_KEY}.#{key}", { :default => '' }.merge(options))
         
     | 
| 
       58 
59 
     | 
    
         
             
                  end
         
     | 
| 
       59 
60 
     | 
    
         | 
| 
       60 
61 
     | 
    
         
             
                  def translate(key, options = {})
         
     | 
| 
       61 
     | 
    
         
            -
                    ::I18n.translate(key, options)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    message = ::I18n.translate(key, options)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    message.present? ? message : ::I18n.translate(key, options.merge({:locale => FALLBACK_LOCALE}))
         
     | 
| 
       62 
64 
     | 
    
         
             
                  end
         
     | 
| 
       63 
65 
     | 
    
         | 
| 
       64 
66 
     | 
    
         
             
                end
         
     | 
| 
         @@ -6,11 +6,21 @@ module Grape 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  attr_accessor :param
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                  def initialize(args = {})
         
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
       11 
     | 
    
         
            -
                    args[:message] = translate_message(args[:message_key] 
     | 
| 
      
 9 
     | 
    
         
            +
                    raise "Param is missing:" unless args.has_key? :param
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @param = args[:param]
         
     | 
| 
      
 11 
     | 
    
         
            +
                    args[:message] = translate_message(args[:message_key]) if args.has_key? :message_key
         
     | 
| 
       12 
12 
     | 
    
         
             
                    super
         
     | 
| 
       13 
13 
     | 
    
         
             
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # remove all the unnecessary stuff from Grape::Exceptions::Base like status
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # and headers when converting a validation error to json or string
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def as_json(*a)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    self.to_s
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 22 
     | 
    
         
            +
                    message
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
       14 
24 
     | 
    
         
             
                end
         
     | 
| 
       15 
25 
     | 
    
         
             
              end
         
     | 
| 
       16 
26 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'grape/exceptions/base'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Grape
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Exceptions
         
     | 
| 
      
 5 
     | 
    
         
            +
                class ValidationErrors < Grape::Exceptions::Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :errors
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(args = {})
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @errors = {}
         
     | 
| 
      
 12 
     | 
    
         
            +
                    args[:errors].each do |validation_error|
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @errors[validation_error.param] ||= []
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @errors[validation_error.param] << validation_error
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super message: full_messages.join(', '), status: 400
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def each
         
     | 
| 
      
 20 
     | 
    
         
            +
                    errors.each_pair do |attribute, errors|
         
     | 
| 
      
 21 
     | 
    
         
            +
                      errors.each do |error|
         
     | 
| 
      
 22 
     | 
    
         
            +
                        yield attribute, error
         
     | 
| 
      
 23 
     | 
    
         
            +
                      end
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  private
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def full_messages
         
     | 
| 
      
 30 
     | 
    
         
            +
                    map { |attribute, error| full_message(attribute, error) }
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def full_message(attribute, error)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    I18n.t(:"grape.errors.format", {
         
     | 
| 
      
 35 
     | 
    
         
            +
                      default:  "%{attribute} %{message}",
         
     | 
| 
      
 36 
     | 
    
         
            +
                      attribute: translate_attribute(attribute),
         
     | 
| 
      
 37 
     | 
    
         
            +
                      message:   error.message
         
     | 
| 
      
 38 
     | 
    
         
            +
                    })
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     |