resourcy-rails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +25 -0
- data/lib/resourcy/engine.rb +4 -0
- data/lib/resourcy/rails.rb +4 -0
- data/lib/resourcy/version.rb +3 -0
- data/lib/resourcy-rails.rb +1 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/jquery-1.7.1.js +9266 -0
- data/spec/dummy/app/assets/javascripts/jquery-1.8.0.js +9227 -0
- data/spec/dummy/app/controllers/posts_controller.rb +85 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/views/posts/_form.html.erb +25 -0
- data/spec/dummy/app/views/posts/edit.html.erb +6 -0
- data/spec/dummy/app/views/posts/index.html.erb +25 -0
- data/spec/dummy/app/views/posts/new.html.erb +5 -0
- data/spec/dummy/app/views/posts/show.html.erb +15 -0
- data/spec/dummy/config/application.rb +63 -0
- data/spec/dummy/config/boot.rb +9 -0
- data/spec/dummy/config/database.yml +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/evergreen.rb +47 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +64 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20120825050219_create_posts.rb +10 -0
- data/spec/dummy/db/structure.sql +4 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/index.html +12 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/javascripts/jquery.resourcy_spec.js.coffee +399 -0
- data/spec/javascripts/resourcy_spec.js.coffee +177 -0
- data/spec/javascripts/spec_helper.js +37 -0
- data/spec/javascripts/templates/ujs.html +3 -0
- data/vendor/assets/javascripts/jquery.resourcy.js.coffee +37 -0
- data/vendor/assets/javascripts/resourcy.js.coffee +104 -0
- metadata +229 -0
@@ -0,0 +1,399 @@
|
|
1
|
+
require '/assets/jquery-1.8.0.js'
|
2
|
+
require '/assets/jquery.resourcy.js'
|
3
|
+
require '/assets/jquery_ujs.js'
|
4
|
+
|
5
|
+
describe "Resourcy jQuery Adapter (1.8.0)", ->
|
6
|
+
|
7
|
+
beforeEach ->
|
8
|
+
R.removeAll()
|
9
|
+
|
10
|
+
describe "plugin signature", ->
|
11
|
+
|
12
|
+
it "has all the methods it should have", ->
|
13
|
+
expect(typeof($.resources)).toBe('function')
|
14
|
+
expect(typeof($.resource)).toBe('function')
|
15
|
+
expect(typeof($.routes)).toBe('function')
|
16
|
+
expect($.handleRequest).toBeUndefined()
|
17
|
+
|
18
|
+
it "removes Resourcy", ->
|
19
|
+
expect(window.Resourcy).toBeUndefined()
|
20
|
+
|
21
|
+
|
22
|
+
describe "plural resources", ->
|
23
|
+
|
24
|
+
beforeEach ->
|
25
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
26
|
+
@resource = $.resources('blogs/:blog_id/posts').add(RESOURCES.POSTS)
|
27
|
+
@url = '/blogs/1/posts'
|
28
|
+
|
29
|
+
it "handles the index action", ->
|
30
|
+
spy = spyOn(@resource.actions, 'index')
|
31
|
+
$.ajax(@url, {type: 'get'})
|
32
|
+
|
33
|
+
expect(spy.callCount).toBe(1)
|
34
|
+
|
35
|
+
it "handles the show action", ->
|
36
|
+
spy = spyOn(@resource.actions, 'show')
|
37
|
+
$.ajax("#{@url}/1", {type: 'get'})
|
38
|
+
|
39
|
+
expect(spy.callCount).toBe(1)
|
40
|
+
|
41
|
+
it "handles the new action", ->
|
42
|
+
spy = spyOn(@resource.actions, 'new')
|
43
|
+
$.ajax("#{@url}/new", {type: 'get'})
|
44
|
+
|
45
|
+
expect(spy.callCount).toBe(1)
|
46
|
+
|
47
|
+
it "handles the create action", ->
|
48
|
+
spy = spyOn(@resource.actions, 'create')
|
49
|
+
$.ajax(@url, {type: 'post'})
|
50
|
+
|
51
|
+
expect(spy.callCount).toBe(1)
|
52
|
+
|
53
|
+
it "handles the edit action", ->
|
54
|
+
spy = spyOn(@resource.actions, 'edit')
|
55
|
+
$.ajax("#{@url}/1/edit", {type: 'get'})
|
56
|
+
|
57
|
+
expect(spy.callCount).toBe(1)
|
58
|
+
|
59
|
+
it "handles the update action", ->
|
60
|
+
spy = spyOn(@resource.actions, 'update')
|
61
|
+
$.ajax("#{@url}/1", {type: 'put'})
|
62
|
+
|
63
|
+
expect(spy.callCount).toBe(1)
|
64
|
+
|
65
|
+
it "handles the destroy action", ->
|
66
|
+
spy = spyOn(@resource.actions, 'destroy')
|
67
|
+
$.ajax("#{@url}/1", {type: 'delete'})
|
68
|
+
|
69
|
+
expect(spy.callCount).toBe(1)
|
70
|
+
|
71
|
+
it "handles get members", ->
|
72
|
+
spy = spyOn(@resource.actions.get, 'comments')
|
73
|
+
$.ajax("#{@url}/1/comments", {type: 'get'})
|
74
|
+
|
75
|
+
expect(spy.callCount).toBe(1)
|
76
|
+
|
77
|
+
it "handles put members", ->
|
78
|
+
spy = spyOn(@resource.actions.put, 'publish')
|
79
|
+
$.ajax("#{@url}/1/publish", {type: 'put'})
|
80
|
+
|
81
|
+
expect(spy.callCount).toBe(1)
|
82
|
+
|
83
|
+
it "handles post members", ->
|
84
|
+
spy = spyOn(@resource.actions.post, 'reorder')
|
85
|
+
$.ajax("#{@url}/1/reorder", {type: 'post'})
|
86
|
+
|
87
|
+
expect(spy.callCount).toBe(1)
|
88
|
+
|
89
|
+
it "handles delete members", ->
|
90
|
+
spy = spyOn(@resource.actions.delete, 'comments')
|
91
|
+
$.ajax("#{@url}/1/comments", {type: 'delete'})
|
92
|
+
|
93
|
+
expect(spy.callCount).toBe(1)
|
94
|
+
|
95
|
+
describe "ajax arguments", ->
|
96
|
+
|
97
|
+
it "accepts the url in the options object", ->
|
98
|
+
spy = spyOn(@resource.actions, 'index')
|
99
|
+
$.ajax({url: @url, type: 'get'})
|
100
|
+
|
101
|
+
expect(spy.callCount).toBe(1)
|
102
|
+
|
103
|
+
it "falls back to _method if it's provided in the data", ->
|
104
|
+
spy = spyOn(@resource.actions, 'create')
|
105
|
+
data = [{name: '_method', value: 'post'}]
|
106
|
+
$.ajax({url: @url, data: data})
|
107
|
+
|
108
|
+
expect(spy.callCount).toBe(1)
|
109
|
+
|
110
|
+
|
111
|
+
describe "singular resources", ->
|
112
|
+
|
113
|
+
beforeEach ->
|
114
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
115
|
+
@resource = $.resource('blogs/:blog_id/owner').add(RESOURCES.OWNER)
|
116
|
+
@url = '/blogs/1/owner'
|
117
|
+
|
118
|
+
it "handles the show action", ->
|
119
|
+
spy = spyOn(@resource.actions, 'show')
|
120
|
+
$.ajax(@url, {type: 'get'})
|
121
|
+
|
122
|
+
expect(spy.callCount).toBe(1)
|
123
|
+
|
124
|
+
it "handles the new action", ->
|
125
|
+
spy = spyOn(@resource.actions, 'new')
|
126
|
+
$.ajax("#{@url}/new", {type: 'get'})
|
127
|
+
|
128
|
+
expect(spy.callCount).toBe(1)
|
129
|
+
|
130
|
+
it "handles the create action", ->
|
131
|
+
spy = spyOn(@resource.actions, 'create')
|
132
|
+
$.ajax(@url, {type: 'post'})
|
133
|
+
|
134
|
+
expect(spy.callCount).toBe(1)
|
135
|
+
|
136
|
+
it "handles the edit action", ->
|
137
|
+
spy = spyOn(@resource.actions, 'edit')
|
138
|
+
$.ajax(@url + '/edit', {type: 'get'})
|
139
|
+
|
140
|
+
expect(spy.callCount).toBe(1)
|
141
|
+
|
142
|
+
it "handles the update action", ->
|
143
|
+
spy = spyOn(@resource.actions, 'update')
|
144
|
+
$.ajax(@url, {type: 'put'})
|
145
|
+
|
146
|
+
expect(spy.callCount).toBe(1)
|
147
|
+
|
148
|
+
it "handles the destroy action", ->
|
149
|
+
spy = spyOn(@resource.actions, 'destroy')
|
150
|
+
$.ajax(@url, {type: 'delete'})
|
151
|
+
|
152
|
+
expect(spy.callCount).toBe(1)
|
153
|
+
|
154
|
+
it "handles get members", ->
|
155
|
+
@resource.add('get:blogs', ->)
|
156
|
+
spy = spyOn(@resource.actions.get, 'blogs')
|
157
|
+
$.ajax("#{@url}/blogs", {type: 'get'})
|
158
|
+
|
159
|
+
expect(spy.callCount).toBe(1)
|
160
|
+
|
161
|
+
it "handles put members", ->
|
162
|
+
@resource.add('put:demote', ->)
|
163
|
+
spy = spyOn(@resource.actions.put, 'demote')
|
164
|
+
$.ajax("#{@url}/demote", {type: 'put'})
|
165
|
+
|
166
|
+
expect(spy.callCount).toBe(1)
|
167
|
+
|
168
|
+
it "handles post members", ->
|
169
|
+
@resource.add('post:blogs', ->)
|
170
|
+
spy = spyOn(@resource.actions.post, 'blogs')
|
171
|
+
$.ajax("#{@url}/blogs", {type: 'post'})
|
172
|
+
|
173
|
+
expect(spy.callCount).toBe(1)
|
174
|
+
|
175
|
+
it "handles delete members", ->
|
176
|
+
@resource.add('delete:blog', ->)
|
177
|
+
spy = spyOn(@resource.actions.delete, 'blog')
|
178
|
+
$.ajax("#{@url}/blog", {type: 'delete'})
|
179
|
+
|
180
|
+
expect(spy.callCount).toBe(1)
|
181
|
+
|
182
|
+
|
183
|
+
describe "callbacks", ->
|
184
|
+
|
185
|
+
beforeEach ->
|
186
|
+
@resource = $.resources('blogs/:blog_id/posts')
|
187
|
+
@url = '/blogs/1/posts'
|
188
|
+
@callback = -> 'callback'
|
189
|
+
|
190
|
+
describe "passed arguments", ->
|
191
|
+
|
192
|
+
beforeEach ->
|
193
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
194
|
+
@resource.add('index', => {success: @callback})
|
195
|
+
@actionSpy = spyOn(@resource.actions, 'index').andCallThrough()
|
196
|
+
|
197
|
+
it "passes the proceed function", ->
|
198
|
+
$.ajax('/blogs/1/posts', {type: 'get'})
|
199
|
+
|
200
|
+
expect(typeof(@actionSpy.argsForCall[0][0])).toEqual('function')
|
201
|
+
|
202
|
+
it "passes parsed path variables with their values", ->
|
203
|
+
$.ajax('/blogs/42/posts', {type: 'get'})
|
204
|
+
|
205
|
+
expect(@actionSpy.argsForCall[0][1]).toEqual({blog_id: '42'})
|
206
|
+
|
207
|
+
it "passes the requests url parts", ->
|
208
|
+
$.ajax('http://jejacks0n:password@localhost:3000/blogs/42/posts.json?foo=bar#hash', {type: 'get'})
|
209
|
+
|
210
|
+
expect(@actionSpy.argsForCall[0][2]).toEqual
|
211
|
+
scheme: 'http'
|
212
|
+
credentials: 'jejacks0n:password'
|
213
|
+
host: 'localhost'
|
214
|
+
port: '3000'
|
215
|
+
path: '/blogs/42/posts'
|
216
|
+
action: 'posts'
|
217
|
+
format: 'json'
|
218
|
+
query: 'foo=bar'
|
219
|
+
hash: 'hash'
|
220
|
+
|
221
|
+
|
222
|
+
describe "returning values", ->
|
223
|
+
|
224
|
+
it "allows returning options that will be used for the request", ->
|
225
|
+
@resource.add('index', => {success: @callback})
|
226
|
+
spy = spyOn(@, 'callback')
|
227
|
+
|
228
|
+
runs -> $.ajax(@url, {type: 'get'})
|
229
|
+
waitsFor -> spy.callCount
|
230
|
+
|
231
|
+
runs -> expect(spy.callCount).toBe(1)
|
232
|
+
|
233
|
+
it "handles the complete callback", ->
|
234
|
+
@resource.add('index', => {success: @callback, complete: @callback})
|
235
|
+
spy = spyOn(@, 'callback')
|
236
|
+
|
237
|
+
runs -> $.ajax(@url, {type: 'get'})
|
238
|
+
waitsFor -> spy.callCount == 2
|
239
|
+
|
240
|
+
runs -> expect(spy.callCount).toBe(2)
|
241
|
+
|
242
|
+
it "handles the beforeSend callback", ->
|
243
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
244
|
+
@resource.add('index', => {beforeSend: @callback})
|
245
|
+
spy = spyOn(@, 'callback')
|
246
|
+
|
247
|
+
$.ajax(@url, {type: 'get'})
|
248
|
+
|
249
|
+
expect(spy.callCount).toBe(1)
|
250
|
+
|
251
|
+
it "handles the dataFilter callback", ->
|
252
|
+
@resource.add('index', => {dataFilter: @callback})
|
253
|
+
spy = spyOn(@, 'callback')
|
254
|
+
|
255
|
+
runs -> $.ajax(@url, {type: 'get', dataType: 'json'})
|
256
|
+
waitsFor -> spy.callCount
|
257
|
+
|
258
|
+
runs -> expect(spy.argsForCall[0][1]).toBe('json')
|
259
|
+
|
260
|
+
it "handles the error callback", ->
|
261
|
+
@resource = $.resources('blogs')
|
262
|
+
@resource.add('index', => {error: @callback})
|
263
|
+
spy = spyOn(@, 'callback')
|
264
|
+
|
265
|
+
runs -> $.ajax('/blogs', {type: 'get'})
|
266
|
+
waitsFor -> spy.callCount
|
267
|
+
|
268
|
+
runs -> expect(spy.callCount).toBe(1)
|
269
|
+
|
270
|
+
describe "and proceeding", ->
|
271
|
+
|
272
|
+
it "proceeds when you return an object", ->
|
273
|
+
@resource.add('index', => {success: @callback})
|
274
|
+
spy = spyOn(@, 'callback')
|
275
|
+
|
276
|
+
runs -> $.ajax(@url, {method: 'get'})
|
277
|
+
waitsFor -> spy.callCount
|
278
|
+
|
279
|
+
runs -> expect(spy.callCount).toBe(1)
|
280
|
+
|
281
|
+
it "doesn't proceed when proceed is called", ->
|
282
|
+
@resource.add('index', (proceed) => proceed({success: @callback}))
|
283
|
+
spy = spyOn(@, 'callback')
|
284
|
+
|
285
|
+
runs -> $.ajax(@url, {method: 'get'})
|
286
|
+
waitsFor -> spy.callCount
|
287
|
+
|
288
|
+
runs -> expect(spy.callCount).toBe(1)
|
289
|
+
|
290
|
+
it "doesn't proceed when returning false", ->
|
291
|
+
spy = spyOn(@, 'callback').andCallFake(-> false)
|
292
|
+
ajaxSpy = spyOn($, 'originalAjax')
|
293
|
+
@resource.add('index', @callback)
|
294
|
+
$.ajax(@url, {method: 'get'})
|
295
|
+
|
296
|
+
expect(ajaxSpy.callCount).toBe(0)
|
297
|
+
|
298
|
+
it "doesn't call proceed more than once", ->
|
299
|
+
@resource.add 'index', (proceed) =>
|
300
|
+
proceed({success: @callback})
|
301
|
+
return {success: @callback}
|
302
|
+
spy = spyOn(@, 'callback')
|
303
|
+
|
304
|
+
runs -> $.ajax(@url, {method: 'get'})
|
305
|
+
waitsFor -> spy.callCount
|
306
|
+
|
307
|
+
runs -> expect(spy.callCount).toBe(1)
|
308
|
+
|
309
|
+
describe "chained callbacks", ->
|
310
|
+
|
311
|
+
beforeEach ->
|
312
|
+
@resource = $.resources('blogs/:blog_id/posts')
|
313
|
+
@url = '/blogs/1/posts'
|
314
|
+
@callback = -> 'callback'
|
315
|
+
|
316
|
+
it "calls both success callbacks", ->
|
317
|
+
@resource.add('index', => {success: @callback})
|
318
|
+
spy = spyOn(@, 'callback')
|
319
|
+
|
320
|
+
runs -> $.ajax(@url, {method: 'get', success: @callback})
|
321
|
+
waitsFor -> spy.callCount == 2
|
322
|
+
|
323
|
+
runs -> expect(spy.callCount).toBe(2)
|
324
|
+
|
325
|
+
it "calls both beforeSend callbacks", ->
|
326
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
327
|
+
@resource.add('index', => {beforeSend: @callback})
|
328
|
+
spy = spyOn(@, 'callback')
|
329
|
+
|
330
|
+
$.ajax(@url, {type: 'get', beforeSend: @callback})
|
331
|
+
|
332
|
+
expect(spy.callCount).toBe(2)
|
333
|
+
|
334
|
+
it "calls both dataFilter callbacks", ->
|
335
|
+
@resource.add('index', => {dataFilter: @callback})
|
336
|
+
spy = spyOn(@, 'callback')
|
337
|
+
|
338
|
+
runs -> $.ajax(@url, {type: 'get', dataType: 'json', dataFilter: @callback})
|
339
|
+
waitsFor -> spy.callCount == 2
|
340
|
+
|
341
|
+
runs -> expect(spy.argsForCall[1][1]).toBe('json')
|
342
|
+
|
343
|
+
it "calls both complete callbacks", ->
|
344
|
+
@resource.add('index', => {complete: @callback})
|
345
|
+
spy = spyOn(@, 'callback')
|
346
|
+
|
347
|
+
runs -> $.ajax(@url, {type: 'get', dataType: 'json', complete: @callback})
|
348
|
+
waitsFor -> spy.callCount == 2
|
349
|
+
|
350
|
+
runs -> expect(spy.callCount).toBe(2)
|
351
|
+
|
352
|
+
it "calls both error callbacks", ->
|
353
|
+
@resource = $.resources('blogs')
|
354
|
+
@resource.add('index', => {error: @callback})
|
355
|
+
spy = spyOn(@, 'callback')
|
356
|
+
|
357
|
+
runs -> $.ajax('/blogs', {method: 'get', error: @callback})
|
358
|
+
waitsFor -> spy.callCount == 2
|
359
|
+
|
360
|
+
runs -> expect(spy.callCount).toBe(2)
|
361
|
+
|
362
|
+
it "allows mixing $.ajax().done() style callbacks", ->
|
363
|
+
@resource.add('index', => {success: @callback})
|
364
|
+
spy = spyOn(@, 'callback')
|
365
|
+
|
366
|
+
runs -> $.ajax(@url, {method: 'get'}).done(@callback)
|
367
|
+
waitsFor -> spy.callCount == 2
|
368
|
+
|
369
|
+
runs -> expect(spy.callCount).toBe(2)
|
370
|
+
|
371
|
+
|
372
|
+
describe "using UJS", ->
|
373
|
+
|
374
|
+
template 'ujs.html'
|
375
|
+
|
376
|
+
beforeEach ->
|
377
|
+
@resource = $.resources('posts')
|
378
|
+
@callback = -> 'callback'
|
379
|
+
|
380
|
+
it "allows :remote => true", ->
|
381
|
+
spyOn(window, 'XMLHttpRequest') # keep these requests from being fully requested
|
382
|
+
spy = spyOn(@, 'callback')
|
383
|
+
@resource.add('show', @callback)
|
384
|
+
@resource.add('edit', @callback)
|
385
|
+
|
386
|
+
$('a#show').click()
|
387
|
+
expect(spy.callCount).toBe(1)
|
388
|
+
|
389
|
+
$('a#edit').click()
|
390
|
+
expect(spy.callCount).toBe(2)
|
391
|
+
|
392
|
+
it "allows :remote => true to call callbacks", ->
|
393
|
+
spy = spyOn(@, 'callback')
|
394
|
+
@resource.add('show', => {success: @callback})
|
395
|
+
|
396
|
+
runs -> $('a#show').click()
|
397
|
+
waitsFor -> spy.callCount
|
398
|
+
|
399
|
+
runs -> expect(spy.callCount).toBe(1)
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require '/assets/resourcy.js'
|
2
|
+
|
3
|
+
describe "Resourcy", ->
|
4
|
+
|
5
|
+
beforeEach ->
|
6
|
+
Resourcy.removeAll()
|
7
|
+
|
8
|
+
describe ".resources (creating a plural resource)", ->
|
9
|
+
|
10
|
+
beforeEach ->
|
11
|
+
@resource = Resourcy.resources('blogs/:blog_id/posts')
|
12
|
+
|
13
|
+
it "returns a resource", ->
|
14
|
+
expect(typeof(@resource)).toBe('object')
|
15
|
+
|
16
|
+
it "sets information on the resource", ->
|
17
|
+
expect(@resource.pathvars).toEqual(['blog_id'])
|
18
|
+
expect(@resource.actions).toEqual({})
|
19
|
+
expect(@resource.singular).toBe(false)
|
20
|
+
expect(@resource.name).toBe('posts')
|
21
|
+
|
22
|
+
it "has an add, remove, and describe method", ->
|
23
|
+
expect(typeof(@resource.add)).toBe('function')
|
24
|
+
expect(typeof(@resource.remove)).toBe('function')
|
25
|
+
expect(typeof(@resource.describe)).toBe('function')
|
26
|
+
|
27
|
+
it "can find an existing resource and return it", ->
|
28
|
+
r2 = Resourcy.resources('blogs/:blog_id/posts')
|
29
|
+
expect(r2).toBe(@resource)
|
30
|
+
|
31
|
+
|
32
|
+
describe ".resource (creating a singular resource)", ->
|
33
|
+
|
34
|
+
beforeEach ->
|
35
|
+
@resource = Resourcy.resource('blogs/:blog_id/owner')
|
36
|
+
|
37
|
+
it "returns a resource", ->
|
38
|
+
expect(typeof(@resource)).toBe('object')
|
39
|
+
|
40
|
+
it "sets information on the resource", ->
|
41
|
+
expect(@resource.pathvars).toEqual(['blog_id'])
|
42
|
+
expect(@resource.actions).toEqual({})
|
43
|
+
expect(@resource.singular).toBe(true)
|
44
|
+
expect(@resource.name).toBe('owner')
|
45
|
+
|
46
|
+
it "has an add, remove, and describe method", ->
|
47
|
+
expect(typeof(@resource.add)).toBe('function')
|
48
|
+
expect(typeof(@resource.remove)).toBe('function')
|
49
|
+
expect(typeof(@resource.describe)).toBe('function')
|
50
|
+
|
51
|
+
it "can find an existing resource and return it", ->
|
52
|
+
r2 = Resourcy.resource('blogs/:blog_id/owner')
|
53
|
+
|
54
|
+
expect(r2).toBe(@resource)
|
55
|
+
|
56
|
+
|
57
|
+
describe ".routes", ->
|
58
|
+
|
59
|
+
beforeEach ->
|
60
|
+
Resourcy.resources('blogs/:blog_id/posts')
|
61
|
+
Resourcy.resource('blogs/:blog_id/owner')
|
62
|
+
|
63
|
+
it "returns an object of registered resources", ->
|
64
|
+
expect(Resourcy.routes()).toEqual({owner: [], posts: []})
|
65
|
+
|
66
|
+
it "calls describe on all the resources", ->
|
67
|
+
spyOn(Resourcy.resources('blogs/:blog_id/posts'), 'describe').andCallFake(-> ['posts => foo'])
|
68
|
+
spyOn(Resourcy.resources('blogs/:blog_id/owner'), 'describe').andCallFake(-> ['owner => foo'])
|
69
|
+
|
70
|
+
expect(Resourcy.routes()).toEqual({owner: ['owner => foo'], posts: ['posts => foo']})
|
71
|
+
|
72
|
+
|
73
|
+
describe ".noConflict", ->
|
74
|
+
|
75
|
+
it "removes Resourcy", ->
|
76
|
+
Resourcy.noConflict() # in specs we've overridden noConflict to assign it to R (and remove it like normal)
|
77
|
+
|
78
|
+
expect(window.Resourcy).toBeUndefined()
|
79
|
+
window.Resourcy = window.R # and put it back now
|
80
|
+
|
81
|
+
|
82
|
+
describe "plural resources", ->
|
83
|
+
|
84
|
+
beforeEach ->
|
85
|
+
@resource = Resourcy.resources('blogs/:blog_id/posts')
|
86
|
+
@callback = -> 'callback'
|
87
|
+
|
88
|
+
describe "#add", ->
|
89
|
+
|
90
|
+
it "accepts an object, and adds to the actions", ->
|
91
|
+
@resource.add({index: @callback})
|
92
|
+
|
93
|
+
expect(@resource.actions.index).toBe(@callback)
|
94
|
+
|
95
|
+
it "accepts an string and callback, and adds to the actions", ->
|
96
|
+
@resource.add('put:activate', @callback)
|
97
|
+
|
98
|
+
expect(@resource.actions.put['activate']).toBe(@callback)
|
99
|
+
|
100
|
+
it "doesn't allow adding the same action more than once", ->
|
101
|
+
@resource.add({index: @callback})
|
102
|
+
|
103
|
+
expect(=> @resource.add({index: @callback}))
|
104
|
+
.toThrow("The index action already exists on the 'posts' resource. Try removing it first.")
|
105
|
+
|
106
|
+
it "returns itself for chaining", ->
|
107
|
+
expect(@resource.add('put:activate', @callback)).toBe(@resource)
|
108
|
+
|
109
|
+
|
110
|
+
describe "#remove", ->
|
111
|
+
|
112
|
+
beforeEach ->
|
113
|
+
@resource.add('index', @callback)
|
114
|
+
@resource.add('put:activate', @callback)
|
115
|
+
|
116
|
+
it "removes the action", ->
|
117
|
+
expect(@resource.actions.index).toBe(@callback)
|
118
|
+
expect(@resource.actions.put['activate']).toBe(@callback)
|
119
|
+
|
120
|
+
@resource.remove('index')
|
121
|
+
@resource.remove('put:activate')
|
122
|
+
|
123
|
+
expect(@resource.actions.index).toBeUndefined()
|
124
|
+
expect(@resource.actions.put['activate']).toBeUndefined()
|
125
|
+
|
126
|
+
it "returns itself for chaining", ->
|
127
|
+
expect(@resource.remove('index')).toBe(@resource)
|
128
|
+
|
129
|
+
|
130
|
+
describe "#removeAll", ->
|
131
|
+
|
132
|
+
beforeEach ->
|
133
|
+
@resource.add('index', @callback)
|
134
|
+
@resource.add('put:activate', @callback)
|
135
|
+
|
136
|
+
it "clears all actions", ->
|
137
|
+
expect(@resource.actions.index).toBe(@callback)
|
138
|
+
expect(@resource.actions.put['activate']).toBe(@callback)
|
139
|
+
|
140
|
+
@resource.removeAll()
|
141
|
+
|
142
|
+
expect(@resource.actions).toEqual({})
|
143
|
+
|
144
|
+
it "returns itself for chaining", ->
|
145
|
+
expect(@resource.removeAll()).toBe(@resource)
|
146
|
+
|
147
|
+
|
148
|
+
describe "#describe", ->
|
149
|
+
|
150
|
+
beforeEach ->
|
151
|
+
@resource.add('index', @callback)
|
152
|
+
@resource.add('put:activate', @callback)
|
153
|
+
|
154
|
+
it "returns an array describing the resource actions", ->
|
155
|
+
expect(@resource.describe()).toEqual(['blogs/:blog_id/posts/activate PUT => posts#activate', 'blogs/:blog_id/posts GET => posts#index'])
|
156
|
+
|
157
|
+
|
158
|
+
describe "singular resources", ->
|
159
|
+
|
160
|
+
beforeEach ->
|
161
|
+
@resource = Resourcy.resource('blogs/:blog_id/owner')
|
162
|
+
@callback = -> 'callback'
|
163
|
+
|
164
|
+
describe "#add", ->
|
165
|
+
|
166
|
+
it "doesn't allow adding the index action", ->
|
167
|
+
expect(=> @resource.add('index')).toThrow("Adding index to 'owner' isn't possible (singular resource).")
|
168
|
+
|
169
|
+
|
170
|
+
describe "#describe", ->
|
171
|
+
|
172
|
+
beforeEach ->
|
173
|
+
@resource.add('show', @callback)
|
174
|
+
@resource.add('put:activate', @callback)
|
175
|
+
|
176
|
+
it "returns an array describing the resource actions", ->
|
177
|
+
expect(@resource.describe()).toEqual(['blogs/:blog_id/owner/activate PUT => owner#activate', 'blogs/:blog_id/owner GET => owner#show'])
|
@@ -0,0 +1,37 @@
|
|
1
|
+
RESOURCES = {
|
2
|
+
POSTS: {
|
3
|
+
'index': function() { return 'PostsController#index' },
|
4
|
+
'show': function() { return 'PostsController#show' },
|
5
|
+
'new': function() { return 'PostsController#new' },
|
6
|
+
'create': function() { return 'PostsController#create' },
|
7
|
+
'edit': function() { return 'PostsController#edit' },
|
8
|
+
'update': function() { return 'PostsController#update' },
|
9
|
+
'destroy': function() { return 'PostsController#destroy'},
|
10
|
+
'get:comments': function() { return 'PostsController#comments:GET' },
|
11
|
+
'post:reorder': function() { return 'PostsController#reorder:POST' },
|
12
|
+
'delete:comments': function() { return 'PostsController#comments:DELETE' },
|
13
|
+
'put:publish': function() { return 'PostsController#publish:PUT' }
|
14
|
+
},
|
15
|
+
COMMENTS: {
|
16
|
+
'index': function() { return 'CommentsController#index' },
|
17
|
+
'new': function() { return 'CommentsController#new' },
|
18
|
+
'create': function() { return 'CommentsController#create' },
|
19
|
+
'destroy': function() { return 'CommentsController#destroy' },
|
20
|
+
'put:approve': function() { return 'CommentsController#publish:PUT' }
|
21
|
+
},
|
22
|
+
OWNER: {
|
23
|
+
'show': function() { return 'OwnerController#show' },
|
24
|
+
'new': function() { return 'OwnerController#new' },
|
25
|
+
'create': function() { return 'OwnerController#create' },
|
26
|
+
'edit': function() { return 'OwnerController#edit' },
|
27
|
+
'update': function() { return 'OwnerController#update' },
|
28
|
+
'destroy': function() { return 'OwnerController#destroy'},
|
29
|
+
}
|
30
|
+
};
|
31
|
+
|
32
|
+
window.Resourcy = {
|
33
|
+
noConflict: function() {
|
34
|
+
window.R = Resourcy;
|
35
|
+
delete(window.Resourcy);
|
36
|
+
}
|
37
|
+
};
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#= require resourcy
|
2
|
+
#
|
3
|
+
# Resourcy Ajax adapter
|
4
|
+
#
|
5
|
+
# This overrides the default jQuery.ajax method and mixes in the logic required to make Resourcy work with the options
|
6
|
+
# and arguments for the jQuery Ajax api.
|
7
|
+
|
8
|
+
# Get the original jQuery.ajax and merge in some additional methods from Resourcy.
|
9
|
+
original = jQuery.ajax
|
10
|
+
jQuery.extend(jQuery, {originalAjax: original, resources: Resourcy.resources, resource: Resourcy.resource, routes: Resourcy.routes})
|
11
|
+
|
12
|
+
# Remove Resourcy from the global namespace.
|
13
|
+
handleRequest = Resourcy.handleRequest
|
14
|
+
Resourcy.noConflict()
|
15
|
+
|
16
|
+
# Define an options handler, that properly merges options for the Ajax request.
|
17
|
+
optionsHandler = (opts1, opts2) ->
|
18
|
+
options = jQuery.extend(true, {}, opts1, opts2)
|
19
|
+
for method in ['beforeSend', 'error', 'dataFilter', 'success', 'complete']
|
20
|
+
if opts1[method] && opts2[method]
|
21
|
+
c1 = opts1[method]
|
22
|
+
c2 = opts2[method]
|
23
|
+
options[method] = ->
|
24
|
+
c1.apply(window, arguments)
|
25
|
+
c2.apply(window, arguments)
|
26
|
+
return options
|
27
|
+
|
28
|
+
# Create a new jQuery.ajax method that works with Resourcy.
|
29
|
+
jQuery.ajax = (url, options = {}) ->
|
30
|
+
if typeof(url) is 'object'
|
31
|
+
options = url
|
32
|
+
url = options.url
|
33
|
+
for data in options.data || []
|
34
|
+
if data.name is '_method'
|
35
|
+
method = data.value
|
36
|
+
break
|
37
|
+
return handleRequest(method || options.type || 'get', url, options, jQuery.originalAjax, optionsHandler)
|