foobara 0.2.7 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +20 -7
- data/projects/builtin_types/lib/foobara/builtin_types.rb +1 -0
- data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb +1 -3
- data/projects/builtin_types/src/builtin_types.rb +6 -4
- data/projects/builtin_types/src/email/transformers/downcase.rb +0 -2
- data/projects/callback/src/block/concerns/keyword_argumentable_block.rb +2 -0
- data/projects/command/src/command_pattern_implementation/concerns/namespace.rb +0 -2
- data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +0 -2
- data/projects/command_connectors/src/command_connector/concerns/reflection.rb +187 -0
- data/projects/command_connectors/src/command_connector.rb +85 -249
- data/projects/command_connectors/src/command_registry/exposed_command.rb +6 -4
- data/projects/command_connectors/src/command_registry.rb +50 -48
- data/projects/command_connectors/src/transformed_command.rb +104 -100
- data/projects/command_connectors/src/transformers/load_atoms_transformer.rb +2 -0
- data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +2 -0
- data/projects/model_attribute_helpers/src/attribute_helpers.rb +4 -4
- data/projects/namespace/src/is_namespace.rb +1 -1
- data/projects/namespace/src/namespace/lookup_mode.rb +6 -0
- data/projects/nested_transactionable/lib/foobara/nested_transactionable.rb +0 -2
- data/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1889d43f30de1d85f60a3a6245feffbed013f4a2ad2b357fd9b61209e815ccd3
|
|
4
|
+
data.tar.gz: e57dfcd26cfb93c4f96084a61e33325644bddfd2d5d592f19e9c608f285244fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd88755c0131cab9ee13fc46b38cafc779e5799aae3c33a8289198a809af9f9a021565ccaadc41d05b5a2c02aed22aad4e9ca0b3b664c0447e488ab8993c939e
|
|
7
|
+
data.tar.gz: b9c4090428c31817a87498f261a50a986594d90e8395dfd2250bd56c963373c44d10a8faa27ec0de7500c764ebfd90b6b0ee04d523d4cd7f061041727305e903
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
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
|
+
|
|
1
6
|
# [0.2.7] - 2025-11-10
|
|
2
7
|
|
|
3
8
|
- Fix CommandConnector authorization bug that can fail to close transactions
|
data/README.md
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
-
Foobara is a software framework
|
|
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
|
-
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
|
|
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)
|
data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb
CHANGED
|
@@ -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
|
|
@@ -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
|
|
@@ -4,6 +4,7 @@ module Foobara
|
|
|
4
4
|
class AlreadyConnectedError < StandardError; end
|
|
5
5
|
|
|
6
6
|
include Concerns::Desugarizers
|
|
7
|
+
include Concerns::Reflection
|
|
7
8
|
|
|
8
9
|
class << self
|
|
9
10
|
def find_builtin_command_class(command_class_name)
|
|
@@ -144,6 +145,68 @@ module Foobara
|
|
|
144
145
|
end
|
|
145
146
|
end
|
|
146
147
|
|
|
148
|
+
def connect(*args, **opts)
|
|
149
|
+
args, opts = desugarize_connect_args(args, opts)
|
|
150
|
+
|
|
151
|
+
registerable = args.first
|
|
152
|
+
|
|
153
|
+
if opts.key?(:authenticator)
|
|
154
|
+
authenticator = opts[:authenticator]
|
|
155
|
+
authenticator = self.class.to_authenticator(authenticator)
|
|
156
|
+
opts = opts.merge(authenticator:)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
case registerable
|
|
160
|
+
when Class
|
|
161
|
+
unless registerable < Command
|
|
162
|
+
# :nocov:
|
|
163
|
+
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
164
|
+
# :nocov:
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
command_registry.register(*args, **opts)
|
|
168
|
+
when Module
|
|
169
|
+
if registerable.foobara_organization?
|
|
170
|
+
args = args[1..]
|
|
171
|
+
registerable.foobara_domains.map do |domain|
|
|
172
|
+
connect(domain, *args, **opts)
|
|
173
|
+
end.flatten
|
|
174
|
+
elsif registerable.foobara_domain?
|
|
175
|
+
args = args[1..]
|
|
176
|
+
connected = []
|
|
177
|
+
|
|
178
|
+
registerable = registerable.foobara_all_command(mode: Namespace::LookupMode::DIRECT)
|
|
179
|
+
|
|
180
|
+
registerable.each do |command_class|
|
|
181
|
+
unless command_class.abstract?
|
|
182
|
+
connected << connect(command_class, *args, **opts)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
connected.flatten
|
|
187
|
+
else
|
|
188
|
+
# :nocov:
|
|
189
|
+
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
190
|
+
# :nocov:
|
|
191
|
+
end
|
|
192
|
+
when Symbol, String
|
|
193
|
+
connect_delayed(*args, **opts)
|
|
194
|
+
else
|
|
195
|
+
# :nocov:
|
|
196
|
+
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
197
|
+
# :nocov:
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# TODO: maybe introduce a Runner interface?
|
|
202
|
+
def run(...)
|
|
203
|
+
process_delayed_connections
|
|
204
|
+
|
|
205
|
+
request = build_request(...)
|
|
206
|
+
|
|
207
|
+
run_request(request)
|
|
208
|
+
end
|
|
209
|
+
|
|
147
210
|
def find_builtin_command_class(command_class_name)
|
|
148
211
|
self.class.find_builtin_command_class(command_class_name)
|
|
149
212
|
end
|
|
@@ -166,6 +229,28 @@ module Foobara
|
|
|
166
229
|
command_registry.foobara_lookup_command(name)
|
|
167
230
|
end
|
|
168
231
|
|
|
232
|
+
def type_from_name(name)
|
|
233
|
+
Foobara.foobara_lookup_type(name, mode: Namespace::LookupMode::RELAXED)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def all_exposed_commands
|
|
237
|
+
process_delayed_connections
|
|
238
|
+
|
|
239
|
+
command_registry.foobara_all_command(mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def all_exposed_command_names
|
|
243
|
+
all_exposed_commands.map(&:full_command_name)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def command_connected?(original_command_class)
|
|
247
|
+
all_exposed_commands.any? do |command|
|
|
248
|
+
command.command_class == original_command_class
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
protected
|
|
253
|
+
|
|
169
254
|
def request_to_command_class(request)
|
|
170
255
|
action = request.action
|
|
171
256
|
full_command_name = request.full_command_name
|
|
@@ -335,59 +420,6 @@ module Foobara
|
|
|
335
420
|
delayed_connections.clear
|
|
336
421
|
end
|
|
337
422
|
|
|
338
|
-
def connect(*args, **opts)
|
|
339
|
-
args, opts = desugarize_connect_args(args, opts)
|
|
340
|
-
|
|
341
|
-
registerable = args.first
|
|
342
|
-
|
|
343
|
-
if opts.key?(:authenticator)
|
|
344
|
-
authenticator = opts[:authenticator]
|
|
345
|
-
authenticator = self.class.to_authenticator(authenticator)
|
|
346
|
-
opts = opts.merge(authenticator:)
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
case registerable
|
|
350
|
-
when Class
|
|
351
|
-
unless registerable < Command
|
|
352
|
-
# :nocov:
|
|
353
|
-
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
354
|
-
# :nocov:
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
command_registry.register(*args, **opts)
|
|
358
|
-
when Module
|
|
359
|
-
if registerable.foobara_organization?
|
|
360
|
-
args = args[1..]
|
|
361
|
-
registerable.foobara_domains.map do |domain|
|
|
362
|
-
connect(domain, *args, **opts)
|
|
363
|
-
end.flatten
|
|
364
|
-
elsif registerable.foobara_domain?
|
|
365
|
-
args = args[1..]
|
|
366
|
-
connected = []
|
|
367
|
-
|
|
368
|
-
registerable = registerable.foobara_all_command(mode: Namespace::LookupMode::DIRECT)
|
|
369
|
-
|
|
370
|
-
registerable.each do |command_class|
|
|
371
|
-
unless command_class.abstract?
|
|
372
|
-
connected << connect(command_class, *args, **opts)
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
connected.flatten
|
|
377
|
-
else
|
|
378
|
-
# :nocov:
|
|
379
|
-
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
380
|
-
# :nocov:
|
|
381
|
-
end
|
|
382
|
-
when Symbol, String
|
|
383
|
-
connect_delayed(*args, **opts)
|
|
384
|
-
else
|
|
385
|
-
# :nocov:
|
|
386
|
-
raise "Don't know how to register #{registerable} (#{registerable.class})"
|
|
387
|
-
# :nocov:
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
|
|
391
423
|
def desugarize_connect_args(args, opts)
|
|
392
424
|
if self.class.desugarizer
|
|
393
425
|
self.class.desugarizer.process_value!([args, opts])
|
|
@@ -406,15 +438,6 @@ module Foobara
|
|
|
406
438
|
end
|
|
407
439
|
end
|
|
408
440
|
|
|
409
|
-
# TODO: maybe introduce a Runner interface?
|
|
410
|
-
def run(...)
|
|
411
|
-
process_delayed_connections
|
|
412
|
-
|
|
413
|
-
request = build_request(...)
|
|
414
|
-
|
|
415
|
-
run_request(request)
|
|
416
|
-
end
|
|
417
|
-
|
|
418
441
|
def run_request(request)
|
|
419
442
|
command_class = determine_command_class(request)
|
|
420
443
|
request.command_class = command_class
|
|
@@ -495,192 +518,5 @@ module Foobara
|
|
|
495
518
|
|
|
496
519
|
response
|
|
497
520
|
end
|
|
498
|
-
|
|
499
|
-
def type_from_name(name)
|
|
500
|
-
Foobara.foobara_lookup_type(name, mode: Namespace::LookupMode::RELAXED)
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
def foobara_manifest
|
|
504
|
-
Namespace.use command_registry do
|
|
505
|
-
foobara_manifest_in_current_namespace
|
|
506
|
-
end
|
|
507
|
-
end
|
|
508
|
-
|
|
509
|
-
# TODO: try to break this giant method up
|
|
510
|
-
def foobara_manifest_in_current_namespace
|
|
511
|
-
process_delayed_connections
|
|
512
|
-
|
|
513
|
-
to_include = Set.new
|
|
514
|
-
|
|
515
|
-
to_include << command_registry.global_organization
|
|
516
|
-
to_include << command_registry.global_domain
|
|
517
|
-
|
|
518
|
-
command_registry.foobara_each_command(mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE) do |exposed_command|
|
|
519
|
-
to_include << exposed_command
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
included = Set.new
|
|
523
|
-
|
|
524
|
-
additional_to_include = Set.new
|
|
525
|
-
|
|
526
|
-
h = {
|
|
527
|
-
organization: {},
|
|
528
|
-
domain: {},
|
|
529
|
-
type: {},
|
|
530
|
-
command: {},
|
|
531
|
-
error: {}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
if TypeDeclarations.include_processors?
|
|
535
|
-
h.merge!(
|
|
536
|
-
processor: {},
|
|
537
|
-
processor_class: {}
|
|
538
|
-
)
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
TypeDeclarations.with_manifest_context(to_include: additional_to_include, remove_sensitive: true) do
|
|
542
|
-
until to_include.empty? && additional_to_include.empty?
|
|
543
|
-
object = nil
|
|
544
|
-
|
|
545
|
-
if to_include.empty?
|
|
546
|
-
until additional_to_include.empty?
|
|
547
|
-
o = additional_to_include.first
|
|
548
|
-
additional_to_include.delete(o)
|
|
549
|
-
|
|
550
|
-
if o.is_a?(::Module)
|
|
551
|
-
if o.foobara_domain? || o.foobara_organization?
|
|
552
|
-
unless o.foobara_root_namespace == command_registry
|
|
553
|
-
next
|
|
554
|
-
end
|
|
555
|
-
elsif o.is_a?(::Class) && o < Foobara::Command
|
|
556
|
-
next
|
|
557
|
-
end
|
|
558
|
-
elsif o.is_a?(Types::Type)
|
|
559
|
-
if o.sensitive?
|
|
560
|
-
# :nocov:
|
|
561
|
-
raise UnexpectedSensitiveTypeInManifestError,
|
|
562
|
-
"Unexpected sensitive type in manifest: #{o.scoped_full_path}. " \
|
|
563
|
-
"Make sure these are not included."
|
|
564
|
-
# :nocov:
|
|
565
|
-
else
|
|
566
|
-
|
|
567
|
-
mode = Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE
|
|
568
|
-
domain_name = o.foobara_domain.scoped_full_name
|
|
569
|
-
|
|
570
|
-
exposed_domain = command_registry.foobara_lookup_domain(domain_name, mode:)
|
|
571
|
-
|
|
572
|
-
exposed_domain ||= command_registry.build_and_register_exposed_domain(domain_name)
|
|
573
|
-
|
|
574
|
-
# Since we don't know which other domains/orgs creating this domain might have created,
|
|
575
|
-
# we will just add them all to be included just in case
|
|
576
|
-
command_registry.foobara_all_domain(mode:).each do |exposed_domain|
|
|
577
|
-
additional_to_include << exposed_domain
|
|
578
|
-
end
|
|
579
|
-
|
|
580
|
-
command_registry.foobara_all_organization(mode:).each do |exposed_organization|
|
|
581
|
-
additional_to_include << exposed_organization
|
|
582
|
-
end
|
|
583
|
-
end
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
object = o
|
|
587
|
-
break
|
|
588
|
-
end
|
|
589
|
-
else
|
|
590
|
-
object = to_include.first
|
|
591
|
-
to_include.delete(object)
|
|
592
|
-
end
|
|
593
|
-
|
|
594
|
-
break unless object
|
|
595
|
-
next if included.include?(object)
|
|
596
|
-
|
|
597
|
-
manifest_reference = object.foobara_manifest_reference.to_sym
|
|
598
|
-
|
|
599
|
-
category_symbol = command_registry.foobara_category_symbol_for(object)
|
|
600
|
-
|
|
601
|
-
unless category_symbol
|
|
602
|
-
# :nocov:
|
|
603
|
-
raise "no category symbol for #{object}"
|
|
604
|
-
# :nocov:
|
|
605
|
-
end
|
|
606
|
-
|
|
607
|
-
namespace = if object.is_a?(Types::Type)
|
|
608
|
-
object.created_in_namespace
|
|
609
|
-
else
|
|
610
|
-
Foobara::Namespace.current
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
# TODO: do we really need to enter the namespace here for this?
|
|
614
|
-
h[category_symbol][manifest_reference] = Foobara::Namespace.use namespace do
|
|
615
|
-
object.foobara_manifest
|
|
616
|
-
end
|
|
617
|
-
|
|
618
|
-
included << object
|
|
619
|
-
end
|
|
620
|
-
end
|
|
621
|
-
|
|
622
|
-
h[:domain].each_value do |domain_manifest|
|
|
623
|
-
# TODO: hack, we need to trim types down to what is actually included in this manifest
|
|
624
|
-
domain_manifest[:types] = domain_manifest[:types].select do |type_name|
|
|
625
|
-
h[:type].key?(type_name.to_sym)
|
|
626
|
-
end
|
|
627
|
-
end
|
|
628
|
-
|
|
629
|
-
h = normalize_manifest(h)
|
|
630
|
-
patch_up_broken_parents_for_errors_with_missing_command_parents(h)
|
|
631
|
-
end
|
|
632
|
-
|
|
633
|
-
def normalize_manifest(manifest_hash)
|
|
634
|
-
manifest_hash.map do |key, entries|
|
|
635
|
-
[key, entries.sort.to_h]
|
|
636
|
-
end.sort.to_h
|
|
637
|
-
end
|
|
638
|
-
|
|
639
|
-
def patch_up_broken_parents_for_errors_with_missing_command_parents(manifest_hash)
|
|
640
|
-
root_manifest = Manifest::RootManifest.new(manifest_hash)
|
|
641
|
-
|
|
642
|
-
error_category = {}
|
|
643
|
-
|
|
644
|
-
root_manifest.errors.each do |error|
|
|
645
|
-
error_manifest = if error.parent_category == :command &&
|
|
646
|
-
!root_manifest.contains?(error.parent_name, error.parent_category)
|
|
647
|
-
domain = error.domain
|
|
648
|
-
index = domain.scoped_full_path.size
|
|
649
|
-
|
|
650
|
-
fixed_scoped_path = error.scoped_full_path[index..]
|
|
651
|
-
fixed_scoped_name = fixed_scoped_path.join("::")
|
|
652
|
-
fixed_scoped_prefix = fixed_scoped_path[..-2]
|
|
653
|
-
fixed_parent = [:domain, domain.reference]
|
|
654
|
-
|
|
655
|
-
error.relevant_manifest.merge(
|
|
656
|
-
parent: fixed_parent,
|
|
657
|
-
scoped_path: fixed_scoped_path,
|
|
658
|
-
scoped_name: fixed_scoped_name,
|
|
659
|
-
scoped_prefix: fixed_scoped_prefix
|
|
660
|
-
)
|
|
661
|
-
else
|
|
662
|
-
error.relevant_manifest
|
|
663
|
-
end
|
|
664
|
-
|
|
665
|
-
error_category[error.scoped_full_name.to_sym] = error_manifest
|
|
666
|
-
end
|
|
667
|
-
|
|
668
|
-
manifest_hash.merge(error: error_category)
|
|
669
|
-
end
|
|
670
|
-
|
|
671
|
-
def all_exposed_commands
|
|
672
|
-
process_delayed_connections
|
|
673
|
-
|
|
674
|
-
command_registry.foobara_all_command(mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE)
|
|
675
|
-
end
|
|
676
|
-
|
|
677
|
-
def all_exposed_command_names
|
|
678
|
-
all_exposed_commands.map(&:full_command_name)
|
|
679
|
-
end
|
|
680
|
-
|
|
681
|
-
def all_exposed_type_names
|
|
682
|
-
# TODO: cache this or better yet cache #foobara_manifest
|
|
683
|
-
foobara_manifest[:type].keys.sort.map(&:to_s)
|
|
684
|
-
end
|
|
685
521
|
end
|
|
686
522
|
end
|
|
@@ -126,10 +126,6 @@ module Foobara
|
|
|
126
126
|
@transformed_command_class = nil
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def _has_delegated_attributes?(type)
|
|
130
|
-
type&.extends?(BuiltinTypes[:model]) && type.target_class&.has_delegated_attributes?
|
|
131
|
-
end
|
|
132
|
-
|
|
133
129
|
def full_command_name
|
|
134
130
|
scoped_full_name
|
|
135
131
|
end
|
|
@@ -191,6 +187,8 @@ module Foobara
|
|
|
191
187
|
end
|
|
192
188
|
end
|
|
193
189
|
|
|
190
|
+
private
|
|
191
|
+
|
|
194
192
|
# TODO: what to do if the whole return type is sensitive? return nil?
|
|
195
193
|
def result_has_sensitive_types?
|
|
196
194
|
result_type = command_class.result_type
|
|
@@ -206,6 +204,10 @@ module Foobara
|
|
|
206
204
|
command_class.result_type.has_sensitive_types?
|
|
207
205
|
end
|
|
208
206
|
end
|
|
207
|
+
|
|
208
|
+
def _has_delegated_attributes?(type)
|
|
209
|
+
type&.extends?(BuiltinTypes[:model]) && type.target_class&.has_delegated_attributes?
|
|
210
|
+
end
|
|
209
211
|
end
|
|
210
212
|
end
|
|
211
213
|
end
|
|
@@ -32,45 +32,11 @@ module Foobara
|
|
|
32
32
|
create_exposed_command(command_class, **)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def create_exposed_command(command_class, **)
|
|
36
|
-
full_domain_name = command_class.domain.scoped_full_name
|
|
37
|
-
exposed_domain = foobara_lookup_domain(full_domain_name,
|
|
38
|
-
mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE) ||
|
|
39
|
-
build_and_register_exposed_domain(full_domain_name)
|
|
40
|
-
|
|
41
|
-
exposed_command = create_exposed_command_without_domain(command_class, **)
|
|
42
|
-
|
|
43
|
-
exposed_domain.foobara_register(exposed_command)
|
|
44
|
-
|
|
45
|
-
exposed_command
|
|
46
|
-
end
|
|
47
|
-
|
|
48
35
|
# TODO: eliminate this method
|
|
49
36
|
def create_exposed_command_without_domain(command_class, **)
|
|
50
37
|
ExposedCommand.new(command_class, **apply_defaults(**))
|
|
51
38
|
end
|
|
52
39
|
|
|
53
|
-
def apply_defaults(
|
|
54
|
-
inputs_transformers: nil,
|
|
55
|
-
result_transformers: nil,
|
|
56
|
-
errors_transformers: nil,
|
|
57
|
-
pre_commit_transformers: nil,
|
|
58
|
-
serializers: nil,
|
|
59
|
-
allowed_rule: default_allowed_rule,
|
|
60
|
-
authenticator: nil,
|
|
61
|
-
**opts
|
|
62
|
-
)
|
|
63
|
-
opts.merge(
|
|
64
|
-
inputs_transformers: [*inputs_transformers, *default_inputs_transformers],
|
|
65
|
-
result_transformers: [*result_transformers, *default_result_transformers],
|
|
66
|
-
errors_transformers: [*errors_transformers, *default_errors_transformers],
|
|
67
|
-
pre_commit_transformers: [*pre_commit_transformers, *default_pre_commit_transformers],
|
|
68
|
-
serializers: [*serializers, *default_serializers],
|
|
69
|
-
allowed_rule: allowed_rule && to_allowed_rule(allowed_rule),
|
|
70
|
-
authenticator: authenticator || self.authenticator
|
|
71
|
-
)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
40
|
def build_and_register_exposed_domain(domain_full_name)
|
|
75
41
|
domain_module = if domain_full_name.to_s == ""
|
|
76
42
|
GlobalDomain
|
|
@@ -211,6 +177,37 @@ module Foobara
|
|
|
211
177
|
default_serializers << serializer
|
|
212
178
|
end
|
|
213
179
|
|
|
180
|
+
def transformed_command_from_name(name)
|
|
181
|
+
foobara_lookup_command(name, mode: Namespace::LookupMode::RELAXED)&.transformed_command_class
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def all_transformed_command_classes
|
|
185
|
+
foobara_all_command.map(&:transformed_command_class)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def each_transformed_command_class(&)
|
|
189
|
+
foobara_all_command.map(&:transformed_command_class).each(&)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def size
|
|
193
|
+
foobara_all_command.size
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
def create_exposed_command(command_class, **)
|
|
199
|
+
full_domain_name = command_class.domain.scoped_full_name
|
|
200
|
+
exposed_domain = foobara_lookup_domain(full_domain_name,
|
|
201
|
+
mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE) ||
|
|
202
|
+
build_and_register_exposed_domain(full_domain_name)
|
|
203
|
+
|
|
204
|
+
exposed_command = create_exposed_command_without_domain(command_class, **)
|
|
205
|
+
|
|
206
|
+
exposed_domain.foobara_register(exposed_command)
|
|
207
|
+
|
|
208
|
+
exposed_command
|
|
209
|
+
end
|
|
210
|
+
|
|
214
211
|
def to_allowed_rule(*args)
|
|
215
212
|
symbol, object = case args.size
|
|
216
213
|
when 1
|
|
@@ -289,20 +286,25 @@ module Foobara
|
|
|
289
286
|
end
|
|
290
287
|
end
|
|
291
288
|
|
|
292
|
-
def
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
289
|
+
def apply_defaults(
|
|
290
|
+
inputs_transformers: nil,
|
|
291
|
+
result_transformers: nil,
|
|
292
|
+
errors_transformers: nil,
|
|
293
|
+
pre_commit_transformers: nil,
|
|
294
|
+
serializers: nil,
|
|
295
|
+
allowed_rule: default_allowed_rule,
|
|
296
|
+
authenticator: nil,
|
|
297
|
+
**opts
|
|
298
|
+
)
|
|
299
|
+
opts.merge(
|
|
300
|
+
inputs_transformers: [*inputs_transformers, *default_inputs_transformers],
|
|
301
|
+
result_transformers: [*result_transformers, *default_result_transformers],
|
|
302
|
+
errors_transformers: [*errors_transformers, *default_errors_transformers],
|
|
303
|
+
pre_commit_transformers: [*pre_commit_transformers, *default_pre_commit_transformers],
|
|
304
|
+
serializers: [*serializers, *default_serializers],
|
|
305
|
+
allowed_rule: allowed_rule && to_allowed_rule(allowed_rule),
|
|
306
|
+
authenticator: authenticator || self.authenticator
|
|
307
|
+
)
|
|
306
308
|
end
|
|
307
309
|
end
|
|
308
310
|
end
|
|
@@ -425,52 +425,6 @@ module Foobara
|
|
|
425
425
|
manifest
|
|
426
426
|
end
|
|
427
427
|
|
|
428
|
-
def processors_to_manifest_symbols(processors)
|
|
429
|
-
return nil if processors.nil? || processors.empty?
|
|
430
|
-
|
|
431
|
-
to_include = TypeDeclarations.foobara_manifest_context_to_include || Set.new
|
|
432
|
-
include_processors = TypeDeclarations.include_processors?
|
|
433
|
-
|
|
434
|
-
processors.map do |processor|
|
|
435
|
-
if processor.respond_to?(:scoped_path_set?) && processor.scoped_path_set?
|
|
436
|
-
if include_processors
|
|
437
|
-
to_include << processor
|
|
438
|
-
end
|
|
439
|
-
processor.foobara_manifest_reference
|
|
440
|
-
elsif processor.is_a?(Value::Processor)
|
|
441
|
-
klass = processor.class
|
|
442
|
-
|
|
443
|
-
if klass.scoped_path_set?
|
|
444
|
-
if include_processors
|
|
445
|
-
to_include << klass
|
|
446
|
-
end
|
|
447
|
-
klass.foobara_manifest_reference
|
|
448
|
-
# TODO: Delete this nocov block
|
|
449
|
-
# TODO: make anonymous scoped path's have better names instead of random hexadecimal
|
|
450
|
-
# :nocov:
|
|
451
|
-
elsif processor.respond_to?(:symbol) && processor.symbol
|
|
452
|
-
processor.symbol
|
|
453
|
-
else
|
|
454
|
-
name = klass.name
|
|
455
|
-
|
|
456
|
-
while name.nil?
|
|
457
|
-
klass = klass.superclass
|
|
458
|
-
name = klass.name
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
"Anonymous#{Util.non_full_name(name)}"
|
|
462
|
-
# :nocov:
|
|
463
|
-
end
|
|
464
|
-
elsif processor.is_a?(::Proc)
|
|
465
|
-
"Proc"
|
|
466
|
-
else
|
|
467
|
-
# :nocov:
|
|
468
|
-
"Unknown"
|
|
469
|
-
# :nocov:
|
|
470
|
-
end
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
|
|
474
428
|
def inputs_transformer
|
|
475
429
|
return @inputs_transformer if defined?(@inputs_transformer)
|
|
476
430
|
|
|
@@ -581,6 +535,54 @@ module Foobara
|
|
|
581
535
|
end
|
|
582
536
|
end
|
|
583
537
|
end
|
|
538
|
+
|
|
539
|
+
private
|
|
540
|
+
|
|
541
|
+
def processors_to_manifest_symbols(processors)
|
|
542
|
+
return nil if processors.nil? || processors.empty?
|
|
543
|
+
|
|
544
|
+
to_include = TypeDeclarations.foobara_manifest_context_to_include || Set.new
|
|
545
|
+
include_processors = TypeDeclarations.include_processors?
|
|
546
|
+
|
|
547
|
+
processors.map do |processor|
|
|
548
|
+
if processor.respond_to?(:scoped_path_set?) && processor.scoped_path_set?
|
|
549
|
+
if include_processors
|
|
550
|
+
to_include << processor
|
|
551
|
+
end
|
|
552
|
+
processor.foobara_manifest_reference
|
|
553
|
+
elsif processor.is_a?(Value::Processor)
|
|
554
|
+
klass = processor.class
|
|
555
|
+
|
|
556
|
+
if klass.scoped_path_set?
|
|
557
|
+
if include_processors
|
|
558
|
+
to_include << klass
|
|
559
|
+
end
|
|
560
|
+
klass.foobara_manifest_reference
|
|
561
|
+
# TODO: Delete this nocov block
|
|
562
|
+
# TODO: make anonymous scoped path's have better names instead of random hexadecimal
|
|
563
|
+
# :nocov:
|
|
564
|
+
elsif processor.respond_to?(:symbol) && processor.symbol
|
|
565
|
+
processor.symbol
|
|
566
|
+
else
|
|
567
|
+
name = klass.name
|
|
568
|
+
|
|
569
|
+
while name.nil?
|
|
570
|
+
klass = klass.superclass
|
|
571
|
+
name = klass.name
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
"Anonymous#{Util.non_full_name(name)}"
|
|
575
|
+
# :nocov:
|
|
576
|
+
end
|
|
577
|
+
elsif processor.is_a?(::Proc)
|
|
578
|
+
"Proc"
|
|
579
|
+
else
|
|
580
|
+
# :nocov:
|
|
581
|
+
"Unknown"
|
|
582
|
+
# :nocov:
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
584
586
|
end
|
|
585
587
|
|
|
586
588
|
attr_accessor :command, :untransformed_inputs, :transformed_inputs, :outcome, :request
|
|
@@ -626,23 +628,6 @@ module Foobara
|
|
|
626
628
|
request.authenticated_credential
|
|
627
629
|
end
|
|
628
630
|
|
|
629
|
-
def transform_inputs
|
|
630
|
-
transformer = self.class.inputs_transformer
|
|
631
|
-
|
|
632
|
-
self.transformed_inputs = if transformer&.applicable?(untransformed_inputs)
|
|
633
|
-
outcome = transformer.process_value(untransformed_inputs)
|
|
634
|
-
|
|
635
|
-
if outcome.success?
|
|
636
|
-
outcome.result
|
|
637
|
-
else
|
|
638
|
-
self.outcome = outcome
|
|
639
|
-
untransformed_inputs
|
|
640
|
-
end
|
|
641
|
-
else
|
|
642
|
-
untransformed_inputs
|
|
643
|
-
end
|
|
644
|
-
end
|
|
645
|
-
|
|
646
631
|
def inputs
|
|
647
632
|
return @inputs if defined?(@inputs)
|
|
648
633
|
|
|
@@ -727,6 +712,60 @@ module Foobara
|
|
|
727
712
|
end
|
|
728
713
|
end
|
|
729
714
|
|
|
715
|
+
def result
|
|
716
|
+
outcome.result
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
def errors
|
|
720
|
+
outcome.errors
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# TODO: kill this
|
|
724
|
+
def serialize_result(body)
|
|
725
|
+
if serializer
|
|
726
|
+
serializer.process_value!(body)
|
|
727
|
+
else
|
|
728
|
+
body
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def raw_inputs
|
|
733
|
+
untransformed_inputs
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
def method_missing(method_name, ...)
|
|
737
|
+
if command.respond_to?(method_name)
|
|
738
|
+
command.send(method_name, ...)
|
|
739
|
+
else
|
|
740
|
+
# :nocov:
|
|
741
|
+
super
|
|
742
|
+
# :nocov:
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def respond_to_missing?(method_name, private = false)
|
|
747
|
+
command.respond_to?(method_name, private) || super
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
private
|
|
751
|
+
|
|
752
|
+
def transform_inputs
|
|
753
|
+
transformer = self.class.inputs_transformer
|
|
754
|
+
|
|
755
|
+
self.transformed_inputs = if transformer&.applicable?(untransformed_inputs)
|
|
756
|
+
outcome = transformer.process_value(untransformed_inputs)
|
|
757
|
+
|
|
758
|
+
if outcome.success?
|
|
759
|
+
outcome.result
|
|
760
|
+
else
|
|
761
|
+
self.outcome = outcome
|
|
762
|
+
untransformed_inputs
|
|
763
|
+
end
|
|
764
|
+
else
|
|
765
|
+
untransformed_inputs
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
730
769
|
def construct_command
|
|
731
770
|
self.command = command_class.new(transformed_inputs)
|
|
732
771
|
end
|
|
@@ -804,18 +843,6 @@ module Foobara
|
|
|
804
843
|
end
|
|
805
844
|
end
|
|
806
845
|
|
|
807
|
-
def result
|
|
808
|
-
outcome.result
|
|
809
|
-
end
|
|
810
|
-
|
|
811
|
-
def errors
|
|
812
|
-
outcome.errors
|
|
813
|
-
end
|
|
814
|
-
|
|
815
|
-
def flush_transactions
|
|
816
|
-
request.opened_transactions&.reverse&.each(&:flush!)
|
|
817
|
-
end
|
|
818
|
-
|
|
819
846
|
def transform_outcome
|
|
820
847
|
if outcome.success?
|
|
821
848
|
# can we do this while still in the transaction of the command???
|
|
@@ -825,31 +852,8 @@ module Foobara
|
|
|
825
852
|
end
|
|
826
853
|
end
|
|
827
854
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
if serializer
|
|
831
|
-
serializer.process_value!(body)
|
|
832
|
-
else
|
|
833
|
-
body
|
|
834
|
-
end
|
|
835
|
-
end
|
|
836
|
-
|
|
837
|
-
def raw_inputs
|
|
838
|
-
untransformed_inputs
|
|
839
|
-
end
|
|
840
|
-
|
|
841
|
-
def method_missing(method_name, ...)
|
|
842
|
-
if command.respond_to?(method_name)
|
|
843
|
-
command.send(method_name, ...)
|
|
844
|
-
else
|
|
845
|
-
# :nocov:
|
|
846
|
-
super
|
|
847
|
-
# :nocov:
|
|
848
|
-
end
|
|
849
|
-
end
|
|
850
|
-
|
|
851
|
-
def respond_to_missing?(method_name, private = false)
|
|
852
|
-
command.respond_to?(method_name, private) || super
|
|
855
|
+
def flush_transactions
|
|
856
|
+
request.opened_transactions&.reverse&.each(&:flush!)
|
|
853
857
|
end
|
|
854
858
|
end
|
|
855
859
|
end
|
|
@@ -18,7 +18,7 @@ module Foobara
|
|
|
18
18
|
# foobara_primary_key_type (nil if not an entity type)
|
|
19
19
|
# foobara_associations
|
|
20
20
|
module AttributeHelpers
|
|
21
|
-
include
|
|
21
|
+
include Concern
|
|
22
22
|
|
|
23
23
|
module ClassMethods
|
|
24
24
|
def foobara_has_primary_key?
|
|
@@ -46,15 +46,15 @@ module Foobara
|
|
|
46
46
|
|
|
47
47
|
Namespace.use foobara_attributes_type.created_in_namespace do
|
|
48
48
|
unless includes_primary_key
|
|
49
|
-
declaration =
|
|
49
|
+
declaration = TypeDeclarations::Attributes.reject(declaration, foobara_primary_key_attribute)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
unless include_private
|
|
53
|
-
declaration =
|
|
53
|
+
declaration = TypeDeclarations::Attributes.reject(declaration, *private_attribute_names)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
unless include_delegates
|
|
57
|
-
declaration =
|
|
57
|
+
declaration = TypeDeclarations::Attributes.reject(declaration, *foobara_delegates.keys)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
Domain.current.foobara_type_from_declaration(declaration)
|
|
@@ -30,6 +30,12 @@ module Foobara
|
|
|
30
30
|
# Maybe use bitmasks for the above 3 places to look instead of a list of 7 lookup types? (There should be 8...)
|
|
31
31
|
module LookupMode
|
|
32
32
|
GENERAL = :general
|
|
33
|
+
# Relaxed will allow you to find registered entries without prefixes as long as it's not ambiguous
|
|
34
|
+
# So if there is a SomeOrg::SomeDomain::SomeCommand `GlobalOrganization.foobara_lookup(:SomeCommand)`
|
|
35
|
+
# will return nil but
|
|
36
|
+
# `GlobalOrganization.foobara_lookup(:SomeCommand, mode: Foobara::Namespace::LookupMode::RELAXED)`
|
|
37
|
+
# will return SomeOrg::SomeDomain::SomeCommand even though we didn't specify the necessary prefixes
|
|
38
|
+
# to navigate to it.
|
|
33
39
|
RELAXED = :relaxed
|
|
34
40
|
DIRECT = :direct
|
|
35
41
|
STRICT = :strict
|
data/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foobara
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miles Georgi
|
|
@@ -190,6 +190,7 @@ files:
|
|
|
190
190
|
- projects/command_connectors/src/command_connector/commands/ping.rb
|
|
191
191
|
- projects/command_connectors/src/command_connector/commands/query_git_commit_info.rb
|
|
192
192
|
- projects/command_connectors/src/command_connector/concerns/desugarizers.rb
|
|
193
|
+
- projects/command_connectors/src/command_connector/concerns/reflection.rb
|
|
193
194
|
- projects/command_connectors/src/command_connector/invalid_context_error.rb
|
|
194
195
|
- projects/command_connectors/src/command_connector/no_command_found_error.rb
|
|
195
196
|
- projects/command_connectors/src/command_connector/no_command_or_type_found_error.rb
|