daylight 0.9.0.rc1

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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +113 -0
  3. data/app/controllers/daylight_documentation/documentation_controller.rb +27 -0
  4. data/app/helpers/daylight_documentation/documentation_helper.rb +57 -0
  5. data/app/views/daylight_documentation/documentation/_header.haml +4 -0
  6. data/app/views/daylight_documentation/documentation/index.haml +12 -0
  7. data/app/views/daylight_documentation/documentation/model.haml +114 -0
  8. data/app/views/layouts/documentation.haml +22 -0
  9. data/config/routes.rb +8 -0
  10. data/doc/actions.md +70 -0
  11. data/doc/benchmarks.md +17 -0
  12. data/doc/contribute.md +80 -0
  13. data/doc/develop.md +1205 -0
  14. data/doc/environment.md +109 -0
  15. data/doc/example.md +3 -0
  16. data/doc/framework.md +31 -0
  17. data/doc/install.md +128 -0
  18. data/doc/principles.md +42 -0
  19. data/doc/testing.md +107 -0
  20. data/doc/usage.md +970 -0
  21. data/lib/daylight/api.rb +293 -0
  22. data/lib/daylight/associations.rb +247 -0
  23. data/lib/daylight/client_reloader.rb +45 -0
  24. data/lib/daylight/collection.rb +161 -0
  25. data/lib/daylight/errors.rb +94 -0
  26. data/lib/daylight/inflections.rb +7 -0
  27. data/lib/daylight/mock.rb +282 -0
  28. data/lib/daylight/read_only.rb +88 -0
  29. data/lib/daylight/refinements.rb +63 -0
  30. data/lib/daylight/reflection_ext.rb +67 -0
  31. data/lib/daylight/resource_proxy.rb +226 -0
  32. data/lib/daylight/version.rb +10 -0
  33. data/lib/daylight.rb +27 -0
  34. data/rails/daylight/api_controller.rb +354 -0
  35. data/rails/daylight/documentation.rb +13 -0
  36. data/rails/daylight/helpers.rb +32 -0
  37. data/rails/daylight/params.rb +23 -0
  38. data/rails/daylight/refiners.rb +186 -0
  39. data/rails/daylight/server.rb +29 -0
  40. data/rails/daylight/tasks.rb +37 -0
  41. data/rails/extensions/array_ext.rb +9 -0
  42. data/rails/extensions/autosave_association_fix.rb +49 -0
  43. data/rails/extensions/has_one_serializer_ext.rb +111 -0
  44. data/rails/extensions/inflections.rb +6 -0
  45. data/rails/extensions/nested_attributes_ext.rb +94 -0
  46. data/rails/extensions/read_only_attributes.rb +35 -0
  47. data/rails/extensions/render_json_meta.rb +99 -0
  48. data/rails/extensions/route_options.rb +47 -0
  49. data/rails/extensions/versioned_url_for.rb +22 -0
  50. data/spec/config/dependencies.rb +2 -0
  51. data/spec/config/factory_girl.rb +4 -0
  52. data/spec/config/simplecov_rcov.rb +26 -0
  53. data/spec/config/test_api.rb +1 -0
  54. data/spec/controllers/documentation_controller_spec.rb +24 -0
  55. data/spec/dummy/README.rdoc +28 -0
  56. data/spec/dummy/Rakefile +6 -0
  57. data/spec/dummy/app/assets/images/.keep +0 -0
  58. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  59. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  60. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  61. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  62. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  63. data/spec/dummy/app/mailers/.keep +0 -0
  64. data/spec/dummy/app/models/.keep +0 -0
  65. data/spec/dummy/app/models/concerns/.keep +0 -0
  66. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  67. data/spec/dummy/bin/bundle +3 -0
  68. data/spec/dummy/bin/rails +4 -0
  69. data/spec/dummy/bin/rake +4 -0
  70. data/spec/dummy/config/application.rb +24 -0
  71. data/spec/dummy/config/boot.rb +5 -0
  72. data/spec/dummy/config/database.yml +25 -0
  73. data/spec/dummy/config/environment.rb +5 -0
  74. data/spec/dummy/config/environments/development.rb +29 -0
  75. data/spec/dummy/config/environments/production.rb +80 -0
  76. data/spec/dummy/config/environments/test.rb +36 -0
  77. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  78. data/spec/dummy/config/initializers/daylight.rb +1 -0
  79. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  80. data/spec/dummy/config/initializers/inflections.rb +16 -0
  81. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  82. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  83. data/spec/dummy/config/initializers/session_store.rb +3 -0
  84. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  85. data/spec/dummy/config/locales/en.yml +23 -0
  86. data/spec/dummy/config/routes.rb +59 -0
  87. data/spec/dummy/config.ru +4 -0
  88. data/spec/dummy/lib/assets/.keep +0 -0
  89. data/spec/dummy/log/.keep +0 -0
  90. data/spec/dummy/public/404.html +58 -0
  91. data/spec/dummy/public/422.html +58 -0
  92. data/spec/dummy/public/500.html +57 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/helpers/documentation_helper_spec.rb +82 -0
  95. data/spec/lib/daylight/api_spec.rb +178 -0
  96. data/spec/lib/daylight/associations_spec.rb +325 -0
  97. data/spec/lib/daylight/collection_spec.rb +235 -0
  98. data/spec/lib/daylight/errors_spec.rb +111 -0
  99. data/spec/lib/daylight/mock_spec.rb +144 -0
  100. data/spec/lib/daylight/read_only_spec.rb +118 -0
  101. data/spec/lib/daylight/refinements_spec.rb +80 -0
  102. data/spec/lib/daylight/reflection_ext_spec.rb +50 -0
  103. data/spec/lib/daylight/resource_proxy_spec.rb +325 -0
  104. data/spec/rails/daylight/api_controller_spec.rb +421 -0
  105. data/spec/rails/daylight/helpers_spec.rb +41 -0
  106. data/spec/rails/daylight/params_spec.rb +45 -0
  107. data/spec/rails/daylight/refiners_spec.rb +178 -0
  108. data/spec/rails/extensions/array_ext_spec.rb +51 -0
  109. data/spec/rails/extensions/has_one_serializer_ext_spec.rb +135 -0
  110. data/spec/rails/extensions/nested_attributes_ext_spec.rb +177 -0
  111. data/spec/rails/extensions/render_json_meta_spec.rb +140 -0
  112. data/spec/rails/extensions/route_options_spec.rb +309 -0
  113. data/spec/rails/extensions/versioned_url_for_spec.rb +46 -0
  114. data/spec/spec_helper.rb +43 -0
  115. data/spec/support/migration_helper.rb +40 -0
  116. metadata +422 -0
