nested 0.0.25 → 0.0.26
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 +4 -4
- data/Gemfile +1 -0
- data/lib/nested/app.rb +31 -0
- data/lib/nested/integration/angular.rb +119 -0
- data/lib/nested/js.rb +42 -0
- data/lib/nested/many.rb +19 -0
- data/lib/nested/one.rb +29 -0
- data/lib/nested/redirect.rb +8 -0
- data/lib/nested/resource.rb +268 -0
- data/lib/nested/serializer.rb +45 -0
- data/lib/nested/serializer_field.rb +9 -0
- data/lib/nested/singleton.rb +13 -0
- data/lib/nested/with_many.rb +11 -0
- data/lib/nested/with_singleton.rb +11 -0
- data/lib/nested.rb +16 -566
- data/nested.gemspec +1 -1
- data/test/nested_test.rb +73 -109
- data/test/test_helper.rb +2 -2
- metadata +14 -2
data/lib/nested.rb
CHANGED
@@ -1,576 +1,26 @@
|
|
1
|
-
require "json"
|
2
|
-
|
3
1
|
module Nested
|
2
|
+
PROC_TRUE = Proc.new{ true }
|
3
|
+
end
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class SingletonAndCollectionError < StandardError
|
9
|
-
end
|
10
|
-
|
11
|
-
class NameMissingError < StandardError
|
12
|
-
end
|
13
|
-
|
14
|
-
class Redirect
|
15
|
-
attr_reader :url
|
16
|
-
def initialize(url)
|
17
|
-
@url = url
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class SerializerField
|
22
|
-
attr_accessor :name, :condition
|
23
|
-
def initialize(name, condition)
|
24
|
-
@name = name
|
25
|
-
@condition = condition
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class Serializer
|
30
|
-
attr_accessor :includes, :excludes
|
31
|
-
|
32
|
-
def initialize(includes=[])
|
33
|
-
@includes = includes.clone
|
34
|
-
@excludes = []
|
35
|
-
end
|
36
|
-
|
37
|
-
def +(field)
|
38
|
-
field = field.is_a?(SerializerField) ? field : SerializerField.new(field, ->{ true })
|
39
|
-
|
40
|
-
@includes << field unless @includes.detect{|e| e.name == field.name}
|
41
|
-
@excludes = @excludes.reject{|e| e.name == field.name}
|
42
|
-
self
|
43
|
-
end
|
44
|
-
|
45
|
-
def -(field)
|
46
|
-
field = field.is_a?(SerializerField) ? field : SerializerField.new(field, ->{ true })
|
47
|
-
|
48
|
-
@excludes << field unless @excludes.detect{|e| e.name == field.name}
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def serialize
|
53
|
-
this = self
|
54
|
-
->(obj) do
|
55
|
-
excludes = this.excludes.select{|e| instance_exec(&e.condition)}
|
56
|
-
|
57
|
-
this.includes.reject{|e| excludes.detect{|e2| e2.name == e.name}}.inject({}) do |memo, field|
|
58
|
-
if instance_exec(&field.condition)
|
59
|
-
case field.name
|
60
|
-
when Symbol
|
61
|
-
memo[field.name] = obj.is_a?(Hash) ? obj[field.name] : obj.send(field.name)
|
62
|
-
when Hash
|
63
|
-
field_name, proc = field.name.to_a.first
|
64
|
-
memo[field_name] = instance_exec(obj, &proc)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
memo
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class Resource
|
74
|
-
attr_reader :name, :parent, :actions, :resources, :serializer
|
75
|
-
|
76
|
-
def initialize(sinatra, name, singleton, collection, parent, init_block)
|
77
|
-
raise SingletonAndCollectionError.new if singleton && collection
|
78
|
-
raise NameMissingError.new if (singleton || collection) && !name
|
79
|
-
|
80
|
-
@sinatra = sinatra
|
81
|
-
@name = name
|
82
|
-
@singleton = singleton
|
83
|
-
@collection = collection
|
84
|
-
@parent = parent
|
85
|
-
@resources = []
|
86
|
-
@actions = []
|
87
|
-
@init_block = init_block
|
88
|
-
@run_blocks = []
|
89
|
-
|
90
|
-
@serializer = Serializer.new(member? ? parent.serializer.includes : [])
|
91
|
-
end
|
92
|
-
|
93
|
-
def singleton?
|
94
|
-
@singleton == true
|
95
|
-
end
|
96
|
-
|
97
|
-
def member?
|
98
|
-
!singleton? && !collection?
|
99
|
-
end
|
100
|
-
|
101
|
-
def collection?
|
102
|
-
@collection == true
|
103
|
-
end
|
104
|
-
|
105
|
-
def run(&block)
|
106
|
-
@run_blocks << block
|
107
|
-
self
|
108
|
-
end
|
109
|
-
|
110
|
-
def type
|
111
|
-
if singleton?
|
112
|
-
:singleton
|
113
|
-
elsif member?
|
114
|
-
:member
|
115
|
-
elsif collection?
|
116
|
-
:collection
|
117
|
-
else
|
118
|
-
raise "undefined"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def serialize(*args)
|
123
|
-
args.each {|arg| serializer + arg }
|
124
|
-
serializer
|
125
|
-
end
|
126
|
-
|
127
|
-
def serialize_include_if(condition, *args)
|
128
|
-
args.each {|arg| @serializer + SerializerField.new(arg, condition) }
|
129
|
-
end
|
130
|
-
|
131
|
-
def serialize_exclude_if(condition, *args)
|
132
|
-
args.each {|arg| @serializer - SerializerField.new(arg, condition) }
|
133
|
-
end
|
134
|
-
|
135
|
-
def route_replace(route, args)
|
136
|
-
args.each do |k, v|
|
137
|
-
route = route.gsub(":#{k}", "#{v}")
|
138
|
-
end
|
139
|
-
route
|
140
|
-
end
|
141
|
-
|
142
|
-
def route(action=nil)
|
143
|
-
"".tap do |r|
|
144
|
-
r << @parent.route if @parent
|
145
|
-
|
146
|
-
|
147
|
-
if singleton? || collection?
|
148
|
-
r << "/#{@name}"
|
149
|
-
else
|
150
|
-
r << "/:#{@name}_id"
|
151
|
-
end
|
152
|
-
|
153
|
-
r << "/#{action}" if action
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def get(action=nil, &block)
|
158
|
-
create_sinatra_route :get, action, &(block||proc {})
|
159
|
-
end
|
160
|
-
|
161
|
-
def post(action=nil, &block)
|
162
|
-
create_sinatra_route :post, action, &block
|
163
|
-
end
|
164
|
-
|
165
|
-
def put(action=nil, &block)
|
166
|
-
create_sinatra_route :put, action, &block
|
167
|
-
end
|
168
|
-
|
169
|
-
def delete(action=nil, &block)
|
170
|
-
create_sinatra_route :delete, action, &block
|
171
|
-
end
|
172
|
-
|
173
|
-
def singleton(name, init_block=nil, &block)
|
174
|
-
child_resource(name, true, false, init_block, &(block||Proc.new{ }))
|
175
|
-
end
|
176
|
-
|
177
|
-
def many(name, init_block=nil, &block)
|
178
|
-
raise ManyInManyError.new "do not nest many in many" if collection?
|
179
|
-
child_resource(name, false, true, init_block, &(block||Proc.new{ }))
|
180
|
-
end
|
181
|
-
|
182
|
-
def default_init_block_singleton
|
183
|
-
if parent
|
184
|
-
Proc.new{ instance_variable_get("@#{@__resource.parent.instance_variable_name}").send(@__resource.name) }
|
185
|
-
else
|
186
|
-
Proc.new { nil }
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def default_init_block_many
|
191
|
-
if parent
|
192
|
-
Proc.new{ instance_variable_get("@#{@__resource.parent.instance_variable_name}").send(@__resource.name) }
|
193
|
-
else
|
194
|
-
Proc.new { nil }
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def default_init_block_one
|
199
|
-
if parent
|
200
|
-
Proc.new do
|
201
|
-
instance_variable_get("@#{@__resource.parent.instance_variable_name}")
|
202
|
-
.where(id: params[:"#{@__resource.parent.name.to_s.singularize.to_sym}_id"])
|
203
|
-
.first
|
204
|
-
end
|
205
|
-
else
|
206
|
-
Proc.new { nil }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def one(&block)
|
211
|
-
raise "calling one() is only allowed within many() resource" unless collection?
|
212
|
-
child_resource(self.name.to_s.singularize.to_sym, false, false, nil, &(block||Proc.new{ }))
|
213
|
-
end
|
214
|
-
|
215
|
-
def child_resource(name, singleton, collection, init_block, &block)
|
216
|
-
Resource.new(@sinatra, name, singleton, collection, self, init_block)
|
217
|
-
.tap{|r| r.instance_eval(&block)}
|
218
|
-
.tap{|r| @resources << r}
|
219
|
-
end
|
220
|
-
|
221
|
-
def instance_variable_name
|
222
|
-
member? ? parent.name.to_s.singularize.to_sym : @name
|
223
|
-
end
|
224
|
-
|
225
|
-
def parents
|
226
|
-
(@parent ? @parent.parents + [@parent] : [])
|
227
|
-
end
|
228
|
-
|
229
|
-
def self_and_parents
|
230
|
-
(self.parents + [self]).reverse
|
231
|
-
end
|
232
|
-
|
233
|
-
# --------------------------
|
234
|
-
|
235
|
-
def sinatra_set_instance_variable(sinatra, name, value)
|
236
|
-
raise "variable @#{name} already defined" if sinatra.instance_variable_defined?(:"@#{name}")
|
237
|
-
sinatra.instance_variable_set(:"@#{name}", value)
|
238
|
-
end
|
239
|
-
|
240
|
-
def sinatra_init(sinatra)
|
241
|
-
sinatra.instance_variable_set("@__resource", self)
|
242
|
-
|
243
|
-
init_block = if @init_block
|
244
|
-
@init_block
|
245
|
-
else
|
246
|
-
if singleton?
|
247
|
-
default_init_block_singleton
|
248
|
-
elsif collection?
|
249
|
-
default_init_block_many
|
250
|
-
else
|
251
|
-
default_init_block_one
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
sinatra.instance_variable_set("@#{self.instance_variable_name}", sinatra.instance_exec(&init_block))
|
256
|
-
|
257
|
-
@run_blocks.each{|e| sinatra.instance_exec(&e)}
|
258
|
-
end
|
259
|
-
|
260
|
-
def sinatra_exec_get_block(sinatra, &block)
|
261
|
-
sinatra_init_data(:get, sinatra, &block)
|
262
|
-
sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block)
|
263
|
-
end
|
264
|
-
|
265
|
-
def sinatra_exec_delete_block(sinatra, &block)
|
266
|
-
sinatra_init_data(:delete, sinatra, &block)
|
267
|
-
sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block)
|
268
|
-
end
|
269
|
-
|
270
|
-
def sinatra_init_data(method, sinatra, &block)
|
271
|
-
raw_data = if [:put, :post].include?(method)
|
272
|
-
sinatra.request.body.rewind
|
273
|
-
HashWithIndifferentAccess.new(JSON.parse(sinatra.request.body.read))
|
274
|
-
elsif [:get, :delete].include?(method)
|
275
|
-
sinatra.params
|
276
|
-
else
|
277
|
-
{}
|
278
|
-
end
|
279
|
-
|
280
|
-
sinatra.instance_variable_set("@__raw_data", raw_data)
|
281
|
-
sinatra.instance_variable_set("@__data", raw_data.values_at(*block.parameters.map(&:last)))
|
282
|
-
end
|
283
|
-
|
284
|
-
def sinatra_exec_put_block(sinatra, &block)
|
285
|
-
sinatra_init_data(:put, sinatra, &block)
|
286
|
-
sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block)
|
287
|
-
end
|
288
|
-
|
289
|
-
def sinatra_exec_post_block(sinatra, &block)
|
290
|
-
sinatra_init_data(:post, sinatra, &block)
|
291
|
-
res = sinatra.instance_exec(*sinatra.instance_variable_get("@__data"), &block)
|
292
|
-
sinatra.instance_variable_set("@#{self.instance_variable_name}", res)
|
293
|
-
# TODO: do we need to check for existing variables here?
|
294
|
-
# sinatra_set_instance_variable(sinatra, self.instance_variable_name, res)
|
295
|
-
end
|
296
|
-
|
297
|
-
def sinatra_response_type(response)
|
298
|
-
(response.is_a?(ActiveModel::Errors) || (response.respond_to?(:errors) && !response.errors.empty?)) ? :error : (response.is_a?(Nested::Redirect) ? :redirect : :data)
|
299
|
-
end
|
300
|
-
|
301
|
-
def sinatra_response(sinatra, method)
|
302
|
-
response = if sinatra.errors.empty?
|
303
|
-
sinatra.instance_variable_get("@#{self.instance_variable_name}")
|
304
|
-
else
|
305
|
-
sinatra.errors
|
306
|
-
end
|
307
|
-
|
308
|
-
response = self.send(:"sinatra_response_create_#{sinatra_response_type(response)}", sinatra, response, method)
|
309
|
-
|
310
|
-
case response
|
311
|
-
when Nested::Redirect then
|
312
|
-
sinatra.redirect(response.url)
|
313
|
-
when String then
|
314
|
-
response
|
315
|
-
else
|
316
|
-
response.to_json
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
def sinatra_response_create_redirect(sinatra, response, method)
|
321
|
-
response
|
322
|
-
end
|
323
|
-
|
324
|
-
def sinatra_response_create_data(sinatra, response, method)
|
325
|
-
data = if response && (collection? || response.is_a?(Array)) && method != :post
|
326
|
-
response.to_a.map{|e| sinatra.instance_exec(e, &@serializer.serialize) }
|
327
|
-
else
|
328
|
-
sinatra.instance_exec(response, &@serializer.serialize)
|
329
|
-
end
|
330
|
-
|
331
|
-
{data: data, ok: true}
|
332
|
-
end
|
333
|
-
|
334
|
-
def sinatra_errors_to_hash(errors)
|
335
|
-
errors.to_hash.inject({}) do |memo, e|
|
336
|
-
memo[e[0]] = e[1][0]
|
337
|
-
memo
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
def sinatra_response_create_error(sinatra, response, method)
|
342
|
-
errors = response.is_a?(ActiveModel::Errors) ? response : response.errors
|
343
|
-
{data: sinatra_errors_to_hash(errors), ok: false}
|
344
|
-
end
|
345
|
-
|
346
|
-
def create_sinatra_route(method, action, &block)
|
347
|
-
@actions << {method: method, action: action, block: block}
|
348
|
-
|
349
|
-
resource = self
|
350
|
-
|
351
|
-
route = resource.route(action)
|
352
|
-
|
353
|
-
@sinatra.send(method, route) do
|
354
|
-
def self.error(message)
|
355
|
-
errors.add(:base, message)
|
356
|
-
end
|
357
|
-
|
358
|
-
def self.errors
|
359
|
-
@__errors ||= ActiveModel::Errors.new({})
|
360
|
-
end
|
361
|
-
|
362
|
-
begin
|
363
|
-
content_type :json
|
364
|
-
|
365
|
-
resource.self_and_parents.reverse.each do |res|
|
366
|
-
res.sinatra_init(self)
|
367
|
-
end
|
368
|
-
|
369
|
-
resource.send(:"sinatra_exec_#{method}_block", self, &block)
|
370
|
-
|
371
|
-
resource.sinatra_response(self, method)
|
372
|
-
rescue Exception => e
|
373
|
-
context_arr = []
|
374
|
-
context_arr << "route: #{route}"
|
375
|
-
context_arr << "method: #{method}"
|
376
|
-
context_arr << "action: #{action}"
|
377
|
-
|
378
|
-
context_arr << "resource: #{resource.name} (#{resource.type})"
|
379
|
-
resource_object = instance_variable_get("@#{resource.instance_variable_name}")
|
380
|
-
context_arr << "@#{resource.instance_variable_name}: #{resource_object.inspect}"
|
381
|
-
|
382
|
-
parent = resource.try(:parent)
|
383
|
-
|
384
|
-
if parent
|
385
|
-
context_arr << "parent: #{parent.try(:name)} (#{parent.try(:type)})"
|
386
|
-
parent_object = instance_variable_get("@#{parent.try(:instance_variable_name)}")
|
387
|
-
context_arr << "@#{parent.try(:instance_variable_name)}: #{parent_object.inspect}"
|
388
|
-
end
|
389
|
-
|
390
|
-
puts context_arr.join("\n")
|
391
|
-
raise e
|
392
|
-
end
|
393
|
-
end
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
module Angular
|
398
|
-
def self.extended(base)
|
399
|
-
base.send(:extend, Nested::Angular::Sinatra)
|
400
|
-
end
|
401
|
-
|
402
|
-
module Sinatra
|
403
|
-
# def create_resource(name, singleton, collection, &block)
|
404
|
-
def create_resource(*args, &block)
|
405
|
-
angularize(super)
|
406
|
-
end
|
407
|
-
|
408
|
-
def nested_angular_config(config=nil)
|
409
|
-
if config
|
410
|
-
@nested_angular_config = config
|
411
|
-
else
|
412
|
-
@nested_angular_config ||= {}
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
end
|
417
|
-
|
418
|
-
def angular_add_functions(js, resource)
|
419
|
-
resource.actions.each do |e|
|
420
|
-
method, action, block = e.values_at :method, :action, :block
|
421
|
-
block_args = block.parameters.map(&:last)
|
422
|
-
|
423
|
-
fun_name = Nested::JsUtil::generate_function_name(resource, method, action)
|
424
|
-
|
425
|
-
args = Nested::JsUtil::function_arguments(resource)
|
426
|
-
|
427
|
-
route_args = args.inject({}) do |memo, e|
|
428
|
-
idx = args.index(e)
|
429
|
-
memo[:"#{e}_id"] = "'+(typeof(values[#{idx}]) == 'number' ? values[#{idx}].toString() : (values[#{idx}].id || values[#{idx}]))+'"
|
430
|
-
memo
|
431
|
-
end
|
432
|
-
route = "#{self.nested_config[:prefix]}" + resource.route_replace(resource.route(action), route_args)
|
433
|
-
when_args = args.map{|a| "$q.when(#{a})"}
|
434
|
-
|
435
|
-
js << " impl.#{fun_name}Url = function(#{args.join(',')}){"
|
436
|
-
js << " var deferred = $q.defer()"
|
437
|
-
js << " $q.all([#{when_args.join(',')}]).then(function(values){"
|
438
|
-
js << " deferred.resolve('#{route}')"
|
439
|
-
js << " })"
|
440
|
-
js << " return deferred.promise"
|
441
|
-
js << " }"
|
442
|
-
|
443
|
-
if [:get, :delete].include?(method)
|
444
|
-
args << "data" if !block_args.empty?
|
445
|
-
|
446
|
-
js << " impl.#{fun_name} = function(#{args.join(',')}){"
|
447
|
-
js << " var deferred = $q.defer()"
|
448
|
-
js << " $q.all([#{when_args.join(',')}]).then(function(values){"
|
449
|
-
js << " $http({"
|
450
|
-
js << " method: '#{method}', "
|
451
|
-
js << (" url: '#{route}'" + (block_args.empty? ? "" : ","))
|
452
|
-
js << " params: data" unless block_args.empty?
|
453
|
-
js << " })"
|
454
|
-
js << " .success(function(responseData){"
|
455
|
-
js << " deferred[responseData.ok ? 'resolve' : 'reject'](responseData.data)"
|
456
|
-
js << " })"
|
457
|
-
js << " .error(function(){ deferred.reject() })"
|
458
|
-
js << " });"
|
459
|
-
js << " return deferred.promise"
|
460
|
-
js << " }"
|
461
|
-
elsif method == :post
|
462
|
-
js << " impl.#{fun_name} = function(#{(args+['data']).join(',')}){"
|
463
|
-
js << " var deferred = $q.defer()"
|
464
|
-
js << " $q.all([#{when_args.join(',')}]).then(function(values){"
|
465
|
-
js << " $http({method: '#{method}', url: '#{route}', data: data})"
|
466
|
-
js << " .success(function(responseData){"
|
467
|
-
js << " deferred[responseData.ok ? 'resolve' : 'reject'](responseData.data)"
|
468
|
-
js << " })"
|
469
|
-
js << " .error(function(){ deferred.reject() })"
|
470
|
-
js << " });"
|
471
|
-
js << " return deferred.promise"
|
472
|
-
js << " }"
|
473
|
-
elsif method == :put
|
474
|
-
args << "data" if args.empty? || !block_args.empty?
|
475
|
-
|
476
|
-
js << " impl.#{fun_name} = function(#{args.join(',')}){"
|
477
|
-
js << " var deferred = $q.defer()"
|
478
|
-
js << " $q.all([#{when_args.join(',')}]).then(function(values){"
|
479
|
-
js << " $http({method: '#{method}', url: '#{route}', data: #{args.last}})"
|
480
|
-
js << " .success(function(responseData){"
|
481
|
-
js << " deferred[responseData.ok ? 'resolve' : 'reject'](responseData.data)"
|
482
|
-
js << " })"
|
483
|
-
js << " .error(function(){ deferred.reject() })"
|
484
|
-
js << " });"
|
485
|
-
js << " return deferred.promise"
|
486
|
-
js << " }"
|
487
|
-
end
|
488
|
-
end
|
489
|
-
|
490
|
-
resource.resources.each {|r| angular_add_functions(js, r) }
|
491
|
-
end
|
492
|
-
|
493
|
-
def angularize(resource)
|
494
|
-
js = []
|
495
|
-
|
496
|
-
module_name = "nested_#{resource.name}".camelcase(:lower)
|
497
|
-
|
498
|
-
js << "angular.module('#{module_name}#{nested_angular_config[:service_suffix]}', [])"
|
499
|
-
js << ".factory('#{resource.name.to_s.camelcase.capitalize}#{nested_angular_config[:service_suffix]}', function($http, $q){"
|
500
|
-
|
501
|
-
js << " var impl = {}"
|
502
|
-
angular_add_functions(js, resource)
|
503
|
-
js << " return impl"
|
504
|
-
|
505
|
-
js << "})"
|
506
|
-
|
507
|
-
response_transform = nested_angular_config[:response_transform] || ->(code){ code }
|
508
|
-
|
509
|
-
get "/#{resource.name}.js" do
|
510
|
-
content_type :js
|
511
|
-
instance_exec(js.join("\n"), &response_transform)
|
512
|
-
end
|
513
|
-
end
|
514
|
-
end
|
515
|
-
|
516
|
-
module JsUtil
|
517
|
-
def self.generate_function_name(resource, method, action)
|
518
|
-
arr = []
|
5
|
+
require "json"
|
6
|
+
require "sinatra/base"
|
519
7
|
|
520
|
-
|
521
|
-
arr << "create" if method == :post
|
522
|
-
arr << "destroy" if method == :delete
|
8
|
+
require "nested/js"
|
523
9
|
|
524
|
-
|
10
|
+
require "nested/redirect"
|
525
11
|
|
526
|
-
|
527
|
-
|
528
|
-
if e == all.last
|
529
|
-
if method == :post
|
530
|
-
arr << e.name.to_s.singularize.to_sym
|
531
|
-
else
|
532
|
-
arr << e.name
|
533
|
-
end
|
534
|
-
else
|
535
|
-
arr << e.name unless all[all.index(e) + 1].member?
|
536
|
-
end
|
537
|
-
else
|
538
|
-
arr << e.name
|
539
|
-
end
|
540
|
-
end
|
12
|
+
require "nested/with_many"
|
13
|
+
require "nested/with_singleton"
|
541
14
|
|
542
|
-
|
15
|
+
require "nested/resource"
|
543
16
|
|
544
|
-
|
545
|
-
|
17
|
+
require "nested/one"
|
18
|
+
require "nested/singleton"
|
19
|
+
require "nested/many"
|
546
20
|
|
547
|
-
|
548
|
-
|
549
|
-
.self_and_parents.select{|r| r.member?}
|
550
|
-
.map{|r| r.name || r.parent.name}
|
551
|
-
.map(&:to_s)
|
552
|
-
.map(&:singularize)
|
553
|
-
.reverse
|
554
|
-
end
|
555
|
-
end
|
21
|
+
require "nested/serializer"
|
22
|
+
require "nested/serializer_field"
|
556
23
|
|
557
|
-
|
558
|
-
def nested_config(config=nil)
|
559
|
-
if config
|
560
|
-
@nested_config = config
|
561
|
-
else
|
562
|
-
@nested_config ||= {}
|
563
|
-
end
|
564
|
-
end
|
565
|
-
def singleton(name, init_block=nil, &block)
|
566
|
-
create_resource(name, true, false, init_block, &block)
|
567
|
-
end
|
568
|
-
def many(name, init_block=nil, &block)
|
569
|
-
create_resource(name, false, true, init_block, &block)
|
570
|
-
end
|
571
|
-
def create_resource(name, singleton, collection, init_block, &block)
|
572
|
-
::Nested::Resource.new(self, name, singleton, collection, nil, init_block).tap{|r| r.instance_eval(&block) }
|
573
|
-
end
|
574
|
-
end
|
24
|
+
require "nested/app"
|
575
25
|
|
576
|
-
|
26
|
+
require "nested/integration/angular"
|