joosy 0.1.0.alpha → 1.0.0.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/.codoopts +5 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +15 -2
  4. data/Gemfile.lock +102 -81
  5. data/Guardfile +16 -16
  6. data/LICENSE +22 -0
  7. data/MIT-LICENSE +2 -2
  8. data/README.md +118 -0
  9. data/app/assets/javascripts/joosy/core/application.js.coffee +53 -0
  10. data/app/assets/javascripts/joosy/core/form.js.coffee +338 -0
  11. data/app/assets/javascripts/joosy/core/helpers/form.js.coffee +72 -0
  12. data/app/assets/javascripts/joosy/core/helpers/view.js.coffee +42 -0
  13. data/app/assets/javascripts/joosy/core/helpers/widgets.js.coffee +14 -0
  14. data/app/assets/javascripts/joosy/core/joosy.js.coffee +184 -0
  15. data/app/assets/javascripts/joosy/core/layout.js.coffee +168 -0
  16. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +124 -0
  17. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +122 -0
  18. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
  19. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +36 -0
  20. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +117 -0
  21. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +200 -0
  22. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +46 -0
  23. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +87 -0
  24. data/app/assets/javascripts/joosy/core/page.js.coffee +387 -0
  25. data/app/assets/javascripts/joosy/core/preloader.js.coffee +13 -0
  26. data/app/assets/javascripts/joosy/core/resource/collection.js.coffee +175 -0
  27. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +303 -0
  28. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +244 -0
  29. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +24 -0
  30. data/app/assets/javascripts/joosy/core/router.js.coffee +201 -0
  31. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +37 -0
  32. data/app/assets/javascripts/joosy/core/widget.js.coffee +85 -0
  33. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +169 -0
  34. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +56 -0
  35. data/{vendor → app}/assets/javascripts/joosy.js.coffee +0 -1
  36. data/app/helpers/joosy/sprockets_helper.rb +39 -12
  37. data/joosy.gemspec +4 -3
  38. data/lib/joosy/rails/engine.rb +12 -1
  39. data/lib/joosy/rails/version.rb +2 -2
  40. data/lib/joosy.rb +9 -0
  41. data/lib/rails/generators/joosy/application_generator.rb +15 -3
  42. data/lib/rails/generators/joosy/joosy_base.rb +2 -2
  43. data/lib/rails/generators/joosy/layout_generator.rb +8 -1
  44. data/lib/rails/generators/joosy/page_generator.rb +21 -6
  45. data/lib/rails/generators/joosy/preloader_generator.rb +14 -7
  46. data/lib/rails/generators/joosy/resource_generator.rb +29 -0
  47. data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
  48. data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +1 -0
  49. data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +1 -1
  50. data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -1
  51. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +3 -3
  52. data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
  53. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
  54. data/lib/rails/generators/joosy/templates/app/routes.js.coffee +7 -1
  55. data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
  56. data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
  57. data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -2
  58. data/lib/rails/generators/joosy/templates/app.js.coffee +4 -0
  59. data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +9 -12
  60. data/lib/rails/generators/joosy/templates/app_resources_predefiner.js.coffee.erb +11 -0
  61. data/lib/rails/generators/joosy/templates/preload.html.erb +5 -6
  62. data/lib/rails/generators/joosy/templates/preload.html.haml +3 -5
  63. data/lib/rails/generators/joosy/widget_generator.rb +8 -1
  64. data/lib/rails/resources_with_joosy.rb +11 -0
  65. data/spec/javascripts/helpers/spec_helper.js.coffee +25 -0
  66. data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
  67. data/spec/javascripts/joosy/core/form_spec.js.coffee +200 -0
  68. data/spec/javascripts/joosy/core/helpers/forms_spec.js.coffee +103 -0
  69. data/spec/javascripts/joosy/core/helpers/view_spec.js.coffee +10 -0
  70. data/spec/javascripts/joosy/core/joosy_spec.js.coffee +97 -0
  71. data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
  72. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +32 -27
  73. data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +55 -18
  74. data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +28 -27
  75. data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +3 -3
  76. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +6 -15
  77. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +203 -0
  78. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +12 -7
  79. data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +31 -17
  80. data/spec/javascripts/joosy/core/page_spec.js.coffee +178 -0
  81. data/spec/javascripts/joosy/core/resource/collection_spec.js.coffee +84 -0
  82. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +149 -0
  83. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +31 -0
  84. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +171 -0
  85. data/spec/javascripts/joosy/core/router_spec.js.coffee +143 -0
  86. data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
  87. data/spec/javascripts/joosy/core/widget_spec.js.coffee +40 -0
  88. data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
  89. data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
  90. data/spec/javascripts/support/assets/coolface.jpg +0 -0
  91. data/spec/javascripts/support/assets/okay.jpg +0 -0
  92. data/spec/javascripts/support/assets/test.js +1 -0
  93. data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
  94. data/vendor/assets/javascripts/jquery.form.js +978 -963
  95. data/vendor/assets/javascripts/metamorph.js +409 -0
  96. data/vendor/assets/javascripts/sugar.js +1057 -366
  97. metadata +95 -50
  98. data/README.rdoc +0 -3
  99. data/lib/joosy/forms.rb +0 -47
  100. data/lib/joosy-rails.rb +0 -5
  101. data/lib/rails/generators/joosy/templates/preload.html.slim +0 -21
  102. data/tmp/javascripts/.gitignore +0 -1
  103. data/tmp/spec/javascripts/helpers/.gitignore +0 -1
  104. data/vendor/assets/javascripts/base64.js +0 -135
  105. data/vendor/assets/javascripts/inflection.js +0 -656
  106. data/vendor/assets/javascripts/joosy/core/application.js.coffee +0 -26
  107. data/vendor/assets/javascripts/joosy/core/form.js.coffee +0 -87
  108. data/vendor/assets/javascripts/joosy/core/joosy.js.coffee +0 -62
  109. data/vendor/assets/javascripts/joosy/core/layout.js.coffee +0 -38
  110. data/vendor/assets/javascripts/joosy/core/modules/container.js.coffee +0 -51
  111. data/vendor/assets/javascripts/joosy/core/modules/events.js.coffee +0 -17
  112. data/vendor/assets/javascripts/joosy/core/modules/filters.js.coffee +0 -39
  113. data/vendor/assets/javascripts/joosy/core/modules/log.js.coffee +0 -12
  114. data/vendor/assets/javascripts/joosy/core/modules/module.js.coffee +0 -28
  115. data/vendor/assets/javascripts/joosy/core/modules/time_manager.js.coffee +0 -23
  116. data/vendor/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +0 -45
  117. data/vendor/assets/javascripts/joosy/core/page.js.coffee +0 -136
  118. data/vendor/assets/javascripts/joosy/core/resource/rest.js.coffee +0 -69
  119. data/vendor/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +0 -42
  120. data/vendor/assets/javascripts/joosy/core/router.js.coffee +0 -75
  121. data/vendor/assets/javascripts/joosy/core/widget.js.coffee +0 -35
  122. data/vendor/assets/javascripts/joosy/preloader/development.js.coffee +0 -27
  123. data/vendor/assets/javascripts/joosy/preloader/production.js.coffee +0 -84
