Skip to content

Commit c9eb939

Browse files
committed
Merged from upstream.
2 parents 9b63d92 + a449fd4 commit c9eb939

File tree

12 files changed

+339
-77
lines changed

12 files changed

+339
-77
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ tmtags
1717
## VIM
1818
*.swp
1919

20+
## RUBYMINE
21+
.idea
22+
2023
## PROJECT::GENERAL
2124
coverage
2225
doc

README.markdown

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ Grape APIs are Rack applications that are created by subclassing `Grape::API`.
3636
Below is a simple example showing some of the more common features of Grape in
3737
the context of recreating parts of the Twitter API.
3838

39-
```ruby
39+
``` ruby
4040
class Twitter::API < Grape::API
41-
version 'v1', :using => :header, :vendor => 'twitter', :format => :json
41+
version 'v1', :using => :header, :vendor => 'twitter'
4242

4343
helpers do
4444
def current_user
@@ -89,7 +89,7 @@ end
8989
The above sample creates a Rack application that can be run from a rackup *config.ru* file
9090
with `rackup`:
9191

92-
```ruby
92+
``` ruby
9393
run Twitter::API
9494
```
9595

@@ -102,9 +102,10 @@ And would respond to the following routes:
102102

103103
In a Rails application, modify *config/routes*:
104104

105-
```ruby
105+
``` ruby
106106
mount Twitter::API => "/"
107107
```
108+
108109
You can mount multiple API implementations inside another one.
109110

110111
```ruby
@@ -126,8 +127,8 @@ Using this versioning strategy, clients should pass the desired version in the H
126127
curl -H Accept=application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
127128

128129
By default, the first matching version is used when no Accept header is
129-
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
130-
one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error
130+
supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
131+
one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error
131132
is returned when no correct Accept header is supplied.
132133

133134
version 'v1', :using => :path
@@ -165,7 +166,7 @@ Headers are available through the `env` hash object.
165166
You can define helper methods that your endpoints can use with the `helpers`
166167
macro by either giving a block or a module:
167168

168-
````ruby
169+
``` ruby
169170
module MyHelpers
170171
def say_hello(user)
171172
"hey there #{user.name}"
@@ -188,20 +189,50 @@ class API < Grape::API
188189
say_hello(current_user)
189190
end
190191
end
191-
````
192+
```
193+
194+
## Cookies
195+
196+
You can set, get and delete your cookies very simply using `cookies` method:
197+
198+
``` ruby
199+
class API < Grape::API
200+
get '/counter' do
201+
cookies[:counter] ||= 0
202+
cookies[:counter] += 1
203+
{ :counter => cookies[:counter] }
204+
end
205+
206+
delete '/counter' do
207+
{ :result => cookies.delete(:counter) }
208+
end
209+
end
210+
```
211+
212+
To set more than value use hash-based syntax:
213+
214+
``` ruby
215+
cookies[:counter] = {
216+
:value => 0,
217+
:expires => Time.tomorrow,
218+
:domain => '.example.com',
219+
:path => '/'
220+
}
221+
cookies[:counter][:value] +=1
222+
```
192223

193224
## Raising Errors
194225

195226
You can raise errors explicitly.
196227

197-
```ruby
228+
``` ruby
198229
error!("Access Denied", 401)
199230
```
200231

201232
You can also return JSON formatted objects explicitly by raising error! and
202233
passing a hash instead of a message.
203234

204-
```ruby
235+
``` ruby
205236
error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
206237
```
207238

@@ -210,15 +241,15 @@ error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
210241
Grape can be told to rescue all exceptions and instead return them in
211242
text or json formats.
212243

213-
```ruby
244+
``` ruby
214245
class Twitter::API < Grape::API
215246
rescue_from :all
216247
end
217248
```
218249

219250
You can also rescue specific exceptions.
220251

221-
```ruby
252+
``` ruby
222253
class Twitter::API < Grape::API
223254
rescue_from ArgumentError, NotImplementedError
224255
end
@@ -227,7 +258,7 @@ end
227258
The error format can be specified using `error_format`. Available formats are
228259
`:json` and `:txt` (default).
229260

