glue_gun_dsl 0.1.13 → 0.1.15

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: a744558606a85cbfc6641c33ba4aae92925712e9ee8b30555aad1309773def0e
4
- data.tar.gz: 49d3742eccba3ed436ee950b74c8aa5627d5a36ac1cca8fafe625904f9cd567d
3
+ metadata.gz: a573097a1db8e4af5573a1b0374e43dc12dcadc22f4e4a950bd6d5fe4a9084a1
4
+ data.tar.gz: 1db836fbee10ab0594495e5f137f0337ec62a8b90eeabc29bc55be0dab6ade9b
5
5
  SHA512:
6
- metadata.gz: 3fd64a4f71a0fd2fee778ce93609bbda6bbf38aff76feeeb9c8bd8d427c75def7c83471ac091cf40dbcc6f7ca16070ed2a89cf1d19e3e1d3eb48c2196d213edf
7
- data.tar.gz: 46e927fdfe42d553b6ee39e069cfea564fa2d10afd6548618d5bfd1b35db964024d0156a84986f126f85929b78a89de31c3994f61b43780906a3b3cf0b0c2194
6
+ metadata.gz: ad634073ed8206277b1eb502b2da7eff90e92cc820adcabc1dc647dee8e2f0c7cdf4ea7c2cc9fdd4b8a3b5f46caff7a6d4c55f82d3780a180b719af5729d4a51
7
+ data.tar.gz: 3048844dcbae257696ab142798ead0957b97bda029c151da4d9e5181b90d3da43099ecd6ec79784efb2499b0fd699a0dca2e24513e1fc20c461dae3648a4390d
data/lib/glue_gun/dsl.rb CHANGED
@@ -28,7 +28,7 @@ module GlueGun
28
28
  prepend ClassMethods
29
29
  end
30
30
 
31
- # Overriding ActiveModel.assign_attributes to ensure change propagation to dependenices
31
+ # Overriding ActiveModel.assign_attributes to ensure change propagation to dependencies
32
32
  def assign_attributes(new_attributes)
33
33
  super(new_attributes)
34
34
  propagate_changes if initialized?
@@ -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)
@@ -79,6 +82,7 @@ module GlueGun
79
82
  elsif ActiveModel.version >= Gem::Version.new("5")
80
83
  ActiveModel::Type::Value.new
81
84
  end
85
+
82
86
  # Override the attribute method to define custom setters
83
87
  def attribute(name, type = DEFAULT_TYPE, **options)
84
88
  super(name, type, **options)
@@ -97,10 +101,20 @@ module GlueGun
97
101
  end
98
102
  end
99
103
 
100
- def dependency(component_type, &block)
101
- dependency_builder = DependencyBuilder.new(component_type)
102
- dependency_builder.instance_eval(&block)
103
- dependency_definitions[component_type] = dependency_builder
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
+
111
+ if factory_class.present?
112
+ dependency_definitions[component_type] = { factory_class: factory_class, array: is_array }
113
+ else
114
+ dependency_builder = DependencyBuilder.new(component_type)
115
+ dependency_builder.instance_eval(&block)
116
+ dependency_definitions[component_type] = { builder: dependency_builder, array: is_array }
117
+ end
104
118
 
105
119
  # Define singleton method to allow hardcoding dependencies in subclasses
106
120
  define_singleton_method component_type do |option = nil, options = {}|
@@ -157,16 +171,57 @@ module GlueGun
157
171
  end
158
172
 
159
173
  def initialize_dependencies(attributes)
160
- self.class.dependency_definitions.each do |component_type, _|
174
+ self.class.dependency_definitions.each do |component_type, definition|
161
175
  value = attributes[component_type] || self.class.hardcoded_dependencies[component_type]
162
- instance_variable_set("@#{component_type}", initialize_dependency(component_type, value))
176
+ instance_variable_set("@#{component_type}", initialize_dependency(component_type, value, definition))
163
177
  end
164
178
  end
165
179
 
