tint 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b646a5aca0a4609a2285d5add776d0b0269ce11
4
- data.tar.gz: d613dd2da3a435acfa9fc7c3e2927e0da9428808
3
+ metadata.gz: 9b243827913ffe5dd0696d1a4c43c4279f2cbe35
4
+ data.tar.gz: c112cffa3c4b79cbb6f540c7c41e4e5d998f70d2
5
5
  SHA512:
6
- metadata.gz: d4ac9d15bc28cefbe96dd4c5b322cd4efe111878abe84c64e9dbb683b99e6ebf2eca68751e868640eed9033c982408c16c3da6f9fbda27f0edf8838f9c43f1ef
7
- data.tar.gz: 6e21cdf0b19fd87cc5f381cf7e9b45344f7d58d283d9d832cd56c020ed5b5c8155f18066bdc55a261d4f3953f82512d76f097a761af267e562a73ad781e8b145
6
+ metadata.gz: 13aa4b8db03c71954930d71dfe6ce16401c6cce0f4b41df22728a2c2f231ff8e955982ab3e8b62e0e9affc09dec07a606d11d843ea625b0afe2d7216c235f63a
7
+ data.tar.gz: 920ae9f4d9cbd7bee7afe69e2d83772a2de9174fc7b693ccbe47a51777402f8fbbe855ed7e9d03e9eccdc40e51594748934516018f71b8a889968e5963b61b2c
@@ -7,7 +7,9 @@ module Tint
7
7
  include JsonConversion
8
8
 
9
9
  def initialize(object, options = {})
10
- super(object, options)
10
+ super(object, options.except(:parent_decorator, :parent_association))
11
+
12
+ @context = @context.merge(options.slice(:parent_decorator, :parent_association))
11
13
  end
12
14
 
13
15
  def column_names
@@ -18,6 +20,23 @@ module Tint
18
20
  object.persisted?
19
21
  end
20
22
 
23
+ def decorate_as_association(association_name, association, options = {})
24
+ options.assert_valid_keys(:with)
25
+
26
+ association_decorator = options[:with]
27
+
28
+ association_context = options.except(:with).merge(context: context.
29
+ merge(parent_decorator: self, parent_association: association_name.to_sym))
30
+
31
+ self.class.eager_load(association_name => {})
32
+
33
+ if association.respond_to?(:each)
34
+ association_decorator.decorate_collection(association, association_context)
35
+ else
36
+ association_decorator.decorate(association, association_context)
37
+ end
38
+ end
39
+
21
40
  class << self
22
41
  attr_accessor :_attributes, :parent_decorator, :parent_association
23
42
 
@@ -50,8 +69,6 @@ module Tint
50
69
  end
51
70
 
52
71
  def eager_load(*schema)
53
- @_attributes ||= Set.new
54
-
55
72
  new_eager_loads =
56
73
  schema.inject({}) do |memo, schema_item|
57
74
  if schema_item.kind_of?(Hash)
@@ -64,39 +81,32 @@ module Tint
64
81
  end
65
82
 
66
83
  self.eager_loads = self.eager_loads.deeper_merge(new_eager_loads)
67
- end
84
+ end
68
85
 
69
86
  def decorates_association(association_name, options = {})
70
87
  options[:with] ||= (association_name.to_s.camelize.singularize + 'Decorator').constantize
71
88
 
72
- association_alias = options.delete(:as)
73
-
74
- options[:context] ||= {}
75
- options[:context][:parent_decorator] = self
76
- options[:context][:parent_association] = association_name
77
-
78
- ap "association_name:"
79
- ap association_name
89
+ association_alias = options.delete(:as) || association_name
80
90
 
81
- ap "options:"
82
- ap options
91
+ options.assert_valid_keys(:with, :scope, :context)
83
92
 
93
+ define_method(association_alias) do
94
+ context_with_association = context.merge({
95
+ parent_decorator: self,
96
+ parent_association: association_name
97
+ })
84
98
 
85
- if association_alias
86
- options.assert_valid_keys(:with, :scope, :context)
87
-
88
- define_method(association_alias) do
89
- decorated_associations[association_alias] ||= Draper::DecoratedAssociation.new(self, association_name, options)
90
- decorated_associations[association_alias].call
91
- end
92
-
93
- attributes(association_alias)
94
- else
95
- super(association_name, options)
99
+ decorated_associations[association_alias] ||= Draper::DecoratedAssociation.new(
100
+ self,
101
+ association_name,
102
+ options.merge(context: context_with_association)
103
+ )
96
104
 
97
- attributes(association_name)
105
+ decorated_associations[association_alias].call
98
106
  end
99
107
 
108
+ attributes(association_alias)
109
+
100
110
  association_eager_loads = options[:with].eager_loads
101
111
 
102
112
  if association_eager_loads.present?
@@ -107,6 +117,7 @@ module Tint
107
117
  end
108
118
 
109
119
  def decorates_associations(*arguments)
120
+
110
121
  options = arguments.extract_options!
111
122
  association_list = arguments
112
123
 
@@ -116,25 +127,16 @@ module Tint
116
127
  end
117
128
 
118
129
  def decorate_collection(collection, options = {})
119
- ap "options:"
120
- ap options
121
-
122
- collection_with_eager_loads = collection
123
-
124
- if options[:context] && options[:context][:parent_decorator] && options[:context][:parent_association]
125
- @parent_decorator = options[:context][:parent_decorator]
126
- @parent_association = options[:context][:parent_association]
127
130
 
131
+ collection_with_eager_loads =
128
132
  if collection.respond_to?(:includes) &&
129
- !eager_loads.blank? &&
130
- !parent_eager_loads_include_own?
131
-
132
- # ap "decorate_collection eager_loading eager_loads:"
133
- # ap eager_loads
133
+ eager_loads.present? &&
134
+ !parent_eager_loads_include_own?(options[:context])
134
135
 
135
- collection_with_eager_loads = collection.includes(*eager_loads)
136
+ collection.includes(eager_loads)
137
+ else
138
+ collection
136
139
  end
137
- end
138
140
 
139
141
  super(collection_with_eager_loads, options)
140
142
  end
@@ -142,42 +144,22 @@ module Tint
142
144
  def decorate(object, options = {})
143
145
  object_class = object.class
144
146
 
145
- # unless already_eager_loaded_associations?(object)
146
- # object =
147
- # if responds_to_methods?(object_class, :includes, :find) && eager_loads.present?
148
- # object_class.includes(*eager_loads).find(object.id)
149
- # else
150
- # object
151
- # end
152
- # end
147
+ unless already_eager_loaded_associations?(object)
148
+ object =
149
+ if responds_to_methods?(object_class, :includes, :find) && eager_loads.present?
150
+ object_class.includes(*eager_loads).find(object.id)
151
+ else
152
+ object
153
+ end
154
+ end
153
155
 
154
156
  super(object, options)
155
157
  end
156
158
 
157
- def parent_eager_loads_include_own?(association = nil)
158
- association_chain = [@parent_assocation]
159
- association_chain.push(association) if association
160
-
161
- eager_loads_include?(@parent_decorator.eager_loads, association_chain) ||
162
- @parent_decorator.parent_eager_loads_include_own?(association_chain)
159
+ def parent_eager_loads_include_own?(context = {})
160
+ !!(context && context[:parent_decorator] && context[:parent_decorator].class.eager_loads[context[:parent_association]])
163
161
  end
164
162
 
165
- def eager_loads_include?(hash, key_list)
166
- if key_list.length > 1
167
- next_key = key_list.shift
168
-
169
- if (next_value = hash[next_key])
170
- eager_loads_include?(next_value, key_list)
171
- else
172
- next_value
173
- end
174
- else
175
- hash[key_list.first]
176
- end
177
- end
178
-
179
- private
180
-
181
163
  def already_eager_loaded_associations?(object)
182
164
  if object.respond_to?(:association_cache)
183
165
  object.association_cache.any?
@@ -1,3 +1,3 @@
1
1
  module Tint
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,4 @@
1
+ RSpec.configure do |config|
2
+ config.filter_run :focus
3
+ config.run_all_when_everything_filtered = true
4
+ end
@@ -1,6 +1,8 @@
1
1
  require 'tint'
2
2
  require_relative '../support/active_record_mock'
3
3
 
4
+ require 'spec_helper'
5
+
4
6
  RSpec.describe Tint::Decorator do
5
7
  subject{ decorator_class.decorate(object).as_json }
6
8
 
@@ -23,7 +25,7 @@ RSpec.describe Tint::Decorator do
23
25
  end
24
26
  end
25
27
 
26
- it "returns an empty object", focus: true do
28
+ it "returns an empty object" do
27
29
  expect(subject).to eql({})
28
30
  end
29
31
  end
@@ -209,4 +211,119 @@ RSpec.describe Tint::Decorator do
209
211
  end
210
212
  end
211
213
  end
214
+
215
+ describe "::parent_eager_loads_include_own?" do
216
+ let(:decorator_class) do
217
+ Class.new(Tint::Decorator) do
218
+ eager_load :products
219
+ end
220
+ end
221
+
222
+ before(:each) do
223
+ Object.const_set('AssociatedDecorator', decorator_class)
224
+ end
225
+
226
+ context "when the decorator has no parent" do
227
+ let(:parent_decorator_class) { nil }
228
+
229
+ it "returns false" do
230
+ expect(decorator_class.parent_eager_loads_include_own?).to eql(false)
231
+ end
232
+ end
233
+
234
+ context "when the decorator has a parent set via decorates_association" do
235
+ let(:parent_decorator_class) do
236
+ Class.new(Tint::Decorator) do
237
+ decorates_association :associated
238
+ end
239
+ end
240
+
241
+ it "returns true" do
242
+ context = {
243
+ parent_decorator: parent_decorator_class.decorate(object_class),
244
+ parent_association: :associated
245
+ }
246
+
247
+ expect(decorator_class.parent_eager_loads_include_own?(context)).to eql(true)
248
+ end
249
+ end
250
+
251
+ context "when a decorator has a parent set via #decorate_association" do
252
+ let(:parent_decorator_class) do
253
+ Class.new(Tint::Decorator) do
254
+ attributes :associated
255
+
256
+ def associated
257
+ decorate_as_association(:association, object, with: AssociatedDecorator)
258
+ end
259
+
260
+ end
261
+ end
262
+
263
+ it "returns true" do
264
+ decorated_class = parent_decorator_class.decorate(object_class.new('foo', 'bar'))
265
+
266
+ context = decorated_class.send(:associated).context
267
+ expect(decorator_class.parent_eager_loads_include_own?(context)).to eql(true)
268
+ end
269
+ end
270
+
271
+ context "when a decorator has a parent manually set" do
272
+ context "and the parent doesn't manually eager load the association" do
273
+ let(:parent_decorator_class) do
274
+ Class.new(Tint::Decorator) do
275
+ attributes :associated
276
+
277
+ def associated
278
+ AssociatedDecorator.decorate(object, context: {
279
+ parent_decorator: self,
280
+ parent_association: :associated
281
+ })
282
+ end
283
+
284
+ end
285
+
286
+ end
287
+
288
+ it "returns false" do
289
+ decorated_class = parent_decorator_class.decorate(object_class.new('foo', 'bar'))
290
+
291
+ context = decorated_class.send(:associated).context
292
+ expect(decorator_class.parent_eager_loads_include_own?(context)).to eql(false)
293
+ end
294
+ end
295
+
296
+ context "and the parent manually loads the eager association" do
297
+ let(:parent_decorator_class) do
298
+ Class.new(Tint::Decorator) do
299
+ attributes :associated
300
+
301
+ eager_load :associated
302
+
303
+ def associated
304
+ AssociatedDecorator.decorate(object, context: {
305
+ parent_decorator: self,
306
+ parent_association: :associated
307
+ })
308
+ end
309
+
310
+ end
311
+
312
+ end
313
+
314
+ it "returns true" do
315
+ decorated_class = parent_decorator_class.decorate(object_class.new('foo', 'bar'))
316
+
317
+ context = decorated_class.send(:associated).context
318
+ expect(decorator_class.parent_eager_loads_include_own?(context)).to eql(true)
319
+ end
320
+ end
321
+ end
322
+
323
+ after(:each) do
324
+ Object.send(:remove_const, 'AssociatedDecorator')
325
+ end
326
+ end
327
+
328
+
212
329
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleck Greenham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-12 00:00:00.000000000 Z
11
+ date: 2016-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: draper
@@ -98,6 +98,7 @@ files:
98
98
  - lib/tint/decorator.rb
99
99
  - lib/tint/json_conversion.rb
100
100
  - lib/tint/version.rb
101
+ - spec/spec_helper.rb
101
102
  - spec/support/active_record_mock.rb
102
103
  - spec/tint/decorator_spec.rb
103
104
  - tint.gemspec
@@ -126,5 +127,6 @@ signing_key:
126
127
  specification_version: 4
127
128
  summary: Declarative object decorators for JSON APIs
128
129
  test_files:
130
+ - spec/spec_helper.rb
129
131
  - spec/support/active_record_mock.rb
130
132
  - spec/tint/decorator_spec.rb