grape 0.6.0 → 0.6.1

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 (84) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +65 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +17 -1
  5. data/Gemfile +1 -0
  6. data/README.md +16 -8
  7. data/RELEASING.md +105 -0
  8. data/grape.gemspec +1 -1
  9. data/lib/grape.rb +1 -0
  10. data/lib/grape/api.rb +88 -54
  11. data/lib/grape/cookies.rb +4 -6
  12. data/lib/grape/endpoint.rb +81 -69
  13. data/lib/grape/error_formatter/base.rb +5 -4
  14. data/lib/grape/error_formatter/json.rb +3 -3
  15. data/lib/grape/error_formatter/txt.rb +1 -1
  16. data/lib/grape/error_formatter/xml.rb +4 -4
  17. data/lib/grape/exceptions/base.rb +7 -7
  18. data/lib/grape/exceptions/incompatible_option_values.rb +13 -0
  19. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  20. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  21. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -4
  22. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  23. data/lib/grape/exceptions/missing_option.rb +1 -1
  24. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  25. data/lib/grape/exceptions/unknown_options.rb +1 -1
  26. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  27. data/lib/grape/exceptions/validation.rb +2 -2
  28. data/lib/grape/exceptions/validation_errors.rb +1 -1
  29. data/lib/grape/formatter/base.rb +5 -4
  30. data/lib/grape/formatter/serializable_hash.rb +7 -6
  31. data/lib/grape/http/request.rb +2 -2
  32. data/lib/grape/locale/en.yml +2 -0
  33. data/lib/grape/middleware/auth/base.rb +3 -3
  34. data/lib/grape/middleware/auth/basic.rb +1 -1
  35. data/lib/grape/middleware/auth/oauth2.rb +18 -20
  36. data/lib/grape/middleware/base.rb +1 -1
  37. data/lib/grape/middleware/error.rb +19 -19
  38. data/lib/grape/middleware/filter.rb +3 -3
  39. data/lib/grape/middleware/formatter.rb +29 -23
  40. data/lib/grape/middleware/versioner.rb +1 -1
  41. data/lib/grape/middleware/versioner/accept_version_header.rb +8 -6
  42. data/lib/grape/middleware/versioner/header.rb +16 -14
  43. data/lib/grape/middleware/versioner/param.rb +7 -7
  44. data/lib/grape/middleware/versioner/path.rb +7 -9
  45. data/lib/grape/parser/base.rb +3 -2
  46. data/lib/grape/path.rb +1 -1
  47. data/lib/grape/route.rb +6 -4
  48. data/lib/grape/util/content_types.rb +2 -1
  49. data/lib/grape/util/deep_merge.rb +5 -5
  50. data/lib/grape/util/hash_stack.rb +2 -2
  51. data/lib/grape/validations.rb +34 -30
  52. data/lib/grape/validations/coerce.rb +6 -5
  53. data/lib/grape/validations/default.rb +0 -1
  54. data/lib/grape/validations/presence.rb +1 -1
  55. data/lib/grape/validations/regexp.rb +2 -2
  56. data/lib/grape/validations/values.rb +16 -0
  57. data/lib/grape/version.rb +1 -1
  58. data/spec/grape/api_spec.rb +229 -210
  59. data/spec/grape/endpoint_spec.rb +56 -54
  60. data/spec/grape/entity_spec.rb +31 -33
  61. data/spec/grape/exceptions/missing_mime_type_spec.rb +3 -9
  62. data/spec/grape/middleware/auth/basic_spec.rb +8 -8
  63. data/spec/grape/middleware/auth/digest_spec.rb +5 -5
  64. data/spec/grape/middleware/auth/oauth2_spec.rb +23 -23
  65. data/spec/grape/middleware/base_spec.rb +6 -6
  66. data/spec/grape/middleware/error_spec.rb +11 -15
  67. data/spec/grape/middleware/exception_spec.rb +45 -25
  68. data/spec/grape/middleware/formatter_spec.rb +56 -45
  69. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +25 -25
  70. data/spec/grape/middleware/versioner/header_spec.rb +54 -54
  71. data/spec/grape/middleware/versioner/param_spec.rb +17 -18
  72. data/spec/grape/middleware/versioner/path_spec.rb +6 -6
  73. data/spec/grape/middleware/versioner_spec.rb +1 -1
  74. data/spec/grape/util/hash_stack_spec.rb +26 -27
  75. data/spec/grape/validations/coerce_spec.rb +39 -34
  76. data/spec/grape/validations/default_spec.rb +12 -13
  77. data/spec/grape/validations/presence_spec.rb +18 -22
  78. data/spec/grape/validations/regexp_spec.rb +9 -9
  79. data/spec/grape/validations/values_spec.rb +64 -0
  80. data/spec/grape/validations_spec.rb +127 -70
  81. data/spec/shared/versioning_examples.rb +5 -5
  82. data/spec/support/basic_auth_encode_helpers.rb +0 -1
  83. data/spec/support/versioned_helpers.rb +5 -6
  84. metadata +10 -4
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
2
+
3
3
  describe Grape::Exceptions::MissingMimeType do