@@ -0,0 +1,178 @@
1
+ describe "Joosy.Page", ->
2
+
3
+ beforeEach ->
4
+ window.JST = 'app/templates/layouts/default': (->)
5
+ class window.ApplicationLayout extends Joosy.Layout
6
+ class @TestPage extends Joosy.Page
7
+
8
+
9
+ describe "not rendered page", ->
10
+
11
+ beforeEach ->
12
+ sinon.stub @TestPage.prototype, '__bootstrap'
13
+ sinon.stub @TestPage.prototype, '__bootstrapLayout'
14
+ @box = new @TestPage()
15
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
16
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
17
+
18
+
19
+ it "should have appropriate accessors", ->
20
+ callback_names = ['fetch', 'beforePaint', 'paint', 'afterPaint', 'erase']
21
+ callback_names.each (func) =>
22
+ @TestPage[func] 'callback'
23
+ expect(@TestPage::['__' + func]).toEqual 'callback'
24
+
25
+ @TestPage.scroll '#here'
26
+ expect(@TestPage::__scrollElement).toEqual '#here'
27
+ expect(@TestPage::__scrollSpeed).toEqual 500
28
+ expect(@TestPage::__scrollMargin).toEqual 0
29
+
30
+ @TestPage.scroll '#there', speed: 1000, margin: -5
31
+ expect(@TestPage::__scrollElement).toEqual '#there'
32
+ expect(@TestPage::__scrollSpeed).toEqual 1000
33
+ expect(@TestPage::__scrollMargin).toEqual -5
34
+
35
+ @TestPage.layout 'test'
36
+ expect(@TestPage::__layoutClass).toEqual 'test'
37
+
38
+ it "should not render layout if it not changes", ->
39
+ @box.layout = new ApplicationLayout()
40
+ @box.layout.yield()
41
+ new @TestPage {}, @box
42
+ expect(@TestPage::__bootstrap.callCount).toEqual 1
43
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
44
+
45
+ it "should render layout if it changes", ->
46
+ class SubLayout extends Joosy.Layout
47
+ @box = new @TestPage()
48
+ new @TestPage {}, @box
49
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
50
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 3
51
+
52
+ it "should stop render on beforeFilter result", ->
53
+ sinon.stub @TestPage.prototype, '__runBeforeLoads'
54
+ @TestPage::__runBeforeLoads.returns(false)
55
+ new @TestPage()
56
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
57
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
58
+
59
+ it "should use Router", ->
60
+ target = sinon.stub Joosy.Router, 'navigate'
61
+ @box.navigate 'there'
62
+ expect(target.callCount).toEqual 1
63
+ expect(target.alwaysCalledWithExactly 'there').toBeTruthy()
64
+ Joosy.Router.navigate.restore()
65
+
66
+ it "should load itself", ->
67
+ spies = []
68
+ spies.push sinon.spy(@box, 'refreshElements')
69
+ spies.push sinon.spy(@box, '__delegateEvents')
70
+ spies.push sinon.spy(@box, '__setupWidgets')
71
+ spies.push sinon.spy(@box, '__runAfterLoads')
72
+ @box.__load()
73
+ expect(spies).toBeSequenced()
74
+
75
+ it "should unload itself", ->
76
+ spies = []
77
+ spies.push sinon.spy(@box, '__clearTime')
78
+ spies.push sinon.spy(@box, '__unloadWidgets')
79
+ spies.push sinon.spy(@box, '__removeMetamorphs')
80
+ spies.push sinon.spy(@box, '__runAfterUnloads')
81
+ @box.__unload()
82
+ expect(spies).toBeSequenced()
83
+
84
+ describe "rendered page", ->
85
+
86
+ beforeEach ->
87
+ @box.previous = new @TestPage()
88
+ @box.previous.layout = new @box.previous.__layoutClass
89
+ @box.__renderer = sinon.spy()
90
+ @box.__layoutClass.prototype.__renderer = sinon.spy()
91
+ @TestPage::__bootstrap.restore()
92
+ @TestPage::__bootstrapLayout.restore()
93
+
94
+
95
+ it "should wait stageClear and dataReceived event to start render", ->
96
+ spies = []
97
+
98
+ spies.push @box.previous.__erase = sinon.spy (stage, callback) ->
99
+ expect(stage.selector).toEqual @layout.content().selector
100
+ callback()
101
+
102
+ spies.push sinon.spy(@box.previous, '__unload')
103
+
104
+ spies.push @box.__beforePaint = sinon.spy (stage, callback) ->
105
+ expect(stage.selector).toEqual @layout.content().selector
106
+ expect(@__oneShotEvents[0][0]).toEqual ['stageClear', 'dataReceived']
107
+ callback()
108
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
109
+
110
+ spies.push @box.__fetch = sinon.spy (callback) ->
111
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
112
+ callback()
113
+ expect(@__oneShotEvents).toEqual []
114
+
115
+ spies.push @box.__paint = sinon.spy (stage, callback) ->
116
+ expect(stage.selector).toEqual @layout.content().selector
117
+ expect(typeof callback).toEqual 'function'
118
+ # callback() - start rendering
119
+
120
+ @box.__bootstrap()
121
+
122
+ expect(spies).toBeSequenced()
123
+
124
+ it "should render page", ->
125
+ spies = []
126
+
127
+ spies.push @box.__renderer
128
+ spies.push sinon.spy(@box, 'swapContainer')
129
+ spies.push sinon.spy(@box, '__load')
130
+
131
+ @box.__bootstrap()
132
+ expect(spies).toBeSequenced()
133
+
134
+ it "should wait stageClear and dataReceived event to start layout render", ->
135
+ spies = []
136
+
137
+ spies.push ApplicationLayout::__erase = sinon.spy (stage, page, callback) ->
138
+ expect(stage.selector).toEqual Joosy.Application.content().selector
139
+ callback()
140
+
141
+ spies.push sinon.spy(@box.previous.layout, '__unload')
142
+ spies.push sinon.spy(@box.previous, '__unload')
143
+
144
+ spies.push ApplicationLayout::__beforePaint = sinon.spy (stage, page, callback) =>
145
+ expect(stage.selector).toEqual Joosy.Application.content().selector
146
+ expect(@box.__oneShotEvents[0][0]).toEqual ['stageClear', 'dataReceived']
147
+ callback()
148
+ expect(@box.__oneShotEvents[0][0]).toEqual ['dataReceived']
149
+
150
+ spies.push @box.__fetch = sinon.spy (callback) ->
151
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
152
+ callback()
153
+ expect(@__oneShotEvents).toEqual []
154
+
155
+ spies.push ApplicationLayout::__paint = sinon.spy (stage, page, callback) ->
156
+ expect(stage.selector).toEqual Joosy.Application.content().selector
157
+ expect(typeof callback).toEqual 'function'
158
+ # callback() - start rendering
159
+
160
+ @box.__bootstrapLayout()
161
+
162
+ expect(spies).toBeSequenced()
163
+
164
+ it "should render layout and page", ->
165
+ spies = []
166
+
167
+ @box.params = {tested: true}
168
+
169
+ spies.push @box.__layoutClass.prototype.__renderer
170
+ spies.push @box.__renderer
171
+ swapContainer = sinon.spy(@box, 'swapContainer')
172
+ spies.push @box.__layoutClass.prototype.__load = sinon.spy()
173
+ spies.push sinon.spy(@box, '__load')
174
+
175
+ @box.__bootstrapLayout()
176
+ expect(spies).toBeSequenced()
177
+ expect(swapContainer.callCount).toEqual 2
178
+ expect(@box.layout.params).toEqual {tested: true}
@@ -0,0 +1,84 @@
1
+ describe "Joosy.Resource.Collection", ->
2
+
3
+ class Test extends Joosy.Resource.Generic
4
+ @entity 'test'
5
+
6
+ data = '[{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]'
7
+
8
+ checkData = (collection) ->
9
+ expect(collection.data.length).toEqual 2
10
+ expect(collection.data[0].constructor == Test).toBeTruthy()
11
+ expect(collection.data[0].data.name).toEqual 'test1'
12
+
13
+ beforeEach ->
14
+ @collection = new Joosy.Resource.Collection(Test)
15
+
16
+ it "should initialize", ->
17
+ expect(@collection.model).toEqual Test
18
+ expect(@collection.data).toEqual []
19
+
20
+ it "should modelize", ->
21
+ result = @collection.modelize $.parseJSON(data)
22
+ expect(result[0].constructor == Test).toBeTruthy()
23
+ expect(result[0].data.name).toEqual 'test1'
24
+
25
+ it "should load", ->
26
+ @collection.load $.parseJSON(data)
27
+ checkData @collection
28
+
29
+ it "should trigger changes", ->
30
+ @collection.bind 'changed', callback = sinon.spy()
31
+ @collection.load $.parseJSON(data)
32
+ expect(callback.callCount).toEqual 1
33
+
34
+ it "should not trigger changes", ->
35
+ @collection.bind 'changed', callback = sinon.spy()
36
+ @collection.load $.parseJSON(data), false
37
+ expect(callback.callCount).toEqual 0
38
+
39
+ it "should properly handle the before filter", ->
40
+ class RC extends Joosy.Resource.Collection
41
+ @beforeLoad (data) ->
42
+ data.each (entry, i) ->
43
+ data[i].tested = true
44
+ data
45
+
46
+ collection = new RC(Test)
47
+ collection.load $.parseJSON(data)
48
+
49
+ expect(collection.at(0)('tested')).toBeTruthy()
50
+
51
+ it "should remove item from collection", ->
52
+ @collection.load $.parseJSON(data)
53
+ @collection.bind 'changed', callback = sinon.spy()
54
+ @collection.remove @collection.data[1]
55
+ expect(@collection.data.length).toEqual 1
56
+ @collection.remove 0
57
+ expect(@collection.data.length).toEqual 0
58
+ expect(callback.callCount).toEqual 2
59
+
60
+ it "should silently remove item from collection", ->
61
+ @collection.load $.parseJSON(data)
62
+ @collection.bind 'changed', callback = sinon.spy()
63
+ @collection.remove @collection.data[1], false
64
+ expect(@collection.data.length).toEqual 1
65
+ @collection.remove 0, false
66
+ expect(@collection.data.length).toEqual 0
67
+ expect(callback.callCount).toEqual 0
68
+
69
+ it "should add item from collection", ->
70
+ @collection.load $.parseJSON(data)
71
+ @collection.bind 'changed', callback = sinon.spy()
72
+ @collection.add new Test {'rocking': 'mocking'}
73
+ expect(@collection.data.length).toEqual 3
74
+ expect(@collection.at(2).data).toEqual {'rocking': 'mocking'}
75
+ @collection.add new Test({'rocking': 'mocking'}), 1
76
+ expect(@collection.data.length).toEqual 4
77
+ expect(@collection.at(1).data).toEqual {'rocking': 'mocking'}
78
+ expect(@collection.at(3).data).toEqual {'rocking': 'mocking'}
79
+
80
+ it "should find items by id", ->
81
+ @collection.load $.parseJSON(data)
82
+
83
+ expect(@collection.findById 1).toEqual @collection.data[0]
84
+ expect(@collection.findById 2).toEqual @collection.data[1]
@@ -0,0 +1,149 @@
1
+ describe "Joosy.Resource.Generic", ->
2
+
3
+ class TestInline extends Joosy.Resource.Generic
4
+ @entity 'test_inline'
5
+
6
+ class Test extends Joosy.Resource.REST
7
+ @entity 'test'
8
+ @map 'test_inlines', TestInline
9
+
10
+ beforeEach ->
11
+ @resource = Joosy.Resource.Generic.build @data =
12
+ foo: 'bar'
13
+ bar: 'baz'
14
+ very:
15
+ deep:
16
+ value: 'boo!'
17
+
18
+ it "has primary key", ->
19
+ expect(Test::__primaryKey).toEqual 'id'
20
+
21
+ it "remembers where it belongs", ->
22
+ resource = new Joosy.Resource.Generic foo: 'bar'
23
+ expect(resource.data).toEqual foo: 'bar'
24
+
25
+ it "produces magic function", ->
26
+ expect(Object.isFunction @resource).toBeTruthy()
27
+ expect(@resource.data).toEqual @data
28
+
29
+ it "gets values", ->
30
+ expect(@resource 'foo').toEqual 'bar'
31
+ expect(@resource 'very.deep').toEqual value: 'boo!'
32
+ expect(@resource 'very.deep.value').toEqual 'boo!'
33
+
34
+ it "sets values", ->
35
+ expect(@resource 'foo').toEqual 'bar'
36
+ @resource 'foo', 'baz'
37
+ expect(@resource 'foo').toEqual 'baz'
38
+
39
+ expect(@resource 'very.deep').toEqual value: 'boo!'
40
+ @resource 'very.deep', 'banana!'
41
+ expect(@resource 'very.deep').toEqual 'banana!'
42
+
43
+ @resource 'another.deep.value', 'banana strikes back'
44
+ expect(@resource 'another.deep').toEqual value: 'banana strikes back'
45
+
46
+ it "handles @at", ->
47
+ class Fluffy extends Joosy.Resource.Generic
48
+
49
+ clone = Fluffy.at('rumbas!')
50
+
51
+ expect(clone.__source).toEqual 'rumbas!'
52
+ expect(Joosy.Module.hasAncestor clone, Fluffy).toBeTruthy()
53
+ # clone won't be instanceof Fluffy in IE
54
+ #expect(clone.build({}) instanceof Fluffy).toBeTruthy()
55
+
56
+ it "triggers 'changed' right", ->
57
+ callback = sinon.spy()
58
+ @resource.bind 'changed', callback
59
+ @resource 'foo', 'baz'
60
+ @resource 'foo', 'baz2'
61
+
62
+ expect(callback.callCount).toEqual(2)
63
+
64
+ it "handles the before filter", ->
65
+ class R extends Joosy.Resource.Generic
66
+ @beforeLoad (data) ->
67
+ data ||= {}
68
+ data.tested = true
69
+ data
70
+
71
+ resource = R.build()
72
+
73
+ expect(resource 'tested').toBeTruthy()
74
+
75
+ it "should map inlines", ->
76
+ class RumbaMumba extends Joosy.Resource.Generic
77
+ @entity 'rumba_mumba'
78
+
79
+ class R extends Joosy.Resource.Generic
80
+ @map 'rumbaMumbas', RumbaMumba
81
+
82
+ class S extends Joosy.Resource.Generic
83
+ @map 'rumbaMumba', RumbaMumba
84
+
85
+ resource = R.build
86
+ rumbaMumbas: [
87
+ {foo: 'bar'},
88
+ {bar: 'baz'}
89
+ ]
90
+ expect(resource('rumbaMumbas') instanceof Joosy.Resource.Collection).toBeTruthy()
91
+ expect(resource('rumbaMumbas').at(0)('foo')).toEqual 'bar'
92
+
93
+ resource = S.build
94
+ rumbaMumba: {foo: 'bar'}
95
+ expect(resource('rumbaMumba') instanceof Joosy.Resource.Generic).toBeTruthy()
96
+ expect(resource('rumbaMumba.foo')).toEqual 'bar'
97
+
98
+ it "should use magic collections", ->
99
+ class window.RumbaMumbasCollection extends Joosy.Resource.Collection
100
+
101
+ class RumbaMumba extends Joosy.Resource.Generic
102
+ @entity 'rumba_mumba'
103
+ class R extends Joosy.Resource.Generic
104
+ @map 'rumbaMumbas', RumbaMumba
105
+
106
+ resource = R.build
107
+ rumbaMumbas: [
108
+ {foo: 'bar'},
109
+ {bar: 'baz'}
110
+ ]
111
+ expect(resource('rumbaMumbas') instanceof RumbaMumbasCollection).toBeTruthy()
112
+ expect(resource('rumbaMumbas').at(0)('foo')).toEqual 'bar'
113
+
114
+ window.RumbaMumbasCollection = undefined
115
+
116
+ it "should use manually set collections", ->
117
+ class OloCollection extends Joosy.Resource.Collection
118
+
119
+ class RumbaMumba extends Joosy.Resource.Generic
120
+ @entity 'rumba_mumba'
121
+ @collection OloCollection
122
+ class R extends Joosy.Resource.Generic
123
+ @map 'rumbaMumbas', RumbaMumba
124
+
125
+ resource = R.build
126
+ rumbaMumbas: [
127
+ {foo: 'bar'},
128
+ {bar: 'baz'}
129
+ ]
130
+ expect(resource('rumbaMumbas') instanceof OloCollection).toBeTruthy()
131
+ expect(resource('rumbaMumbas').at(0)('foo')).toEqual 'bar'
132
+
133
+ describe "identity map", ->
134
+
135
+ it "handles builds", ->
136
+ foo = Test.build 1
137
+ bar = Test.build 1
138
+
139
+ expect(foo).toEqual bar
140
+
141
+ it "handles maps", ->
142
+ inline = TestInline.build(1)
143
+ root = Test.build
144
+ id: 1
145
+ test_inlines: [{id: 1}, {id: 2}]
146
+
147
+ inline('foo', 'bar')
148
+
149
+ expect(root('test_inlines').at(0)('foo')).toEqual 'bar'
@@ -0,0 +1,31 @@
1
+ describe "Joosy.Resource.RESTCollection", ->
2
+
3
+ class Test extends Joosy.Resource.REST
4
+ @entity 'test'
5
+
6
+ beforeEach ->
7
+ @server = sinon.fakeServer.create()
8
+ @collection = new Joosy.Resource.RESTCollection(Test)
9
+
10
+ afterEach ->
11
+ @server.restore()
12
+
13
+ it "loads", ->
14
+ @collection.load [{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]
15
+ console.log @collection.data[0].constructor
16
+ expect(@collection.data.length).toEqual 2
17
+ expect(@collection.data[0] instanceof Test).toBeTruthy()
18
+ expect(@collection.data[0].data.name).toEqual 'test1'
19
+
20
+ it "reloads", ->
21
+ @collection.load [{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]
22
+ @collection.reload from: 'test'
23
+
24
+ target = @server.requests.last()
25
+ expect(target.method).toEqual 'GET'
26
+ expect(target.url).toMatch /^\/tests\/test\?_=\d+/
27
+ target.respond 200, 'Content-Type': 'application/json', '[{"id": 3, "name": "test3"}, {"id": 4, "name": "test4"}, {"id": 5, "name": "test5"}]'
28
+
29
+ expect(@collection.data.length).toEqual 3
30
+ expect(@collection.data[0].constructor == Test).toBeTruthy()
31
+ expect(@collection.data[0].data.name).toEqual 'test3'
@@ -0,0 +1,171 @@
1
+ describe "Joosy.Resource.REST", ->
2
+
3
+ class FluffyInline extends Joosy.Resource.REST
4
+ @entity 'fluffy_inline'
5
+
6
+ class FluffyParent extends Joosy.Resource.REST
7
+ @entity 'fluffy_parent'
8
+
9
+ class Fluffy extends Joosy.Resource.REST
10
+ @entity 'fluffy'
11
+ @map 'fluffy_inlines', FluffyInline
12
+
13
+ beforeEach ->
14
+ @server = sinon.fakeServer.create()
15
+
16
+ afterEach ->
17
+ @server.restore()
18
+
19
+ checkAndRespond = (target, method, url, data) ->
20
+ expect(target.method).toEqual method
21
+ expect(target.url).toMatch url
22
+ target.respond 200, 'Content-Type': 'application/json', data
23
+
24
+ it "builds member path", ->
25
+ parent = FluffyParent.build 1
26
+
27
+ expect(Fluffy.memberPath 1).toEqual '/fluffies/1'
28
+ expect(Fluffy.memberPath 1, parent: parent).toEqual '/fluffy_parents/1/fluffies/1'
29
+ expect(Fluffy.memberPath 1, parent: parent, from: 'test').toEqual '/fluffy_parents/1/fluffies/1/test'
30
+ expect(Fluffy.memberPath 1, parent: parent, from: 'test', params: {foo: 'bar'}).toEqual '/fluffy_parents/1/fluffies/1/test'
31
+
32
+ it "builds collection path", ->
33
+ parent = FluffyParent.build 1
34
+
35
+ expect(Fluffy.collectionPath()).toEqual '/fluffies'
36
+ expect(Fluffy.collectionPath parent: parent).toEqual '/fluffy_parents/1/fluffies'
37
+ expect(Fluffy.collectionPath parent: parent, from: 'test').toEqual '/fluffy_parents/1/fluffies/test'
38
+ expect(Fluffy.collectionPath parent: parent, from: 'test', params: {foo: 'bar'}).toEqual '/fluffy_parents/1/fluffies/test'
39
+
40
+
41
+ describe "finds resource", ->
42
+ rawData = '{"fluffy": {"id": 1, "name": "test1"}}'
43
+
44
+ callback = sinon.spy (target) ->
45
+ expect(target instanceof Fluffy).toEqual true
46
+ expect(target.id()).toEqual 1
47
+ expect(target 'name').toEqual 'test1'
48
+
49
+ it "without params", ->
50
+ resource = Fluffy.find 1, callback
51
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\?_=\d+/, rawData
52
+ expect(callback.callCount).toEqual 1
53
+
54
+ it "with from", ->
55
+ resource = Fluffy.find 1, {from: 'action'}, callback
56
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\/action\?_=\d+/, rawData
57
+ expect(callback.callCount).toEqual 2
58
+
59
+ it "with from and parent", ->
60
+ resource = Fluffy.find 1, {parent: FluffyParent.build(1), from: 'action'}, callback
61
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffy_parents\/1\/fluffies\/1\/action\?_=\d+/, rawData
62
+ expect(callback.callCount).toEqual 3
63
+
64
+ it "with params", ->
65
+ resource = Fluffy.find 1, params: {foo: 'bar'}, callback
66
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\?foo=bar&_=\d+/, rawData
67
+ expect(callback.callCount).toEqual 4
68
+
69
+ it "with direct assignation", ->
70
+ resource = Fluffy.find 1, ->
71
+ expect(resource instanceof Fluffy).toEqual true
72
+ expect(resource.id()).toEqual 1
73
+ expect(resource 'name').toEqual 'test1'
74
+
75
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\?_=\d+/, rawData
76
+
77
+ describe "finds collection", ->
78
+ rawData = '{"fluffies": [{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]}'
79
+
80
+ callback = sinon.spy (target) ->
81
+ expect(target instanceof Joosy.Resource.RESTCollection).toEqual true
82
+ expect(target.size()).toEqual 2
83
+ expect(target.at(0) instanceof Fluffy).toEqual true
84
+
85
+ it "without params", ->
86
+ resource = Fluffy.find 'all', callback
87
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\?_=\d+/, rawData
88
+ expect(callback.callCount).toEqual 1
89
+
90
+ it "with from", ->
91
+ resource = Fluffy.find 'all', {from: 'action'}, callback
92
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/action\?_=\d+/, rawData
93
+ expect(callback.callCount).toEqual 2
94
+
95
+ it "with from and parent", ->
96
+ resource = Fluffy.find 'all', {parent: FluffyParent.build(1), from: 'action'}, callback
97
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffy_parents\/1\/fluffies\/action\?_=\d+/, rawData
98
+ expect(callback.callCount).toEqual 3
99
+
100
+ it "with params", ->
101
+ resource = Fluffy.find 'all', params: {foo: 'bar'}, callback
102
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\?foo=bar&_=\d+/, rawData
103
+ expect(callback.callCount).toEqual 4
104
+
105
+ it "reloads resource", ->
106
+ rawData = '{"fluffy": {"id": 1, "name": "test1"}}'
107
+ resource = Fluffy.find 1
108
+ callback = sinon.spy()
109
+
110
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\?_=\d+/, rawData
111
+ resource.bind 'changed', callback = sinon.spy()
112
+ resource.reload()
113
+ checkAndRespond @server.requests[1], 'GET', /^\/fluffies\/1\?_=\d+/, rawData
114
+ expect(callback.callCount).toEqual 1
115
+
116
+ describe "requests", ->
117
+ rawData = '{"foo": "bar"}'
118
+ callback = sinon.spy (data) ->
119
+ expect(data).toEqual {foo: 'bar'}
120
+
121
+ describe "member", ->
122
+ resource = Fluffy.build 1
123
+
124
+ it "with get", ->
125
+ resource.get {from: 'foo', params: {foo: 'bar'}}, callback
126
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\/foo\?foo=bar&_=\d+/, rawData
127
+
128
+ it "with post", ->
129
+ resource.post callback
130
+ checkAndRespond @server.requests[0], 'POST', /^\/fluffies\/1/, rawData
131
+
132
+ it "with put", ->
133
+ resource.put callback
134
+ checkAndRespond @server.requests[0], 'PUT', /^\/fluffies\/1/, rawData
135
+
136
+ it "with delete", ->
137
+ resource.delete callback
138
+ checkAndRespond @server.requests[0], 'DELETE', /^\/fluffies\/1/, rawData
139
+
140
+ describe "collection", ->
141
+ resource = Fluffy
142
+
143
+ it "with get", ->
144
+ resource.get {from: 'foo', params: {foo: 'bar'}}, callback
145
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/foo\?foo=bar&_=\d+/, rawData
146
+
147
+ it "with post", ->
148
+ resource.post callback
149
+ checkAndRespond @server.requests[0], 'POST', /^\/fluffies/, rawData
150
+
151
+ it "with put", ->
152
+ resource.put callback
153
+ checkAndRespond @server.requests[0], 'PUT', /^\/fluffies/, rawData
154
+
155
+ it "with delete", ->
156
+ resource.delete callback
157
+ checkAndRespond @server.requests[0], 'DELETE', /^\/fluffies/, rawData
158
+
159
+ describe "identity map", ->
160
+
161
+ it "handles finds", ->
162
+ inline = FluffyInline.build(1)
163
+ root = Fluffy.find 1
164
+
165
+ inline.bind 'changed', callback = sinon.spy()
166
+
167
+ checkAndRespond @server.requests[0], 'GET', /^\/fluffies\/1\?_=\d+/,
168
+ '{"id": 1, "fluffy_inlines": [{"id": 1, "name": 1}, {"id": 2, "name": 2}]}'
169
+
170
+ expect(inline 'name').toEqual 1
171
+ expect(callback.callCount).toEqual 1