glue_gun_dsl 0.1.24 → 0.1.27

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
  SHA256:
3
- metadata.gz: e2fd5acfe5156d1581b51d68d5598ef181faea52ec3c46d730fef428f7faba15
4
- data.tar.gz: c6185af99fd906dd841582b283b4559d8f1fbc4e3046086d7cf4a15ac5e1b1d3
3
+ metadata.gz: 697e6798ae2b2c4c3db3f4e3cd9b2c65ccc8081386636c08366e4d023cb04afe
4
+ data.tar.gz: f7a025244f1b5627691676d784658d2a14a289914533e17f4c1daca896c6ebdf
5
5
  SHA512:
6
- metadata.gz: 587486d0afa4a7cde26ffc1a6d6a766123db4c09111b4f2e9d3b4f9f17651856a6a587b81832cb78fe93fa6d0f9f23cae88c145a61ac9905968508ffb6f8b7fc
7
- data.tar.gz: 14d80f872b13ada859d605068799e8331136c36db88e9dd5ba81eadd93b34b7362918e08eb3e1a48848e8b42ea4477f597d43cc1b3633205dfdc2d2e84d66b5d
6
+ metadata.gz: 8d32f478f2e294ae9510abb04b0ac5b5490c8468918879363f790eebc5167d7c3e28ec5edf9675301a2a211b7f5493bcf24c1884295598e9cf859f5b6b146f21
7
+ data.tar.gz: ee627464ed957cffac221bd2d701e9a9deba768e1cac558349878d101b67281a2c5977379f79496af43ed7bdbc392489c60e7d3fec2d09445b2e35526d2d256f
@@ -3,6 +3,40 @@ module GlueGun
3
3
  module Model
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ class ServiceRegistry
7
+ attr_accessor :services
8
+
9
+ def register(k, v)
10
+ @services ||= {}
11
+ @services[k.to_sym] = v
12
+ end
13
+
14
+ def options
15
+ services.keys
16
+ end
17
+
18
+ def []=(k, v)
19
+ register(k, v)
20
+ end
21
+
22
+ def [](k)
23
+ return nil if k.nil?
24
+
25
+ @services ||= {}
26
+ @services.dig(k.to_sym)
27
+ end
28
+
29
+ def default_key
30
+ return unless services.keys.count == 1
31
+
32
+ services.keys.first
33
+ end
34
+
35
+ def default
36
+ default_key.present? ? services[default_key] : nil
37
+ end
38
+ end
39
+
6
40
  included do
7
41
  include GlueGun::Shared
8
42
 
@@ -16,6 +50,13 @@ module GlueGun
16
50
  # Set default service attribute name based on the class name
17
51
  self.service_attribute_name = "#{name.demodulize.underscore}_service".to_sym
18
52
 
53
+ class_attribute :service_registry
54
+ self.service_registry = ServiceRegistry.new
55
+
56
+ # Set default option key based on the class name
57
+ class_attribute :option_key
58
+ self.option_key = "#{name.demodulize.underscore}_type".to_sym
59
+
19
60
  def assign_attributes(attributes)
20
61
  return if attributes.blank?
21
62
 
@@ -31,14 +72,8 @@ module GlueGun
31
72
  end
32
73
 
33
74
  class_methods do
34
- def service(class_or_proc = nil, &block)
35
- if class_or_proc.is_a?(Class)
36
- self.service_class = class_or_proc
37
- elsif block_given?
38
- self.service_class_resolver = block
39
- else
40
- raise ArgumentError, "You must provide a service class, factory, or a block to resolve the service class."
41
- end
75
+ def service(key, service_class)
76
+ service_registry[key] = service_class
42
77
  end
43
78
 
44
79
  def find_or_create_by!(attributes)
@@ -77,8 +112,10 @@ module GlueGun
77
112
  end
78
113
 
79
114
  def initialize(attributes = {})
80
- attributes[:root_dir] = detect_root_dir
115
+ attributes = {} if attributes.nil?
116
+ attributes[:root_dir] ||= detect_root_dir
81
117
  attributes = attributes.deep_symbolize_keys
118
+ attributes[option_key] ||= resolve_service_type(attributes, true)
82
119
  db_attributes = self.class.extract_db_attributes(attributes)
83
120
  super(db_attributes)
84
121
  build_service_object(attributes)
@@ -119,14 +156,26 @@ module GlueGun
119
156
  instance_variable_set("@#{service_attribute_name}", service_instance)
120
157
  end
121
158
 
159
+ def resolve_service_type(attributes, initializing = false)
160
+ attrs = if initializing || !persisted? || attributes.key?(self.class.option_key)
161
+ attributes
162
+ else
163
+ { self.class.option_key => send(self.class.option_key) }
164
+ end
165
+ attrs[self.class.option_key] || self.class.service_registry.default_key
166
+ end
167
+
122
168
  def resolve_service_class(attributes)
