grape 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (62) hide show
  1. checksums.yaml +5 -13
  2. data/.rubocop.yml +6 -6
  3. data/.travis.yml +11 -2
  4. data/CHANGELOG.md +23 -1
  5. data/Gemfile +11 -10
  6. data/Guardfile +5 -6
  7. data/README.md +194 -13
  8. data/UPGRADING.md +3 -3
  9. data/grape.gemspec +1 -1
  10. data/grape.png +0 -0
  11. data/lib/grape/api.rb +21 -13
  12. data/lib/grape/endpoint.rb +31 -13
  13. data/lib/grape/exceptions/validation.rb +2 -2
  14. data/lib/grape/locale/en.yml +2 -0
  15. data/lib/grape/middleware/auth/oauth2.rb +69 -65
  16. data/lib/grape/middleware/error.rb +4 -2
  17. data/lib/grape/middleware/formatter.rb +2 -2
  18. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
  19. data/lib/grape/middleware/versioner/header.rb +3 -3
  20. data/lib/grape/util/hash_stack.rb +1 -1
  21. data/lib/grape/validations.rb +22 -8
  22. data/lib/grape/validations/default.rb +1 -1
  23. data/lib/grape/validations/exactly_one_of.rb +26 -0
  24. data/lib/grape/validations/mutual_exclusion.rb +25 -0
  25. data/lib/grape/validations/presence.rb +1 -1
  26. data/lib/grape/validations/regexp.rb +2 -1
  27. data/lib/grape/validations/values.rb +7 -1
  28. data/lib/grape/version.rb +1 -1
  29. data/spec/grape/api_spec.rb +390 -333
  30. data/spec/grape/endpoint_spec.rb +129 -99
  31. data/spec/grape/entity_spec.rb +47 -27
  32. data/spec/grape/exceptions/invalid_formatter_spec.rb +1 -1
  33. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -1
  34. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -2
  35. data/spec/grape/exceptions/missing_option_spec.rb +1 -1
  36. data/spec/grape/exceptions/unknown_options_spec.rb +1 -1
  37. data/spec/grape/exceptions/unknown_validator_spec.rb +1 -1
  38. data/spec/grape/middleware/auth/basic_spec.rb +3 -3
  39. data/spec/grape/middleware/auth/digest_spec.rb +4 -4
  40. data/spec/grape/middleware/auth/oauth2_spec.rb +11 -11
  41. data/spec/grape/middleware/base_spec.rb +9 -9
  42. data/spec/grape/middleware/error_spec.rb +4 -4
  43. data/spec/grape/middleware/exception_spec.rb +17 -17
  44. data/spec/grape/middleware/formatter_spec.rb +38 -38
  45. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +11 -11
  46. data/spec/grape/middleware/versioner/header_spec.rb +39 -39
  47. data/spec/grape/middleware/versioner/param_spec.rb +10 -10
  48. data/spec/grape/middleware/versioner/path_spec.rb +7 -7
  49. data/spec/grape/middleware/versioner_spec.rb +4 -4
  50. data/spec/grape/path_spec.rb +6 -6
  51. data/spec/grape/util/hash_stack_spec.rb +22 -22
  52. data/spec/grape/validations/coerce_spec.rb +34 -34
  53. data/spec/grape/validations/default_spec.rb +16 -16
  54. data/spec/grape/validations/exactly_one_of_spec.rb +71 -0
  55. data/spec/grape/validations/mutual_exclusion_spec.rb +61 -0
  56. data/spec/grape/validations/presence_spec.rb +34 -34
  57. data/spec/grape/validations/regexp_spec.rb +11 -4
  58. data/spec/grape/validations/values_spec.rb +34 -20
  59. data/spec/grape/validations_spec.rb +300 -147
  60. data/spec/shared/versioning_examples.rb +18 -18
  61. data/spec/spec_helper.rb +2 -1
  62. metadata +81 -38
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NzU0ZDEzNjI0ZDhlMzg5M2YxOTMzMmU2NmUxMWIyZDYxMGM3ODBiNQ==
5
- data.tar.gz: !binary |-
6
- NmMwYmIxODY2ZmI0YzY5MzljYTM0NWE5MDM4MzAwZDQ3M2Y4MmYwNg==
2
+ SHA1:
3
+ metadata.gz: 16ab2241d8805f0449737830d3fb60b5ecf6a1e3
4
+ data.tar.gz: b2d2d3cce8167bac238d0d8ac770edac583b0a81
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ODgwYzYzMzlkNzJjMTgyYzkyMmQ3ZDhlNWEyNDRmMGNiZDMxZDI4NDIzZGRk
10
- NzEwNjdjYjI0MzkzNzE1M2QwM2ExZGM2NDRlMmFlNDJlZWY3NjljMGMxN2Zm
11
- OWNkMGM0ZGFkMDQwYzk1MDBlNDZkNjI4ZmJmZjM4M2Y3MmU4NDI=
12
- data.tar.gz: !binary |-
13
- N2Y5Y2NhNWQxMjNmYmZmMzJhZDQyMzE2NDY1ODRlNjVhNDc2ZjQxNTE4NjRl
14
- YzczZTk5NGUwZGQ1ZmJiNTUwNmQ5MTM1ZWVkNzA0M2JlNDZhNGVkM2MyNTM5
15
- Zjg2MzhkNGI5YjMxNzRlNWUyZDg1YzA2NjY4MjdkMWE4MTU1N2Y=
6
+ metadata.gz: ead66bb7118fdb6c173dcb4e9459a6385cd1ea984738e60c23754ff1c508d8562ff8d0a161ac7bebd14ec9afc22fd73170b7f15324facfc1ce79e6688d0a2d5b
7
+ data.tar.gz: 10be3eceb5dcd72fcf5952d4d8bac3fa0eb9eb1a3eb5f08fa14486a2e24dcf21b578886dc314f09b6227d12214fa8ba9326f488405e2082acf1397e397d24d88
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- Excludes:
2
+ Exclude:
3
3
  - vendor/**
4
4
  - bin/**
5
5
 
@@ -24,11 +24,6 @@ Encoding:
24
24
  # no need to always specify encoding
25
25
  Enabled: false
26
26
 
27
- HashMethods:
28
- # key? instead of has_key?
29
- # value? instead of has_value?
30
- Enabled: false
31
-
32
27
  StringLiterals:
33
28
  # use single or double-quoted strings, as you please
34
29
  Enabled: false
@@ -68,3 +63,8 @@ WordArray:
68
63
  CyclomaticComplexity:
69
64
  Enabled: false
70
65
 
66
+ DoubleNegation:
67
+ Enabled: false
68
+
69
+ PredicateName:
70
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,9 +1,18 @@
1
1
  language: ruby
2
+
2
3
  cache: bundler
3
- before_install:
4
- - gem install bundler -v '= 1.5.1'
4
+
5
5
  rvm:
6
+ - ruby-head
7
+ - 2.1.2
6
8
  - 2.1.0
7
9
  - 2.0.0
8
10
  - 1.9.3
9
11
  - jruby-19mode
12
+ - jruby-head
13
+ - rbx-2
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
data/CHANGELOG.md CHANGED
@@ -1,7 +1,29 @@
1
- 0.7.0 (4/2/2013)
1
+ 0.8.0 (7/10/2014)
2
2
  =================
3
3
 
4
4
  #### Features
5
+
6
+ * [#639](https://github.com/intridea/grape/pull/639): Added support for blocks with reusable params - [@mibon](https://github.com/mibon).
7
+ * [#637](https://github.com/intridea/grape/pull/637): Added 'exactly_one_of' validation - [@Morred](https://github.com/Morred).
8
+ * [#626](https://github.com/intridea/grape/pull/626): Mutually exclusive params - [@oliverbarnes](https://github.com/oliverbarnes).
9
+ * [#617](https://github.com/intridea/grape/pull/617): Running tests on Ruby 2.1.1, Rubinius 2.1 and 2.2, Ruby and JRuby HEAD - [@dblock](https://github.com/dblock).
10
+ * [#397](https://github.com/intridea/grape/pull/397): Adds `Grape::Endpoint.before_each` to allow easy helper stubbing - [@mbleigh](https://github.com/mbleigh).
11
+ * [#673](https://github.com/intridea/grape/pull/673): Avoid requiring non-existent fields when using Grape::Entity documentation - [@qqshfox](https://github.com/qqshfox).
12
+
13
+ #### Fixes
14
+
15
+ * [#671](https://github.com/intridea/grape/pull/671): Allow required param with predefined set of values to be nil inside optional group - [@dm1try](https://github.com/dm1try).
16
+ * [#651](https://github.com/intridea/grape/pull/651): The `rescue_from` keyword now properly defaults to rescuing subclasses of exceptions - [@xevix](https://github.com/xevix).
17
+ * [#614](https://github.com/intridea/grape/pull/614): Params with `nil` value are now refused by `RegexpValidator` - [@dm1try](https://github.com/dm1try).
18
+ * [#494](https://github.com/intridea/grape/issues/494): Fixed performance issue with requests carrying a large payload - [@dblock](https://github.com/dblock).
19
+ * [#619](https://github.com/intridea/grape/pull/619): Convert specs to RSpec 3 syntax with Transpec - [@danielspector](https://github.com/danielspector).
20
+ * [#632](https://github.com/intridea/grape/pull/632): `Grape::Endpoint#present` causes ActiveRecord to make an extra query during entity's detection - [@fixme](https://github.com/fixme).
21
+
22
+ 0.7.0 (4/2/2014)
23
+ =================
24
+
25
+ #### Features
26
+
5
27
  * [#558](https://github.com/intridea/grape/pull/558): Support lambda-based values for params - [@wpschallenger](https://github.com/wpschallenger).
6
28
  * [#510](https://github.com/intridea/grape/pull/510): Support lambda-based default values for params - [@myitcv](https://github.com/myitcv).
7
29
  * [#511](https://github.com/intridea/grape/pull/511): Added `required` option for OAuth2 middleware - [@bcm](https://github.com/bcm).
data/Gemfile CHANGED
@@ -3,18 +3,19 @@ source 'http://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :development, :test do
6
- gem 'pry'
7
- gem 'guard'
8
- gem 'guard-rspec'
9
- gem 'guard-bundler'
10
- gem 'rb-fsevent'
11
- gem 'growl'
12
- gem 'json'
13
6
  gem 'rspec', '~> 2.14.1'
14
7
  gem 'rack-test', '~> 0.6.2', require: 'rack/test'
15
- gem 'github-markup'
16
8
  gem 'cookiejar'
17
9
  gem 'rack-contrib'
18
- gem 'redcarpet', platforms: :ruby
19
- gem 'rubocop', '~> 0.15.0'
10
+ gem 'rubocop', '~> 0.20.1'
11
+ gem 'guard'
12
+ gem 'guard-rspec'
13
+ gem 'guard-rubocop'
14
+ gem 'mime-types'
15
+ end
16
+
17
+ platforms :rbx do
18
+ gem 'rubysl'
19
+ gem 'rubinius-developer_tools'
20
+ gem 'racc'
20
21
  end
data/Guardfile CHANGED
@@ -1,15 +1,14 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard 'rspec', :version => 2 do
4
+ guard :rspec do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
6
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
- watch(%r{^spec/support/shared_versioning_examples.rb$}) { |m| "spec/" }
8
- watch('spec/spec_helper.rb') { "spec/" }
7
+ watch('spec/spec_helper.rb') { "spec" }
9
8
  end
10
9
 
11
10
 
12
- guard 'bundler' do
13
- watch('Gemfile')
14
- watch(/^.+\.gemspec/)
11
+ guard :rubocop do
12
+ watch(%r{.+\.rb$})
13
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
15
14
  end
data/README.md CHANGED
@@ -1,4 +1,70 @@
1
- ![grape logo](https://github.com/intridea/grape/wiki/grape_logo.png)
1
+ ![grape logo](grape.png)
2
+
3
+ [![Build Status](https://travis-ci.org/intridea/grape.png?branch=master)](http://travis-ci.org/intridea/grape) [![Code Climate](https://codeclimate.com/github/intridea/grape.png)](https://codeclimate.com/github/intridea/grape) [![Inline docs](http://inch-ci.org/github/intridea/grape.png)](http://inch-ci.org/github/intridea/grape) [![Dependency Status](https://www.versioneye.com/ruby/grape/0.7.0/badge.png)](https://www.versioneye.com/ruby/grape/0.7.0)
4
+
5
+ ## Table of Contents
6
+
7
+ - [What is Grape?](#what-is-grape)
8
+ - [Stable Release](#stable-release)
9
+ - [Project Resources](#project-resources)
10
+ - [Installation](#installation)
11
+ - [Basic Usage](#basic-usage)
12
+ - [Mounting](#mounting)
13
+ - [Rack](#rack)
14
+ - [Alongside Sinatra (or other frameworks)](#alongside-sinatra-or-other-frameworks)
15
+ - [Rails](#rails)
16
+ - [Modules](#modules)
17
+ - [Versioning](#versioning)
18
+ - [Path](#path)
19
+ - [Header](#header)
20
+ - [Accept-Version Header](#accept-version-header)
21
+ - [Param](#param)
22
+ - [Describing Methods](#describing-methods)
23
+ - [Parameters](#parameters)
24
+ - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
25
+ - [Namespace Validation and Coercion](#namespace-validation-and-coercion)
26
+ - [Custom Validators](#custom-validators)
27
+ - [Validation Errors](#validation-errors)
28
+ - [I18n](#i18n)
29
+ - [Headers](#headers)
30
+ - [Routes](#routes)
31
+ - [Helpers](#helpers)
32
+ - [Parameter Documentation](#parameter-documentation)
33
+ - [Cookies](#cookies)
34
+ - [Redirecting](#redirecting)
35
+ - [Allowed Methods](#allowed-methods)
36
+ - [Raising Exceptions](#raising-exceptions)
37
+ - [Default Error HTTP Status Code](#default-error-http-status-code)
38
+ - [Handling 404](#handling-404)
39
+ - [Exception Handling](#exception-handling)
40
+ - [Rails 3.x](#rails-3x)
41
+ - [Logging](#logging)
42
+ - [API Formats](#api-formats)
43
+ - [JSONP](#jsonp)
44
+ - [CORS](#cors)
45
+ - [Content-type](#content-type)
46
+ - [API Data Formats](#api-data-formats)
47
+ - [RESTful Model Representations](#restful-model-representations)
48
+ - [Grape Entities](#grape-entities)
49
+ - [Hypermedia](#hypermedia)
50
+ - [Rabl](#rabl)
51
+ - [Active Model Serializers](#active-model-serializers)
52
+ - [Authentication](#authentication)
53
+ - [Describing and Inspecting an API](#describing-and-inspecting-an-api)
54
+ - [Current Route and Endpoint](#current-route-and-endpoint)
55
+ - [Before and After](#before-and-after)
56
+ - [Anchoring](#anchoring)
57
+ - [Writing Tests](#writing-tests)
58
+ - [Writing Tests with Rack](#writing-tests-with-rack)
59
+ - [Writing Tests with Rails](#writing-tests-with-rails)
60
+ - [Stubbing Helpers](#stubbing-helpers)
61
+ - [Reloading API Changes in Development](#reloading-api-changes-in-development)
62
+ - [Rails 3.x](#rails-3x)
63
+ - [Performance Monitoring](#performance-monitoring)
64
+ - [Contributing to Grape](#contributing-to-grape)
65
+ - [Hacking on Grape](#hacking-on-grape)
66
+ - [License](#license)
67
+ - [Copyright](#copyright)
2
68
 
3
69
  ## What is Grape?
4
70
 
@@ -8,11 +74,10 @@ providing a simple DSL to easily develop RESTful APIs. It has built-in support
8
74
  for common conventions, including multiple formats, subdomain/prefix restriction,
9
75
  content negotiation, versioning and much more.
10
76
 
11
- [![Build Status](https://travis-ci.org/intridea/grape.png?branch=master)](http://travis-ci.org/intridea/grape) [![Code Climate](https://codeclimate.com/github/intridea/grape.png)](https://codeclimate.com/github/intridea/grape) [![Inline docs](http://inch-pages.github.io/github/intridea/grape.png)](http://inch-pages.github.io/github/intridea/grape) [![Dependency Status](https://www.versioneye.com/ruby/grape/0.6.1/badge.png)](https://www.versioneye.com/ruby/grape/0.6.1)
12
-
13
77
  ## Stable Release
14
78
 
15
- You're reading the documentation for the stable release of Grape, 0.7.0.
79
+ You're reading the documentation for the stable release of Grape, 0.8.0.
80
+ Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
16
81
 
17
82
  ## Project Resources
18
83
 
@@ -164,7 +229,9 @@ run Rack::Cascade.new [API, Web]
164
229
 
165
230
  ### Rails
166
231
 
167
- Place API files into `app/api` and modify `application.rb`.
232
+ Place API files into `app/api`. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for `Twitter::API` should be `app/api/twitter/api.rb`.
233
+
234
+ Modify `application.rb`:
168
235
 
169
236
  ```ruby
170
237
  config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
@@ -345,6 +412,7 @@ params do
345
412
  optional :audio do
346
413
  requires :format, type: Symbol, values: [:mp3, :wav, :aac, :ogg], default: :mp3
347
414
  end
415
+ mutually_exclusive :media, :audio
348
416
  end
349
417
  put ':id' do
350
418
  # params[:id] is an Integer
@@ -406,6 +474,41 @@ params do
406
474
  end
407
475
  ```
408
476
 
477
+ Parameters can be defined as `mutually_exclusive`, ensuring that they aren't present at the same time in a request.
478
+
479
+ ```ruby
480
+ params do
481
+ optional :beer
482
+ optional :wine
483
+ mutually_exclusive :beer, :wine
484
+ end
485
+ ```
486
+
487
+ Multiple sets can be defined:
488
+
489
+ ```ruby
490
+ params do
491
+ optional :beer
492
+ optional :wine
493
+ mutually_exclusive :beer, :wine
494
+ optional :scotch
495
+ optional :aquavit
496
+ mutually_exclusive :scotch, :aquavit
497
+ end
498
+ ```
499
+
500
+ **Warning**: Never define mutually exclusive sets with any required params. Two mutually exclusive required params will mean params are never valid, thus making the endpoint useless. One required param mutually exclusive with an optional param will mean the latter is never valid.
501
+
502
+ Parameters can be defined as 'exactly_one_of', ensuring that exactly one parameter gets selected.
503
+
504
+ ```ruby
505
+ params do
506
+ optional :beer
507
+ optional :wine
508
+ exactly_one_of :beer, :wine
509
+ end
510
+ ```
511
+
409
512
  ### Namespace Validation and Coercion
410
513
 
411
514
  Namespaces allow parameter definitions and apply to every method within the namespace.
@@ -624,13 +727,43 @@ end
624
727
  class API < Grape::API
625
728
  helpers SharedParams
626
729
 
627
- desc "Get collection"
730
+ desc "Get collection."
628
731
  params do
629
732
  use :period, :pagination
630
733
  end
734
+
631
735
  get do
632
- Collection.from(params[:start_date]).to(params[:end_date])
633
- .page(params[:page]).per(params[:per_page])
736
+ Collection
737
+ .from(params[:start_date])
738
+ .to(params[:end_date])
739
+ .page(params[:page])
740
+ .per(params[:per_page])
741
+ end
742
+ end
743
+ ```
744
+
745
+ Helpers support blocks that can help set default values. The following API can return a collection sorted by `id` or `created_at` in `asc` or `desc` order.
746
+
747
+ ```ruby
748
+ module SharedParams
749
+ extend Grape::API::Helpers
750
+
751
+ params :order do |options|
752
+ optional :order_by, type:Symbol, values:options[:order_by], default:options[:default_order_by]
753
+ optional :order, type:Symbol, values:%i(asc desc), default:options[:default_order]
754
+ end
755
+ end
756
+
757
+ class API < Grape::API
758
+ helpers SharedParams
759
+
760
+ desc "Get a sorted collection."
761
+ params do
762
+ use :order, order_by:%i(id created_at), default_order_by: :created_at, default_order: :asc
763
+ end
764
+
765
+ get do
766
+ Collection.send(params[:order], params[:order_by])
634
767
  end
635
768
  end
636
769
  ```
@@ -911,7 +1044,7 @@ The code below will rescue exceptions of type `RuntimeError` but _not_ its subcl
911
1044
 
912
1045
  ```ruby
913
1046
  rescue_from RuntimeError, rescue_subclasses: false do |e|
914
- Rack::Response.new(
1047
+ Rack::Response.new({
915
1048
  status: e.status,
916
1049
  message: e.message,
917
1050
  errors: e.errors
@@ -1072,6 +1205,21 @@ The order for choosing the format is the following.
1072
1205
  * Use the default format, if specified by the `default_format` option.
1073
1206
  * Default to `:txt`.
1074
1207
 
1208
+ You can override this process explicitly by specifying `env['api.format']` in the API itself.
1209
+ For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
1210
+
1211
+ ```ruby
1212
+ class Twitter::API < Grape::API
1213
+ post "attachment" do
1214
+ filename = params[:file][:filename]
1215
+ content_type MIME::Types.type_for(filename)[0].to_s
1216
+ env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
1217
+ header "Content-Disposition", "attachment; filename*=UTF-8''#{URI.escape(filename)}"
1218
+ params[:file][:tempfile].read
1219
+ end
1220
+ end
1221
+ ```
1222
+
1075
1223
  ### JSONP
1076
1224
 
1077
1225
  Grape supports JSONP via [Rack::JSONP](https://github.com/rack/rack-contrib), part of the
@@ -1183,7 +1331,7 @@ module API
1183
1331
  expose :user_name
1184
1332
  expose :text, documentation: { type: "string", desc: "Status update text." }
1185
1333
  expose :ip, if: { type: :full }
1186
- expose :user_type, user_id, if: lambda { |status, options| status.user.public? }
1334
+ expose :user_type, :user_id, if: lambda { |status, options| status.user.public? }
1187
1335
  expose :digest { |status, options| Digest::MD5.hexdigest(status.txt) }
1188
1336
  expose :replies, using: API::Status, as: :replies
1189
1337
  end
@@ -1211,9 +1359,10 @@ module API
1211
1359
  class Statuses < Grape::API
1212
1360
  version 'v1'
1213
1361
 
1214
- desc 'Create a status', {
1362
+ desc 'Create a status'
1363
+ params do
1215
1364
  requires :all, except: [:ip], using: API::Entities::Status.documentation.except(:id)
1216
- }
1365
+ end
1217
1366
  post '/status' do
1218
1367
  Status.create! params
1219
1368
  end
@@ -1450,7 +1599,7 @@ default anchors requests to match from the start to the end, or not at all.
1450
1599
  Rails solves this problem by using a `anchor: false` option in your routes.
1451
1600
  In Grape this option can be used as well when a method is defined.
1452
1601
 
1453
- For instance when you're API needs to get part of an URL, for instance:
1602
+ For instance when your API needs to get part of an URL, for instance:
1454
1603
 
1455
1604
  ```ruby
1456
1605
  class TwitterAPI < Grape::API
@@ -1540,6 +1689,31 @@ RSpec.configure do |config|
1540
1689
  end
1541
1690
  ```
1542
1691
 
1692
+ ### Stubbing Helpers
1693
+
1694
+ Because helpers are mixed in based on the context when an endpoint is defined, it can
1695
+ be difficult to stub or mock them for testing. The `Grape::Endpoint.before_each` method
1696
+ can help by allowing you to define behavior on the endpoint that will run before every
1697
+ request.
1698
+
1699
+ ```ruby
1700
+ describe 'an endpoint that needs helpers stubbed' do
1701
+ before do
1702
+ Grape::Endpoint.before_each do |endpoint|
1703
+ endpoint.stub(:helper_name).and_return('desired_value')
1704
+ end
1705
+ end
1706
+
1707
+ after do
1708
+ Grape::Endpoint.before_each nil
1709
+ end
1710
+
1711
+ it 'should properly stub the helper' do
1712
+ # ...
1713
+ end
1714
+ end
1715
+ ```
1716
+
1543
1717
  ## Reloading API Changes in Development
1544
1718
 
1545
1719
  ### Rails 3.x
@@ -1583,6 +1757,13 @@ features and discuss issues.
1583
1757
 
1584
1758
  See [CONTRIBUTING](CONTRIBUTING.md).
1585
1759
 
1760
+ ## Hacking on Grape
1761
+
1762
+ You can start hacking on Grape on
1763
+ [Nitrous.IO](https://www.nitrous.io/?utm_source=github.com&utm_campaign=grape&utm_medium=hackonnitrous) in a matter of seconds:
1764
+
1765
+ [![Hack intridea/grape on Nitrous.IO](https://d3o0mnbgv6k92a.cloudfront.net/assets/hack-l-v1-3cc067e71372f6045e1949af9d96095b.png)](https://www.nitrous.io/hack_button?source=embed&runtime=rails&repo=intridea%2Fgrape&file_to_open=README.md)
1766
+
1586
1767
  ## License
1587
1768
 
1588
1769
  MIT License. See LICENSE for details.