glue_gun_dsl 0.1.28 → 0.1.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/glue_gun/model.rb +14 -106
- data/lib/glue_gun/serializers.rb +164 -0
- data/lib/glue_gun/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d8acb6f057ab8a1af500f7c179ab11799e76a5a00936e3b75c2e8d89ebf31b
|
4
|
+
data.tar.gz: c1eca08d776bb20638e544ccf4263a65cabde137bbc821f871b0f0898b7b062d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5560e86452000ea065de2721466104a8c1f108db0b57c608c8248ab84565e317db518ea93be0ea2bad3f148075ac78666fed7c48674f59978af07196d485a8b6
|
7
|
+
data.tar.gz: 0b384297f71a53a34f3def7fe0542ed993e5fb9c09160f0ec4f10b39a4481a83503d7e5b38337f4eea597eba6c3f73adecce59d551886b6d1bfc6d137e61452d
|
data/lib/glue_gun/model.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative "shared"
|
2
|
+
require_relative "serializers"
|
2
3
|
module GlueGun
|
3
4
|
module Model
|
4
5
|
extend ActiveSupport::Concern
|
@@ -139,6 +140,10 @@ module GlueGun
|
|
139
140
|
|
140
141
|
private
|
141
142
|
|
143
|
+
def awesome_print(message)
|
144
|
+
ap message
|
145
|
+
end
|
146
|
+
|
142
147
|
def build_service_object(attributes)
|
143
148
|
self.class.send(:attr_reader, service_attribute_name)
|
144
149
|
service_class = resolve_service_class(attributes)
|
@@ -148,9 +153,9 @@ module GlueGun
|
|
148
153
|
begin
|
149
154
|
service_instance = service_class.new(service_attributes)
|
150
155
|
rescue StandardError => e
|
151
|
-
|
152
|
-
|
153
|
-
|
156
|
+
awesome_print %(Error building service object #{service_class}:)
|
157
|
+
awesome_print e.message
|
158
|
+
awesome_print e.backtrace
|
154
159
|
raise e
|
155
160
|
end
|
156
161
|
instance_variable_set("@#{service_attribute_name}", service_instance)
|
@@ -159,8 +164,10 @@ module GlueGun
|
|
159
164
|
def resolve_service_type(attributes, initializing = false)
|
160
165
|
attrs = if initializing || !persisted? || attributes.key?(self.class.option_key)
|
161
166
|
attributes
|
162
|
-
|
167
|
+
elsif respond_to?(self.class.option_key)
|
163
168
|
{ self.class.option_key => send(self.class.option_key) }
|
169
|
+
else
|
170
|
+
{ self.class.option_key => self.class.service_registry.default_key }
|
164
171
|
end
|
165
172
|
attrs[self.class.option_key] || self.class.service_registry.default_key
|
166
173
|
end
|
@@ -211,119 +218,20 @@ module GlueGun
|
|
211
218
|
end.symbolize_keys
|
212
219
|
end
|
213
220
|
|
214
|
-
def serialize_object(object)
|
215
|
-
if object.respond_to?(:serialize)
|
216
|
-
object.serialize
|
217
|
-
elsif object.respond_to?(:attributes)
|
218
|
-
object.attributes.deep_compact
|
219
|
-
else
|
220
|
-
Hash[object.instance_variables.map do |var|
|
221
|
-
[var.to_s.delete("@"), object.instance_variable_get(var)]
|
222
|
-
end].deep_compact
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def serialize_dependency(dependency, dep_instance = nil)
|
227
|
-
dep_instance = service_object.send(dependency) if dep_instance.nil?
|
228
|
-
return nil unless dep_instance.present?
|
229
|
-
|
230
|
-
return dep_instance.map { |dep| serialize_dependency(dependency, dep) } if dep_instance.is_a?(Array)
|
231
|
-
|
232
|
-
opts = service_object.dependency_definitions[dependency].option_configs
|
233
|
-
selected_option = opts.detect do |_k, v|
|
234
|
-
dep_instance.class == v.class_name
|
235
|
-
end&.first
|
236
|
-
unless selected_option.present?
|
237
|
-
raise "Don't know how to serialize dependency of type #{dependency}, available options are #{opts.keys}. You didn't specify an option."
|
238
|
-
end
|
239
|
-
|
240
|
-
serialized = serialize_object(dep_instance)
|
241
|
-
{
|
242
|
-
selected_option => serialized
|
243
|
-
}
|
244
|
-
end
|
245
|
-
|
246
221
|
def service_object
|
247
222
|
instance_variable_get("@#{service_attribute_name}")
|
248
223
|
end
|
249
224
|
|
250
|
-
def service_class
|
251
|
-
service_object.class
|
252
|
-
end
|
253
|
-
|
254
225
|
def serialize_service_object
|
255
|
-
|
256
|
-
deps = allowed_names(service_object.dependency_definitions.keys).inject({}) do |hash, dep|
|
257
|
-
hash.tap do
|
258
|
-
serialized = serialize_dependency(dep)
|
259
|
-
next if serialized.nil?
|
260
|
-
|
261
|
-
hash[dep] = serialized
|
262
|
-
end
|
263
|
-
end
|
264
|
-
json = serializable!(attrs.merge(deps).deep_symbolize_keys)
|
265
|
-
write_attribute(:configuration, json.to_json)
|
266
|
-
end
|
267
|
-
|
268
|
-
def serializable!(json)
|
269
|
-
regular_args = json.slice(*allowed_names(json.keys))
|
270
|
-
assoc_names = self.class.reflect_on_all_associations.map(&:name)
|
271
|
-
found_associations = assoc_names & json.keys
|
272
|
-
found_associations.each do |association|
|
273
|
-
regular_args[association] = true
|
274
|
-
end
|
275
|
-
regular_args
|
276
|
-
end
|
277
|
-
|
278
|
-
def deserialize_associations(json)
|
279
|
-
assoc_names = self.class.reflect_on_all_associations.map(&:name)
|
280
|
-
found_associations = assoc_names & json.keys
|
281
|
-
found_associations.each do |association|
|
282
|
-
json[association] = send(association)
|
283
|
-
end
|
284
|
-
json
|
285
|
-
end
|
286
|
-
|
287
|
-
def deserialize_dependency(serialized, definition)
|
288
|
-
return serialized.map { |dep| deserialize_dependency(dep, definition) } if serialized.is_a?(Array)
|
289
|
-
|
290
|
-
dep_name = serialized.keys.first
|
291
|
-
selected_option = definition.option_configs[dep_name]
|
292
|
-
dependency_class = selected_option.class_name
|
293
|
-
arguments = serialized[dep_name]
|
294
|
-
|
295
|
-
dependency_class.respond_to?(:deserialize) ? dependency_class.deserialize(arguments) : arguments
|
296
|
-
{
|
297
|
-
dep_name => arguments
|
298
|
-
}
|
299
|
-
end
|
300
|
-
|
301
|
-
def deserialize_dependencies(serialized_data, service_class)
|
302
|
-
serialized_deps = (serialized_data.keys & allowed_names(service_class.dependency_definitions.keys))
|
303
|
-
serialized_deps.each do |name|
|
304
|
-
serialized = serialized_data[name]
|
305
|
-
definition = service_class.dependency_definitions[name]
|
306
|
-
serialized_data[name] = deserialize_dependency(serialized, definition)
|
307
|
-
end
|
308
|
-
serialized_data
|
226
|
+
GlueGun::Serializers.new(self).serialize_service_object(service_object)
|
309
227
|
end
|
310
228
|
|
311
229
|
def deserialize_service_object
|
312
|
-
|
313
|
-
|
314
|
-
service_class = resolve_service_class(serialized_data)
|
315
|
-
serialized_data = deserialize_associations(serialized_data)
|
316
|
-
serialized_data = service_class.deserialize(serialized_data) if service_class.respond_to?(:deserialize)
|
317
|
-
serialized_data = deserialize_dependencies(serialized_data, service_class)
|
318
|
-
service_instance = build_service_object(serialized_data)
|
230
|
+
deserialized = GlueGun::Serializers.new(self).deserialize_service_object
|
231
|
+
service_instance = build_service_object(deserialized)
|
319
232
|
instance_variable_set("@#{service_attribute_name}", service_instance)
|
320
233
|
end
|
321
234
|
|
322
|
-
def allowed_names(names)
|
323
|
-
assoc_names = self.class.reflect_on_all_associations.map(&:name)
|
324
|
-
[names.map(&:to_sym) - assoc_names.map(&:to_sym)].flatten
|
325
|
-
end
|
326
|
-
|
327
235
|
def method_missing(method_name, *args, **kwargs, &block)
|
328
236
|
service_object = instance_variable_get("@#{service_attribute_name}")
|
329
237
|
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module GlueGun
|
2
|
+
class Serializers
|
3
|
+
attr_accessor :instance
|
4
|
+
|
5
|
+
def initialize(instance)
|
6
|
+
@instance = instance
|
7
|
+
end
|
8
|
+
|
9
|
+
def serialize_object(object)
|
10
|
+
if object.respond_to?(:serialize)
|
11
|
+
object.serialize
|
12
|
+
elsif object.respond_to?(:attributes)
|
13
|
+
object.attributes.deep_compact
|
14
|
+
else
|
15
|
+
Hash[object.instance_variables.map do |var|
|
16
|
+
[var.to_s.delete("@"), object.instance_variable_get(var)]
|
17
|
+
end].deep_compact
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize_dependency(service_object, dependency, dep_instance = nil)
|
22
|
+
dep_instance = service_object.send(dependency) if dep_instance.nil?
|
23
|
+
return nil unless dep_instance.present?
|
24
|
+
|
25
|
+
if dep_instance.is_a?(Array)
|
26
|
+
return dep_instance.map do |dep|
|
27
|
+
serialize_dependency(service_object, dependency, dep)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
opts = service_object.dependency_definitions[dependency].option_configs
|
32
|
+
selected_option = opts.detect do |_k, v|
|
33
|
+
dep_instance.class == v.class_name
|
34
|
+
end&.first
|
35
|
+
unless selected_option.present?
|
36
|
+
raise "Don't know how to serialize dependency of type #{dependency}, available options are #{opts.keys}. You didn't specify an option."
|
37
|
+
end
|
38
|
+
|
39
|
+
serialized = serialize_object(dep_instance)
|
40
|
+
{
|
41
|
+
selected_option => serialized
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def service_class
|
46
|
+
service_object.class
|
47
|
+
end
|
48
|
+
|
49
|
+
def allowed_names(names)
|
50
|
+
assoc_names = instance.class.reflect_on_all_associations.map(&:name)
|
51
|
+
[names.map(&:to_sym) - assoc_names.map(&:to_sym)].flatten
|
52
|
+
end
|
53
|
+
|
54
|
+
def serialize_service_object(service_object)
|
55
|
+
attrs = serialize_object(service_object)
|
56
|
+
deps = allowed_names(service_object.dependency_definitions.keys).inject({}) do |hash, dep|
|
57
|
+
hash.tap do
|
58
|
+
serialized = serialize_dependency(service_object, dep)
|
59
|
+
next if serialized.nil?
|
60
|
+
|
61
|
+
hash[dep] = serialized
|
62
|
+
end
|
63
|
+
end
|
64
|
+
json = serializable!(serialize_attrs(attrs.merge(deps).deep_symbolize_keys))
|
65
|
+
instance.write_attribute(:configuration, json.to_json)
|
66
|
+
end
|
67
|
+
|
68
|
+
def serializable!(json)
|
69
|
+
regular_args = json.slice(*allowed_names(json.keys))
|
70
|
+
assoc_names = instance.class.reflect_on_all_associations.map(&:name)
|
71
|
+
found_associations = assoc_names & json.keys
|
72
|
+
found_associations.each do |association|
|
73
|
+
regular_args[association] = true
|
74
|
+
end
|
75
|
+
regular_args
|
76
|
+
end
|
77
|
+
|
78
|
+
def deserialize_associations(json)
|
79
|
+
assoc_names = instance.class.reflect_on_all_associations.map(&:name)
|
80
|
+
found_associations = assoc_names & json.keys
|
81
|
+
found_associations.each do |association|
|
82
|
+
json[association] = instance.send(association)
|
83
|
+
end
|
84
|
+
json
|
85
|
+
end
|
86
|
+
|
87
|
+
def deserialize_dependency(serialized, definition)
|
88
|
+
return serialized.map { |dep| deserialize_dependency(dep, definition) } if serialized.is_a?(Array)
|
89
|
+
|
90
|
+
dep_name = serialized.keys.first
|
91
|
+
selected_option = definition.option_configs[dep_name]
|
92
|
+
dependency_class = selected_option.class_name
|
93
|
+
arguments = serialized[dep_name]
|
94
|
+
|
95
|
+
dependency_class.respond_to?(:deserialize) ? dependency_class.deserialize(arguments) : arguments
|
96
|
+
{
|
97
|
+
dep_name => arguments
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
def deserialize_dependencies(serialized_data, service_class)
|
102
|
+
serialized_deps = (serialized_data.keys & allowed_names(service_class.dependency_definitions.keys))
|
103
|
+
serialized_deps.each do |name|
|
104
|
+
serialized = serialized_data[name]
|
105
|
+
definition = service_class.dependency_definitions[name]
|
106
|
+
serialized_data[name] = deserialize_dependency(serialized, definition)
|
107
|
+
end
|
108
|
+
serialized_data
|
109
|
+
end
|
110
|
+
|
111
|
+
def deserialize_service_object
|
112
|
+
serialized_data = JSON.parse(instance.read_attribute(:configuration) || "{}")
|
113
|
+
serialized_data.deep_symbolize_keys!
|
114
|
+
serialized_data = deserialize_attrs(serialized_data)
|
115
|
+
service_class = instance.send(:resolve_service_class, serialized_data)
|
116
|
+
serialized_data = deserialize_associations(serialized_data)
|
117
|
+
serialized_data = service_class.deserialize(serialized_data) if service_class.respond_to?(:deserialize)
|
118
|
+
deserialize_dependencies(serialized_data, service_class)
|
119
|
+
end
|
120
|
+
|
121
|
+
def serialize_attrs(attrs)
|
122
|
+
attrs.deep_transform_values do |value|
|
123
|
+
case value
|
124
|
+
when ActiveSupport::TimeWithZone
|
125
|
+
{ "__type__" => "ActiveSupport::TimeWithZone", "value" => value.iso8601 }
|
126
|
+
else
|
127
|
+
value
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def deserialize_attrs(attrs)
|
133
|
+
return nil if attrs.nil?
|
134
|
+
|
135
|
+
attrs.transform_values do |value|
|
136
|
+
recursive_deserialize(value)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def recursive_deserialize(value)
|
141
|
+
case value
|
142
|
+
when Hash
|
143
|
+
if value[:__type__]
|
144
|
+
deserialize_special_type(value)
|
145
|
+
else
|
146
|
+
value.transform_values { |v| recursive_deserialize(v) }
|
147
|
+
end
|
148
|
+
when Array
|
149
|
+
value.map { |v| recursive_deserialize(v) }
|
150
|
+
else
|
151
|
+
value
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def deserialize_special_type(value)
|
156
|
+
case value[:__type__]
|
157
|
+
when "ActiveSupport::TimeWithZone"
|
158
|
+
Time.zone.parse(value[:value])
|
159
|
+
else
|
160
|
+
value[:value]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
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.30
|
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-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -196,6 +196,20 @@ dependencies:
|
|
196
196
|
- - "~>"
|
197
197
|
- !ruby/object:Gem::Version
|
198
198
|
version: '1.4'
|
199
|
+
- !ruby/object:Gem::Dependency
|
200
|
+
name: timecop
|
201
|
+
requirement: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
type: :development
|
207
|
+
prerelease: false
|
208
|
+
version_requirements: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
199
213
|
description: GlueGun makes dependency injection and hydration a first-order concern
|
200
214
|
email:
|
201
215
|
- brett.shollenberger@gmail.com
|
@@ -208,6 +222,7 @@ files:
|
|
208
222
|
- lib/glue_gun/core_ext/hash_extensions.rb
|
209
223
|
- lib/glue_gun/dsl.rb
|
210
224
|
- lib/glue_gun/model.rb
|
225
|
+
- lib/glue_gun/serializers.rb
|
211
226
|
- lib/glue_gun/shared.rb
|
212
227
|
- lib/glue_gun/types.rb
|
213
228
|
- lib/glue_gun/types/array_type.rb
|