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.
- checksums.yaml +7 -0
- data/README.md +113 -0
- data/app/controllers/daylight_documentation/documentation_controller.rb +27 -0
- data/app/helpers/daylight_documentation/documentation_helper.rb +57 -0
- data/app/views/daylight_documentation/documentation/_header.haml +4 -0
- data/app/views/daylight_documentation/documentation/index.haml +12 -0
- data/app/views/daylight_documentation/documentation/model.haml +114 -0
- data/app/views/layouts/documentation.haml +22 -0
- data/config/routes.rb +8 -0
- data/doc/actions.md +70 -0
- data/doc/benchmarks.md +17 -0
- data/doc/contribute.md +80 -0
- data/doc/develop.md +1205 -0
- data/doc/environment.md +109 -0
- data/doc/example.md +3 -0
- data/doc/framework.md +31 -0
- data/doc/install.md +128 -0
- data/doc/principles.md +42 -0
- data/doc/testing.md +107 -0
- data/doc/usage.md +970 -0
- data/lib/daylight/api.rb +293 -0
- data/lib/daylight/associations.rb +247 -0
- data/lib/daylight/client_reloader.rb +45 -0
- data/lib/daylight/collection.rb +161 -0
- data/lib/daylight/errors.rb +94 -0
- data/lib/daylight/inflections.rb +7 -0
- data/lib/daylight/mock.rb +282 -0
- data/lib/daylight/read_only.rb +88 -0
- data/lib/daylight/refinements.rb +63 -0
- data/lib/daylight/reflection_ext.rb +67 -0
- data/lib/daylight/resource_proxy.rb +226 -0
- data/lib/daylight/version.rb +10 -0
- data/lib/daylight.rb +27 -0
- data/rails/daylight/api_controller.rb +354 -0
- data/rails/daylight/documentation.rb +13 -0
- data/rails/daylight/helpers.rb +32 -0
- data/rails/daylight/params.rb +23 -0
- data/rails/daylight/refiners.rb +186 -0
- data/rails/daylight/server.rb +29 -0
- data/rails/daylight/tasks.rb +37 -0
- data/rails/extensions/array_ext.rb +9 -0
- data/rails/extensions/autosave_association_fix.rb +49 -0
- data/rails/extensions/has_one_serializer_ext.rb +111 -0
- data/rails/extensions/inflections.rb +6 -0
- data/rails/extensions/nested_attributes_ext.rb +94 -0
- data/rails/extensions/read_only_attributes.rb +35 -0
- data/rails/extensions/render_json_meta.rb +99 -0
- data/rails/extensions/route_options.rb +47 -0
- data/rails/extensions/versioned_url_for.rb +22 -0
- data/spec/config/dependencies.rb +2 -0
- data/spec/config/factory_girl.rb +4 -0
- data/spec/config/simplecov_rcov.rb +26 -0
- data/spec/config/test_api.rb +1 -0
- data/spec/controllers/documentation_controller_spec.rb +24 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/daylight.rb +1 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +59 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/helpers/documentation_helper_spec.rb +82 -0
- data/spec/lib/daylight/api_spec.rb +178 -0
- data/spec/lib/daylight/associations_spec.rb +325 -0
- data/spec/lib/daylight/collection_spec.rb +235 -0
- data/spec/lib/daylight/errors_spec.rb +111 -0
- data/spec/lib/daylight/mock_spec.rb +144 -0
- data/spec/lib/daylight/read_only_spec.rb +118 -0
- data/spec/lib/daylight/refinements_spec.rb +80 -0
- data/spec/lib/daylight/reflection_ext_spec.rb +50 -0
- data/spec/lib/daylight/resource_proxy_spec.rb +325 -0
- data/spec/rails/daylight/api_controller_spec.rb +421 -0
- data/spec/rails/daylight/helpers_spec.rb +41 -0
- data/spec/rails/daylight/params_spec.rb +45 -0
- data/spec/rails/daylight/refiners_spec.rb +178 -0
- data/spec/rails/extensions/array_ext_spec.rb +51 -0
- data/spec/rails/extensions/has_one_serializer_ext_spec.rb +135 -0
- data/spec/rails/extensions/nested_attributes_ext_spec.rb +177 -0
- data/spec/rails/extensions/render_json_meta_spec.rb +140 -0
- data/spec/rails/extensions/route_options_spec.rb +309 -0
- data/spec/rails/extensions/versioned_url_for_spec.rb +46 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/migration_helper.rb +40 -0
- 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
|