glue_gun_dsl 0.1.17 → 0.1.18

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: '0962a5666114730f40d7b78a9e70e2762480f318cf4790641c47e8406d6af3aa'
4
- data.tar.gz: 161576a11d2ff360e5c4fc34327c9db3ecf3201fe9f81fd864e84c34ce223c12
3
+ metadata.gz: 1cf96906f1af3fd62ba4c0e7aa061d9d109aee45ced7284e7776cb74d7dca313
4
+ data.tar.gz: 47f2454a802ce7a9bd335e7413fd2851551eae2437d4de9bebb0f1f31ad82b53
5
5
  SHA512:
6
- metadata.gz: 3231f0758ae02faea304068b16bd9da17b6910a2f2f3ccd3ddec5c08ee6c9af651b36fc376e9e9a80d330d24448c4d18389cab87a76ade9fbd5db52eeaabb1d6
7
- data.tar.gz: 1f5f68fd1879dc28a708214a794d0d2f39410b912e0659d63a67c2244dffb82b89dea4084bfa4db028c0e0aef46a501a4b017a000c64c7fc8027798a669c303e
6
+ metadata.gz: 8f4be572fe72494ab001d7ea71ec0f35064d1914a7982ab026ffd12f40126dd01051c1594e9baf78ae3a6415b3bfb44d7524f512986af53dcaa0db3ab5924ba3
7
+ data.tar.gz: fcf9a586af6236a3595b6a215daca49239a5e7407ab4086626dbcc105f755a76a82ae45de536047a7a8464be0035a89b81e8c4ca5bb11dd1c7aca31eae049b97
data/lib/glue_gun/dsl.rb CHANGED
@@ -107,13 +107,14 @@ module GlueGun
107
107
  options = {}
108
108
  end
109
109
 
110
+ dependency_builder = DependencyBuilder.new(component_type)
111
+
110
112
  if factory_class.present?
111
- dependency_definitions[component_type] = { factory_class: factory_class }
113
+ dependency_builder.set_factory_class(factory_class)
112
114
  else
113
- dependency_builder = DependencyBuilder.new(component_type)
114
115
  dependency_builder.instance_eval(&block)
115
- dependency_definitions[component_type] = { builder: dependency_builder }
116
116
  end
117
+ dependency_definitions[component_type] = dependency_builder
117
118
 
118
119
  # Define singleton method to allow hardcoding dependencies in subclasses
119
120
  define_singleton_method component_type do |option = nil, options = {}|
@@ -176,72 +177,33 @@ module GlueGun
176
177
  end
177
178
  end
178
179
 
179
- def allowed_configurations(init_args, definition)
180
- if definition[:factory_class]
181
- factory_instance = definition[:factory_class].new
182
- dep_defs = factory_instance.dependency_definitions
183
- definition = dep_defs[dep_defs.keys.first]
184
- return allowed_configurations(init_args, definition)
185
- elsif definition[:builder]
186
- builder = definition[:builder]
187
- allowed_configs = builder.option_configs.keys
188
- end
189
-
190
- allowed_configs
191
- end
192
-
193
- def is_hash?(init_args, definition)
194
- return false unless init_args.is_a?(Hash)
195
-
196
- allowed_configs = allowed_configurations(init_args, definition)
197
- return false if allowed_configs.count == 1 && allowed_configs == [:default]
198
-
199
- if init_args.key?(:option_name)
200
- allowed_configs.exclude?(init_args[:option_name])
201
- else
202
- init_args.keys.none? { |k| allowed_configs.include?(k) }
203
- end
204
- end
205
-
206
- def validate_hash_dependencies(init_args, definition, component_type)
207
- allowed_configs = allowed_configurations(init_args, definition)
208
-
209
- init_args.each do |_named_key, configuration|
210
- next unless configuration.is_a?(Hash)
211
-
212
- key = configuration.keys.first
213
- if key.nil? || allowed_configs.exclude?(key)
214
- raise ArgumentError,
215
- "Unknown #{component_type} option: #{init_args.keys.first}."
216
- end
217
- end
218
- end
219
-
220
- def initialize_dependency(component_type, init_args = {}, definition = nil)
180
+ def initialize_dependency(component_type, init_args = nil, definition = nil)
221
181
  definition ||= self.class.dependency_definitions[component_type]
222
182
  is_array = init_args.is_a?(Array)
223
- is_hash = is_hash?(init_args, definition)
183
+ is_hash = definition.is_hash?(init_args)
184
+
185
+ return nil if init_args.nil? && definition.default_option_name.nil?
224
186
 
225
187
  if is_array
226
188
  dep = []
227
189
  config = []
228
190
  Array(init_args).each do |args|