123
- if self.class.service_class
124
- self.class.service_class
125
- elsif self.class.service_class_resolver
126
- self.class.service_class_resolver.call(attributes)
127
- else
128
- raise "Service class not defined for #{self.class.name}"
169
+ type = resolve_service_type(attributes)
170
+ service_class = self.class.service_registry[type] || self.class.service_registry.default
171
+
172
+ unless service_class
173
+ available_types = self.class.service_registry.options
174
+ raise ArgumentError,
175
+ "#{self.class} requires argument #{self.class.option_key}. Invalid option key received: #{type}. Allowed options are: #{available_types}"
129
176
  end
177
+
178
+ service_class
130
179
  end
131
180
 
132
181
  def extract_service_attributes(attributes, service_class)
@@ -162,29 +211,45 @@ module GlueGun
162
211
  end.symbolize_keys
163
212
  end
164
213
 
214
+ def serialize_dependency(dependency, dep_instance = nil)
215
+ dep_instance = service_object.send(dependency) if dep_instance.nil?
216
+ return nil unless dep_instance.present?
217
+
218
+ return dep_instance.map { |dep| serialize_dependency(dependency, dep) } if dep_instance.is_a?(Array)
219
+
220
+ opts = service_object.dependency_definitions[dependency].option_configs
221
+ selected_option = opts.detect do |_k, v|
222
+ dep_instance.class == v.class_name
223
+ end&.first
224
+ unless selected_option.present?
225
+ raise "Don't know how to serialize dependency of type #{dependency}, available options are #{opts.keys}. You didn't specify an option."
226
+ end
227
+
228
+ serialized = dep_instance.respond_to?(:serialize) ? dep_instance.serialize : dep_instance.attributes.deep_compact
229
+ {
230
+ selected_option => serialized
231
+ }
232
+ end
233
+
234
+ def service_object
235
+ instance_variable_get("@#{service_attribute_name}")
236
+ end
237
+
238
+ def service_class
239
+ service_object.class
240
+ end
241
+
165
242
  def serialize_service_object
166
- service_object = instance_variable_get("@#{service_attribute_name}")
167
- service_klass = service_object.class
168
- attrs = service_klass.respond_to?(:serialize) ? service_klass.serialize(service_object) : service_object.attributes
243
+ attrs = service_object.respond_to?(:serialize) ? service_object.serialize : service_object.attributes.deep_compact
169
244
  deps = allowed_names(service_object.dependency_definitions.keys).inject({}) do |hash, dep|
170
245
  hash.tap do
171
- this_dep = service_object.send(dep)
172
- next unless this_dep.present?
173
-
174
- opts = service_object.dependency_definitions[dep].option_configs
175
- selected_option = opts.detect do |_k, v|
176
- this_dep.class == v.class_name
177
- end&.first
178
- unless selected_option.present?
179
- raise "Don't know how to serialize dependency of type #{dep}, available options are #{opts.keys}. You didn't specify an option."
180
- end
246
+ serialized = serialize_dependency(dep)
247
+ next if serialized.nil?
181
248
 
182
- hash[dep] = {
183
- selected_option => service_object.send(dep).attributes
184
- }
249
+ hash[dep] = serialized
185
250
  end
186
251
  end
187
- json = serializable!(attrs.merge(deps.deep_compact).deep_symbolize_keys)
252
+ json = serializable!(attrs.merge(deps).deep_symbolize_keys)
188
253
  write_attribute(:configuration, json.to_json)
189
254
  end
190
255
 
@@ -207,12 +272,37 @@ module GlueGun
207
272
  json
208
273
  end
209
274
 
275
+ def deserialize_dependency(serialized, definition)
276
+ return serialized.map { |dep| deserialize_dependency(dep, definition) } if serialized.is_a?(Array)
277
+
278
+ dep_name = serialized.keys.first
279
+ selected_option = definition.option_configs[dep_name]
280
+ dependency_class = selected_option.class_name
281
+ arguments = serialized[dep_name]
282
+
283
+ dependency_class.respond_to?(:deserialize) ? dependency_class.deserialize(arguments) : arguments
284
+ {
285
+ dep_name => arguments
286
+ }
287
+ end
288
+
289
+ def deserialize_dependencies(serialized_data, service_class)
290
+ serialized_deps = (serialized_data.keys & allowed_names(service_class.dependency_definitions.keys))
291
+ serialized_deps.each do |name|
292
+ serialized = serialized_data[name]
293
+ definition = service_class.dependency_definitions[name]
294
+ serialized_data[name] = deserialize_dependency(serialized, definition)
295
+ end
296
+ serialized_data
297
+ end
298
+
210
299
  def deserialize_service_object
211
300
  serialized_data = JSON.parse(read_attribute(:configuration) || "{}")
212
301
  serialized_data.deep_symbolize_keys!
213
302
  service_class = resolve_service_class(serialized_data)
214
303
  serialized_data = deserialize_associations(serialized_data)
215
304
  serialized_data = service_class.deserialize(serialized_data) if service_class.respond_to?(:deserialize)
305
+ serialized_data = deserialize_dependencies(serialized_data, service_class)
216
306
  service_instance = build_service_object(serialized_data)
217
307
  instance_variable_set("@#{service_attribute_name}", service_instance)
218
308
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GlueGun
4
- VERSION = "0.1.24"
4
+ VERSION = "0.1.27"
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.24
4
+ version: 0.1.27
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-23 00:00:00.000000000 Z
11
+ date: 2024-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel