foobara 0.0.87 → 0.0.89

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: 45093221881afa7419b208493f3787403c664a149f77728ac64daaea00c7b083
4
- data.tar.gz: 4103467f677825cd70e2d8d468cc9845511789c32e4a2f69c3cc4901fb9704c5
3
+ metadata.gz: 424a065d4e4a0543f55ac9c3b7c0c87db4a5f334241c5b8e5a46b44a45907a55
4
+ data.tar.gz: ec082f769eaae6bc5f9b4dd079722b044e417243ad1cf0cabcf0c21b9648efa6
5
5
  SHA512:
6
- metadata.gz: e655dc065c7b923be1d76742e9fc651f8d7581cdfd3ad9130cc20e474ca42bb15791ebc35238bc52d8b255cef440237234c01eda4189b850287ecd142141271e
7
- data.tar.gz: 54893503e3dfed78a608590f44a9673aca2b8c208094a306c7b10634afea59380caee6a0998cd283c1ecb7097b227705b9a3644186d2f3afe561ee0676170717
6
+ metadata.gz: 5b6b51362c480c26f1690c17874607a2bcf34d14b6d3882665798efe6511e3fc2f602214cae1b005dd788cf23f33a68a4c1781b631108248e2bb1baca0ed0204
7
+ data.tar.gz: 2e910c95484b092eb2bfdef1eeed079f99794801a3bb345efc0291f51ca1b832301f3540e454b0bd749d9028b591bbc3b919a0301d03db965e576644c9c72284
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [0.0.89] - 2025-03-29
2
+
3
+ - Make attributes transformers work with either a from type or a to type
4
+
5
+ # [0.0.88] - 2025-03-28
6
+
7
+ - Implement response mutator concept
8
+ - Break up #request_to_response for easier overriding/extension
9
+ - Add AttributesTransformers::Reject
10
+ - Fix problem causing downcase/regex processors to explode on allows_nil types
11
+
1
12
  # [0.0.87] - 2025-03-26
2
13
 
3
14
  - TypedTransformer refactor to reduce confusion and bugs
@@ -5,9 +5,6 @@ module Foobara
5
5
  # Seems like it might be cleaner to just assemble these parts in one place instead of in different files?
6
6
  # Hard to say.
7
7
  class Downcase < BuiltinTypes::String::SupportedTransformers::Downcase
8
- def always_applicable?
9
- true
10
- end
11
8
  end
12
9
  end
13
10
  end
@@ -27,10 +27,6 @@ module Foobara
27
27
  end
28
28
  end
29
29
 
30
- def always_applicable?
31
- true
32
- end
33
-
34
30
  def regex
35
31
  # :nocov:
36
32
  raise "subclass responsibility"
@@ -76,6 +72,11 @@ module Foobara
76
72
  class_name = "#{name}::#{Util.classify(symbol)}"
77
73
 
78
74
  Util.make_class(class_name, ValidatorBase) do
75
+ define_method :applicable? do |value|
76
+ # TODO: hmmm, I wonder how we can short-circuit these checks if :allows_nil matches??
77
+ value.is_a?(::String)
78
+ end
79
+
79
80
  define_method :regex do
80
81
  regex
81
82
  end
@@ -3,7 +3,11 @@ module Foobara
3
3
  # TODO: Rename to StringType to avoid needing to remember ::String elsewhere in the code
4
4
  module String
5
5
  module SupportedTransformers
6
- class Downcase < Value::Transformer.subclass(transform: :downcase.to_proc, name: "Downcase")
6
+ class Downcase < Value::Transformer.subclass(
7
+ transform: :downcase.to_proc,
8
+ name: "Downcase",
9
+ applicable?: ->(value) { value.respond_to?(:downcase) }
10
+ )
7
11
  end
8
12
  end
9
13
  end
@@ -13,6 +13,10 @@ module Foobara
13
13
  :pre_commit_transformers,
14
14
  # TODO: get at least these serializers out of here...
15
15
  :serializers,
16
+ # TODO: probably should also get these mutators out of here. But where should they live?
17
+ # On exposed command? On the command registry? On the command connector?
18
+ # This is the easiest place to implement them but feels awkward.
19
+ :response_mutators,
16
20
  :allowed_rule,
17
21
  :requires_authentication,
18
22
  :authenticator
@@ -27,6 +31,7 @@ module Foobara
27
31
  errors_transformers:,
28
32
  pre_commit_transformers:,
29
33
  serializers:,
34
+ response_mutators:,
30
35
  allowed_rule:,
31
36
  requires_authentication:,
32
37
  authenticator:,
@@ -36,7 +41,6 @@ module Foobara
36
41
  result_type = command_class.result_type
37
42
 
38
43
  if result_type&.has_sensitive_types?
39
-
40
44
  remover_class = Foobara::TypeDeclarations.sensitive_value_remover_class_for_type(result_type)
41
45
 
42
46
  remover = Namespace.use scoped_namespace do
@@ -59,6 +63,7 @@ module Foobara
59
63
  klass.errors_transformers = Util.array(errors_transformers)
60
64
  klass.pre_commit_transformers = Util.array(pre_commit_transformers)
61
65
  klass.serializers = Util.array(serializers)
66
+ klass.response_mutators = Util.array(response_mutators)
62
67
  klass.allowed_rule = allowed_rule
63
68
  klass.requires_authentication = requires_authentication
64
69
  klass.authenticator = authenticator
@@ -109,6 +114,18 @@ module Foobara
109
114
  result_type_from_transformers(command_class.result_type, result_transformers)
110
115
  end
111
116
 
117
+ def result_type_for_manifest
118
+ return @result_type_for_manifest if defined?(@result_type_for_manifest)
119
+
120
+ mutated_result_type = result_type
121
+
122
+ response_mutators&.reverse&.each do |mutator|
123
+ mutated_result_type = mutator.instance.result_type_from(mutated_result_type)
124
+ end
125
+
126
+ @result_type_for_manifest = mutated_result_type
127
+ end
128
+
112
129
  def error_context_type_map
113
130
  @error_context_type_map ||= begin
114
131
  set = {}
@@ -208,12 +225,13 @@ module Foobara
208
225
  end
209
226
  end
210
227
 
228
+ response_mutators = self.response_mutators.map { |t| t.foobara_manifest(to_include:) }
229
+
211
230
  command_class.foobara_manifest(to_include:, remove_sensitive:).merge(
212
231
  Util.remove_blank(
213
232
  types_depended_on: types,
214
233
  inputs_type: inputs_type&.reference_or_declaration_data,
215
- # TODO: we need a way to unmask values in the result type that we want to expose
216
- result_type: result_type&.reference_or_declaration_data(remove_sensitive:),
234
+ result_type: result_type_for_manifest&.reference_or_declaration_data(remove_sensitive:),
217
235
  possible_errors: possible_errors_manifest(to_include:, remove_sensitive:),
218
236
  capture_unknown_error:,
219
237
  inputs_transformers:,
@@ -221,6 +239,7 @@ module Foobara
221
239
  errors_transformers:,
222
240
  pre_commit_transformers:,
223
241
  serializers:,
242
+ response_mutators:,
224
243
  requires_authentication:,
225
244
  authenticator: authenticator&.manifest
226
245
  )
@@ -247,6 +266,25 @@ module Foobara
247
266
  end
248
267
  end
249
268
 
269
+ def response_mutator
270
+ return @response_mutator if defined?(@response_mutator)
271
+
272
+ if response_mutators.empty?
273
+ @response_mutator = nil
274
+ return
275
+ end
276
+
277
+ @response_mutator = begin
278
+ transformers = transformers_to_processors(response_mutators, result_type, direction: :from)
279
+
280
+ if transformers.size == 1
281
+ transformers.first
282
+ else
283
+ Value::Processor::Pipeline.new(processors: transformers)
284
+ end
285
+ end
286
+ end
287
+
250
288
  def result_transformer
251
289
  return @result_transformer if defined?(@result_transformer)
252
290
 
@@ -344,6 +382,10 @@ module Foobara
344
382
  end
345
383
  end
346
384
 
385
+ def mutate_response(response)
386
+ self.class.response_mutator&.process_value!(response)
387
+ end
388
+
347
389
  def transform_errors
348
390
  if errors_transformer
349
391
  self.outcome = Outcome.errors(errors_transformer.process_value!(errors))
@@ -483,13 +525,7 @@ module Foobara
483
525
  end
484
526
 
485
527
  # TODO: kill this
486
- def serialize_result
487
- body = if outcome.success?
488
- outcome.result
489
- else
490
- outcome.errors
491
- end
492
-
528
+ def serialize_result(body)
493
529
  if serializer
494
530
  serializer.process_value!(body)
495
531
  else
@@ -1,14 +1,14 @@
1
1
  module Foobara
2
2
  class CommandConnector
3
3
  class Response
4
- attr_accessor :status,
5
- :body,
6
- :request
4
+ attr_accessor :request,
5
+ :status,
6
+ :body
7
7
 
8
- def initialize(status:, body:, request:)
8
+ def initialize(request:, status: nil, body: nil)
9
+ self.request = request
9
10
  self.status = status
10
11
  self.body = body
11
- self.request = request
12
12
  end
13
13
 
14
14
  foobara_delegate :command, :error, to: :request
@@ -95,6 +95,7 @@ module Foobara
95
95
  :add_default_errors_transformer,
96
96
  :add_default_pre_commit_transformer,
97
97
  :add_default_serializer,
98
+ :add_default_response_mutator,
98
99
  :allowed_rule,
99
100
  :allowed_rules,
100
101
  :transform_command_class,
@@ -232,16 +233,34 @@ module Foobara
232
233
  end
233
234
 
234
235
  def request_to_response(request)
235
- command = request.command
236
- outcome = command.outcome
236
+ self.class::Response.new(request:)
237
+ end
238
+
239
+ def set_response_status(response)
240
+ outcome = response.request.outcome
241
+ response.status = outcome.success? ? 0 : 1
242
+ end
237
243
 
238
- status = outcome.success? ? 0 : 1
244
+ def set_response_body(response)
245
+ outcome = response.request.outcome
246
+ # response.body = outcome.success? ? outcome.result : outcome.error_collection
247
+ response.body = outcome.success? ? outcome.result : outcome.error_collection
248
+ end
239
249
 
240
- # TODO: feels awkward to call this here... Maybe use result/errors transformers instead??
241
- # Or call the serializer here??
242
- body = command.respond_to?(:serialize_result) ? command.serialize_result : request.response_body
250
+ def mutate_response(response)
251
+ command = response.command
243
252
 
244
- self.class::Response.new(request:, status:, body:)
253
+ if command.respond_to?(:mutate_response)
254
+ command.mutate_response(response)
255
+ end
256
+ end
257
+
258
+ def serialize_response_body(response)
259
+ command = response.command
260
+
261
+ if command.respond_to?(:serialize_result)
262
+ response.body = command.serialize_result(response.body)
263
+ end
245
264
  end
246
265
 
247
266
  def initialize(authenticator: nil, default_serializers: nil)
@@ -343,7 +362,12 @@ module Foobara
343
362
 
344
363
  def build_response(request)
345
364
  response = request_to_response(request)
346
- response.request = request
365
+
366
+ set_response_status(response)
367
+ set_response_body(response)
368
+ mutate_response(response)
369
+ serialize_response_body(response)
370
+
347
371
  response
348
372
  end
349
373
 
@@ -12,6 +12,7 @@ module Foobara
12
12
  :errors_transformers,
13
13
  :pre_commit_transformers,
14
14
  :serializers,
15
+ :response_mutators,
15
16
  :allowed_rule,
16
17
  :requires_authentication,
17
18
  :authenticator,
@@ -27,6 +28,7 @@ module Foobara
27
28
  result_transformers: nil,
28
29
  errors_transformers: nil,
29
30
  pre_commit_transformers: nil,
31
+ response_mutators: nil,
30
32
  serializers: nil,
31
33
  allowed_rule: nil,
32
34
  requires_authentication: nil,
@@ -76,6 +78,7 @@ module Foobara
76
78
  self.result_transformers = result_transformers
77
79
  self.errors_transformers = errors_transformers
78
80
  self.pre_commit_transformers = pre_commit_transformers
81
+ self.response_mutators = response_mutators
79
82
  self.serializers = serializers
80
83
  self.allowed_rule = allowed_rule
81
84
  self.requires_authentication = requires_authentication
@@ -111,6 +114,7 @@ module Foobara
111
114
  result_transformers,
112
115
  errors_transformers,
113
116
  pre_commit_transformers,
117
+ response_mutators,
114
118
  serializers,
115
119
  allowed_rule,
116
120
  requires_authentication,
@@ -130,6 +134,7 @@ module Foobara
130
134
  result_transformers:,
131
135
  errors_transformers:,
132
136
  pre_commit_transformers:,
137
+ response_mutators:,
133
138
  serializers:,
134
139
  allowed_rule:,
135
140
  requires_authentication:,
@@ -0,0 +1,24 @@
1
+ module Foobara
2
+ module CommandConnectors
3
+ class ResponseMutator < Foobara::Value::Mutator
4
+ def result_type_declaration_from(_result_type)
5
+ # :nocov:
6
+ raise "subclass responsibility"
7
+ # :nocov:
8
+ end
9
+
10
+ def result_type_from(result_type)
11
+ declaration = result_type_declaration_from(result_type)
12
+ Domain.current.foobara_type_from_declaration(declaration)
13
+ end
14
+
15
+ def mutate
16
+ # :nocov:
17
+ raise "subclass responsibility"
18
+ # :nocov:
19
+ end
20
+
21
+ alias response declaration_data
22
+ end
23
+ end
24
+ end
@@ -8,7 +8,8 @@ module Foobara
8
8
  !request.outcome.success?
9
9
  end
10
10
 
11
- def serialize(errors)
11
+ def serialize(error_collection)
12
+ errors = error_collection.errors
12
13
  errors.map(&:to_h)
13
14
  end
14
15
  end
@@ -0,0 +1,41 @@
1
+ module Foobara
2
+ class AttributesTransformers < TypeDeclarations::TypedTransformer
3
+ class << self
4
+ def only(*attribute_names)
5
+ transformer_class = Class.new(Only)
6
+ transformer_class.only_attributes = attribute_names
7
+
8
+ transformer_class
9
+ end
10
+ end
11
+
12
+ class Only < AttributesTransformers
13
+ class << self
14
+ attr_accessor :only_attributes
15
+ end
16
+
17
+ def to_type_declaration
18
+ if from_type
19
+ from_declaration = from_type.declaration_data
20
+ TypeDeclarations::Attributes.only(from_declaration, *self.class.only_attributes)
21
+ end
22
+ end
23
+
24
+ def from_type_declaration
25
+ if to_type
26
+ to_declaration = to_type.declaration_data
27
+ TypeDeclarations::Attributes.only(to_declaration, *self.class.only_attributes)
28
+ end
29
+ end
30
+
31
+ def transform(inputs)
32
+ inputs = Util.symbolize_keys(inputs)
33
+ inputs.slice(*allowed_keys)
34
+ end
35
+
36
+ def allowed_keys
37
+ to_type.element_types.keys
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module Foobara
2
+ class AttributesTransformers < TypeDeclarations::TypedTransformer
3
+ class << self
4
+ def reject(*attribute_names)
5
+ transformer_class = Class.new(Reject)
6
+ transformer_class.reject_attributes = attribute_names
7
+
8
+ transformer_class
9
+ end
10
+ end
11
+
12
+ class Reject < AttributesTransformers
13
+ class << self
14
+ attr_accessor :reject_attributes
15
+ end
16
+
17
+ def to_type_declaration
18
+ if from_type
19
+ from_declaration = from_type.declaration_data
20
+ TypeDeclarations::Attributes.reject(from_declaration, *self.class.reject_attributes)
21
+ end
22
+ end
23
+
24
+ def from_type_declaration
25
+ if to_type
26
+ to_declaration = to_type.declaration_data
27
+ TypeDeclarations::Attributes.reject(to_declaration, *self.class.reject_attributes)
28
+ end
29
+ end
30
+
31
+ def transform(inputs)
32
+ inputs = Util.symbolize_keys(inputs)
33
+ inputs.slice(*allowed_keys)
34
+ end
35
+
36
+ def allowed_keys
37
+ to_type.element_types.keys
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ module Foobara
2
+ module Value
3
+ class Mutator < Processor
4
+ class << self
5
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
6
+ super.merge(processor_type: :mutator)
7
+ end
8
+
9
+ def error_classes
10
+ []
11
+ end
12
+ end
13
+
14
+ def mutate(_value)
15
+ # :nocov:
16
+ raise "subclass responsibility"
17
+ # :nocov:
18
+ end
19
+
20
+ def process_value(value)
21
+ if applicable?(value)
22
+ mutate(value)
23
+ end
24
+
25
+ Outcome.success(value)
26
+ end
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.87
4
+ version: 0.0.89
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-26 00:00:00.000000000 Z
10
+ date: 2025-03-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -27,30 +27,30 @@ dependencies:
27
27
  name: foobara-lru-cache
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
30
+ - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: 0.0.2
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
39
+ version: 0.0.2
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: foobara-util
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - ">="
44
+ - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0'
46
+ version: 0.0.11
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: 0.0.11
54
54
  description: A command-centric and discoverable software framework with a focus on
55
55
  domain concepts and abstracting away integration code
56
56
  email:
@@ -179,6 +179,7 @@ files:
179
179
  - projects/command_connectors/src/command_registry/exposed_command.rb
180
180
  - projects/command_connectors/src/command_registry/exposed_domain.rb
181
181
  - projects/command_connectors/src/command_registry/exposed_organization.rb
182
+ - projects/command_connectors/src/response_mutator.rb
182
183
  - projects/command_connectors/src/serializer.rb
183
184
  - projects/command_connectors/src/serializers/aggregate_serializer.rb
184
185
  - projects/command_connectors/src/serializers/atomic_serializer.rb
@@ -359,7 +360,8 @@ files:
359
360
  - projects/thread_parent/src/thread_parent.rb
360
361
  - projects/type_declarations/lib/foobara/type_declarations.rb
361
362
  - projects/type_declarations/src/attributes.rb
362
- - projects/type_declarations/src/attributes_transformer.rb
363
+ - projects/type_declarations/src/attributes_transformers/only.rb
364
+ - projects/type_declarations/src/attributes_transformers/reject.rb
363
365
  - projects/type_declarations/src/caster.rb
364
366
  - projects/type_declarations/src/desugarizer.rb
365
367
  - projects/type_declarations/src/dsl/attributes.rb
@@ -418,6 +420,7 @@ files:
418
420
  - projects/value/lib/foobara/value.rb
419
421
  - projects/value/src/caster.rb
420
422
  - projects/value/src/data_error.rb
423
+ - projects/value/src/mutator.rb
421
424
  - projects/value/src/processor.rb
422
425
  - projects/value/src/processor/casting.rb
423
426
  - projects/value/src/processor/multi.rb
@@ -1,27 +0,0 @@
1
- module Foobara
2
- class AttributesTransformer < TypeDeclarations::TypedTransformer
3
- class << self
4
- attr_accessor :only_attributes
5
-
6
- def only(*attribute_names)
7
- transformer_class = Class.new(self)
8
- transformer_class.only_attributes = attribute_names
9
-
10
- transformer_class
11
- end
12
- end
13
-
14
- def to_type_declaration
15
- from_declaration = from_type.declaration_data
16
- TypeDeclarations::Attributes.only(from_declaration, *self.class.only_attributes)
17
- end
18
-
19
- def transform(inputs)
20
- inputs.slice(*allowed_keys)
21
- end
22
-
23
- def allowed_keys
24
- to_type.element_types.keys
25
- end
26
- end
27
- end