@@ -0,0 +1,325 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daylight::ResourceProxy do
4
+
5
+ class ProxyTestClass < Daylight::API
6
+ self.password = nil
7
+
8
+ scopes :foo, :bar
9
+ has_many :related_proxy_test_classes, through: :associated
10
+
11
+ def self.wibble
12
+ 'wibble'
13
+ end
14
+ end
15
+
16
+ class RelatedProxyTestClass < Daylight::API
17
+ scopes :baz
18
+
19
+ self.password = nil
20
+ end
21
+
22
+ class ProxyTestClass1 < Daylight::API
23
+ self.password = nil
24
+ end
25
+
26
+ class ProxyTestClass2 < Daylight::API
27
+ self.password = nil
28
+ end
29
+
30
+ before do
31
+ data = [{name: 'one'}, {name: 'two'}]
32
+ [RelatedProxyTestClass, ProxyTestClass].each do |clazz|
33
+ stub_request(:get, %r{#{clazz.site}}).to_return(body: data.to_json)
34
+ end
35
+ end
36
+
37
+ it "supports (missing) class methods as calls on resource" do
38
+ results = ProxyTestClass.foo
39
+
40
+ results.should_not respond_to(:wibble)
41
+ results.wibble.should == 'wibble'
42
+
43
+ # now delegating on the defined
44
+ results.should respond_to(:wibble)
45
+ results.wibble.should == 'wibble'
46
+ end
47
+
48
+ it "shows custom inspect method" do
49
+ # resource proxy data
50
+ ProxyTestClass.foo.inspect.should match(/#<ProxyTestClass::ResourceProxy \[.*\] @current_params={:scopes=>\[:foo\]}>/)
51
+
52
+ # results returned by the proxy
53
+ ProxyTestClass.foo.inspect.should match(/#<ProxyTestClass:0x.* @attributes={"name"=>"one"}[^>]*>/)
54
+ ProxyTestClass.foo.inspect.should match(/#<ProxyTestClass:0x.* @attributes={"name"=>"two"}[^>]*>/)
55
+ end
56
+
57
+ describe "NoMethodError" do
58
+ it "still thrown when chaining" do
59
+ expect { ProxyTestClass.foo.not_a_method }.to raise_error(NoMethodError)
60
+ end
61
+
62
+ it "still thrown when appending to scopes" do
63
+ ProxyTestClass.foo.association_resource.should be_nil
64
+
65
+ expect { ProxyTestClass.foo << ['foo class'] }.to raise_error(NoMethodError)
66
+ end
67
+ end
68
+
69
+ describe "Array methods" do
70
+ it "supported as a generated method" do
71
+ mock = ProxyTestClass.new(name: 'three')
72
+ results = ProxyTestClass.foo
73
+
74
+ results.should_not respond_to(:push)
75
+ results.push(mock).last.name.should == 'three'
76
+
77
+ # now has the delegate
78
+ results.should respond_to(:push)
79
+ end
80
+
81
+ it "supported as delegates" do
82
+ result = ProxyTestClass.foo
83
+ result.should == ProxyTestClass.foo
84
+ result.size.should == 2
85
+ result.length.should == 2
86
+ result.to_ary.should be_instance_of Array
87
+ result.last.name.should == 'two'
88
+ result[0].name.should == 'one'
89
+ end
90
+
91
+ it "supported through Enumerable methods" do
92
+ ProxyTestClass.foo.map {|f| f.name}.should == %w[one two]
93
+ end
94
+ end
95
+
96
+ describe "results fetch" do
97
+ it "is loaded and cached" do
98
+ results = ProxyTestClass.foo
99
+ records = results.records
100
+ records.should == results.records
101
+ end
102
+
103
+ it "is reloadable" do
104
+ WebMock.reset!
105
+ data = [{name: 'one'}, {name: 'two'}]
106
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
107
+
108
+ proxy = ProxyTestClass.foo
109
+ results = ProxyTestClass.foo.load
110
+
111
+ WebMock.reset!
112
+ data = [{name: 'one'}, {name: 'two'}, {name: 'three'}]
113
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
114
+
115
+ results.should_not == proxy.reload
116
+ results.count.should == 2
117
+ proxy.records.count.should == 3
118
+ end
119
+
120
+ it "is resetable" do
121
+ WebMock.reset!
122
+ data = [{name: 'one'}, {name: 'two'}]
123
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
124
+
125
+ proxy = ProxyTestClass.foo
126
+ results = ProxyTestClass.foo.load
127
+
128
+ WebMock.reset!
129
+ data = [{name: 'one'}, {name: 'two'}, {name: 'three'}]
130
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
131
+
132
+ results.should_not == proxy.send(:reset)
133
+ results.count.should == 2
134
+
135
+ proxy.to_params.should == {}
136
+ proxy.records.count.should == 3
137
+ end
138
+
139
+ it "is resetable with new conditions" do
140
+ WebMock.reset!
141
+ data = [{name: 'one'}, {name: 'two'}]
142
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
143
+
144
+ proxy = ProxyTestClass.foo
145
+ results = ProxyTestClass.foo.load
146
+
147
+ WebMock.reset!
148
+ data = [{name: 'one'}, {name: 'two'}, {name: 'three'}]
149
+ stub_request(:get, %r{#{ProxyTestClass.site}}).to_return(body: data.to_json)
150
+
151
+ results.should_not == proxy.send(:reset, {limit: 2})
152
+ results.count.should == 2
153
+
154
+ proxy.to_params[:limit].should == 2
155
+ proxy.records.count.should == 3
156
+ end
157
+ end
158
+
159
+ describe "current parameters" do
160
+ it 'resets the scopes between calls' do
161
+ ProxyTestClass.foo.to_params[:scopes].should == [:foo]
162
+ ProxyTestClass.bar.to_params[:scopes].should == [:bar]
163
+ end
164
+
165
+ it 'appends scopes' do
166
+ ProxyTestClass.foo.bar.to_params[:scopes].should == [:foo, :bar]
167
+ end
168
+
169
+ it "supports 'where'" do
170
+ proxy = ProxyTestClass.where(baz: 'wibble')
171
+
172
+ proxy.should be_kind_of(Daylight::ResourceProxy)
173
+ proxy.to_params[:filters].should == {baz: 'wibble'}
174
+ end
175
+
176
+ it "supports 'order'" do
177
+ proxy = ProxyTestClass.order(foo: 'asc')
178
+
179
+ proxy.should be_kind_of(Daylight::ResourceProxy)
180
+ proxy.to_params[:order].should == {foo: 'asc'}
181
+ end
182
+
183
+ it "supports 'limit'" do
184
+ proxy = ProxyTestClass.limit(10)
185
+
186
+ proxy.should be_kind_of(Daylight::ResourceProxy)
187
+ proxy.to_params[:limit].should == 10
188
+ end
189
+
190
+ it "supports 'offset'" do
191
+ proxy = ProxyTestClass.offset(100)
192
+
193
+ proxy.should be_kind_of(Daylight::ResourceProxy)
194
+ proxy.to_params[:offset].should == 100
195
+ end
196
+
197
+ it 'creates a ResourceProxy to support chaining' do
198
+ proxy = ProxyTestClass.foo
199
+ proxy.should be_kind_of(Daylight::ResourceProxy)
200
+
201
+ proxy.should respond_to(:foo)
202
+ proxy.should respond_to(:bar)
203
+
204
+ # use everything!
205
+ proxy = proxy.bar.where(baz: 'wibble').order(foo: 'asc').limit(10).offset(100)
206
+
207
+ proxy.to_params[:scopes].should == [:foo, :bar]
208
+ proxy.to_params[:filters].should == {baz: 'wibble'}
209
+ proxy.to_params[:order].should == {foo: 'asc'}
210
+ proxy.to_params[:limit].should == 10
211
+ proxy.to_params[:offset].should == 100
212
+ end
213
+
214
+ it "supports 'first'" do
215
+ ProxyTestClass.first.name.should == 'one'
216
+ end
217
+
218
+ it "supports 'first' with chaining" do
219
+ ProxyTestClass.foo.first.name.should == 'one'
220
+ end
221
+
222
+ it "supports 'find_by'" do
223
+ # get a hook to the resource proxy
224
+ proxy = ProxyTestClass.send(:resource_proxy)
225
+ ProxyTestClass.stub(resource_proxy: proxy)
226
+ proxy.should be_kind_of(Daylight::ResourceProxy)
227
+
228
+ result = ProxyTestClass.find_by(baz: 'wibble')
229
+ result.should be_kind_of(ProxyTestClass)
230
+ result.name.should == 'one'
231
+ end
232
+
233
+ it "supports 'find_by' with chaining" do
234
+ proxy = ProxyTestClass.foo
235
+ proxy.should be_kind_of(Daylight::ResourceProxy)
236
+
237
+ result = proxy.find_by(baz: 'wibble')
238
+ result.should be_kind_of(ProxyTestClass)
239
+ result.name.should == 'one'
240
+
241
+ proxy.to_params[:scopes].should == [:foo]
242
+ end
243
+
244
+ it "spawns new ResourceProxy for each part of the chain" do
245
+ proxy = ProxyTestClass.foo
246
+
247
+ limit = proxy.bar.limit(1)
248
+ proxy.object_id.should_not == limit.object_id
249
+
250
+ limit.to_params.should == {limit: 1, scopes: [:foo, :bar]}
251
+ proxy.to_params.should == {scopes: [:foo]}
252
+ end
253
+ end
254
+
255
+ describe "associations" do
256
+ it "returns associated collection" do
257
+ resource = ProxyTestClass.foo.first
258
+ results = resource.related_proxy_test_classes
259
+
260
+ results.size.should == 2
261
+
262
+ associated = results.first
263
+ associated.should be_kind_of(RelatedProxyTestClass)
264
+ associated.name.should == 'one'
265
+ end
266
+
267
+ it "creates a ResourceProxy to support chaining" do
268
+ resource = ProxyTestClass.foo.first
269
+ proxy = resource.related_proxy_test_classes.baz.where(name: 'wibble')
270
+
271
+ proxy.should be_kind_of(Daylight::ResourceProxy)
272
+ proxy.to_params.should == {scopes: [:baz], filters: {name: 'wibble'}}
273
+ end
274
+
275
+ it "spawns new ResourceProxy for each part of the chain" do
276
+ resource = ProxyTestClass.foo.first
277
+ proxy = resource.related_proxy_test_classes.baz
278
+
279
+ limit = proxy.limit(1)
280
+ proxy.object_id.should_not == limit.object_id
281
+
282
+ limit.to_params.should == {limit: 1, scopes: [:baz]}
283
+ proxy.to_params.should == {scopes: [:baz]}
284
+ end
285
+
286
+ it 'adds to end of collection' do
287
+ resource = ProxyTestClass.foo.first
288
+ related = RelatedProxyTestClass.new(name: 'three')
289
+ existing = resource.related_proxy_test_classes.to_a.dup
290
+
291
+ resource.related_proxy_test_classes << related
292
+ resource.related_proxy_test_classes.should == existing + [related]
293
+ end
294
+
295
+ it 'adds multiples to end of collection' do
296
+ resource = ProxyTestClass.foo.first
297
+ related1 = RelatedProxyTestClass.new(name: 'three')
298
+ related2 = RelatedProxyTestClass.new(name: 'four')
299
+ existing = resource.related_proxy_test_classes.to_a.dup
300
+
301
+ resource.related_proxy_test_classes << related1
302
+ resource.related_proxy_test_classes << related2
303
+ resource.related_proxy_test_classes.should == existing + [related1, related2]
304
+ end
305
+ end
306
+
307
+ describe "ResourceProxy class" do
308
+ it 'cannot create without factory' do
309
+ expect { Daylight::ResourceProxy.new }.to raise_error(NoMethodError, /private method `new' called for/)
310
+ end
311
+
312
+ it "is a singleton" do
313
+ Daylight::ResourceProxy[ProxyTestClass].object_id.should == Daylight::ResourceProxy[ProxyTestClass].object_id
314
+ end
315
+
316
+ it "defined for each subclass" do
317
+ ProxyTestClass1.should be_const_defined(:ResourceProxy)
318
+ ProxyTestClass2.should be_const_defined(:ResourceProxy)
319
+
320
+ ProxyTestClass1::ResourceProxy.name.should == 'ProxyTestClass1::ResourceProxy'
321
+ ProxyTestClass2::ResourceProxy.name.should == 'ProxyTestClass2::ResourceProxy'
322
+ end
323
+ end
324
+
325
+ end