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.
- 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)
|