foobara 0.2.6 → 0.3.0

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +20 -7
  4. data/projects/builtin_types/lib/foobara/builtin_types.rb +1 -0
  5. data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb +1 -3
  6. data/projects/builtin_types/src/builtin_types.rb +6 -4
  7. data/projects/builtin_types/src/email/transformers/downcase.rb +0 -2
  8. data/projects/callback/src/block/concerns/keyword_argumentable_block.rb +2 -0
  9. data/projects/command/src/command_pattern_implementation/concerns/namespace.rb +0 -2
  10. data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +0 -2
  11. data/projects/command_connectors/src/command_connector/concerns/reflection.rb +187 -0
  12. data/projects/command_connectors/src/command_connector.rb +89 -255
  13. data/projects/command_connectors/src/command_registry/exposed_command.rb +6 -4
  14. data/projects/command_connectors/src/command_registry.rb +50 -48
  15. data/projects/command_connectors/src/serializers/atomic_serializer.rb +4 -1
  16. data/projects/command_connectors/src/transformed_command.rb +104 -100
  17. data/projects/command_connectors/src/transformers/load_atoms_transformer.rb +2 -0
  18. data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +2 -0
  19. data/projects/detached_entity/lib/foobara/detached_entity.rb +2 -0
  20. data/projects/detached_entity/src/remove_sensitive_values_transformer_extensions.rb +64 -0
  21. data/projects/domain/src/domain_module_extension.rb +0 -21
  22. data/projects/model/src/concerns/types.rb +1 -0
  23. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +1 -1
  24. data/projects/model_attribute_helpers/src/attribute_helpers.rb +4 -4
  25. data/projects/namespace/src/is_namespace.rb +1 -1
  26. data/projects/namespace/src/namespace/lookup_mode.rb +6 -0
  27. data/projects/nested_transactionable/lib/foobara/nested_transactionable.rb +0 -2
  28. data/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +0 -2
  29. data/projects/persistence/src/entity_base.rb +1 -0
  30. data/projects/type_declarations/lib/foobara/type_declarations.rb +3 -1
  31. data/projects/type_declarations/src/remove_sensitive_values_transformer.rb +0 -59
  32. data/version.rb +1 -1
  33. metadata +3 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3b6525afdbf01d8f0d56dce1f067430111781670ebac06dc4a90297e5fb1188
4
- data.tar.gz: fc79448ff4613758061b9c6336855fed97b6328356d510b77eb438097d55c99d
3
+ metadata.gz: 1889d43f30de1d85f60a3a6245feffbed013f4a2ad2b357fd9b61209e815ccd3
4
+ data.tar.gz: e57dfcd26cfb93c4f96084a61e33325644bddfd2d5d592f19e9c608f285244fe
5
5
  SHA512:
6
- metadata.gz: 46d2df3884c269014f64a0b040d867e63bf65bd4c0822a4d810e07a506f296a2c6a967be2437542e7d6b56af8080094f1510da9d8143e94880428bd816bf32ad
7
- data.tar.gz: 878e815dad1a261fa6bf9fc64525d06ea6cef4c499770fa6f621487a1fce011a2781750e53b75c40f8f8d1d3db57ef4cd17e4c542fba899c2474ca3576e239ab
6
+ metadata.gz: cd88755c0131cab9ee13fc46b38cafc779e5799aae3c33a8289198a809af9f9a021565ccaadc41d05b5a2c02aed22aad4e9ca0b3b664c0447e488ab8993c939e
7
+ data.tar.gz: b9c4090428c31817a87498f261a50a986594d90e8395dfd2250bd56c963373c44d10a8faa27ec0de7500c764ebfd90b6b0ee04d523d4cd7f061041727305e903
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # [0.3.0] - 2025-11-23
2
+
3
+ - Fix bug caused by exposing errors with organizations as parents
4
+ - Restructure code in some projects and make many more methods private
5
+
6
+ # [0.2.7] - 2025-11-10
7
+
8
+ - Fix CommandConnector authorization bug that can fail to close transactions
9
+
1
10
  # [0.2.6] - 2025-10-30
2
11
 
3
12
  - Add a set inputs transformer
data/README.md CHANGED
@@ -1,12 +1,25 @@
1
- Foobara is a software framework to help you encapsulate your high-level
2
- domain operations in commands, and automatically expose machine-readable formal metadata about those
3
- commands so that integration code can be decoupled and abstracted away.
1
+ Foobara is a software framework that is command-centric and discoverable.
4
2
 
5
- This, as well as some other features of foobara, help manage domain complexity and produce
6
- more flexible systems.
3
+ Domain operations are
4
+ encapsulated in commands, which serve as the public interface to systems, and which automatically
5
+ provide machine-readable formal metadata about those commands.
7
6
 
8
- You can watch a video that gives a good overview of what Foobara is and its goals here:
9
- [Introduction to the Foobara software framework](https://youtu.be/SSOmQqjNSVY)
7
+ This metadata makes your domain discoverable and can be used to abstract away integrations,
8
+ such as HTTP, CLI, MCP, whatever. It also makes your domain logic
9
+ forward-compatible with integrations you didn't know you needed or that might not even have
10
+ existed yet when you built your commands.
11
+
12
+ This metadata is also used to help export commands from one system and import them into another
13
+ as remote commands. This means you can write your domain logic and automatically get a Ruby SDK or Typescript SDK for
14
+ free.
15
+
16
+ This also helps with rearchitecting efforts since a remote command has the same interface
17
+ as the local command. Domain logic refactors are not required to relocate domain logic
18
+ in/out of other systems. And this also helps a system communicate and impose its mental model
19
+ on consuming systems.
20
+
21
+ You can use Foobara as a full standalone framework or you can use it with existing code
22
+ as a service-objects layer and leverage the integration features of Foobara when/if necessary.
10
23
 
11
24
  <!-- TOC -->
12
25
  * [Overview of Features/Concepts/Goals](#overview-of-featuresconceptsgoals)
@@ -66,6 +66,7 @@ module Foobara
66
66
 
67
67
  def reset_all
68
68
  Foobara.raise_if_production!("reset_all")
69
+
69
70
  builtin_types.each do |builtin_type|
70
71
  builtin_type.foobara_each do |scoped|
71
72
  if scoped.scoped_namespace == builtin_type
@@ -35,9 +35,7 @@ module Foobara
35
35
  return Outcome.error(
36
36
  build_error(
37
37
  attributes_hash,
38
- message: "Unexpected attributes #{
39
- unexpected_attributes
40
- }. Expected only #{allowed_attributes}",
38
+ message: "Unexpected attributes #{unexpected_attributes}. Expected only #{allowed_attributes}",
41
39
  context: {
42
40
  unexpected_attributes:,
43
41
  allowed_attributes:
@@ -5,10 +5,6 @@ module Foobara
5
5
 
6
6
  module BuiltinTypes
7
7
  class << self
8
- def global_type_declaration_handler_registry
9
- TypeDeclarations.global_type_declaration_handler_registry
10
- end
11
-
12
8
  # TODO: break this up
13
9
  # TODO: much of this behavior is helpful to non-builtin types as well.
14
10
  def build_and_register!(
@@ -158,6 +154,12 @@ module Foobara
158
154
  type
159
155
  end
160
156
 
157
+ private
158
+
159
+ def global_type_declaration_handler_registry
160
+ TypeDeclarations.global_type_declaration_handler_registry
161
+ end
162
+
161
163
  def install_type_declaration_extensions_for(processor_class)
162
164
  extension_module = Util.constant_value(processor_class, :TypeDeclarationExtension)
163
165
 
@@ -2,8 +2,6 @@ module Foobara
2
2
  module BuiltinTypes
3
3
  module Email
4
4
  module Transformers
5
- # Seems like it might be cleaner to just assemble these parts in one place instead of in different files?
6
- # Hard to say.
7
5
  class Downcase < BuiltinTypes::String::SupportedTransformers::Downcase
8
6
  end
9
7
  end
@@ -13,6 +13,8 @@ module Foobara
13
13
  end
14
14
  end
15
15
 
16
+ private
17
+
16
18
  def validate_original_block!
17
19
  super
18
20
 
@@ -59,8 +59,6 @@ module Foobara
59
59
  end
60
60
  end
61
61
  end
62
-
63
- foobara_delegate :type_for_declaration, to: :class
64
62
  end
65
63
  end
66
64
  end
@@ -167,8 +167,6 @@ module Foobara
167
167
  end
168
168
  end
169
169
  end
170
-
171
- foobara_delegate :type_for_declaration, to: :class
172
170
  end
173
171
  end
174
172
  end
@@ -0,0 +1,187 @@
1
+ module Foobara
2
+ class CommandConnector
3
+ module Concerns
4
+ module Reflection
5
+ include Concern
6
+
7
+ def foobara_manifest
8
+ Namespace.use command_registry do
9
+ foobara_manifest_in_current_namespace
10
+ end
11
+ end
12
+
13
+ # TODO: figure out how this is used
14
+ def all_exposed_type_names
15
+ # TODO: cache this or better yet cache #foobara_manifest
16
+ foobara_manifest[:type].keys.sort.map(&:to_s)
17
+ end
18
+
19
+ private
20
+
21
+ # TODO: try to break this giant method up
22
+ def foobara_manifest_in_current_namespace
23
+ process_delayed_connections
24
+
25
+ to_include = Set.new
26
+
27
+ to_include << command_registry.global_organization
28
+ to_include << command_registry.global_domain
29
+
30
+ command_registry.foobara_each_command(
31
+ mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE
32
+ ) do |exposed_command|
33
+ to_include << exposed_command
34
+ end
35
+
36
+ included = Set.new
37
+
38
+ additional_to_include = Set.new
39
+
40
+ h = {
41
+ organization: {},
42
+ domain: {},
43
+ type: {},
44
+ command: {},
45
+ error: {}
46
+ }
47
+
48
+ if TypeDeclarations.include_processors?
49
+ h.merge!(
50
+ processor: {},
51
+ processor_class: {}
52
+ )
53
+ end
54
+
55
+ TypeDeclarations.with_manifest_context(to_include: additional_to_include, remove_sensitive: true) do
56
+ until to_include.empty? && additional_to_include.empty?
57
+ object = nil
58
+
59
+ if to_include.empty?
60
+ until additional_to_include.empty?
61
+ o = additional_to_include.first
62
+ additional_to_include.delete(o)
63
+
64
+ if o.is_a?(::Module)
65
+ if o.foobara_domain? || o.foobara_organization?
66
+ unless o.foobara_root_namespace == command_registry
67
+ next
68
+ end
69
+ elsif o.is_a?(::Class) && o < Foobara::Command
70
+ next
71
+ end
72
+ elsif o.is_a?(Types::Type)
73
+ if o.sensitive?
74
+ # :nocov:
75
+ raise UnexpectedSensitiveTypeInManifestError,
76
+ "Unexpected sensitive type in manifest: #{o.scoped_full_path}. " \
77
+ "Make sure these are not included."
78
+ # :nocov:
79
+ else
80
+
81
+ mode = Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE
82
+ domain_name = o.foobara_domain.scoped_full_name
83
+
84
+ exposed_domain = command_registry.foobara_lookup_domain(domain_name, mode:)
85
+
86
+ exposed_domain ||= command_registry.build_and_register_exposed_domain(domain_name)
87
+
88
+ # Since we don't know which other domains/orgs creating this domain might have created,
89
+ # we will just add them all to be included just in case
90
+ command_registry.foobara_all_domain(mode:).each do |exposed_domain|
91
+ additional_to_include << exposed_domain
92
+ end
93
+
94
+ command_registry.foobara_all_organization(mode:).each do |exposed_organization|
95
+ additional_to_include << exposed_organization
96
+ end
97
+ end
98
+ end
99
+
100
+ object = o
101
+ break
102
+ end
103
+ else
104
+ object = to_include.first
105
+ to_include.delete(object)
106
+ end
107
+
108
+ break unless object
109
+ next if included.include?(object)
110
+
111
+ manifest_reference = object.foobara_manifest_reference.to_sym
112
+
113
+ category_symbol = command_registry.foobara_category_symbol_for(object)
114
+
115
+ unless category_symbol
116
+ # :nocov:
117
+ raise "no category symbol for #{object}"
118
+ # :nocov:
119
+ end
120
+
121
+ namespace = if object.is_a?(Types::Type)
122
+ object.created_in_namespace
123
+ else
124
+ Foobara::Namespace.current
125
+ end
126
+
127
+ # TODO: do we really need to enter the namespace here for this?
128
+ h[category_symbol][manifest_reference] = Foobara::Namespace.use namespace do
129
+ object.foobara_manifest
130
+ end
131
+
132
+ included << object
133
+ end
134
+ end
135
+
136
+ h[:domain].each_value do |domain_manifest|
137
+ # TODO: hack, we need to trim types down to what is actually included in this manifest
138
+ domain_manifest[:types] = domain_manifest[:types].select do |type_name|
139
+ h[:type].key?(type_name.to_sym)
140
+ end
141
+ end
142
+
143
+ h = normalize_manifest(h)
144
+ patch_up_broken_parents_for_errors_with_missing_command_parents(h)
145
+ end
146
+
147
+ def normalize_manifest(manifest_hash)
148
+ manifest_hash.map do |key, entries|
149
+ [key, entries.sort.to_h]
150
+ end.sort.to_h
151
+ end
152
+
153
+ def patch_up_broken_parents_for_errors_with_missing_command_parents(manifest_hash)
154
+ root_manifest = Manifest::RootManifest.new(manifest_hash)
155
+
156
+ error_category = {}
157
+
158
+ root_manifest.errors.each do |error|
159
+ error_manifest = if (error.parent_category == :command || error.parent_category == :organization) &&
160
+ !root_manifest.contains?(error.parent_name, error.parent_category)
161
+ domain = error.domain
162
+ index = domain.scoped_full_path.size
163
+
164
+ fixed_scoped_path = error.scoped_full_path[index..]
165
+ fixed_scoped_name = fixed_scoped_path.join("::")
166
+ fixed_scoped_prefix = fixed_scoped_path[..-2]
167
+ fixed_parent = [:domain, domain.reference]
168
+
169
+ error.relevant_manifest.merge(
170
+ parent: fixed_parent,
171
+ scoped_path: fixed_scoped_path,
172
+ scoped_name: fixed_scoped_name,
173
+ scoped_prefix: fixed_scoped_prefix
174
+ )
175
+ else
176
+ error.relevant_manifest
177
+ end
178
+
179
+ error_category[error.scoped_full_name.to_sym] = error_manifest
180
+ end
181
+
182
+ manifest_hash.merge(error: error_category)
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end