poncho 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -10,7 +10,9 @@ It's compatible with any rack-based framework, such as Rails or Sinatra.
10
10
 
11
11
  Add this line to your application's Gemfile:
12
12
 
13
- gem 'poncho'
13
+ ```ruby
14
+ gem 'poncho'
15
+ ```
14
16
 
15
17
  And then execute:
16
18
 
@@ -22,30 +24,32 @@ Or install it yourself as:
22
24
 
23
25
  ## TLDR Usage
24
26
 
25
- class ChargeResource < Poncho::Resource
26
- param :amount, :type => :integer
27
- param :currency
27
+ ```ruby
28
+ class ChargeResource < Poncho::Resource
29
+ param :amount, :type => :integer
30
+ param :currency
28
31
 
29
- def currency
30
- super || 'USD'
31
- end
32
- end
32
+ def currency
33
+ super || 'USD'
34
+ end
35
+ end
33
36
 
34
- class ChargeCreateMethod < Poncho::JSONMethod
35
- param :amount, :type => :integer, :required => true
36
- param :currency, :in => ['USD', 'GBP']
37
+ class ChargeCreateMethod < Poncho::JSONMethod
38
+ param :amount, :type => :integer, :required => true
39
+ param :currency, :in => ['USD', 'GBP']
37
40
 
38
- def invoke
39
- charge = Charge.new
40
- charge.amount = param(:amount)
41
- charge.currency = param(:currency)
42
- charge.save
41
+ def invoke
42
+ charge = Charge.new
43
+ charge.amount = param(:amount)
44
+ charge.currency = param(:currency)
45
+ charge.save
43
46
 
44
- ChargeResource.new(charge)
45
- end
46
- end
47
+ ChargeResource.new(charge)
48
+ end
49
+ end
47
50
 
48
- post '/charges', &ChargeCreateMethod
51
+ post '/charges', &ChargeCreateMethod
52
+ ```
49
53
 
50
54
  ## Getting started with Methods
51
55
 
@@ -54,27 +58,35 @@ Methods inherit from `Poncho::Method` and override `invoke`, where they perform
54
58
  In a similar vein to Sinatra, anything returned from `invoke` is sent right back to the user. You can
55
59
  return a http status code, a body string, or even a Rack response array.
56
60
 
57
- class ChargeListMethod < Poncho::Method
58
- def invoke
59
- # Some DB shizzle
61
+ ```ruby
62
+ class ChargeListMethod < Poncho::Method
63
+ def invoke
64
+ # Some DB shizzle
60
65
 
61
- 200
62
- end
63
- end
66
+ 200
67
+ end
68
+ end
69
+ ```
64
70
 
65
71
  To invoke the method just add it to your routes.
66
72
 
67
73
  Using Rails:
68
74
 
69
- match '/users' => UsersListMethod, :via => :get
75
+ ```ruby
76
+ match '/users' => UsersListMethod, :via => :get
77
+ ```
70
78
 
71
79
  Using Sinatra:
72
80
 
73
- get '/users', &UsersListMethod
81
+ ```ruby
82
+ get '/users', &UsersListMethod
83
+ ```
74
84
 
75
85
  Or invoke manually:
76
86
 
77
- UsersListMethod.call(rack_env)
87
+ ```ruby
88
+ UsersListMethod.call(rack_env)
89
+ ```
78
90
 
79
91
  If you're writing a JSON API, you'll probably want to inherit the Method from `Poncho::JSONMethod` instead of
80
92
  `Poncho::Method`, but we'll cover that later.
@@ -85,11 +97,15 @@ You can get access to the request params, via the `params` or `param(name)` meth
85
97
 
86
98
  Before you can use a param though, you need to define it:
87
99
 
88
- param :param_name
100
+ ```ruby
101
+ param :param_name
102
+ ```
89
103
 
90
104
  By default, param are of type 'string'. you can choose a different type via the `:type` option:
91
105
 
92
- param :amount, :type => :integer
106
+ ```ruby
107
+ param :amount, :type => :integer
108
+ ```
93
109
 
94
110
  There are a bunch of predefined types, such as `:integer`, `:array`, `:boolean_string` etc, but you can
95
111
  also easily define your own custom ones (covered later).
@@ -106,35 +122,45 @@ As well as the default type validation, Poncho lets you validate presence, forma
106
122
 
