tint 0.0.3 → 0.0.4

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 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