4
4
  describe "#message" do
5
5
 
@@ -8,17 +8,11 @@ describe Grape::Exceptions::MissingMimeType do
8
8
  end
9
9
 
10
10
  it "contains the problem in the message" do
11
- error.message.should include(
12
- "missing mime type for new_json"
13
- )
11
+ error.message.should include "missing mime type for new_json"
14
12
  end
15
13
 
16
14
  it "contains the resolution in the message" do
17
- error.message.should include(
18
- "or add your own with content_type :new_json, 'application/new_json' "
19
- )
15
+ error.message.should include "or add your own with content_type :new_json, 'application/new_json' "
20
16
  end
21
17
  end
22
-
23
-
24
18
  end
@@ -6,26 +6,26 @@ describe Grape::Middleware::Auth::Basic do
6
6
  def app
7
7
  Rack::Builder.new do |b|
8
8
  b.use Grape::Middleware::Error
9
- b.use(Grape::Middleware::Auth::Basic) do |u,p|
9
+ b.use(Grape::Middleware::Auth::Basic) do |u, p|
10
10
  u && p && u == p
11
11
  end
12
- b.run lambda{|env| [200, {}, ["Hello there."]]}
12
+ b.run lambda { |env| [200, {}, ["Hello there."]] }
13
13
  end
14
14
  end
15
-
15
+
16
16
  it 'throws a 401 if no auth is given' do
17
- @proc = lambda{ false }
17
+ @proc = lambda { false }
18
18
  get '/whatever'
19
19
  last_response.status.should == 401
20
20
  end
21
-
21
+
22
22
  it 'authenticates if given valid creds' do
23
- get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin','admin')
23
+ get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'admin')
24
24
  last_response.status.should == 200
25
25
  end
26
-
26
+
27
27
  it 'throws a 401 is wrong auth is given' do
28
- get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin','wrong')
28
+ get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'wrong')
29
29
  last_response.status.should == 401
30
30
  end
31
31
  end
@@ -9,12 +9,12 @@ RSpec::Matchers.define :be_challenge do
9
9
  end
10
10
 
11
11
  class Test < Grape::API
12
- http_digest({:realm => 'Test Api', :opaque => 'secret'}) do |username|
13
- {'foo' => 'bar'}[username]
12
+ http_digest(realm: 'Test Api', opaque: 'secret') do |username|
13
+ { 'foo' => 'bar' }[username]
14
14
  end
15
15
 
16
16
  get '/test' do