107
123
  For example, to validate that a `:currency` parameter is provided, pass in the `:presence' option:
108
124
 
109
- param :currency, :presence => true
125
+ ```ruby
126
+ param :currency, :presence => true
127
+ ```
110
128
 
111
129
  To validate that a currency is either 'USD' or 'GBP', use the `:in` option.
112
130
 
113
- param :currency, :in => ['USD', 'GBP']
131
+ ```ruby
132
+ param :currency, :in => ['USD', 'GBP']
133
+ ```
114
134
 
115
135
  The other supported validations out of the box are `:format`, `:not_in`, and `:length`:
116
136
 
117
- param :email, :format => /@/
118
- param :password, :length => 5..20
137
+ ```ruby
138
+ param :email, :format => /@/
139
+ param :password, :length => 5..20
140
+ ```
119
141
 
120
142
  ## Custom Validation
121
143
 
122
144
  You can use a custom validator via the `validate` method, passing in a block:
123
145
 
124
- validate do
125
- unless param(:customer_id) ~= /\Acus_/
126
- errors.add(:customer_id, :invalid_customer)
127
- end
128
- end
146
+ ```ruby
147
+ validate do
148
+ unless param(:customer_id) ~= /\Acus_/
149
+ errors.add(:customer_id, :invalid_customer)
150
+ end
151
+ end
129
152
 
130
- # Or
153
+ # Or
131
154
 
132
- validates :customer_id, :customer_validate
155
+ validates :customer_id, :customer_validate
156
+ ```
133
157
 
134
158
  Alternatively, if your validation is being used in multiple places, you can wrap it up in a class and
135
- pass it to the `validate_with` method.
159
+ pass it to the `validates_with` method.
136
160
 
137
- validates_with CustomValidator
161
+ ```ruby
162
+ validates_with CustomValidator
163
+ ```
138
164
 
139
165
  For a good example of how to build validations, see the [
140
166
  existing ones](https://github.com/stripe/poncho/tree/master/lib/poncho/validations).
@@ -148,72 +174,84 @@ To define a custom parameter, simply inherit from `Poncho::Param`. For example,
148
174
  `CardHashParam`. It needs to validate input via overriding the `validate_each` method, and convert input via
149
175
  overriding the `convert` method.
150
176
 
151
- module Poncho
152
- module Params
153
- class CardHashParam < Param
154
- def validate_each(method, attribute, value)
155
- value = convert(value)
156
-
157
- unless value.is_a?(Hash) && value.keys == [:number, :exp_month, :exp_year, :cvc]
158
- method.errors.add(attribute, :invalid_card_hash, options.merge(:value => value))
159
- end
160
- end
161
-
162
- def convert(value)
163
- value && value.symbolize_keys
164
- end
165
- end
177
+ ```ruby
178
+ module Poncho
179
+ module Params
180
+ class CardHashParam < Param
181
+ def validate_each(method, attribute, value)
182
+ value = convert(value)
183
+
184
+ unless value.is_a?(Hash) && value.keys == [:number, :exp_month, :exp_year, :cvc]
185
+ method.errors.add(attribute, :invalid_card_hash, options.merge(:value => value))
166
186
  end
167
187
  end
168
188
 
189
+ def convert(value)
190
+ value && value.symbolize_keys
191
+ end
192
+ end
193
+ end
194
+ end
195
+ ```
196
+
169
197
  You can use custom parameters via the `:type` option.
170
198
 
171
- param :card, :type => Poncho::Params::CardHashParam
199
+ ```ruby
200
+ param :card, :type => Poncho::Params::CardHashParam
172
201
 
173
- # Or the shortcut
174
- param :card, :type => :card_hash
202
+ # Or the shortcut
203
+ param :card, :type => :card_hash
204
+ ```
175
205
 
176
206
  ## Request & Response
177
207
 
178
208
  You can gain access to the rack request via the `request` method, for example:
179
209
 
180
- def invoke
181
- accept = request.headers['Accept']
182
- 200
183
- end
210
+ ```ruby
211
+ def invoke
212
+ accept = request.headers['Accept']
213
+ 200
214
+ end
215
+ ```
184
216
 
185
217
  The same goes for the response object:
186
218
 
187
- def invoke
188
- response.body = ['Fee-fi-fo-fum']
189
- 200
190
- end
219
+ ```ruby
220
+ def invoke
221
+ response.body = ['Fee-fi-fo-fum']
222
+ 200
223
+ end
224
+ ```
191
225
 
192
226
  There are some helper methods to set such things as the HTTP status response codes and body.
193
227
 
194
- def invoke
195
- status 201
196
- body 'Created!'
197
- end
228
+ ```ruby
229
+ def invoke
230
+ status 201
231
+ body 'Created!'
232
+ end
233
+ ```
198
234
 
199
235
  ## Method filters
200
236
 
201
237
  There are various filters you can apply to the request, for example:
202
238
 
203
- class MyMethod < Poncho::Method
204
- before_validation do
205
- # Before validation
206
- end
239
+ ```ruby
240
+ class MyMethod < Poncho::Method
241
+ before_validation do
242
+ # Before validation
243
+ end
207
244
 
208
- before do
209
- # Before invoke
210
- p params
211
- end
245
+ before do
246
+ # Before invoke
247
+ p params
248
+ end
212
249
 
213
- after do
214
- # After invocation
215
- end
216
- end
250
+ after do
251
+ # After invocation
252
+ end
253
+ end
254
+ ```
217
255
 
218
256
  ## Error responses
219
257
 
@@ -221,15 +259,17 @@ You can provide custom responses to exceptions via the `error` class method.
221
259
 
222
260
  Pass `error` a exception type or status code.
223
261
 
224
- class MyMethod < Poncho::Method
225
- error MyCustomClass do
226
- 'Sorry, something went wrong.'
227
- end
262
+ ```ruby
263
+ class MyMethod < Poncho::Method
264
+ error MyCustomClass do
265
+ 'Sorry, something went wrong.'
266
+ end
228
267
 
229
- error 403 do
230
- 'Not authorized.'
231
- end
232
- end
268
+ error 403 do
269
+ 'Not authorized.'
270
+ end
271
+ end
272
+ ```
233
273
 
234
274
  ## JSON APIs
235
275
 
@@ -237,13 +277,15 @@ If your API only returns JSON then Poncho has a convenient `JSONMethod` class wh
237
277
  will ensure that all response bodies are converted into JSON and that the correct content type
238
278
  header is set.
239
279
 
240
- class TokenCreateMethod < Poncho::JSONMethod
241
- param :number, :required => true
280
+ ```ruby
281
+ class TokenCreateMethod < Poncho::JSONMethod
282
+ param :number, :required => true
242
283
 
243
- def invoke
244
- {:token => '123'}
245
- end
246
- end
284
+ def invoke
285
+ {:token => '123'}
286
+ end
287
+ end
288
+ ```
247
289
 
248
290
  `JSONMethod` also ensures that there's valid JSON error responses to 404s and 500s, as well
249
291
  as returning a JSON error hash for validation errors.
@@ -257,45 +299,49 @@ Resources are wrappers around other classes, such as models, providing a view re
257
299
 
258
300
  You can specify attributes to be returned to the client using the same `param` syntax as documented above.
259
301
 
260
- class Card
261
- attr_reader :number
302
+ ```ruby
303
+ class Card
304
+ attr_reader :number
262
305
 
263
- def initialize(number)
264
- @number = number
265
- end
266
- end
306
+ def initialize(number)
307
+ @number = number
308
+ end
309
+ end
267
310
 
268
- class CardResource < Poncho::Resource
269
- param :number
270
- param :description
311
+ class CardResource < Poncho::Resource
312
+ param :number
313
+ param :description
271
314
 
