resourcy-rails 1.0.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 (44) hide show
  1. data/LICENSE +25 -0
  2. data/lib/resourcy/engine.rb +4 -0
  3. data/lib/resourcy/rails.rb +4 -0
  4. data/lib/resourcy/version.rb +3 -0
  5. data/lib/resourcy-rails.rb +1 -0
  6. data/spec/dummy/Rakefile +7 -0
  7. data/spec/dummy/app/assets/javascripts/jquery-1.7.1.js +9266 -0
  8. data/spec/dummy/app/assets/javascripts/jquery-1.8.0.js +9227 -0
  9. data/spec/dummy/app/controllers/posts_controller.rb +85 -0
  10. data/spec/dummy/app/models/post.rb +3 -0
  11. data/spec/dummy/app/views/posts/_form.html.erb +25 -0
  12. data/spec/dummy/app/views/posts/edit.html.erb +6 -0
  13. data/spec/dummy/app/views/posts/index.html.erb +25 -0
  14. data/spec/dummy/app/views/posts/new.html.erb +5 -0
  15. data/spec/dummy/app/views/posts/show.html.erb +15 -0
  16. data/spec/dummy/config/application.rb +63 -0
  17. data/spec/dummy/config/boot.rb +9 -0
  18. data/spec/dummy/config/database.yml +10 -0
  19. data/spec/dummy/config/environment.rb +5 -0
  20. data/spec/dummy/config/environments/development.rb +37 -0
  21. data/spec/dummy/config/environments/test.rb +37 -0
  22. data/spec/dummy/config/evergreen.rb +47 -0
  23. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  24. data/spec/dummy/config/initializers/inflections.rb +15 -0
  25. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  26. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  27. data/spec/dummy/config/initializers/session_store.rb +8 -0
  28. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  29. data/spec/dummy/config/locales/en.yml +5 -0
  30. data/spec/dummy/config/routes.rb +64 -0
  31. data/spec/dummy/config.ru +4 -0
  32. data/spec/dummy/db/development.sqlite3 +0 -0
  33. data/spec/dummy/db/migrate/20120825050219_create_posts.rb +10 -0
  34. data/spec/dummy/db/structure.sql +4 -0
  35. data/spec/dummy/log/.gitkeep +0 -0
  36. data/spec/dummy/public/index.html +12 -0
  37. data/spec/dummy/script/rails +6 -0
  38. data/spec/javascripts/jquery.resourcy_spec.js.coffee +399 -0
  39. data/spec/javascripts/resourcy_spec.js.coffee +177 -0
  40. data/spec/javascripts/spec_helper.js +37 -0
  41. data/spec/javascripts/templates/ujs.html +3 -0
  42. data/vendor/assets/javascripts/jquery.resourcy.js.coffee +37 -0
  43. data/vendor/assets/javascripts/resourcy.js.coffee +104 -0
  44. 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,3 @@
1
+ <a id="show" href="/posts/1" data-remote="true">Show</a>
2
+ <a id="edit" href="/posts/1/edit" data-remote="true">Edit</a>
3
+ <a id="destroy" href="/posts/1" data-confirm="Are you sure?" data-method="delete" data-remote="true" rel="nofollow">Destroy</a>
@@ -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)