230-
```ruby
261+
``` ruby
231262
class Twitter::API < Grape::API
232263
error_format :json
233264
end
@@ -236,7 +267,7 @@ end
236267
You can rescue all exceptions with a code block. The `rack_response` wrapper
237268
automatically sets the default error code and content-type.
238269

239-
```ruby
270+
``` ruby
240271
class Twitter::API < Grape::API
241272
rescue_from :all do |e|
242273
rack_response({ :message => "rescued from #{e.class.name}" })
@@ -247,7 +278,7 @@ end
247278
You can also rescue specific exceptions with a code block and handle the Rack
248279
response at the lowest level.
249280

250-
```ruby
281+
``` ruby
251282
class Twitter::API < Grape::API
252283
rescue_from :all do |e|
253284
Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
@@ -257,7 +288,7 @@ end
257288

258289
Or rescue specific exceptions.
259290

260-
```ruby
291+
``` ruby
261292
class Twitter::API < Grape::API
262293
rescue_from ArgumentError do |e|
263294
Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
@@ -270,16 +301,31 @@ end
270301

271302
## Content-Types
272303

273-
By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
274-
Your API can declare additional types to support. Response format is determined by the
304+
By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
305+
Your API can declare additional types to support. Response format is determined by the
275306
request's extension or `Accept` header.
276307

277-
```ruby
308+
``` ruby
278309
class Twitter::API < Grape::API
279310
content_type :xls, "application/vnd.ms-excel"
280311
end
281312
```
282313

314+
You can also set the default format. The order for choosing the format is the following.
315+
316+
* Use the file extension, if specified. If the file is .json, choose the JSON format.
317+
* Use the format, if specified by the `format` option.
318+
* Attempt to find an acceptable format from the `Accept` header.
319+
* Use the default format, if specified by the `default_format` option.
320+
* Default to `:txt` otherwise.
321+
322+
``` ruby
323+
class Twitter::API < Grape::API
324+
format :json
325+
default_format :json
326+
end
327+
```
328+
283329
## Writing Tests
284330

285331
You can test a Grape API with RSpec by making HTTP requests and examining the response.
@@ -319,7 +365,7 @@ end
319365

320366
### Writing Tests with Rails
321367

322-
```ruby
368+
``` ruby
323369
require 'spec_helper'
324370

325371
describe Twitter::API do
@@ -354,10 +400,10 @@ end
354400
## Describing and Inspecting an API
355401

356402
Grape lets you add a description to an API along with any other optional
357-
elements that can also be inspected at runtime.
403+
elements that can also be inspected at runtime.
358404
This can be useful for generating documentation.
359405

360-
```ruby
406+
``` ruby
361407
class TwitterAPI < Grape::API
362408

363409
version 'v1'
@@ -382,7 +428,7 @@ contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`,
382428
follows the API path may contain any number of keys and its values are also
383429
accessible via dynamically-generated `route_[name]` functions.
384430

385-
```ruby
431+
``` ruby
386432
TwitterAPI::versions # yields [ 'v1', 'v2' ]
387433
TwitterAPI::routes # yields an array of Grape::Route objects
388434
TwitterAPI::routes[0].route_version # yields 'v1'
@@ -391,7 +437,7 @@ TwitterAPI::routes[0].route_description # yields [ { "s" => { :desc => "string t
391437

392438
Parameters can also be tagged to the method declaration itself.
393439

394-
```ruby
440+
``` ruby
395441
class StringAPI < Grape::API
396442
get "split/:string", { :params => [ "token" ], :optional_params => [ "limit" ] } do
397443
params[:string].split(params[:token], (params[:limit] || 0))
@@ -404,7 +450,7 @@ StringAPI::routes[0].route_optional_params # yields an array [ "limit" ]
404450

405451
It's possible to retrieve the information about the current route from within an API call with `route`.
406452

407-
```ruby
453+
``` ruby
408454
class MyAPI < Grape::API
409455
desc "Returns a description of a parameter.", { :params => { "id" => "a required id" } }
410456
get "params/:id" do
@@ -427,7 +473,7 @@ In Grape this option can be used as well when a method is defined.
427473