272
- def number
273
- super[-4..-1]
274
- end
275
- end
315
+ def number
316
+ super[-4..-1]
317
+ end
318
+ end
319
+ ```
276
320
 
277
321
  As you can see in the example above, you can override params and return a custom response.
278
322
 
279
323
  When the `Resource` instance is converted into JSON the appropriate params will be used and serialized.
280
324
 
281
- class ChargeResource < Poncho::Resource
282
- param :amount, :type => :integer
283
- param :currency
284
- param :card, :resource => CardResource
285
-
286
- def currency
287
- super || 'USD'
288
- end
289
- end
290
-
291
- class ChargeListMethod < Poncho::JSONMethod
292
- def invoke
293
- [
294
- ChargeResource.new(Charge.new(1000, 'USD')),
295
- ChargeResource.new(Charge.new(50, 'USD'))
296
- ]
297
- end
298
- end
325
+ ```ruby
326
+ class ChargeResource < Poncho::Resource
327
+ param :amount, :type => :integer
328
+ param :currency
329
+ param :card, :resource => CardResource
330
+
331
+ def currency
332
+ super || 'USD'
333
+ end
334
+ end
335
+
336
+ class ChargeListMethod < Poncho::JSONMethod
337
+ def invoke
338
+ [
339
+ ChargeResource.new(Charge.new(1000, 'USD')),
340
+ ChargeResource.new(Charge.new(50, 'USD'))
341
+ ]
342
+ end
343
+ end
344
+ ```
299
345
 
300
346
  If a particular param points to another resource, you can use the `:type => :resource` option as demonstrated above.
301
347
 
data/lib/poncho/error.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Poncho
2
2
  class Error < StandardError
3
- def to_json
3
+ def to_json(*)
4
4
  as_json.to_json
5
5
  end
6
6
 
data/lib/poncho/errors.rb CHANGED
@@ -118,7 +118,7 @@ module Poncho
118
118
  }
119
119
  end
120
120
 
121
- def to_json(options=nil)
121
+ def to_json(*)
122
122
  as_json.to_json
123
123
  end
124
124
 
@@ -10,7 +10,7 @@ module Poncho
10
10
  json ServerError.new
11
11
  end
12
12
 
13
- error 403 do
13
+ error 400 do
14
14
  json InvalidRequestError.new
15
15
  end
16
16
 
data/lib/poncho/method.rb CHANGED
@@ -223,6 +223,9 @@ module Poncho
223
223
  end
224
224
 
225
225
  def handle_exception!(error)
226
+ # Exception raised in error handling
227
+ raise error if env['poncho.error']
228
+
226
229
  env['poncho.error'] = error
227
230
 
228
231
  status error.respond_to?(:code) ? Integer(error.code) : 500
@@ -33,7 +33,7 @@ module Poncho
33
33
  [to_json]
34
34
  end
35
35
 
36
- def to_json(options = nil)
36
+ def to_json(*)
37
37
  as_json.to_json
38
38
  end
39
39
 
@@ -1,3 +1,3 @@
1
1
  module Poncho
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,40 @@
1
+ require 'minitest/autorun'
2
+ require 'rack/mock'
3
+ require 'poncho'
4
+
5
+ class TestJSONMethod < MiniTest::Unit::TestCase
6
+ def env(params = {})
7
+ Rack::MockRequest.env_for('http://api.com/charges', :params => params)
8
+ end
9
+
10
+ def setup
11
+ end
12
+
13
+ def test_serializes_body
14
+ method = Class.new(Poncho::JSONMethod) do
15
+ param :id, :type => :integer
16
+ param :body, :type => :string
17
+
18
+ def invoke
19
+ params
20
+ end
21
+ end
22
+
23
+ status, headers, body = method.call(env(:id => '1', :body => 'wem'))
24
+ assert_equal({:id => 1, :body => 'wem'}.to_json, body.body.first)
25
+ end
26
+
27
+ def test_serializes_errors
28
+ method = Class.new(Poncho::JSONMethod) do
29
+ param :id, :type => :integer
30
+ param :body, :type => :string
31
+
32
+ def invoke
33
+ params
34
+ end
35
+ end
36
+
37
+ status, headers, body = method.call(env(:id => 'string', :body => 'wem'))
38
+ assert_equal({:error => {:param => 'id', :type => 'invalid_integer', :message => nil}}.to_json, body.body.first)
39
+ end
40
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poncho
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-02 00:00:00.000000000 Z
12
+ date: 2013-04-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Poncho is an API to build REST APIs with a convenient DSL.
15
15
  email:
@@ -53,6 +53,7 @@ files:
53
53
  - lib/poncho/validator.rb
54
54
  - lib/poncho/version.rb
55
55
  - poncho.gemspec
56
+ - test/poncho/test_json_method.rb
56
57
  - test/poncho/test_method.rb
57
58
  - test/poncho/test_resource.rb
58
59
  homepage: https://github.com/stripe/poncho
@@ -80,5 +81,6 @@ signing_key:
80
81
  specification_version: 3
81
82
  summary: Poncho is an API to build APIs
82
83
  test_files:
84
+ - test/poncho/test_json_method.rb
83
85
  - test/poncho/test_method.rb
84
86
  - test/poncho/test_resource.rb