glue_gun_dsl 0.1.17 → 0.1.18
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/lib/glue_gun/dsl.rb +192 -192
- data/lib/glue_gun/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cf96906f1af3fd62ba4c0e7aa061d9d109aee45ced7284e7776cb74d7dca313
|
4
|
+
data.tar.gz: 47f2454a802ce7a9bd335e7413fd2851551eae2437d4de9bebb0f1f31ad82b53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
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
|
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(
|
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
|
198
|
+
definition.validate_hash_dependencies(init_args)
|
237
199
|
|
238
200
|
init_args.each do |key, args|
|
239
|
-
d, c = initialize_single_dependency(
|
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(
|
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
|
-
|
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)
|
data/lib/glue_gun/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2024-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|