glue_gun_dsl 0.1.24 → 0.1.27

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: 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