428474
For instance when you're API needs to get part of an URL, for instance:
429475

430-
```ruby
476+
``` ruby
431477
class UrlAPI < Grape::API
432478
namespace :urls do
433479
get '/(*:url)', :anchor => false do
@@ -458,5 +504,5 @@ MIT License. See LICENSE for details.
458504

459505
## Copyright
460506

461-
Copyright (c) 2010-2012 Michael Bleigh and Intridea, Inc.
507+
Copyright (c) 2010-2012 Michael Bleigh and Intridea, Inc.
462508

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Grape
88
autoload :Client, 'grape/client'
99
autoload :Route, 'grape/route'
1010
autoload :Entity, 'grape/entity'
11+
autoload :Cookies, 'grape/cookies'
1112

1213
module Middleware
1314
autoload :Base, 'grape/middleware/base'

lib/grape/api.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,18 @@ def desc(description, options = {})
109109
@last_description = options.merge(:description => description)
110110
end
111111

112-
# Specify the default format for the API's
113-
# serializers. Currently only `:json` is
114-
# supported.
112+
# Specify the default format for the API's serializers.
113+
# May be `:json` or `:txt` (default).
115114
def default_format(new_format = nil)
116115
new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
117116
end
118117

118+
# Specify the format for the API's serializers.
119+
# May be `:json` or `:txt`.
120+
def format(new_format = nil)
121+
new_format ? set(:format, new_format.to_sym) : settings[:format]
122+
end
123+
119124
# Specify the format for error messages.
120125
# May be `:json` or `:txt` (default).
121126
def error_format(new_format = nil)

lib/grape/cookies.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module Grape
2+
class Cookies
3+
4+
def initialize
5+
@cookies = {}
6+
@send_cookies = {}
7+
end
8+
9+
def read(request)
10+
request.cookies.each do |name, value|
11+
@cookies[name.to_sym] = value
12+
end
13+
end
14+
15+
def write(header)
16+
@cookies.select { |key, value|
17+
@send_cookies[key.to_sym] == true
18+
}.each { |name, value|
19+
Rack::Utils.set_cookie_header!(
20+
header, name, value.instance_of?(Hash) ? value : { :value => value })
21+
}
22+
end
23+
24+
def [](name)
25+
@cookies[name]
26+
end
27+
28+
def []=(name, value)
29+
@cookies[name.to_sym] = value
30+
@send_cookies[name.to_sym] = true
31+
end
32+
33+
def each(&block)
34+
@cookies.each(&block)
35+
end
36+
37+
def delete(name)
38+
self.[]=(name, { :value => 'deleted', :expires => Time.at(0) })
39+
end
40+
end
41+
end

lib/grape/endpoint.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,18 @@ def header(key = nil, val = nil)
157157
end
158158
end
159159

160+
# Set or get a cookie
161+
#
162+
# @example
163+
# cookies[:mycookie] = 'mycookie val'
164+
# cookies['mycookie-string'] = 'mycookie string val'
165+
# cookies[:more] = { :value => '123', :expires => Time.at(0) }
166+
# cookies.delete :more
167+
#
168+
def cookies
169+
@cookies ||= Cookies.new
170+
end
171+
160172
# Allows you to define the response body as something other than the
161173
# return value.
162174
#
@@ -231,10 +243,12 @@ def run(env)
231243
@request = Rack::Request.new(@env)
232244

233245
self.extend helpers
246+
cookies.read(@request)
234247
run_filters befores
235248
response_text = instance_eval &self.block
236249
run_filters afters
237-
250+
cookies.write(header)
251+
238252
[status, header, [body || response_text]]
239253
end
240254

@@ -259,9 +273,10 @@ def build_middleware
259273
:version_options => settings[:version_options]
260274
}
261275
end
262-
276+
263277
b.use Grape::Middleware::Formatter,
264-
:default_format => settings[:default_format] || :json,
278+
:format => settings[:format],
279+
:default_format => settings[:default_format] || :txt,
265280
:content_types => settings[:content_types]
266281

267282
aggregate_setting(:middleware).each do |m|

0 commit comments

Comments
 (0)