17
- [{:hey => 'you'},{:there => 'bar'},{:foo => 'baz'}]
17
+ [{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
18
18
  end
19
19
  end
20
20
 
@@ -22,12 +22,12 @@ describe Grape::Middleware::Auth::Digest do
22
22
  def app
23
23
  Test
24
24
  end
25
-
25
+
26
26
  it 'is a digest authentication challenge' do
27
27
  get '/test'
28
28
  last_response.should be_challenge
29
29
  end
30
-
30
+
31
31
  it 'throws a 401 if no auth is given' do
32
32
  get '/test'
33
33
  last_response.status.should == 401
@@ -2,88 +2,88 @@ require 'spec_helper'
2
2
 
3
3
  describe Grape::Middleware::Auth::OAuth2 do
4
4
  class FakeToken
5
+ attr_accessor :token
6
+
5
7
  def self.verify(token)
6
8
  FakeToken.new(token) if %w(g e).include?(token[0..0])
7
9
  end
8
-
10
+
9
11
  def initialize(token)
10
- self.token = token
12
+ @token = token
11
13
  end
12
-
14
+
13
15
  def expired?
14
- self.token[0..0] == 'e'
16
+ @token[0..0] == 'e'
15
17
  end
16
-
18
+
17
19
  def permission_for?(env)
18
20
  env['PATH_INFO'] == '/forbidden' ? false : true
19
21
  end
20
-
21
- attr_accessor :token
22
22
  end
23
23
 
24
24
  def app
25
25
  Rack::Builder.app do
26
- use Grape::Middleware::Auth::OAuth2, :token_class => 'FakeToken'
27
- run lambda{|env| [200, {}, [ (env['api.token'].token rescue '') ]]}
26
+ use Grape::Middleware::Auth::OAuth2, token_class: 'FakeToken'
27
+ run lambda { |env| [200, {}, [(env['api.token'].token if env['api.token'])]] }
28
28
  end
29
29
  end
30
-
30
+
31
31
  context 'with the token in the query string' do
32
32
  context 'and a valid token' do
33
33
  before { get '/awesome?oauth_token=g123' }
34
-
34
+
35
35
  it 'sets env["api.token"]' do
36
36
  last_response.body.should == 'g123'
37
37
  end
38
38
  end
39
-
39
+
40
40
  context 'and an invalid token' do
41
41
  before do
42
42
  @err = catch :error do
43
43
  get '/awesome?oauth_token=b123'
44
44
  end
45
45
  end
46
-
46
+
47
47
  it 'throws an error' do
48
48
  @err[:status].should == 401
49
49
  end
50
-
50
+
51
51
  it 'sets the WWW-Authenticate header in the response' do
52
52
  @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='invalid_token'"
53
53
  end
54
54
  end
55
55
  end
56
-
56
+
57
57
  context 'with an expired token' do
58
58
  before do
59
59
  @err = catch :error do
60
60
  get '/awesome?oauth_token=e123'
61
61
  end
62
62
  end
63
-
63
+
64
64
  it { @err[:status].should == 401 }
65
65
  it { @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='expired_token'" }
66
66
  end
67
-
68
- %w(HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION).each do |head|
67
+
68
+ %w(HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION).each do |head|
69
69
  context 'with the token in the #{head} header' do
70
70
  before { get '/awesome', {}, head => 'OAuth g123' }
71
71
  it { last_response.body.should == 'g123' }
72
72
  end
73
73
  end
74
-
74
+
75
75
  context 'with the token in the POST body' do
76
- before { post '/awesome', {'oauth_token' => 'g123'} }
77
- it { last_response.body.should == 'g123'}
76
+ before { post '/awesome', { 'oauth_token' => 'g123' } }
77
+ it { last_response.body.should == 'g123' }
78
78
  end
79
-
79
+
80
80
  context 'when accessing something outside its scope' do
81
81
  before do
82
82
  @err = catch :error do
83
83
  get '/forbidden?oauth_token=g123'
84
84
  end
85
85
  end
86
-
86
+
87
87
  it { @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='insufficient_scope'" }
88
88
  it { @err[:status].should == 403 }
89
89
  end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::Middleware::Base do
4
- subject { Grape::Middleware::Base.new( blank_app) }
5
- let(:blank_app) { lambda{|_| [200, {}, 'Hi there.']} }
4
+ subject { Grape::Middleware::Base.new(blank_app) }
5
+ let(:blank_app) { lambda { |_| [200, {}, 'Hi there.'] } }
6
6
 
7
7
  before do
8
8
  # Keep it one object for testing.
@@ -31,7 +31,7 @@ describe Grape::Middleware::Base do
31
31
  subject.should_receive(:after)
32
32
  end
33
33
 
34
- after{ subject.call!({}) }
34
+ after { subject.call!({}) }
35
35
  end
36
36
 
37
37
  it 'is able to access the response' do
@@ -41,13 +41,13 @@ describe Grape::Middleware::Base do
41
41
 
42
42
  context 'options' do
43
43
  it 'persists options passed at initialization' do
44
- Grape::Middleware::Base.new(blank_app, {:abc => true}).options[:abc].should be_true
44
+ Grape::Middleware::Base.new(blank_app, abc: true).options[:abc].should be_true
45
45
  end
46
46
 
47
47
  context 'defaults' do
48
48
  class ExampleWare < Grape::Middleware::Base
49
49
  def default_options
50
- {:monkey => true}
50
+ { monkey: true }
51
51
  end
52
52
  end
53
53
 
@@ -56,7 +56,7 @@ describe Grape::Middleware::Base do
56
56
  end
57
57
 
58
58
  it 'overrides default options when provided' do
59
- ExampleWare.new(blank_app, :monkey => false).options[:monkey].should be_false
59
+ ExampleWare.new(blank_app, monkey: false).options[:monkey].should be_false
60
60
  end
61
61
  end
62
62
  end
@@ -2,48 +2,44 @@ require 'spec_helper'
2
2
 
3
3
  describe Grape::Middleware::Error do
4
4
  class ErrApp
5
- class << self
5
+ class << self
6
6
  attr_accessor :error
7
7
  attr_accessor :format
8
-
8
+
9
9
  def call(env)
10
- throw :error, self.error
10
+ throw :error, error
11
11
  end
12
12
  end
13
13
  end
14
-
14
+
15
15
  def app
16
16
  Rack::Builder.app do
17
- use Grape::Middleware::Error, :default_message => 'Aww, hamburgers.'
17
+ use Grape::Middleware::Error, default_message: 'Aww, hamburgers.'
18
18
  run ErrApp
19
19
  end
20
20
  end
21
-
21
+
22
22
  it 'sets the status code appropriately' do
23
- ErrApp.error = {:status => 410}
23
+ ErrApp.error = { status: 410 }
24
24
  get '/'
25
25
  last_response.status.should == 410
26
26
  end
27
-
27
+
28
28
  it 'sets the error message appropriately' do
29
- ErrApp.error = {:message => 'Awesome stuff.'}
29
+ ErrApp.error = { message: 'Awesome stuff.' }
30
30
  get '/'
31
31
  last_response.body.should == 'Awesome stuff.'
32
32
  end
33
-
33
+
34
34
  it 'defaults to a 403 status' do
35
35
  ErrApp.error = {}
36
36
  get '/'
37
37
  last_response.status.should == 403
38
38
  end
39
-
39
+
40
40
  it 'has a default message' do
41
41
  ErrApp.error = {}
42
42
  get '/'
43
43
  last_response.body.should == 'Aww, hamburgers.'
44
44
  end
45
-
46
- context 'with formatting' do
47
-
48
- end
49
45
  end
@@ -15,9 +15,10 @@ describe Grape::Middleware::Error do
15
15
  # raises a hash error
16
16
  class ErrorHashApp
17
17
  class << self
18
- def error!(message, status=403)
19
- throw :error, :message => { :error => message, :detail => "missing widget" }, :status => status
18
+ def error!(message, status = 403)
19
+ throw :error, message: { error: message, detail: "missing widget" }, status: status
20
20
  end
21
+
21
22
  def call(env)
22
23
  error!("rain!", 401)
23
24
  end
@@ -27,9 +28,10 @@ describe Grape::Middleware::Error do
27
28
  # raises an error!
28
29
  class AccessDeniedApp
29
30
  class << self
30
- def error!(message, status=403)
31
- throw :error, :message => message, :status => status
31
+ def error!(message, status = 403)
32
+ throw :error, message: message, status: status
32
33
  end
34
+
33
35
  def call(env)
34
36
  error!("Access Denied", 401)
35
37
  end
@@ -37,18 +39,18 @@ describe Grape::Middleware::Error do
37
39
  end
38
40
 
39
41
  # raises a custom error
40
- class CustomError < Grape::Exceptions::Base; end
42
+ class CustomError < Grape::Exceptions::Base
43
+ end
44
+
41
45
  class CustomErrorApp
42
46
  class << self
43
47
  def call(env)
44
- raise CustomError, :status => 400, :message => 'failed validation'
48
+ raise CustomError, status: 400, message: 'failed validation'
45
49
  end
46
50
  end
47
51
  end
48
52
 
49
- def app
50
- @app
51
- end
53
+ attr_reader :app
52
54
 
53
55
  it 'does not trap errors by default' do
54
56
  @app ||= Rack::Builder.app do
@@ -61,7 +63,7 @@ describe Grape::Middleware::Error do
61
63
  context 'with rescue_all set to true' do
62
64
  it 'sets the message appropriately' do
63
65
  @app ||= Rack::Builder.app do
64
- use Grape::Middleware::Error, :rescue_all => true
66
+ use Grape::Middleware::Error, rescue_all: true
65
67
  run ExceptionApp
66
68
  end
67
69
  get '/'
@@ -70,7 +72,7 @@ describe Grape::Middleware::Error do
70
72
 
71
73
  it 'defaults to a 403 status' do
72
74
  @app ||= Rack::Builder.app do
73
- use Grape::Middleware::Error, :rescue_all => true
75
+ use Grape::Middleware::Error, rescue_all: true
74
76
  run ExceptionApp
75
77
  end
76
78
  get '/'
@@ -79,7 +81,7 @@ describe Grape::Middleware::Error do
79
81
 
80
82
  it 'is possible to specify a different default status code' do
81
83
  @app ||= Rack::Builder.app do
82
- use Grape::Middleware::Error, :rescue_all => true, :default_status => 500
84
+ use Grape::Middleware::Error, rescue_all: true, default_status: 500
83
85
  run ExceptionApp
84
86
  end
85
87
  get '/'
@@ -88,7 +90,7 @@ describe Grape::Middleware::Error do
88
90
 
89
91
  it 'is possible to return errors in json format' do
90
92
  @app ||= Rack::Builder.app do
91
- use Grape::Middleware::Error, :rescue_all => true, :format => :json
93
+ use Grape::Middleware::Error, rescue_all: true, format: :json
92
94
  run ExceptionApp
93
95
  end
94
96
  get '/'
@@ -97,7 +99,26 @@ describe Grape::Middleware::Error do
97
99
 
98
100
  it 'is possible to return hash errors in json format' do
99
101
  @app ||= Rack::Builder.app do
100
- use Grape::Middleware::Error, :rescue_all => true, :format => :json
102
+ use Grape::Middleware::Error, rescue_all: true, format: :json
103
+ run ErrorHashApp
104
+ end
105
+ get '/'
106
+ ['{"error":"rain!","detail":"missing widget"}',
107
+ '{"detail":"missing widget","error":"rain!"}'].should include(last_response.body)
108
+ end
109
+
110
+ it 'is possible to return errors in jsonapi format' do
111
+ @app ||= Rack::Builder.app do
112
+ use Grape::Middleware::Error, rescue_all: true, format: :jsonapi
113
+ run ExceptionApp
114
+ end
115
+ get '/'
116
+ last_response.body.should == '{"error":"rain!"}'
117
+ end
118
+
119
+ it 'is possible to return hash errors in jsonapi format' do
120
+ @app ||= Rack::Builder.app do
121
+ use Grape::Middleware::Error, rescue_all: true, format: :jsonapi
101
122
  run ErrorHashApp
102
123
  end
103
124
  get '/'
@@ -107,7 +128,7 @@ describe Grape::Middleware::Error do
107
128
 
108
129
  it 'is possible to return errors in xml format' do
109
130
  @app ||= Rack::Builder.app do
110
- use Grape::Middleware::Error, :rescue_all => true, :format => :xml
131
+ use Grape::Middleware::Error, rescue_all: true, format: :xml
111
132
  run ExceptionApp
112
133
  end
113
134
  get '/'
@@ -116,7 +137,7 @@ describe Grape::Middleware::Error do
116
137
 
117
138
  it 'is possible to return hash errors in xml format' do
118
139
  @app ||= Rack::Builder.app do
119
- use Grape::Middleware::Error, :rescue_all => true, :format => :xml
140
+ use Grape::Middleware::Error, rescue_all: true, format: :xml
120
141
  run ErrorHashApp
121
142
  end
122
143
  get '/'
@@ -126,14 +147,13 @@ describe Grape::Middleware::Error do
126
147
 
127
148
  it 'is possible to specify a custom formatter' do
128
149
  @app ||= Rack::Builder.app do
129
- use Grape::Middleware::Error,
130
- :rescue_all => true,
131
- :format => :custom,
132
- :error_formatters => {
133
- :custom => lambda { |message, backtrace, options, env|
134
- { :custom_formatter => message }.inspect
135
- }
136
- }
150
+ use Grape::Middleware::Error, rescue_all: true,
151
+ format: :custom,
152
+ error_formatters: {
153
+ custom: lambda { |message, backtrace, options, env|
154
+ { custom_formatter: message }.inspect
155
+ }
156
+ }
137
157
  run ExceptionApp
138
158
  end
139
159
  get '/'
@@ -151,7 +171,7 @@ describe Grape::Middleware::Error do
151
171
 
152
172
  it 'responds to custom Grape exceptions appropriately' do
153
173
  @app ||= Rack::Builder.app do
154
- use Grape::Middleware::Error, :rescue_all => false
174
+ use Grape::Middleware::Error, rescue_all: false
155
175
  run CustomErrorApp
156
176
  end
157
177