166
- def initialize_dependency(component_type, init_args = {})
167
- return init_args if dependency_injected?(component_type, init_args)
180
+ def initialize_dependency(component_type, init_args = {}, definition = nil)
181
+ definition ||= self.class.dependency_definitions[component_type]
182
+ is_array = definition[:array]
183
+
184
+ if is_array
185
+ dep = []
186
+ config = []
187
+ Array(init_args).each do |args|
188
+ d, c = initialize_single_dependency(component_type, args, definition)
189
+ dep.push(d)
190
+ config.push(c)
191
+ end
192
+ else
193
+ dep, config = initialize_single_dependency(component_type, init_args, definition)
194
+ end
195
+
196
+ dependencies[component_type] = {
197
+ instance: dep,
198
+ option: config
199
+ }
200
+
201
+ dep
202
+ end
203
+
204
+ def initialize_factory_dependency(component_type, init_args, definition)
205
+ factory_instance = definition[:factory_class].new
168
206
 
169
- dependency_builder = self.class.dependency_definitions[component_type]
207
+ # Pass the parent instance to the factory
208
+ factory_instance.instance_variable_set(:@parent, self)
209
+
210
+ dep_defs = factory_instance.dependency_definitions
211
+ definition = dep_defs[dep_defs.keys.first]
212
+
213
+ if dep_defs.key?(component_type)
214
+ factory_instance.send(:initialize_single_dependency, component_type, init_args, definition)
215
+ elsif dep_defs.keys.one?
216
+ factory_instance.send(:initialize_single_dependency, dep_defs.keys.first, init_args, definition)
217
+ else
218
+ raise ArgumentError,
219
+ "Don't know how to use Factory #{factory_instance.class} to build dependency '#{component_type}'"
220
+ end
221
+ end
222
+
223
+ def initialize_builder_dependency(component_type, init_args, definition)
224
+ dependency_builder = definition[:builder]
170
225
 
171
226
  if init_args && init_args.is_a?(Hash) && init_args.key?(:option_name)
172
227
  option_name = init_args[:option_name]
@@ -179,30 +234,24 @@ module GlueGun
179
234
 
180
235
  raise ArgumentError, "Unknown #{component_type} option '#{option_name}'" unless option_config
181
236
 
182
- dep_attributes = init_args.is_a?(Hash) ? init_args : {}
183
-
184
- # Build dependency attributes, including sourcing from parent
185
- dep_attributes = build_dependency_attributes(option_config, dep_attributes)
237
+ [instantiate_dependency(option_config, init_args), option_config]
238
+ end
186
239
 
187
- if dep_attributes.key?(:id)
188
- raise ArgumentError,
189
- "cannot bind attribute 'id' between #{self.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
240
+ def initialize_single_dependency(component_type, init_args, definition)
241
+ if dependency_injected?(component_type, init_args)
242
+ dep = init_args
243
+ option_config = injected_dependency(component_type, init_args)
244
+ elsif definition[:factory_class]
245
+ dep, option_config = initialize_factory_dependency(component_type, init_args, definition)
246
+ else
247
+ dep, option_config = initialize_builder_dependency(component_type, init_args, definition)
190
248
  end
191
249
 
192
- dependency_instance = instantiate_dependency(option_config, dep_attributes)
193
-
194
- # Keep track of dependencies for attribute binding
195
- dependencies[component_type] = {
196
- instance: dependency_instance,
197
- option: option_config
198
- }
199
-
200
- dependency_instance
250
+ [dep, option_config]
201
251
  end
202
252
 
203
253
  def build_dependency_attributes(option_config, dep_attributes)
204
254
  option_config.attributes.each do |attr_name, attr_config|
205
- # If the attribute is already provided, use it
206
255
  if dep_attributes.key?(attr_name)
207
256
  value = dep_attributes[attr_name]
208
257
  else
@@ -210,6 +259,8 @@ module GlueGun
210
259
  send(attr_config.source)
211
260
  elsif respond_to?(attr_name)
212
261
  send(attr_name)
262
+ elsif instance_variable_defined?(:@parent) && @parent.respond_to?(attr_name)
263
+ @parent.send(attr_name)
213
264
  else
214
265
  attr_config.default
215
266
  end
@@ -222,7 +273,7 @@ module GlueGun
222
273
  end
223
274
 
224
275
  def determine_option_name(component_type, init_args)
225
- dependency_builder = self.class.dependency_definitions[component_type]
276
+ dependency_builder = self.class.dependency_definitions[component_type][:builder]
226
277
 
227
278
  option_name = nil
228
279
 
@@ -256,11 +307,18 @@ module GlueGun
256
307
  [option_name, init_args]