229
- d, c = initialize_single_dependency(component_type, args, definition)
191
+ d, c = definition.initialize_single_dependency(args, self)
230
192
  dep.push(d)
231
193
  config.push(c)
232
194
  end
233
195
  elsif is_hash
234
196
  dep = {}
235
197
  config = {}
236
- validate_hash_dependencies(init_args, definition, component_type)
198
+ definition.validate_hash_dependencies(init_args)
237
199
 
238
200
  init_args.each do |key, args|
239
- d, c = initialize_single_dependency(component_type, args, definition)
201
+ d, c = definition.initialize_single_dependency(args, self)
240
202
  dep[key] = d
241
203
  config[key] = c
242
204
  end
243
205
  else
244
- dep, config = initialize_single_dependency(component_type, init_args, definition)
206
+ dep, config = definition.initialize_single_dependency(init_args, self)
245
207
  end
246
208
 
247
209
  dependencies[component_type] = {
@@ -252,126 +214,6 @@ module GlueGun
252
214
  dep
253
215
  end
254
216
 
255
- def initialize_factory_dependency(component_type, init_args, definition)
256
- factory_instance = definition[:factory_class].new
257
-
258
- # Pass the parent instance to the factory
259
- factory_instance.instance_variable_set(:@parent, self)
260
-
261
- dep_defs = factory_instance.dependency_definitions
262
- definition = dep_defs[dep_defs.keys.first]
263
-
264
- if dep_defs.key?(component_type)
265
- factory_instance.send(:initialize_single_dependency, component_type, init_args, definition)
266
- elsif dep_defs.keys.one?
267
- factory_instance.send(:initialize_single_dependency, dep_defs.keys.first, init_args, definition)
268
- else
269
- raise ArgumentError,
270
- "Don't know how to use Factory #{factory_instance.class} to build dependency '#{component_type}'"
271
- end
272
- end
273
-
274
- def initialize_builder_dependency(component_type, init_args, definition)
275
- dependency_builder = definition[:builder]
276
-
277
- if init_args && init_args.is_a?(Hash) && init_args.key?(:option_name)
278
- option_name = init_args[:option_name]
279
- init_args = init_args[:value]
280
- else
281
- option_name, init_args = determine_option_name(component_type, init_args)
282
- end
283
-
284
- option_config = dependency_builder.option_configs[option_name]
285
-
286
- raise ArgumentError, "Unknown #{component_type} option '#{option_name}'" unless option_config
287
-
288
- [instantiate_dependency(option_config, init_args), option_config]
289
- end
290
-
291
- def initialize_single_dependency(component_type, init_args, definition)
292
- if dependency_injected?(component_type, init_args)
293
- dep = init_args
294
- option_config = injected_dependency(component_type, init_args)
295
- elsif definition[:factory_class]
296
- dep, option_config = initialize_factory_dependency(component_type, init_args, definition)
297
- else
298
- dep, option_config = initialize_builder_dependency(component_type, init_args, definition)
299
- end
300
-
301
- [dep, option_config]
302
- end
303
-
304
- def build_dependency_attributes(option_config, dep_attributes)
305
- option_config.attributes.each do |attr_name, attr_config|
306
- if dep_attributes.key?(attr_name)
307
- value = dep_attributes[attr_name]
308
- else
309
- value = if attr_config.source && respond_to?(attr_config.source)
310
- send(attr_config.source)
311
- elsif respond_to?(attr_name)
312
- send(attr_name)
313
- elsif instance_variable_defined?(:@parent) && @parent.respond_to?(attr_name)
314
- @parent.send(attr_name)
315
- else
316
- attr_config.default
317
- end
318
- value = attr_config.process_value(value, self) if attr_config.respond_to?(:process_value)
319
- dep_attributes[attr_name] = value
320
- end
321
- end
322
-
323
- dep_attributes
324
- end
325
-
326
- def determine_option_name(component_type, init_args)
327
- dependency_builder = self.class.dependency_definitions[component_type][:builder]
328
-
329
- option_name = nil
330
-
331
- # Use when block if defined
332
- if dependency_builder.when_block
333
- result = instance_exec(init_args, &dependency_builder.when_block)
334
- if result.is_a?(Hash) && result[:option]
335
- option_name = result[:option]
336
- as_attr = result[:as]
337
- init_args = { as_attr => init_args } if as_attr && init_args
338
- end
339
- end
340
-
341
- # Detect option from user input
342
- if option_name.nil? && (init_args.is_a?(Hash) && init_args.keys.size == 1)
343
- if dependency_builder.option_configs.key?(init_args.keys.first)
344
- option_name = init_args.keys.first
345
- init_args = init_args[option_name] # Extract the inner value
346
- else
347
- default_option = dependency_builder.get_option(dependency_builder.default_option_name)
348
- raise ArgumentError, "Unknown #{component_type} option: #{init_args.keys.first}." unless default_option.only?
349
- unless default_option.attributes.keys.include?(init_args.keys.first)
350
- raise ArgumentError, "#{default_option.class_name} does not respond to #{init_args.keys.first}"
351
- end
352
- end
353
- end
354
-
355
- # Use default option if none determined
356
- option_name ||= dependency_builder.default_option_name
357
-
358
- [option_name, init_args]
359
- end
360
-
361
- def instantiate_dependency(option_config, init_args)
362
- dep_attributes = init_args.is_a?(Hash) ? init_args : {}
363
-
364
- # Build dependency attributes, including sourcing from parent
365
- dep_attributes = build_dependency_attributes(option_config, dep_attributes)
366
-
367
- if dep_attributes.key?(:id)
368
- raise ArgumentError,
369
- "cannot bind attribute 'id' between #{self.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
370
- end
371
- dependency_class = option_config.class_name
372
- dependency_class.new(dep_attributes)
373
- end
374
-
375
217
  def propagate_changes
376
218
  changed_attributes.each do |attr_name, _old_value|
377
219
  new_value = read_attribute(attr_name)
@@ -421,26 +263,6 @@ module GlueGun
421
263
  end
422
264
  end
423
265
 
424
- def injected_dependency(component_type, value)
425
- definition = self.class.dependency_definitions[component_type]
426
- builder = definition[:builder]
427
- factory = definition[:factory_class]
428
-
429
- option_configs = if builder
430
- builder.option_configs
431
- else
432
- factory.dependency_definitions.values.first.values.first.option_configs
433
- end
434
- option_configs.values.detect do |option|
435
- option_class = option.class_name
436
- value.is_a?(option_class)
437
- end
438
- end
439
-
440
- def dependency_injected?(component_type, value)
441
- injected_dependency(component_type, value).present?
442
- end
443
-
444
266
  def dependencies
445
267
  @dependencies ||= {}
446
268
  end
@@ -490,7 +312,7 @@ module GlueGun
490
312
  end
491
313
 
492
314
  class DependencyBuilder
493
- attr_reader :component_type, :option_configs, :when_block, :is_only
315
+ attr_reader :component_type, :option_configs, :when_block, :is_only, :factory_class
494
316
 
495
317
  def initialize(component_type)
496
318
  @component_type = component_type
@@ -500,6 +322,180 @@ module GlueGun
500
322
  @is_only = false
501
323
  end
502
324
 
325
+ def set_factory_class(factory_class)
326
+ @factory_class = factory_class
327
+ end
328
+
329
+ def builder
330
+ if factory?
331
+ factory_instance = factory_class.new
332
+ dep_defs = factory_instance.dependency_definitions
333
+ dep_defs[dep_defs.keys.first]
334
+ else
335
+ self
336
+ end
337
+ end
338
+
339
+ def get_option_configs
340
+ builder.option_configs
341
+ end
342
+
343
+ def allowed_configurations
344
+ get_option_configs.keys
345
+ end
346
+
347
+ def allowed_classes
348
+ get_option_configs.values
349
+ end
350
+
351
+ def factory?
352
+ @factory_class.present?
353
+ end
354
+
355
+ def builder?
356
+ !factory?
357
+ end
358
+
359
+ def is_hash?(init_args)
360
+ return false unless init_args.is_a?(Hash)
361
+
362
+ allowed_configs = allowed_configurations
363
+ return false if allowed_configs.count == 1 && allowed_configs == [:default]
364
+
365
+ if init_args.key?(:option_name)
366
+ allowed_configs.exclude?(init_args[:option_name])
367
+ else
368
+ init_args.keys.none? { |k| allowed_configs.include?(k) }
369
+ end
370
+ end
371
+
372
+ def initialize_factory_dependency(init_args, parent)
373
+ builder.initialize_single_dependency(init_args, parent)
374
+ end
375
+
376
+ def initialize_builder_dependency(init_args, parent)
377
+ if init_args && init_args.is_a?(Hash) && init_args.key?(:option_name)
378
+ option_name = init_args[:option_name]
379
+ init_args = init_args[:value]
380
+ else
381
+ option_name, init_args = determine_option_name(init_args)
382
+ end
383
+
384
+ option_config = option_configs[option_name]
385
+
386
+ raise ArgumentError, "Unknown #{component_type} option '#{option_name}'" unless option_config
387
+
388
+ [instantiate_dependency(option_config, init_args, parent), option_config]
389
+ end
390
+
391
+ def initialize_single_dependency(init_args, parent)
392
+ if dependency_injected?(init_args)
393
+ dep = init_args
394
+ option_config = injected_dependency(init_args)
395
+ elsif factory?
396
+ dep, option_config = initialize_factory_dependency(init_args, parent)
397
+ else
398
+ dep, option_config = initialize_builder_dependency(init_args, parent)
399
+ end
400
+
401
+ [dep, option_config]
402
+ end
403
+
404
+ def build_dependency_attributes(option_config, dep_attributes, parent)
405
+ option_config.attributes.each do |attr_name, attr_config|
406
+ if dep_attributes.key?(attr_name)
407
+ value = dep_attributes[attr_name]
408
+ else
409
+ value = if attr_config.source && parent.respond_to?(attr_config.source)
410
+ parent.send(attr_config.source)
411
+ elsif parent.respond_to?(attr_name)
412
+ parent.send(attr_name)
413
+ else
414
+ attr_config.default
415
+ end
416
+ value = attr_config.process_value(value, self) if attr_config.respond_to?(:process_value)
417
+ dep_attributes[attr_name] = value
418
+ end
419
+ end
420
+
421
+ dep_attributes
422
+ end
423
+
424
+ def determine_option_name(init_args)
425
+ option_name = nil
426
+
427
+ # Use when block if defined
428
+ if when_block
429
+ result = instance_exec(init_args, &when_block)
430
+ if result.is_a?(Hash) && result[:option]
431
+ option_name = result[:option]
432
+ as_attr = result[:as]
433
+ init_args = { as_attr => init_args } if as_attr && init_args
434
+ end
435
+ end
436
+
437
+ # Detect option from user input
438
+ if option_name.nil? && (init_args.is_a?(Hash) && init_args.keys.size == 1)
439
+ if option_configs.key?(init_args.keys.first)
440
+ option_name = init_args.keys.first
441
+ init_args = init_args[option_name] # Extract the inner value
442
+ else
443
+ default_option = get_option(default_option_name)
444
+ unless default_option.only?
445
+ raise ArgumentError,
446
+ "Unknown #{component_type} option: #{init_args.keys.first}."
447
+ end
448
+ unless default_option.attributes.keys.include?(init_args.keys.first)
449
+ raise ArgumentError, "#{default_option.class_name} does not respond to #{init_args.keys.first}"
450
+ end
451
+ end
452
+ end
453
+
454
+ # Use default option if none determined
455
+ option_name ||= default_option_name
456
+
457
+ [option_name, init_args]
458
+ end
459
+
460
+ def instantiate_dependency(option_config, init_args, parent)
461
+ dep_attributes = init_args.is_a?(Hash) ? init_args : {}
462
+
463
+ # Build dependency attributes, including sourcing from parent
464
+ dep_attributes = build_dependency_attributes(option_config, dep_attributes, parent)
465
+
466
+ if dep_attributes.key?(:id)
467
+ raise ArgumentError,
468
+ "cannot bind attribute 'id' between #{parent.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
469
+ end
470
+ dependency_class = option_config.class_name
471
+ dependency_class.new(dep_attributes)
472
+ end
473
+
474
+ def injected_dependency(value)
475
+ allowed_classes.detect do |option|
476
+ option_class = option.class_name
477
+ value.is_a?(option_class)
478
+ end
479
+ end
480
+
481
+ def dependency_injected?(value)
482
+ injected_dependency(value).present?
483
+ end
484
+
485
+ def validate_hash_dependencies(init_args)
486
+ allowed_configs = allowed_configurations
487
+
488
+ init_args.each do |_named_key, configuration|
489
+ next unless configuration.is_a?(Hash)
490
+
491
+ key = configuration.keys.first
492
+ if key.nil? || allowed_configs.exclude?(key)
493
+ raise ArgumentError,
494
+ "Unknown #{component_type} option: #{init_args.keys.first}."
495
+ end
496
+ end
497
+ end
498
+
503
499
  # Support set_class and attribute for single-option dependencies
504
500
  def set_class(class_name)
505
501
  single_option.set_class(class_name)
@@ -523,7 +519,11 @@ module GlueGun
523
519
  end
524
520
 
525
521
  def default_option_name
526
- @default_option_name || (@single_option ? :default : nil)
522
+ if factory?
523
+ builder.default_option_name
524
+ else
525
+ @default_option_name || (@single_option ? :default : nil)
526
+ end
527
527
  end
528
528
 
529
529
  def when(&block)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GlueGun
4
- VERSION = "0.1.17"
4
+ VERSION = "0.1.18"
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.17
4
+ version: 0.1.18
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-16 00:00:00.000000000 Z
11
+ date: 2024-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel