foobara 0.0.125 → 0.0.127
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 +13 -0
- data/README.md +86 -19
- data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/desugarizers/move_defaults_from_element_types_to_root.rb +1 -1
- data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/desugarizers/move_required_from_element_types_to_root.rb +1 -1
- data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_type_desugarizer.rb +32 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of.rb +10 -0
- data/projects/command/src/command/concerns/shortcut_for_run.rb +2 -0
- data/projects/command/src/command_pattern_implementation/concerns/inputs.rb +0 -2
- data/projects/command/src/command_pattern_implementation/concerns/runtime.rb +2 -1
- data/projects/command/src/command_pattern_implementation/concerns/subcommands.rb +2 -0
- data/projects/command_connectors/src/command_connector.rb +5 -0
- data/projects/command_connectors/src/transformed_command.rb +25 -0
- data/projects/detached_entity/src/concerns/associations.rb +1 -1
- data/projects/domain_mapper/src/domain_mapper_lookups.rb +2 -2
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +1 -0
- data/projects/nested_transactionable/lib/foobara/nested_transactionable.rb +31 -1
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb +2 -1
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/handlers/registered_type_declaration.rb +3 -1
- data/projects/types/src/type.rb +23 -5
- data/projects/value/src/processor/casting.rb +3 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 531c75e332f6e7cc297b0b56689d91f59737040fe533814a8b780defc937b2aa
|
4
|
+
data.tar.gz: 16dd8725423abe9155c1fd5b89c752271ce568ec83cca52c7654204ee114f559
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c97ed1f00a114ea3ff8e1932cb32a13e8e538b1a0dc694f542060febafcae9e515e4888695cdbeede192e490ea280e6bddf8bf54b64e6339fe7adeaaeaa42a1
|
7
|
+
data.tar.gz: 4e414afd9090bc83685ce1b2e30fb31948963f4d57cff4d77ba4aa698547e716fd5a562442845f60cd8e6affb06263797fcf0c539a7f5478fceb9dec6b1412de
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# [0.0.127] - 2025-05-25
|
2
|
+
|
3
|
+
- Add better support for using ruby classes as types
|
4
|
+
- Support using :attributes as a type directly
|
5
|
+
- Make TransformedCommand#inputs reflect actual received inputs not transformed inputs
|
6
|
+
- Add NestedTransactionable.with_needed_transactions_for_type
|
7
|
+
|
8
|
+
# [0.0.126] - 2025-05-21
|
9
|
+
|
10
|
+
- Fix bugs with transactions, Command.depends_on
|
11
|
+
- Allow anonymous commands
|
12
|
+
- Add CommandConnector#all_exposed_type_names
|
13
|
+
|
1
14
|
# [0.0.125] - 2025-05-15
|
2
15
|
|
3
16
|
- Create a yaml inputs sugar
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
Foobara is a software framework
|
2
|
-
|
3
|
-
|
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.
|
4
|
+
|
5
|
+
This, as well as some other features of foobara, help manage domain complexity and produce
|
6
|
+
more flexible systems with better management of domain complexity.
|
4
7
|
|
5
8
|
You can watch a video that gives a good overview of what Foobara is and its goals here:
|
6
9
|
[Introduction to the Foobara software framework](https://youtu.be/SSOmQqjNSVY)
|
@@ -24,6 +27,7 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
24
27
|
* [HTTP Command Connectors](#http-command-connectors)
|
25
28
|
* [Rack Connector](#rack-connector)
|
26
29
|
* [Rails Connector](#rails-connector)
|
30
|
+
* [MCP Command Connector](#mcp-command-connector)
|
27
31
|
* [Async Command Connectors](#async-command-connectors)
|
28
32
|
* [Scheduler Command Connectors](#scheduler-command-connectors)
|
29
33
|
* [Intermediate Foobara](#intermediate-foobara)
|
@@ -51,6 +55,7 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
51
55
|
* [Namespaces](#namespaces)
|
52
56
|
* [Value processors](#value-processors)
|
53
57
|
* [Additional learning materials/Documentation](#additional-learning-materialsdocumentation)
|
58
|
+
* [Help](#help)
|
54
59
|
* [Contributing](#contributing)
|
55
60
|
* [Developing locally](#developing-locally)
|
56
61
|
* [Monorepo Structure](#monorepo-structure)
|
@@ -67,7 +72,7 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
67
72
|
|
68
73
|
## Discoverability
|
69
74
|
|
70
|
-
* This means there is a formal machine-readable description of the systems/subsystems
|
75
|
+
* This means there is a formal, machine-readable, description of the systems/subsystems
|
71
76
|
* The implication of this is that integration code can be abstracted away.
|
72
77
|
|
73
78
|
## Implications of command-centric + discoverability
|
@@ -75,6 +80,7 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
75
80
|
* The system better communicates the mental model of the problem and the chosen solution
|
76
81
|
* Engineers are able to spend more time writing code relevant to the domain and less time
|
77
82
|
writing code related to specific tech-stack, software pattern, or architecture decisions.
|
83
|
+
* Engineers are much less likely to harmfully couple domain logic to integration logic.
|
78
84
|
* Engineers can spend more time operating within a specific mental model at a time instead of
|
79
85
|
multiple mental models all at once.
|
80
86
|
|
@@ -86,14 +92,14 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
86
92
|
* Domains are namespaces of Commands, types, and errors
|
87
93
|
* Domains (and commands) have explicit, unidirectional dependencies on other domains
|
88
94
|
* Organizations are namespaces of Domains
|
89
|
-
* Domain mappers
|
90
|
-
* These can map a concept from one domain to another
|
91
|
-
* This separation of concerns leads to commands that have code
|
92
|
-
that reflects the domain they belong to as opposed to logic from many different domains
|
93
95
|
* Remote commands
|
94
96
|
* These have the same interface as commands that live in other systems and act as a proxy to them
|
95
97
|
* This allows rearchitecting of systems without changing interfaces and so reducing refactoring/testing required
|
96
98
|
* These currently exist for both Ruby and Typescript
|
99
|
+
* Domain mappers
|
100
|
+
* These can map a concept from one domain to another
|
101
|
+
* This separation of concerns leads to commands that have code
|
102
|
+
that reflects the domain they belong to as opposed to logic from many different domains
|
97
103
|
* Code generators
|
98
104
|
* Similar to remote commands, discoverability enables other types of tooling, including code generators,
|
99
105
|
documentation tools, etc
|
@@ -107,8 +113,6 @@ You can watch a video that gives a good overview of what Foobara is and its goal
|
|
107
113
|
# Installation
|
108
114
|
|
109
115
|
To add foobara to an existing project, you can add `foobara` gem to your Gemfile or .gemspec as you normally would.
|
110
|
-
You can also `gem install foobara` and whatever additional foobara gems you need and use them in
|
111
|
-
scripts by requiring them.
|
112
116
|
|
113
117
|
You could also use a generator to create a new Ruby Foobara project using the `foob` gem with `gem install foob` and
|
114
118
|
then run `foob generate ruby-project --name your-org/your-new-project-name`
|
@@ -344,7 +348,7 @@ We have so far seen one Foobara type which is `integer` but there are many other
|
|
344
348
|
We used :integer to type the operands of our Add command. There are many ways to express types in Foobara
|
345
349
|
but in this case we used the attributes DSL. It has the form:
|
346
350
|
|
347
|
-
`<
|
351
|
+
`<attribute_name> <type_symbol> [processors] [description]`
|
348
352
|
|
349
353
|
We used a processor `:required` but there are many others and you can create your own.
|
350
354
|
|
@@ -830,6 +834,67 @@ end
|
|
830
834
|
|
831
835
|
This has the same effect as the previous code and is just a stylistic alternative.
|
832
836
|
|
837
|
+
### MCP Command Connector
|
838
|
+
|
839
|
+
We can have an MCP server for free for our commands. Let's try it!
|
840
|
+
|
841
|
+
Let's simulate some bad data and expose some commands over MCP and ask an
|
842
|
+
MCP client like Claude Code to find/fix the bad data.
|
843
|
+
|
844
|
+
```ruby
|
845
|
+
CreateCapybara.run!(name: "Fumiko", year_of_birth: 2020)
|
846
|
+
# Simulate a year accidentally entered with a 2-digit format where a 4-digit format was expected:
|
847
|
+
CreateCapybara.run!(name: "Barbara", year_of_birth: 19)
|
848
|
+
CreateCapybara.run!(name: "Basil", year_of_birth: 2021)
|
849
|
+
|
850
|
+
mcp_connector = Foobara::McpConnector.new
|
851
|
+
|
852
|
+
mcp_connector.connect(FindAllCapybaras)
|
853
|
+
mcp_connector.connect(UpdateCapybara)
|
854
|
+
|
855
|
+
mcp_connector.run_stdio_server
|
856
|
+
```
|
857
|
+
|
858
|
+
Oh whoops, somebody entered Barbara's year of birth as 19 instead of 2019, whoops!
|
859
|
+
Let's ask Claude Code to find/fix the bad record:
|
860
|
+
|
861
|
+
```
|
862
|
+
$ claude
|
863
|
+
> Hi! There's a Capybara whose birth year was entered incorrectly. Can you find which one
|
864
|
+
and fix it? Thanks!
|
865
|
+
● I'll help find and fix the capybara with the incorrect birth year. Let me search for the
|
866
|
+
capybaras first.
|
867
|
+
● mcp-test:FindAllCapybaras (MCP)()…
|
868
|
+
⎿ [
|
869
|
+
{
|
870
|
+
"name": "Fumiko",
|
871
|
+
"year_of_birth": 2020,
|
872
|
+
"id": 1
|
873
|
+
|
874
|
+
… +7 lines (ctrl+r to expand)
|
875
|
+
|
876
|
+
"name": "Basil",
|
877
|
+
"year_of_birth": 2021,
|
878
|
+
"id": 3
|
879
|
+
}
|
880
|
+
]
|
881
|
+
● It looks like Barbara (id 2) has an incorrect birth year of 19, which is too low. Let me
|
882
|
+
fix that to 2019.
|
883
|
+
● mcp-test:UpdateCapybara (MCP)(id: 2, year_of_birth: 2019)…
|
884
|
+
⎿ {
|
885
|
+
"name": "Barbara",
|
886
|
+
"year_of_birth": 2019,
|
887
|
+
"id": 2
|
888
|
+
}
|
889
|
+
● Fixed! Barbara's birth year has been updated from 19 to 2019.
|
890
|
+
> Great! Thanks!
|
891
|
+
● You're welcome!
|
892
|
+
```
|
893
|
+
Record fixed! A benefit of encapsulating your high-level domain operations behind commands that have machine-readable
|
894
|
+
formal manifests describing them is easy tooling like this.
|
895
|
+
|
896
|
+
See https://github.com/foobara/mcp-connector for details on how to do this if interested.
|
897
|
+
|
833
898
|
#### Async Command Connectors
|
834
899
|
|
835
900
|
Let's connect a command to some sort of async job solution. We'll connect our IncrementAge command to Resque:
|
@@ -2041,17 +2106,19 @@ TODO: give some code examples
|
|
2041
2106
|
* All docs combined: https://docs.foobara.com/all/
|
2042
2107
|
* Per-repository docs: https://foobara.com/docs
|
2043
2108
|
|
2044
|
-
#
|
2109
|
+
# Help
|
2045
2110
|
|
2046
|
-
|
2047
|
-
forms of help. We could pair on what you have in mind and you could drive or at least we can make sure
|
2048
|
-
it's a good use of time. I can be reached at azimux@gmail.com
|
2111
|
+
Are you actually trying to build something with Foobara? Happy to help! miles@foobara.com
|
2049
2112
|
|
2050
|
-
|
2113
|
+
# Contributing
|
2051
2114
|
|
2052
|
-
|
2115
|
+
There are many ways you could help! There are tasks in the codebase for all skill levels including absolute beginner.
|
2116
|
+
There's also much need for improved documentation. If you're interested in helping but don't know how, then
|
2117
|
+
please reach out! miles@foobara.com
|
2053
2118
|
|
2054
|
-
|
2119
|
+
You are welcome to also contribute via a github pull request or open issues for bugs.
|
2120
|
+
Make sure the test suite and linter pass locally before opening a pull request as
|
2121
|
+
the build will fail if test coverage is below 100%.
|
2055
2122
|
|
2056
2123
|
## Developing locally
|
2057
2124
|
|
@@ -2068,7 +2135,7 @@ And if the tests/linter pass then you could dive into modifying the code
|
|
2068
2135
|
|
2069
2136
|
## Monorepo Structure
|
2070
2137
|
|
2071
|
-
Foobara is split up into many projects
|
2138
|
+
Foobara is split up into many, many projects
|
2072
2139
|
|
2073
2140
|
Many are in separate repositories which you can see at: https://github.com/orgs/foobara/repositories
|
2074
2141
|
|
@@ -8,7 +8,7 @@ module Foobara
|
|
8
8
|
module Desugarizers
|
9
9
|
class MoveDefaultsFromElementTypesToRoot < TypeDeclarations::Desugarizer
|
10
10
|
def applicable?(value)
|
11
|
-
value.is_a?(::Hash) && value[:type] == :attributes
|
11
|
+
value.is_a?(::Hash) && value[:type] == :attributes && value.key?(:element_type_declarations)
|
12
12
|
end
|
13
13
|
|
14
14
|
def desugarize(rawish_type_declaration)
|
@@ -8,7 +8,7 @@ module Foobara
|
|
8
8
|
module Desugarizers
|
9
9
|
class MoveRequiredFromElementTypesToRoot < TypeDeclarations::Desugarizer
|
10
10
|
def applicable?(value)
|
11
|
-
value.is_a?(::Hash) && value[:type] == :attributes
|
11
|
+
value.is_a?(::Hash) && value[:type] == :attributes && value.key?(:element_type_declarations)
|
12
12
|
end
|
13
13
|
|
14
14
|
def desugarize(rawish_type_declaration)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Foobara
|
2
|
+
module BuiltinTypes
|
3
|
+
module Duck
|
4
|
+
module SupportedValidators
|
5
|
+
class InstanceOf < TypeDeclarations::Validator
|
6
|
+
module TypeDeclarationExtension
|
7
|
+
module ExtendRegisteredTypeDeclaration
|
8
|
+
module Desugarizers
|
9
|
+
class ClassTypeDesugarizer < TypeDeclarations::Desugarizer
|
10
|
+
def applicable?(rawish_type_declaration)
|
11
|
+
return false unless rawish_type_declaration.is_a?(::Hash)
|
12
|
+
|
13
|
+
rawish_type_declaration[:type].is_a?(::Class)
|
14
|
+
end
|
15
|
+
|
16
|
+
def desugarize(rawish_type_declaration)
|
17
|
+
klass = rawish_type_declaration[:type]
|
18
|
+
rawish_type_declaration.merge(type: :duck, instance_of: klass.name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def priority
|
22
|
+
Priority::LOWEST + 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -14,6 +14,16 @@ module Foobara
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
class << self
|
18
|
+
def requires_parent_declaration_data?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def applicable?(value)
|
24
|
+
!value.nil? || !parent_declaration_data[:allow_nil]
|
25
|
+
end
|
26
|
+
|
17
27
|
def expected_class_name
|
18
28
|
declaration_data
|
19
29
|
end
|
@@ -19,6 +19,8 @@ module Foobara
|
|
19
19
|
|
20
20
|
module ClassMethods
|
21
21
|
def define_command_named_function
|
22
|
+
return if name.nil?
|
23
|
+
|
22
24
|
command_class = self
|
23
25
|
convenience_method_name = Foobara::Util.non_full_name(command_class)
|
24
26
|
containing_module = Foobara::Util.module_for(command_class) || Object
|
@@ -644,5 +644,10 @@ module Foobara
|
|
644
644
|
|
645
645
|
command_registry.foobara_all_command(mode: Namespace::LookupMode::ABSOLUTE)
|
646
646
|
end
|
647
|
+
|
648
|
+
def all_exposed_type_names
|
649
|
+
# TODO: cache this or better yet cache #foobara_manifest
|
650
|
+
foobara_manifest[:type].keys.sort.map(&:to_s)
|
651
|
+
end
|
647
652
|
end
|
648
653
|
end
|
@@ -578,6 +578,7 @@ module Foobara
|
|
578
578
|
def run
|
579
579
|
apply_allowed_rule
|
580
580
|
apply_pre_commit_transformers
|
581
|
+
set_inputs
|
581
582
|
run_command
|
582
583
|
# this gives us primary keys
|
583
584
|
flush_transactions
|
@@ -609,6 +610,22 @@ module Foobara
|
|
609
610
|
end
|
610
611
|
end
|
611
612
|
|
613
|
+
def inputs
|
614
|
+
return @inputs if defined?(@inputs)
|
615
|
+
|
616
|
+
@inputs = if inputs_type
|
617
|
+
outcome = inputs_type.process_value(untransformed_inputs)
|
618
|
+
|
619
|
+
if outcome.success?
|
620
|
+
outcome.result
|
621
|
+
else
|
622
|
+
untransformed_inputs
|
623
|
+
end
|
624
|
+
else
|
625
|
+
{}
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
612
629
|
def transform_result
|
613
630
|
if self.class.result_transformer
|
614
631
|
self.outcome = Outcome.success(self.class.result_transformer.process_value!(result))
|
@@ -723,6 +740,14 @@ module Foobara
|
|
723
740
|
end
|
724
741
|
end
|
725
742
|
|
743
|
+
def set_inputs
|
744
|
+
if self.class.inputs_type
|
745
|
+
command.after_cast_and_validate_inputs do |**|
|
746
|
+
inputs
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
726
751
|
def run_command
|
727
752
|
outcome = command.run
|
728
753
|
self.outcome = outcome if outcome
|
@@ -187,7 +187,7 @@ module Foobara
|
|
187
187
|
construct_associations(element_type, path.append(:"#"), result, initial: false)
|
188
188
|
end
|
189
189
|
elsif type.extends?(BuiltinTypes[:attributes]) # TODO: matches attributes itself instead of only subtypes
|
190
|
-
type.element_types
|
190
|
+
type.element_types&.each_pair do |attribute_name, element_type|
|
191
191
|
if remove_sensitive && element_type.sensitive?
|
192
192
|
next
|
193
193
|
end
|
@@ -89,9 +89,9 @@ module Foobara
|
|
89
89
|
|
90
90
|
unless strict
|
91
91
|
if from
|
92
|
-
lookup_matching_domain_mapper(from: nil, to:)
|
92
|
+
lookup_matching_domain_mapper(from: nil, to:, criteria:)
|
93
93
|
elsif to
|
94
|
-
lookup_matching_domain_mapper(from:, to: nil)
|
94
|
+
lookup_matching_domain_mapper(from:, to: nil, criteria:)
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
@@ -10,6 +10,7 @@ module Foobara
|
|
10
10
|
type_symbol = strict_type_declaration[:type]
|
11
11
|
|
12
12
|
return false if type_symbol == expected_type_symbol
|
13
|
+
return false unless type_symbol.is_a?(::Symbol) || type_symbol.is_a?(::String)
|
13
14
|
|
14
15
|
if type_registered?(type_symbol)
|
15
16
|
type = lookup_type!(type_symbol)
|
@@ -17,6 +17,33 @@ module Foobara
|
|
17
17
|
|
18
18
|
entity_classes.uniq
|
19
19
|
end
|
20
|
+
|
21
|
+
def with_needed_transactions_for_type(type, &)
|
22
|
+
relevant_entity_classes = relevant_entity_classes_for_type(type)
|
23
|
+
|
24
|
+
if relevant_entity_classes.empty?
|
25
|
+
return yield
|
26
|
+
end
|
27
|
+
|
28
|
+
tx_class = Class.new
|
29
|
+
tx_class.include NestedTransactionable
|
30
|
+
|
31
|
+
tx_class.define_method(:relevant_entity_classes) do
|
32
|
+
relevant_entity_classes
|
33
|
+
end
|
34
|
+
|
35
|
+
tx_instance = tx_class.new
|
36
|
+
|
37
|
+
begin
|
38
|
+
tx_instance.open_transaction
|
39
|
+
result = Persistence::EntityBase.using_transactions(tx_instance.transactions, &)
|
40
|
+
tx_instance.commit_transaction
|
41
|
+
result
|
42
|
+
rescue
|
43
|
+
tx_instance.rollback_transaction
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
end
|
20
47
|
end
|
21
48
|
|
22
49
|
def relevant_entity_classes_for_type(type)
|
@@ -45,7 +72,10 @@ module Foobara
|
|
45
72
|
|
46
73
|
bases.each do |base|
|
47
74
|
tx = base.current_transaction
|
48
|
-
|
75
|
+
|
76
|
+
if tx&.open?
|
77
|
+
transactions << tx
|
78
|
+
end
|
49
79
|
end
|
50
80
|
end
|
51
81
|
|
data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb
CHANGED
@@ -17,7 +17,8 @@ module Foobara
|
|
17
17
|
type_symbol = sugary_type_declaration[:type]
|
18
18
|
|
19
19
|
if [:attributes, "attributes"].include?(type_symbol)
|
20
|
-
|
20
|
+
sugary_type_declaration.key?(:element_type_declarations) &&
|
21
|
+
Util.all_symbolizable_keys?(sugary_type_declaration[:element_type_declarations])
|
21
22
|
elsif type_symbol.is_a?(::Symbol)
|
22
23
|
# Why is this done?
|
23
24
|
!type_registered?(type_symbol)
|
@@ -9,7 +9,7 @@ module Foobara
|
|
9
9
|
def transform(strict_type_declaration)
|
10
10
|
super.tap do |type|
|
11
11
|
type_declarations = type.declaration_data[:element_type_declarations]
|
12
|
-
type.element_types = type_declarations
|
12
|
+
type.element_types = type_declarations&.transform_values do |attribute_declaration|
|
13
13
|
type_for_declaration(attribute_declaration)
|
14
14
|
end
|
15
15
|
end
|
@@ -13,7 +13,9 @@ module Foobara
|
|
13
13
|
# we only handle case where it's a builtin type not an extension of one
|
14
14
|
if strict_type_declaration.keys == [:type]
|
15
15
|
type_symbol = strict_type_declaration[:type]
|
16
|
-
|
16
|
+
if type_symbol.is_a?(::Symbol) || type_symbol.is_a?(::String)
|
17
|
+
type_registered?(type_symbol)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
data/projects/types/src/type.rb
CHANGED
@@ -35,7 +35,7 @@ module Foobara
|
|
35
35
|
:element_type
|
36
36
|
|
37
37
|
def initialize(
|
38
|
-
|
38
|
+
declaration_data,
|
39
39
|
target_classes:,
|
40
40
|
base_type:,
|
41
41
|
description: nil,
|
@@ -52,10 +52,12 @@ module Foobara
|
|
52
52
|
sensitive_exposed: nil,
|
53
53
|
**opts
|
54
54
|
)
|
55
|
+
self.declaration_data = declaration_data
|
55
56
|
self.sensitive = sensitive
|
56
57
|
self.sensitive_exposed = sensitive_exposed
|
57
58
|
self.base_type = base_type
|
58
59
|
self.description = description
|
60
|
+
self.name = name
|
59
61
|
self.casters = [*casters, *base_type&.casters]
|
60
62
|
self.transformers = [*transformers, *base_type&.transformers]
|
61
63
|
self.validators = [*validators, *base_type&.validators]
|
@@ -65,11 +67,10 @@ module Foobara
|
|
65
67
|
# TODO: combine these maybe with the term "children_types"?
|
66
68
|
self.element_types = element_types
|
67
69
|
self.element_type = element_type
|
68
|
-
self.name = name
|
69
70
|
self.target_classes = Util.array(target_classes)
|
70
71
|
self.processor_classes_requiring_type = processor_classes_requiring_type
|
71
72
|
|
72
|
-
super(
|
73
|
+
super(declaration_data, **opts.merge(processors:, prioritize: false))
|
73
74
|
|
74
75
|
apply_all_processors_needing_type!
|
75
76
|
|
@@ -274,8 +275,25 @@ module Foobara
|
|
274
275
|
end
|
275
276
|
|
276
277
|
def value_caster
|
277
|
-
# TODO:
|
278
|
-
|
278
|
+
# TODO: figure out what would be needed to successfully memoize this
|
279
|
+
# return @value_caster if defined?(@value_caster)
|
280
|
+
|
281
|
+
# We make this exception for :duck because it will match any instance of
|
282
|
+
# Object but AllowNil will match nil which is also an instance of Object.
|
283
|
+
# This results in two matching casters. Instead of figuring out a way to make one
|
284
|
+
# conditional on the other we will just turn off this unique enforcement for :duck
|
285
|
+
enforce_unique = if declaration_data.is_a?(::Hash)
|
286
|
+
declaration_data[:type] != :duck
|
287
|
+
else
|
288
|
+
true
|
289
|
+
end
|
290
|
+
|
291
|
+
Value::Processor::Casting.new(
|
292
|
+
{ cast_to: declaration_data },
|
293
|
+
casters:,
|
294
|
+
target_classes:,
|
295
|
+
enforce_unique:
|
296
|
+
)
|
279
297
|
end
|
280
298
|
|
281
299
|
def applicable?(value)
|
@@ -39,7 +39,7 @@ module Foobara
|
|
39
39
|
|
40
40
|
attr_accessor :target_classes
|
41
41
|
|
42
|
-
def initialize(*, casters:, target_classes: nil)
|
42
|
+
def initialize(*, casters:, target_classes: nil, **)
|
43
43
|
self.target_classes = Util.array(target_classes)
|
44
44
|
|
45
45
|
processors = [
|
@@ -47,7 +47,7 @@ module Foobara
|
|
47
47
|
*casters
|
48
48
|
]
|
49
49
|
|
50
|
-
super(*, processors
|
50
|
+
super(*, processors:, **)
|
51
51
|
end
|
52
52
|
|
53
53
|
def needs_cast?(value)
|
@@ -113,7 +113,7 @@ module Foobara
|
|
113
113
|
build_error(*args)
|
114
114
|
elsif error_class == MoreThanOneApplicableProcessorError
|
115
115
|
# :nocov:
|
116
|
-
raise "Matched too many casters for #{args.inspect} with #{opts.inspect}"
|
116
|
+
raise "Matched too many casters for #{args.map(&:inspect).join(",")} with #{opts.inspect}"
|
117
117
|
# :nocov:
|
118
118
|
else
|
119
119
|
super
|
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.
|
4
|
+
version: 0.0.127
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 2025-05-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bigdecimal
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- projects/builtin_types/src/duck/supported_casters/allow_nil.rb
|
117
117
|
- projects/builtin_types/src/duck/supported_validators/instance_of.rb
|
118
118
|
- projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_desugarizer.rb
|
119
|
+
- projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_type_desugarizer.rb
|
119
120
|
- projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_class_desugarizer.rb
|
120
121
|
- projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_symbol_desugarizer.rb
|
121
122
|
- projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/type_declaration_validators/is_valid_class.rb
|
@@ -528,7 +529,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
528
529
|
- !ruby/object:Gem::Version
|
529
530
|
version: '0'
|
530
531
|
requirements: []
|
531
|
-
rubygems_version: 3.6.
|
532
|
+
rubygems_version: 3.6.2
|
532
533
|
specification_version: 4
|
533
534
|
summary: A command-centric and discoverable software framework with a focus on domain
|
534
535
|
concepts and abstracting away integration code
|