cathode 0.0.1 → 0.1.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +346 -125
  3. data/Rakefile +1 -0
  4. data/app/controllers/cathode/base_controller.rb +28 -45
  5. data/app/models/cathode/token.rb +21 -0
  6. data/config/routes.rb +16 -0
  7. data/db/migrate/20140425164100_create_cathode_tokens.rb +11 -0
  8. data/lib/cathode.rb +0 -13
  9. data/lib/cathode/_version.rb +2 -1
  10. data/lib/cathode/action.rb +197 -39
  11. data/lib/cathode/action_dsl.rb +60 -0
  12. data/lib/cathode/base.rb +81 -12
  13. data/lib/cathode/create_request.rb +21 -0
  14. data/lib/cathode/custom_request.rb +5 -0
  15. data/lib/cathode/debug.rb +25 -0
  16. data/lib/cathode/destroy_request.rb +13 -0
  17. data/lib/cathode/engine.rb +9 -0
  18. data/lib/cathode/exceptions.rb +20 -0
  19. data/lib/cathode/index_request.rb +40 -0
  20. data/lib/cathode/object_collection.rb +49 -0
  21. data/lib/cathode/query.rb +24 -0
  22. data/lib/cathode/railtie.rb +21 -0
  23. data/lib/cathode/request.rb +139 -7
  24. data/lib/cathode/resource.rb +50 -19
  25. data/lib/cathode/resource_dsl.rb +46 -0
  26. data/lib/cathode/show_request.rb +13 -0
  27. data/lib/cathode/update_request.rb +26 -0
  28. data/lib/cathode/version.rb +112 -23
  29. data/lib/tasks/cathode_tasks.rake +5 -4
  30. data/spec/dummy/app/api/api.rb +0 -0
  31. data/spec/dummy/app/models/payment.rb +3 -0
  32. data/spec/dummy/app/models/product.rb +1 -0
  33. data/spec/dummy/app/models/sale.rb +5 -0
  34. data/spec/dummy/app/models/salesperson.rb +3 -0
  35. data/spec/dummy/db/development.sqlite3 +0 -0
  36. data/spec/dummy/db/migrate/20140409183635_create_sales.rb +11 -0
  37. data/spec/dummy/db/migrate/20140423172419_create_salespeople.rb +11 -0
  38. data/spec/dummy/db/migrate/20140424181343_create_payments.rb +10 -0
  39. data/spec/dummy/db/schema.rb +31 -1
  40. data/spec/dummy/db/test.sqlite3 +0 -0
  41. data/spec/dummy/log/development.log +1167 -0
  42. data/spec/dummy/log/test.log +180602 -0
  43. data/spec/dummy/spec/factories/payments.rb +8 -0
  44. data/spec/dummy/spec/factories/products.rb +1 -1
  45. data/spec/dummy/spec/factories/sales.rb +9 -0
  46. data/spec/dummy/spec/factories/salespeople.rb +7 -0
  47. data/spec/dummy/spec/requests/requests_spec.rb +434 -0
  48. data/spec/lib/cathode/action_spec.rb +136 -0
  49. data/spec/lib/cathode/base_spec.rb +34 -0
  50. data/spec/lib/cathode/create_request_spec.rb +40 -0
  51. data/spec/lib/cathode/custom_request_spec.rb +31 -0
  52. data/spec/lib/cathode/debug_spec.rb +25 -0
  53. data/spec/lib/cathode/destroy_request_spec.rb +28 -0
  54. data/spec/lib/cathode/index_request_spec.rb +62 -0
  55. data/spec/lib/cathode/object_collection_spec.rb +66 -0
  56. data/spec/lib/cathode/query_spec.rb +28 -0
  57. data/spec/lib/cathode/request_spec.rb +58 -0
  58. data/spec/lib/cathode/resource_spec.rb +482 -0
  59. data/spec/lib/cathode/show_request_spec.rb +23 -0
  60. data/spec/lib/cathode/update_request_spec.rb +41 -0
  61. data/spec/lib/cathode/version_spec.rb +416 -0
  62. data/spec/models/cathode/token_spec.rb +62 -0
  63. data/spec/spec_helper.rb +8 -2
  64. data/spec/support/factories/payments.rb +3 -0
  65. data/spec/support/factories/sale.rb +3 -0
  66. data/spec/support/factories/salespeople.rb +3 -0
  67. data/spec/support/factories/token.rb +3 -0
  68. data/spec/support/helpers.rb +13 -2
  69. metadata +192 -47
  70. data/app/helpers/cathode/application_helper.rb +0 -4
  71. data/spec/dummy/app/api/dummy_api.rb +0 -4
  72. data/spec/integration/api_spec.rb +0 -88
  73. data/spec/lib/action_spec.rb +0 -140
  74. data/spec/lib/base_spec.rb +0 -28
  75. data/spec/lib/request_spec.rb +0 -5
  76. data/spec/lib/resources_spec.rb +0 -78
  77. data/spec/lib/versioning_spec.rb +0 -104
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cathode::ShowRequest do
4
+ subject do
5
+ Cathode::ShowRequest.new(context_stub(params: ActionController::Parameters.new(params.merge(controller: 'products', action: 'show'))))
6
+ end
7
+ before do
8
+ use_api do
9
+ resources :products, actions: [:show]
10
+ end
11
+ end
12
+
13
+ let(:params) { { id: 3 } }
14
+ let!(:products) { create_list(:product, 3) }
15
+
16
+ it 'sets status as ok' do
17
+ expect(subject._status).to eq(:ok)
18
+ end
19
+
20
+ it 'sets body as the resource' do
21
+ expect(subject._body).to eq(products[2])
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cathode::UpdateRequest do
4
+ subject do
5
+ Cathode::UpdateRequest.new(context_stub(params: ActionController::Parameters.new(params.merge(controller: 'products', action: 'update'))))
6
+ end
7
+ before do
8
+ use_api do
9
+ resources :products, actions: [:update] do
10
+ attributes do
11
+ params.require(:product).permit(:title)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ let!(:product) { create(:product, title: 'cool product') }
17
+
18
+ context 'with valid attributes' do
19
+ let(:params) { { id: product.id, product: { title: 'cooler product' } } }
20
+
21
+ it 'sets status as ok' do
22
+ expect(subject._status).to eq(:ok)
23
+ end
24
+
25
+ it 'sets body as the updated record' do
26
+ expect(subject._body.title).to eq('cooler product')
27
+ end
28
+ end
29
+
30
+ context 'with invalid attributes' do
31
+ let(:params) { { id: product.id, title: 'cooler product' } }
32
+
33
+ it 'sets status as bad request' do
34
+ expect(subject._status).to eq(:bad_request)
35
+ end
36
+
37
+ it 'sets body as error message' do
38
+ expect(subject._body).to eq('param is missing or the value is empty: product')
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,416 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cathode::Version do
4
+ describe '.standardize' do
5
+ subject { Cathode::Version.standardize(version) }
6
+
7
+ context 'with integer' do
8
+ let(:version) { 1 }
9
+
10
+ it 'sets the semantic version' do
11
+ expect(subject).to eq('1.0.0')
12
+ end
13
+ end
14
+
15
+ context 'with float' do
16
+ let(:version) { 1.5 }
17
+
18
+ it 'sets the semantic version' do
19
+ expect(subject).to eq('1.5.0')
20
+ end
21
+ end
22
+
23
+ context 'with string' do
24
+ let(:version) { '1.5.1' }
25
+
26
+ it 'sets the semantic version' do
27
+ expect(subject).to eq('1.5.1')
28
+ end
29
+ end
30
+
31
+ context 'with prerelease' do
32
+ let(:version) { '1.6.0-pre' }
33
+
34
+ it 'sets the semantic version' do
35
+ expect(subject).to eq('1.6.0-pre')
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '.define' do
41
+ subject { Cathode::Version.define('1.0.0') { resources :sales } }
42
+
43
+ context 'when version already exists' do
44
+ before do
45
+ use_api do
46
+ resources :products, actions: [:index]
47
+ end
48
+ end
49
+
50
+ it 'adds to the version' do
51
+ expect(subject._resources.names).to match_array([:products, :sales])
52
+ end
53
+ end
54
+
55
+ context 'when version does not exist' do
56
+ it 'creates a new version' do
57
+ expect(subject._resources.names).to match_array([:sales])
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '.new' do
63
+ subject { Cathode::Version.new(version, &block) }
64
+ let(:version) { 1 }
65
+ before(:each) do
66
+ Cathode::Version.all.clear
67
+ end
68
+
69
+ context 'with bad version number' do
70
+ let(:version) { 'a' }
71
+ let(:block) { nil }
72
+
73
+ it 'raises an error' do
74
+ expect { subject }.to raise_error(ArgumentError)
75
+ end
76
+ end
77
+
78
+ context 'with no params or block' do
79
+ let(:block) do
80
+ proc do
81
+ resources :products
82
+ end
83
+ end
84
+
85
+ it 'creates the resource' do
86
+ expect(Cathode::Resource).to receive(:new) do |resource, params, &block|
87
+ expect(resource).to eq(:products)
88
+ expect(params).to eq(singular: false)
89
+ expect(block).to be_nil
90
+ end
91
+ subject
92
+ end
93
+ end
94
+
95
+ context 'with params' do
96
+ let(:block) do
97
+ proc do
98
+ resources :sales, actions: [:index, :create]
99
+ end
100
+ end
101
+
102
+ it 'creates the resource' do
103
+ expect(Cathode::Resource).to receive(:new) do |resource, params, &block|
104
+ expect(resource).to eq(:sales)
105
+ expect(params).to eq(actions: [:index, :create], singular: false)
106
+ expect(block).to be_nil
107
+ end
108
+ subject
109
+ end
110
+ end
111
+
112
+ context 'with params and block' do
113
+ let(:block) do
114
+ proc do
115
+ get :custom
116
+ resources :sales, actions: [:index] do
117
+ action :show
118
+ end
119
+ end
120
+ end
121
+
122
+ it 'creates the resource' do
123
+ expect(subject._resources.names).to match_array([:sales])
124
+ end
125
+
126
+ it 'creates the action' do
127
+ expect(subject.actions.names).to match_array([:custom])
128
+ end
129
+ end
130
+
131
+ context 'with duplicate resource' do
132
+ let(:block) do
133
+ proc do
134
+ resources :products, actions: [:index]
135
+ resources :products, actions: [:show]
136
+ end
137
+ end
138
+
139
+ it 'combines the actions' do
140
+ expect(subject._resources.names).to match_array([:products])
141
+ expect(subject._resources.find(:products).actions.names).to match_array([:index, :show])
142
+ end
143
+ end
144
+
145
+ context 'with inherited version' do
146
+ before do
147
+ Cathode::Version.new 1 do
148
+ resources :sales, actions: [:index, :show]
149
+ get :status
150
+ end
151
+ end
152
+ let(:version) { 1.5 }
153
+
154
+ context 'with a new action' do
155
+ let(:block) do
156
+ proc do
157
+ resources :sales do
158
+ action :destroy
159
+ end
160
+ end
161
+ end
162
+
163
+ it 'inherits the actions from the previous version' do
164
+ expect(subject._resources.names).to match_array([:sales])
165
+ expect(subject._resources.find(:sales).actions.names).to match_array([:index, :show, :destroy])
166
+ expect(subject.actions.names).to eq([:status])
167
+ end
168
+
169
+ it 'leaves the previous version intact' do
170
+ subject
171
+ previous_version = Cathode::Version.find('1.0.0')
172
+ expect(previous_version._resources.find(:sales).actions.names).to match_array([:index, :show])
173
+ end
174
+ end
175
+
176
+ context 'with a new resource' do
177
+ let(:block) { proc { resources :products, actions: [:index] } }
178
+
179
+ it 'inherits the resources from the previous version' do
180
+ expect(subject._resources.names).to match_array([:products, :sales])
181
+ expect(subject._resources.find(:sales).actions.names).to match_array([:index, :show])
182
+ expect(subject._resources.find(:products).actions.names).to match_array([:index])
183
+ end
184
+ end
185
+
186
+ context 'with a removed resource' do
187
+ context 'with an unkown resource' do
188
+ let(:block) { proc { remove_resources :factories } }
189
+
190
+ it 'raises an error' do
191
+ expect { subject }.to raise_error(Cathode::UnknownResourceError)
192
+ end
193
+ end
194
+
195
+ context 'with a single resource' do
196
+ let(:block) do
197
+ proc do
198
+ resources :products, actions: [:index]
199
+ remove_resources :sales
200
+ end
201
+ end
202
+
203
+ it 'does not use the resource' do
204
+ expect(subject._resources.names).to match_array([:products])
205
+ end
206
+ end
207
+
208
+ context 'with an array of resources' do
209
+ before do
210
+ Cathode::Version.new 1.2 do
211
+ resources :products, actions: [:index]
212
+ end
213
+ end
214
+
215
+ let(:block) { proc { remove_resources [:sales, :products] } }
216
+
217
+ it 'does not use the resource' do
218
+ expect(subject._resources.names).to be_empty
219
+ end
220
+ end
221
+ end
222
+
223
+ context 'with a removed action' do
224
+ context 'within a resource' do
225
+ context 'with an unknown resource' do
226
+ let(:block) { proc { remove_action :destroy, from: :unknown } }
227
+
228
+ it 'raises an error' do
229
+ expect { subject }.to raise_error(
230
+ Cathode::UnknownResourceError,
231
+ "Unknown resource `unknown' on ancestor version 1.0.0"
232
+ )
233
+ end
234
+ end
235
+
236
+ context 'with an unkown action' do
237
+ let(:block) { proc { remove_action :destroy, from: :sales } }
238
+
239
+ it 'raises an error' do
240
+ expect { subject }.to raise_error(
241
+ Cathode::UnknownActionError,
242
+ "Unknown action `destroy' on resource `sales'"
243
+ )
244
+ end
245
+ end
246
+
247
+ context 'with a single action' do
248
+ let(:block) do
249
+ proc do
250
+ resources :products, actions: [:index]
251
+ remove_action :index, from: :sales
252
+ end
253
+ end
254
+
255
+ it 'does not use the action' do
256
+ subject
257
+ expect(subject._resources.find(:sales).actions.names).to match_array([:show])
258
+ expect(subject._resources.find(:products).actions.names).to match_array([:index])
259
+ end
260
+ end
261
+
262
+ context 'with multiple actions' do
263
+ let(:block) do
264
+ proc do
265
+ resources :products, actions: [:index]
266
+ remove_actions :index, :show, from: :sales
267
+ end
268
+ end
269
+
270
+ it 'does not use the actions' do
271
+ subject
272
+ expect(subject._resources.find(:sales).actions.names).to match_array([])
273
+ expect(subject._resources.find(:products).actions.names).to match_array([:index])
274
+ end
275
+ end
276
+ end
277
+
278
+ context 'outside of a resource' do
279
+ before do
280
+ Cathode::Version.new 1.5 do
281
+ get :custom
282
+ delete :custom2
283
+ end
284
+ end
285
+ let(:version) { 2 }
286
+
287
+ context 'with an unkown action' do
288
+ let(:block) { proc { remove_action :unknown } }
289
+
290
+ it 'raises an error' do
291
+ expect { subject }.to raise_error(
292
+ Cathode::UnknownActionError,
293
+ "Unknown action `unknown' on ancestor version 1.5.0"
294
+ )
295
+ end
296
+ end
297
+
298
+ context 'with a single action' do
299
+ let(:block) { proc { remove_action :custom } }
300
+
301
+ it 'removes the action' do
302
+ expect(subject.actions.names).to match_array([:status, :custom2])
303
+ end
304
+ end
305
+
306
+ context 'with multiple actions' do
307
+ let(:block) { proc { remove_actions :custom, :custom2 } }
308
+
309
+ it 'removes the action' do
310
+ expect(subject.actions.names).to eq([:status])
311
+ end
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end
317
+
318
+ describe '.find' do
319
+ subject { Cathode::Version.find(version_number) }
320
+ before do
321
+ use_api do
322
+ resources :products
323
+ version 1.5 do
324
+ resources :sales
325
+ end
326
+ end
327
+ end
328
+
329
+ context 'with a valid SemVer number' do
330
+ let(:version_number) { '1.5.0' }
331
+
332
+ it 'returns the version matching the version number' do
333
+ expect(subject.version).to eq('1.5.0')
334
+ end
335
+ end
336
+
337
+ context 'with a non-standard SemVer number' do
338
+ let(:version_number) { '1.5' }
339
+
340
+ it 'returns the version matching the standardized number' do
341
+ expect(subject.version).to eq('1.5.0')
342
+ end
343
+ end
344
+
345
+ context 'with an invalid SemVer number' do
346
+ let(:version_number) { '1.x' }
347
+
348
+ it 'returns nil' do
349
+ expect(subject).to be_nil
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#resource?' do
355
+ subject { Cathode::Version.find('1.0.0').resource?(resource) }
356
+ before do
357
+ use_api do
358
+ resources :products
359
+ end
360
+ end
361
+
362
+ context 'when the resource is present' do
363
+ let(:resource) { 'products' }
364
+
365
+ it 'is true' do
366
+ expect(subject).to be_true
367
+ end
368
+ end
369
+
370
+ context 'when the resource is not present' do
371
+ let(:resource) { 'sales' }
372
+
373
+ it 'is false' do
374
+ expect(subject).to be_false
375
+ end
376
+ end
377
+ end
378
+
379
+ describe '#action?' do
380
+ subject { Cathode::Version.find('1.0.0').action?(resource, action) }
381
+ before do
382
+ use_api do
383
+ resources :products, actions: [:index]
384
+ end
385
+ end
386
+
387
+ context 'when the resource is not present' do
388
+ let(:resource) { 'sales' }
389
+ let(:action) { 'index' }
390
+
391
+ it 'is false' do
392
+ expect(subject).to be_false
393
+ end
394
+ end
395
+
396
+ context 'when the resource is present' do
397
+ let(:resource) { 'products' }
398
+
399
+ context 'when the action is present' do
400
+ let(:action) { 'index' }
401
+
402
+ it 'is true' do
403
+ expect(subject).to be_true
404
+ end
405
+ end
406
+
407
+ context 'when the action is not present' do
408
+ let(:action) { 'show' }
409
+
410
+ it 'is false' do
411
+ expect(subject).to be_false
412
+ end
413
+ end
414
+ end
415
+ end
416
+ end