257
308
  end
258
309
 
259
- def instantiate_dependency(option_config, dep_attributes)
310
+ def instantiate_dependency(option_config, init_args)
311
+ dep_attributes = init_args.is_a?(Hash) ? init_args : {}
312
+
313
+ # Build dependency attributes, including sourcing from parent
314
+ dep_attributes = build_dependency_attributes(option_config, dep_attributes)
315
+
316
+ if dep_attributes.key?(:id)
317
+ raise ArgumentError,
318
+ "cannot bind attribute 'id' between #{self.class.name} and #{option_config.class_name}. ID is reserved for primary keys in Ruby on Rails"
319
+ end
260
320
  dependency_class = option_config.class_name
261
- dependency_instance = dependency_class.new(dep_attributes)
262
- dependency_instance.validate! if false # dependency_instance.respond_to?(:validate!)
263
- dependency_instance
321
+ dependency_class.new(dep_attributes)
264
322
  end
265
323
 
266
324
  def propagate_changes
@@ -274,33 +332,58 @@ module GlueGun
274
332
  end
275
333
 
276
334
  def propagate_attribute_change(attr_name, value)
277
- self.class.dependency_definitions.each do |component_type, _dependency_builder|
335
+ self.class.dependency_definitions.each do |component_type, _builder|
278
336
  dependency_instance = send(component_type)
279
- option_config = dependencies.dig(component_type, :option)
280
- next unless option_config
281
337
 
282
- bound_attrs = option_config.attributes.select do |_, attr_config|
283
- (attr_config.source == attr_name.to_sym) || (attr_config.name == attr_name.to_sym)
284
- end
338
+ if dependency_instance.is_a?(Array)
339
+ option_config = dependencies.dig(component_type, :option)
285
340
 
286
- bound_attrs.each do |dep_attr_name, config_attr|
287
- block = config_attr.block.present? ? config_attr.block : proc { |att| att }
288
- if dependency_instance.respond_to?("#{dep_attr_name}=")
289
- dependency_instance.send("#{dep_attr_name}=",
290
- block.call(value))
341
+ dependency_instance.zip(option_config).each do |dep, opt|
342
+ propagate_attribute_to_instance(attr_name, value, dep, opt)
291
343
  end
344
+ else
345
+ option_config = dependencies.dig(component_type, :option)
346
+ next unless option_config
347
+
348
+ propagate_attribute_to_instance(attr_name, value, dependency_instance, option_config)
292
349
  end
293
350
  end
294
351
  end
295
352
 
296
- def dependency_injected?(component_type, value)
297
- dependency_builder = self.class.dependency_definitions[component_type]
298
- dependency_builder.option_configs.values.any? do |option|
353
+ def propagate_attribute_to_instance(attr_name, value, dependency_instance, option_config)
354
+ bound_attrs = option_config.attributes.select do |_, attr_config|
355
+ (attr_config.source == attr_name.to_sym) || (attr_config.name == attr_name.to_sym)
356
+ end
357
+
358
+ bound_attrs.each do |dep_attr_name, config_attr|
359
+ block = config_attr.block.present? ? config_attr.block : proc { |att| att }
360
+ if dependency_instance.respond_to?("#{dep_attr_name}=")
361
+ dependency_instance.send("#{dep_attr_name}=",
362
+ block.call(value))
363
+ end
364
+ end
365
+ end
366
+
367
+ def injected_dependency(component_type, value)
368
+ definition = self.class.dependency_definitions[component_type]
369
+ builder = definition[:builder]
370
+ factory = definition[:factory_class]
371
+
372
+ option_configs = if builder
373
+ builder.option_configs
374
+ else
375
+ factory.dependency_definitions.values.first.values.first.option_configs
376
+ end
377
+ option_configs.values.select do |option|
299
378
  option_class = option.class_name
300
379
  value.is_a?(option_class)
301
380
  end
302
381
  end
303
382
 
383
+ def dependency_injected?(component_type, value)
384
+ injected_dependency(component_type, value).any?
385
+ end
386
+
304
387
  def dependencies
305
388
  @dependencies ||= {}
306
389
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GlueGun
4
- VERSION = "0.1.13"
4
+ VERSION = "0.1.15"
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.13
4
+ version: 0.1.15
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-08 00:00:00.000000000 Z
11
+ date: 2024-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel