glue_gun_dsl 0.1.14 → 0.1.16

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
  SHA256:
3
- metadata.gz: 204effd0afcc5b7a8b1ac6f80ec1ddde4f99039817b0fe84e1a6747c76c13e27
4
- data.tar.gz: 227f7029e97ef1639ffbbebf5b0d8273ff0c7a084b5950aa8040c9f91e3be26c
3
+ metadata.gz: cc6aaef2a48bc81e0383a4b88f0afc691a3f99097e12877579c7d579953cfea7
4
+ data.tar.gz: ceb228b7381a0fbc7e2b3c07fe650cc05d89524dcec7199490fafb8813117bcc
5
5
  SHA512:
6
- metadata.gz: 3ee786e7b526c47e62de741a0fd0eb686e890d8e176e4424157d7bd4488f81e0750b7efb2d1d27ee0092e415d92b342ae7d4f6575e1c82ce932aaebcaf56cc26
7
- data.tar.gz: 67434b47dc06d5b258d5a1f1286859879c414b4131d17e66a8651378586312ff0b157825e45e2a939625b3a355a0dcbcff7691f0220d5f61cf6fbe8ba2933746
6
+ metadata.gz: 7624649374c85a5822bb6a74096e50c69947db98bd1097ec020e3e82edde37c35a9057905534271da63385ef1c37d43b479712d0442247837151c0ab23ef9cbc
7
+ data.tar.gz: 1f18555d5938dc3fb16bed600e3216502601e0b97c8a7c0998b22dd636cea40263f5ec7225767232e873778690c5ca0d752786c4e5017b371c35b17d191277aa
data/lib/glue_gun/dsl.rb CHANGED
@@ -61,7 +61,10 @@ module GlueGun
61
61
  end
62
62
  end
63
63
 
64
- normal_attributes.reverse_merge!(root_dir: detect_root_dir) if attribute_definitions.keys.include?(:root_dir)
64
+ if attribute_definitions.keys.include?(:root_dir) && attribute_definitions.dig(:root_dir, :options,
65
+ :default).nil?
66
+ normal_attributes.reverse_merge!(root_dir: detect_root_dir)
67
+ end
65
68
 
66
69
  # Call super to allow ActiveModel to assign attributes
67
70
  super(normal_attributes)
@@ -98,13 +101,20 @@ module GlueGun
98
101
  end
99
102
  end
100
103
 
101
- def dependency(component_type, factory_class = nil, &block)
102
- if factory_class
103
- dependency_definitions[component_type] = factory_class
104
+ def dependency(component_type, options = {}, factory_class = nil, &block)
105
+ if options.is_a?(Class)
106
+ factory_class = options
107
+ options = {}
108
+ end
109
+ is_array = options[:array] || false
110
+ is_hash = options[:hash] || false
111
+
112
+ if factory_class.present?
113
+ dependency_definitions[component_type] = { factory_class: factory_class, array: is_array, hash: is_hash }
104
114
  else
105
115
  dependency_builder = DependencyBuilder.new(component_type)
106
116
  dependency_builder.instance_eval(&block)
107
- dependency_definitions[component_type] = dependency_builder
117
+ dependency_definitions[component_type] = { builder: dependency_builder, array: is_array, hash: is_hash }
108
118
  end
109
119
 
110
120
  # Define singleton method to allow hardcoding dependencies in subclasses
@@ -170,16 +180,58 @@ module GlueGun
170
180
 
171
181
  def initialize_dependency(component_type, init_args = {}, definition = nil)
172
182
  definition ||= self.class.dependency_definitions[component_type]
173
-
174
- if definition.is_a?(Class) && definition.include?(GlueGun::DSL)
175
- # If the definition is a factory class, use it to create the dependency
176
- factory_instance = definition.new
177
- return factory_instance.send(:initialize_dependency, component_type, init_args)
183
+ is_array = definition[:array]
184
+ is_hash = definition[:hash]
185
+
186
+ if is_array
187
+ dep = []
188
+ config = []
189
+ Array(init_args).each do |args|
190
+ d, c = initialize_single_dependency(component_type, args, definition)
191
+ dep.push(d)
192
+ config.push(c)
193
+ end
194
+ elsif is_hash
195
+ dep = {}
196
+ config = {}
197
+ init_args.each do |key, args|
198
+ d, c = initialize_single_dependency(component_type, args, definition)
199
+ dep[key] = d
200
+ config[key] = c
201
+ end
202
+ else
203
+ dep, config = initialize_single_dependency(component_type, init_args, definition)
178
204
  end
179
205
 
180
- return init_args if dependency_injected?(component_type, init_args)
206
+ dependencies[component_type] = {
207
+ instance: dep,
208
+ option: config
209
+ }
210
+
211
+ dep
212
+ end
213
+
214
+ def initialize_factory_dependency(component_type, init_args, definition)
215
+ factory_instance = definition[:factory_class].new
216
+
217
+ # Pass the parent instance to the factory
218
+ factory_instance.instance_variable_set(:@parent, self)
219
+
220
+ dep_defs = factory_instance.dependency_definitions
221
+ definition = dep_defs[dep_defs.keys.first]
181
222
 
182
- dependency_builder = definition
223
+ if dep_defs.key?(component_type)
224
+ factory_instance.send(:initialize_single_dependency, component_type, init_args, definition)
225
+ elsif dep_defs.keys.one?
226
+ factory_instance.send(:initialize_single_dependency, dep_defs.keys.first, init_args, definition)
227
+ else
228
+ raise ArgumentError,
229
+ "Don't know how to use Factory #{factory_instance.class} to build dependency '#{component_type}'"
230
+ end
231
+ end
232
+
233
+ def initialize_builder_dependency(component_type, init_args, definition)
234
+ dependency_builder = definition[:builder]
183
235
 
184
236
  if init_args && init_args.is_a?(Hash) && init_args.key?(:option_name)
185
237
  option_name = init_args[:option_name]
@@ -192,30 +244,24 @@ module GlueGun
192
244
 
193
245
  raise ArgumentError, "Unknown #{component_type} option '#{option_name}'" unless option_config
194
246
 
195
- dep_attributes = init_args.is_a?(Hash) ? init_args : {}
196
-
197
- # Build dependency attributes, including sourcing from parent
198
- dep_attributes = build_dependency_attributes(option_config, dep_attributes)
247
+ [instantiate_dependency(option_config, init_args), option_config]
248
+ end
199
249
 
200
- if dep_attributes.key?(:id)
201
- raise ArgumentError,
202
- "cannot bind attribute 'id' between #{self.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
250
+ def initialize_single_dependency(component_type, init_args, definition)
251
+ if dependency_injected?(component_type, init_args)
252
+ dep = init_args
253
+ option_config = injected_dependency(component_type, init_args)
254
+ elsif definition[:factory_class]
255
+ dep, option_config = initialize_factory_dependency(component_type, init_args, definition)
256
+ else
257
+ dep, option_config = initialize_builder_dependency(component_type, init_args, definition)
203
258
  end
204
259
 
205
- dependency_instance = instantiate_dependency(option_config, dep_attributes)
206
-
207
- # Keep track of dependencies for attribute binding
208
- dependencies[component_type] = {
209
- instance: dependency_instance,
210
- option: option_config
211
- }
212
-
213
- dependency_instance
260
+ [dep, option_config]
214
261
  end
215
262
 
216
263
  def build_dependency_attributes(option_config, dep_attributes)
217
264
  option_config.attributes.each do |attr_name, attr_config|
218
- # If the attribute is already provided, use it
219
265
  if dep_attributes.key?(attr_name)
220
266
  value = dep_attributes[attr_name]
221
267
  else
@@ -223,6 +269,8 @@ module GlueGun
223
269
  send(attr_config.source)
224
270
  elsif respond_to?(attr_name)
225
271
  send(attr_name)
272
+ elsif instance_variable_defined?(:@parent) && @parent.respond_to?(attr_name)
273
+ @parent.send(attr_name)
226
274
  else
227
275
  attr_config.default
228
276
  end
@@ -235,7 +283,7 @@ module GlueGun
235
283
  end
236
284
 
237
285
  def determine_option_name(component_type, init_args)
238
- dependency_builder = self.class.dependency_definitions[component_type]
286
+ dependency_builder = self.class.dependency_definitions[component_type][:builder]
239
287
 
240
288
  option_name = nil
241
289
 
@@ -269,11 +317,18 @@ module GlueGun
269
317
  [option_name, init_args]
270
318
  end
271
319
 
272
- def instantiate_dependency(option_config, dep_attributes)
320
+ def instantiate_dependency(option_config, init_args)
321
+ dep_attributes = init_args.is_a?(Hash) ? init_args : {}
322
+
323
+ # Build dependency attributes, including sourcing from parent
324
+ dep_attributes = build_dependency_attributes(option_config, dep_attributes)
325
+
326
+ if dep_attributes.key?(:id)
327
+ raise ArgumentError,
328
+ "cannot bind attribute 'id' between #{self.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
329
+ end
273
330
  dependency_class = option_config.class_name
274
- dependency_instance = dependency_class.new(dep_attributes)
275
- dependency_instance.validate! if false # dependency_instance.respond_to?(:validate!)
276
- dependency_instance
331
+ dependency_class.new(dep_attributes)
277
332
  end
278
333
 
279
334
  def propagate_changes
@@ -287,33 +342,64 @@ module GlueGun
287
342
  end
288
343
 
289
344
  def propagate_attribute_change(attr_name, value)
290
- self.class.dependency_definitions.each do |component_type, _dependency_builder|
345
+ self.class.dependency_definitions.each do |component_type, _builder|
291
346
  dependency_instance = send(component_type)
292
- option_config = dependencies.dig(component_type, :option)
293
- next unless option_config
294
347
 
295
- bound_attrs = option_config.attributes.select do |_, attr_config|
296
- (attr_config.source == attr_name.to_sym) || (attr_config.name == attr_name.to_sym)
297
- end
348
+ if dependency_instance.is_a?(Array)
349
+ option_config = dependencies.dig(component_type, :option)
298
350
 
299
- bound_attrs.each do |dep_attr_name, config_attr|
300
- block = config_attr.block.present? ? config_attr.block : proc { |att| att }
301
- if dependency_instance.respond_to?("#{dep_attr_name}=")
302
- dependency_instance.send("#{dep_attr_name}=",
303
- block.call(value))
351
+ dependency_instance.zip(option_config).each do |dep, opt|
352
+ propagate_attribute_to_instance(attr_name, value, dep, opt)
304
353
  end
354
+ elsif dependency_instance.is_a?(Hash)
355
+ option_config = dependencies.dig(component_type, :option)
356
+
357
+ dependency_instance.each do |key, dep|
358
+ propagate_attribute_to_instance(attr_name, value, dep, option_config[key])
359
+ end
360
+ else
361
+ option_config = dependencies.dig(component_type, :option)
362
+ next unless option_config
363
+
364
+ propagate_attribute_to_instance(attr_name, value, dependency_instance, option_config)
305
365
  end
306
366
  end
307
367
  end
308
368
 
309
- def dependency_injected?(component_type, value)
310
- dependency_builder = self.class.dependency_definitions[component_type]
311
- dependency_builder.option_configs.values.any? do |option|
369
+ def propagate_attribute_to_instance(attr_name, value, dependency_instance, option_config)
370
+ bound_attrs = option_config.attributes.select do |_, attr_config|
371
+ (attr_config.source == attr_name.to_sym) || (attr_config.name == attr_name.to_sym)
372
+ end
373
+
374
+ bound_attrs.each do |dep_attr_name, config_attr|
375
+ block = config_attr.block.present? ? config_attr.block : proc { |att| att }
376
+ if dependency_instance.respond_to?("#{dep_attr_name}=")
377
+ dependency_instance.send("#{dep_attr_name}=",
378
+ block.call(value))
379
+ end
380
+ end
381
+ end
382
+
383
+ def injected_dependency(component_type, value)
384
+ definition = self.class.dependency_definitions[component_type]
385
+ builder = definition[:builder]
386
+ factory = definition[:factory_class]
387
+
388
+ option_configs = if builder
389
+ builder.option_configs
390
+ else
391
+ factory.dependency_definitions.values.first.values.first.option_configs
392
+ end
393
+ option_configs.values.select do |option|
312
394
  option_class = option.class_name
313
395
  value.is_a?(option_class)
314
396
  end
315
397
  end
316
398
 
399
+ def dependency_injected?(component_type, value)
400
+ injected_dependency(component_type, value).any?
401
+ end
402
+
317
403
  def dependencies
318
404
  @dependencies ||= {}
319
405
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GlueGun
4
- VERSION = "0.1.14"
4
+ VERSION = "0.1.16"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glue_gun_dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Shollenberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-11 00:00:00.000000000 Z
11
+ date: 2024-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel