foobara 0.0.1
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 +7 -0
- data/.rspec +5 -0
- data/.rubocop.yml +20 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +10 -0
- data/DECISION_LOG.md +220 -0
- data/Guardfile +9 -0
- data/LICENSE-AGPL.txt +666 -0
- data/LICENSE.txt +4 -0
- data/README.md +50 -0
- data/Rakefile +10 -0
- data/concepts.md +153 -0
- data/projects/builtin_types/lib/foobara/builtin_types.rb +67 -0
- data/projects/builtin_types/src/README.md +140 -0
- data/projects/builtin_types/src/array/casters/arrayable.rb +22 -0
- data/projects/builtin_types/src/array/supported_processors/element_type_declaration.rb +41 -0
- data/projects/builtin_types/src/array/supported_validators/size.rb +43 -0
- data/projects/builtin_types/src/associative_array/casters/array.rb +22 -0
- data/projects/builtin_types/src/associative_array/supported_processors/key_type_declaration.rb +44 -0
- data/projects/builtin_types/src/associative_array/supported_processors/value_type_declaration.rb +44 -0
- data/projects/builtin_types/src/atomic_duck.rb +6 -0
- data/projects/builtin_types/src/attributes/casters/array.rb +33 -0
- data/projects/builtin_types/src/attributes/casters/hash.rb +28 -0
- data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb +89 -0
- 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 +40 -0
- data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/desugarizers/symbolize_defaults.rb +31 -0
- data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/hash_with_symbolic_keys.rb +37 -0
- data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/valid_attribute_names.rb +60 -0
- data/projects/builtin_types/src/attributes/supported_transformers/defaults.rb +41 -0
- 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 +55 -0
- data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/array_of_symbols.rb +47 -0
- data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/array_with_valid_attribute_names.rb +54 -0
- data/projects/builtin_types/src/attributes/supported_validators/required.rb +51 -0
- data/projects/builtin_types/src/big_decimal/casters/integer.rb +21 -0
- data/projects/builtin_types/src/big_decimal/casters/string.rb +24 -0
- data/projects/builtin_types/src/boolean/casters/numeric.rb +21 -0
- data/projects/builtin_types/src/boolean/casters/string_or_symbol.rb +27 -0
- data/projects/builtin_types/src/builtin_types.rb +189 -0
- data/projects/builtin_types/src/date/casters/hash.rb +23 -0
- data/projects/builtin_types/src/date/casters/string.rb +40 -0
- data/projects/builtin_types/src/datetime/casters/date.rb +21 -0
- data/projects/builtin_types/src/datetime/casters/hash.rb +77 -0
- data/projects/builtin_types/src/datetime/casters/seconds_since_epoch.rb +21 -0
- data/projects/builtin_types/src/datetime/casters/string.rb +31 -0
- data/projects/builtin_types/src/duck/supported_casters/allow_nil.rb +38 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_desugarizer.rb +29 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_class_desugarizer.rb +31 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_symbol_desugarizer.rb +31 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/type_declaration_validators/is_valid_class.rb +43 -0
- data/projects/builtin_types/src/duck/supported_validators/instance_of.rb +42 -0
- data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/cast_one_of.rb +37 -0
- data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/module_desugarizer.rb +41 -0
- data/projects/builtin_types/src/duck/supported_validators/one_of.rb +41 -0
- data/projects/builtin_types/src/duck.rb +6 -0
- data/projects/builtin_types/src/duckture.rb +6 -0
- data/projects/builtin_types/src/email/transformers/downcase.rb +15 -0
- data/projects/builtin_types/src/email/validator_base.rb +94 -0
- data/projects/builtin_types/src/float/casters/integer.rb +21 -0
- data/projects/builtin_types/src/float/casters/string.rb +24 -0
- data/projects/builtin_types/src/integer/casters/string.rb +23 -0
- data/projects/builtin_types/src/number/supported_validators/max.rb +41 -0
- data/projects/builtin_types/src/number/supported_validators/min.rb +41 -0
- data/projects/builtin_types/src/string/casters/numeric.rb +21 -0
- data/projects/builtin_types/src/string/casters/symbol.rb +21 -0
- data/projects/builtin_types/src/string/supported_transformers/downcase.rb +11 -0
- data/projects/builtin_types/src/string/supported_validators/matches.rb +41 -0
- data/projects/builtin_types/src/string/supported_validators/max_length.rb +37 -0
- data/projects/builtin_types/src/symbol/casters/string.rb +21 -0
- data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations/type_declaration_extension/extend_tuple_type_declaration/desugarizers/set_size.rb +32 -0
- data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations/type_declaration_extension/extend_tuple_type_declaration/type_declaration_validators/size_matches.rb +50 -0
- data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations.rb +59 -0
- data/projects/callback/lib/foobara/callback.rb +1 -0
- data/projects/callback/src/block/after.rb +10 -0
- data/projects/callback/src/block/around.rb +10 -0
- data/projects/callback/src/block/before.rb +10 -0
- data/projects/callback/src/block/concerns/block_parameter_not_allowed.rb +21 -0
- data/projects/callback/src/block/concerns/block_parameter_required.rb +21 -0
- data/projects/callback/src/block/concerns/keyword_argumentable_block.rb +31 -0
- data/projects/callback/src/block/concerns/single_argument_block.rb +22 -0
- data/projects/callback/src/block/concerns/type.rb +17 -0
- data/projects/callback/src/block/error.rb +10 -0
- data/projects/callback/src/block.rb +83 -0
- data/projects/callback/src/registry/base.rb +90 -0
- data/projects/callback/src/registry/chained_conditioned.rb +24 -0
- data/projects/callback/src/registry/chained_multiple_action.rb +24 -0
- data/projects/callback/src/registry/conditioned.rb +101 -0
- data/projects/callback/src/registry/multiple_action.rb +110 -0
- data/projects/callback/src/registry/single_action.rb +15 -0
- data/projects/callback/src/runner.rb +89 -0
- data/projects/callback/src/set.rb +56 -0
- data/projects/command/lib/foobara/command.rb +9 -0
- data/projects/command/src/command/entity_helpers.rb +145 -0
- data/projects/command/src/command.rb +36 -0
- data/projects/command/src/concerns/callbacks.rb +93 -0
- data/projects/command/src/concerns/description.rb +23 -0
- data/projects/command/src/concerns/domain_mappers.rb +35 -0
- data/projects/command/src/concerns/entities.rb +88 -0
- data/projects/command/src/concerns/errors.rb +181 -0
- data/projects/command/src/concerns/errors_type.rb +124 -0
- data/projects/command/src/concerns/inputs.rb +59 -0
- data/projects/command/src/concerns/inputs_type.rb +58 -0
- data/projects/command/src/concerns/namespace.rb +49 -0
- data/projects/command/src/concerns/reflection.rb +137 -0
- data/projects/command/src/concerns/result.rb +25 -0
- data/projects/command/src/concerns/result_type.rb +29 -0
- data/projects/command/src/concerns/runtime.rb +119 -0
- data/projects/command/src/concerns/state_machine.rb +12 -0
- data/projects/command/src/concerns/subcommands.rb +102 -0
- data/projects/command/src/concerns/transactions.rb +81 -0
- data/projects/command/src/state_machine.rb +57 -0
- data/projects/command/src/transformed_command.rb +459 -0
- data/projects/command_connectors/lib/foobara/command_connectors.rb +12 -0
- data/projects/command_connectors/src/command_connector.rb +401 -0
- data/projects/command_connectors/src/command_registry/allowed_rule.rb +29 -0
- data/projects/command_connectors/src/command_registry/exposed_command.rb +140 -0
- data/projects/command_connectors/src/command_registry/exposed_domain.rb +30 -0
- data/projects/command_connectors/src/command_registry/exposed_organization.rb +30 -0
- data/projects/command_connectors/src/command_registry.rb +257 -0
- data/projects/command_connectors/src/commands/describe.rb +36 -0
- data/projects/command_connectors/src/commands/list_commands.rb +51 -0
- data/projects/command_connectors/src/commands/ping.rb +21 -0
- data/projects/command_connectors/src/commands/query_git_commit_info.rb +81 -0
- data/projects/command_connectors/src/request.rb +99 -0
- data/projects/command_connectors/src/response.rb +17 -0
- data/projects/command_connectors/src/serializer.rb +25 -0
- data/projects/command_connectors/src/serializers/aggregate_serializer.rb +32 -0
- data/projects/command_connectors/src/serializers/atomic_serializer.rb +25 -0
- data/projects/command_connectors/src/serializers/entities_to_primary_keys_serializer.rb +28 -0
- data/projects/command_connectors/src/serializers/errors_serializer.rb +18 -0
- data/projects/command_connectors/src/serializers/json_serializer.rb +20 -0
- data/projects/command_connectors/src/serializers/noop_serializer.rb +20 -0
- data/projects/command_connectors/src/serializers/record_store_serializer.rb +31 -0
- data/projects/command_connectors/src/serializers/success_serializer.rb +14 -0
- data/projects/command_connectors/src/serializers/yaml_serializer.rb +20 -0
- data/projects/command_connectors/src/transformers/auth_errors_transformer.rb +35 -0
- data/projects/command_connectors/src/transformers/load_aggregates_pre_commit_transformer.rb +36 -0
- data/projects/command_connectors_http/lib/foobara/command_connectors_http.rb +6 -0
- data/projects/command_connectors_http/src/http/commands/get_options.rb +16 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/command.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/domain.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/entity.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/error.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/model.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/organization.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/processor.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/processor_class.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/root.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter/type.rb +14 -0
- data/projects/command_connectors_http/src/http/commands/help/presenter.rb +162 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/command.html.erb +11 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/domain.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/entity.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/error.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/model.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/organization.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/processor.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/processor_class.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/root.html.erb +3 -0
- data/projects/command_connectors_http/src/http/commands/help/templates/type.html.erb +1 -0
- data/projects/command_connectors_http/src/http/commands/help.rb +98 -0
- data/projects/command_connectors_http/src/http/request.rb +98 -0
- data/projects/command_connectors_http/src/http/response.rb +14 -0
- data/projects/command_connectors_http/src/http.rb +84 -0
- data/projects/common/lib/foobara/common.rb +11 -0
- data/projects/common/src/data_path.rb +272 -0
- data/projects/common/src/error.rb +215 -0
- data/projects/common/src/error_collection.rb +97 -0
- data/projects/common/src/error_key.rb +168 -0
- data/projects/common/src/outcome.rb +101 -0
- data/projects/common/src/possible_error.rb +80 -0
- data/projects/common/src/runtime_error.rb +24 -0
- data/projects/concerns/lib/foobara/concerns.rb +1 -0
- data/projects/concerns/src/concern.rb +93 -0
- data/projects/delegate/lib/foobara/delegate.rb +1 -0
- data/projects/delegate/src/extensions/module.rb +12 -0
- data/projects/domain/lib/foobara/domain.rb +25 -0
- data/projects/domain/src/domain.rb +65 -0
- data/projects/domain/src/domain_mapper/registry.rb +47 -0
- data/projects/domain/src/domain_mapper.rb +162 -0
- data/projects/domain/src/domain_module_extension.rb +510 -0
- data/projects/domain/src/extensions/foobara.rb +69 -0
- data/projects/domain/src/global_domain.rb +14 -0
- data/projects/domain/src/global_organization.rb +12 -0
- data/projects/domain/src/is_manifestable.rb +68 -0
- data/projects/domain/src/manifestable.rb +12 -0
- data/projects/domain/src/module_extension.rb +122 -0
- data/projects/domain/src/organization.rb +52 -0
- data/projects/domain/src/organization_module_extension.rb +50 -0
- data/projects/entity/lib/foobara/entity.rb +27 -0
- data/projects/entity/src/concerns/associations.rb +241 -0
- data/projects/entity/src/concerns/attributes.rb +170 -0
- data/projects/entity/src/concerns/callbacks.rb +97 -0
- data/projects/entity/src/concerns/initialization.rb +127 -0
- data/projects/entity/src/concerns/persistence.rb +142 -0
- data/projects/entity/src/concerns/primary_key.rb +43 -0
- data/projects/entity/src/concerns/queries.rb +96 -0
- data/projects/entity/src/concerns/reflection.rb +51 -0
- data/projects/entity/src/concerns/transactions.rb +31 -0
- data/projects/entity/src/concerns/types.rb +31 -0
- data/projects/entity/src/entity.rb +61 -0
- data/projects/entity/src/extensions/builtin_types/entity/casters/hash.rb +33 -0
- data/projects/entity/src/extensions/builtin_types/entity/validators/attributes_declaration.rb +32 -0
- data/projects/entity/src/extensions/builtin_types/entity.rb +6 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/attributes_handler_desugarizer.rb +14 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/hash_desugarizer.rb +43 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/model_class_desugarizer.rb +21 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/primary_key_desugarizer.rb +19 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/to_type_transformer.rb +64 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_is_symbol.rb +35 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_present.rb +27 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_references_attribute.rb +36 -0
- data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration.rb +11 -0
- data/projects/entity/src/new_prepend.rb +21 -0
- data/projects/entity/src/not_found_error.rb +72 -0
- data/projects/enumerated/lib/foobara/enumerated.rb +1 -0
- data/projects/enumerated/src/accessors.rb +61 -0
- data/projects/enumerated/src/values.rb +121 -0
- data/projects/foobara/lib/foobara/all.rb +44 -0
- data/projects/in_memory_crud_driver/lib/foobara/in_memory_crud_driver.rb +3 -0
- data/projects/in_memory_crud_driver/src/in_memory.rb +10 -0
- data/projects/in_memory_crud_driver_minimal/lib/foobara/in_memory_crud_driver_minimal.rb +1 -0
- data/projects/in_memory_crud_driver_minimal/src/in_memory_minimal.rb +113 -0
- data/projects/manifest/lib/foobara/manifest.rb +4 -0
- data/projects/manifest/src/foobara/manifest/array.rb +13 -0
- data/projects/manifest/src/foobara/manifest/attributes.rb +40 -0
- data/projects/manifest/src/foobara/manifest/base_manifest.rb +161 -0
- data/projects/manifest/src/foobara/manifest/command.rb +59 -0
- data/projects/manifest/src/foobara/manifest/domain.rb +43 -0
- data/projects/manifest/src/foobara/manifest/entity.rb +35 -0
- data/projects/manifest/src/foobara/manifest/error.rb +33 -0
- data/projects/manifest/src/foobara/manifest/model.rb +43 -0
- data/projects/manifest/src/foobara/manifest/organization.rb +45 -0
- data/projects/manifest/src/foobara/manifest/possible_error.rb +30 -0
- data/projects/manifest/src/foobara/manifest/processor.rb +11 -0
- data/projects/manifest/src/foobara/manifest/processor_class.rb +11 -0
- data/projects/manifest/src/foobara/manifest/root_manifest.rb +112 -0
- data/projects/manifest/src/foobara/manifest/type.rb +86 -0
- data/projects/manifest/src/foobara/manifest/type_declaration.rb +117 -0
- data/projects/model/lib/foobara/model.rb +23 -0
- data/projects/model/src/concerns/reflection.rb +22 -0
- data/projects/model/src/concerns/types.rb +104 -0
- data/projects/model/src/extensions/builtin_types/model/casters/hash.rb +23 -0
- data/projects/model/src/extensions/builtin_types/model/transformers/mutable.rb +26 -0
- data/projects/model/src/extensions/builtin_types/model/validators/attributes_declaration.rb +33 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/attributes_handler_desugarizer.rb +24 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/hash_desugarizer.rb +32 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +119 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +57 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration.rb +21 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/hash_desugarizer.rb +37 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/model_class_type_desugarizer.rb +25 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/mutable_validator.rb +46 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/normalize_mutable_attributes_desugarizer.rb +28 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/to_type_transformer.rb +27 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +31 -0
- data/projects/model/src/extensions/type_declarations/handlers/registered_type_declaration/model_class_desugarizer.rb +23 -0
- data/projects/model/src/model.rb +320 -0
- data/projects/monorepo/lib/foobara/monorepo/project.rb +52 -0
- data/projects/monorepo/lib/foobara/monorepo.rb +63 -0
- data/projects/namespace/lib/foobara/namespace.rb +4 -0
- data/projects/namespace/src/ambiguous_registry.rb +104 -0
- data/projects/namespace/src/base_registry.rb +66 -0
- data/projects/namespace/src/extensions/module.rb +5 -0
- data/projects/namespace/src/is_namespace.rb +352 -0
- data/projects/namespace/src/namespace/lookup_mode.rb +41 -0
- data/projects/namespace/src/namespace.rb +61 -0
- data/projects/namespace/src/namespace_helpers.rb +273 -0
- data/projects/namespace/src/prefixless_registry.rb +54 -0
- data/projects/namespace/src/scoped.rb +113 -0
- data/projects/namespace/src/unambiguous_registry.rb +65 -0
- data/projects/persistence/lib/foobara/persistence.rb +22 -0
- data/projects/persistence/src/entity_attributes_crud_driver.rb +241 -0
- data/projects/persistence/src/entity_base/table.rb +14 -0
- data/projects/persistence/src/entity_base/transaction/concerns/entity_callback_handling.rb +157 -0
- data/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +83 -0
- data/projects/persistence/src/entity_base/transaction/concerns/transaction_tracking.rb +53 -0
- data/projects/persistence/src/entity_base/transaction/state_machine.rb +27 -0
- data/projects/persistence/src/entity_base/transaction.rb +163 -0
- data/projects/persistence/src/entity_base/transaction_table/concerns/queries.rb +42 -0
- data/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +134 -0
- data/projects/persistence/src/entity_base/transaction_table.rb +620 -0
- data/projects/persistence/src/entity_base.rb +114 -0
- data/projects/persistence/src/persistence.rb +172 -0
- data/projects/state_machine/lib/foobara/state_machine.rb +1 -0
- data/projects/state_machine/src/callbacks.rb +158 -0
- data/projects/state_machine/src/log_entry.rb +13 -0
- data/projects/state_machine/src/state_machine.rb +91 -0
- data/projects/state_machine/src/sugar.rb +125 -0
- data/projects/state_machine/src/transition_log.rb +19 -0
- data/projects/state_machine/src/validations.rb +69 -0
- data/projects/thread_parent/lib/foobara/thread_parent.rb +1 -0
- data/projects/thread_parent/src/thread_parent.rb +38 -0
- data/projects/type_declarations/lib/foobara/type_declarations.rb +131 -0
- data/projects/type_declarations/src/attributes.rb +34 -0
- data/projects/type_declarations/src/caster.rb +7 -0
- data/projects/type_declarations/src/desugarizer.rb +25 -0
- data/projects/type_declarations/src/dsl/attributes.rb +199 -0
- data/projects/type_declarations/src/element_processor.rb +7 -0
- data/projects/type_declarations/src/error_extension.rb +73 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb +31 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/element_type_declaration_desugarizer.rb +37 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb +22 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +36 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration.rb +14 -0
- data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration/to_type_transformer.rb +28 -0
- data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration.rb +20 -0
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/dsl_desugarizer.rb +25 -0
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/element_type_declarations_desugarizer.rb +34 -0
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb +60 -0
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +21 -0
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration.rb +16 -0
- data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +75 -0
- data/projects/type_declarations/src/handlers/extend_registered_type_declaration.rb +23 -0
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb +30 -0
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb +24 -0
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration.rb +13 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/desugarizer_metadata_cleanup_desugarizer.rb +29 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/short_type_name_desugarizer.rb +65 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/strict_desugarizer.rb +32 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/strict_stringified_desugarizer.rb +39 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/symbol_desugarizer.rb +26 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb +28 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/type_desugarizer.rb +24 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration.rb +26 -0
- data/projects/type_declarations/src/processor.rb +7 -0
- data/projects/type_declarations/src/to_type_transformer.rb +11 -0
- data/projects/type_declarations/src/transformer.rb +7 -0
- data/projects/type_declarations/src/type_builder.rb +112 -0
- data/projects/type_declarations/src/type_declaration_error.rb +9 -0
- data/projects/type_declarations/src/type_declaration_handler.rb +120 -0
- data/projects/type_declarations/src/type_declaration_handler_registry.rb +27 -0
- data/projects/type_declarations/src/type_declaration_validator.rb +19 -0
- data/projects/type_declarations/src/type_declarations.rb +128 -0
- data/projects/type_declarations/src/typed_transformer.rb +89 -0
- data/projects/type_declarations/src/validator.rb +7 -0
- data/projects/type_declarations/src/with_registries.rb +41 -0
- data/projects/types/lib/foobara/types.rb +11 -0
- data/projects/types/src/element_processor.rb +7 -0
- data/projects/types/src/extensions/error.rb +32 -0
- data/projects/types/src/type/concerns/reflection.rb +79 -0
- data/projects/types/src/type/concerns/supported_processor_registration.rb +56 -0
- data/projects/types/src/type.rb +375 -0
- data/projects/types/src/types.rb +4 -0
- data/projects/value/lib/foobara/value.rb +7 -0
- data/projects/value/src/caster.rb +84 -0
- data/projects/value/src/data_error.rb +27 -0
- data/projects/value/src/processor/casting.rb +123 -0
- data/projects/value/src/processor/multi.rb +63 -0
- data/projects/value/src/processor/pipeline.rb +27 -0
- data/projects/value/src/processor/runner.rb +38 -0
- data/projects/value/src/processor/selection.rb +90 -0
- data/projects/value/src/processor.rb +358 -0
- data/projects/value/src/transformer.rb +84 -0
- data/projects/value/src/validator.rb +53 -0
- data/projects/version/lib/foobara/version.rb +4 -0
- data/projects/version/src/version.rb +5 -0
- data/projects/weak_object_set/lib/foobara/weak_object_set.rb +3 -0
- data/projects/weak_object_set/src/weak_object_set.rb +163 -0
- metadata +445 -0
data/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Foobara
|
|
2
|
+
|
|
3
|
+
Foobara is a command-based software framework with an emphasis on reflection features to facilitate integration with
|
|
4
|
+
other systems or subsystems. The focus of the framework is to provide these features to help
|
|
5
|
+
with managing domain complexity in projects with higher domain complexity. However, Foobara
|
|
6
|
+
is also expected to be pleasant for use in projects with simpler domains as well.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
To add foobara to an existing project, you can add `foobara` gem to your Gemfile or .gemspec as you normally would.
|
|
11
|
+
|
|
12
|
+
To create a new project using a foobara generator, you could install the `foob` gem with `gem install foob` and then
|
|
13
|
+
run `foob generate ruby-project --name your-org/your-new-project-name`
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
TODO: Write usage instructions here or defer to some tutorial somewhere
|
|
18
|
+
|
|
19
|
+
## Contributing
|
|
20
|
+
|
|
21
|
+
Can contribute via a github pull request as is typical but see info about licensing below first.
|
|
22
|
+
|
|
23
|
+
Make sure the test suite and linter pass locally before opening a pull request.
|
|
24
|
+
The build will fail if test coverage is below 100%.
|
|
25
|
+
|
|
26
|
+
It might be a good idea to reach out for advice if unsure how to chip away at the part of this project
|
|
27
|
+
that you are interested in.
|
|
28
|
+
|
|
29
|
+
### Developing locally
|
|
30
|
+
|
|
31
|
+
You should be able to run `bundle install` and then `rake` to run the test suite and the linter.
|
|
32
|
+
|
|
33
|
+
### Monorepo Structure
|
|
34
|
+
|
|
35
|
+
Foobara is split up into many projects. Many are in separate repositories. This repository however is unique
|
|
36
|
+
in the Foobara ecosystem of projects because it is a monorepo. Sometimes projects are extracted from here
|
|
37
|
+
into their own repositories.
|
|
38
|
+
|
|
39
|
+
Each project has its own directory in the projects/ directory.
|
|
40
|
+
|
|
41
|
+
### Licensing
|
|
42
|
+
|
|
43
|
+
Temporarily licensed under the AGPL-3.0 license. This is to to get the gem out there for convenient use in demos,
|
|
44
|
+
releasing it under a very restrictive
|
|
45
|
+
license to buy time on a final licensing decision (leaning towards `Apache-2.0 OR MIT`)
|
|
46
|
+
|
|
47
|
+
My intention is to either release this under MIT license, Apache 2.0, or MPL,
|
|
48
|
+
or a similar license (permissive or possibly weak copyleft.)
|
|
49
|
+
|
|
50
|
+
See DECISION_LOG.md for the current thoughts on licensing.
|
data/Rakefile
ADDED
data/concepts.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!-- TOC -->
|
|
2
|
+
|
|
3
|
+
* [Command](#command)
|
|
4
|
+
* [Type < Value::Processor](#type--valueprocessor)
|
|
5
|
+
* [type declaration value](#type-declaration-value)
|
|
6
|
+
* [Type reference](#type-reference)
|
|
7
|
+
* [Domain](#domain)
|
|
8
|
+
* [Organization](#organization)
|
|
9
|
+
* [Domain mapper](#domain-mapper)
|
|
10
|
+
* [Value::Processor](#valueprocessor)
|
|
11
|
+
* [Value::Caster < Value::Processor](#valuecaster--valueprocessor)
|
|
12
|
+
* [Value::Validator < Value::Processor](#valuevalidator--valueprocessor)
|
|
13
|
+
* [Value::Transformer < Value::Processor](#valuetransformer--valueprocessor)
|
|
14
|
+
* [Desugarizer < Value::Transformer](#desugarizer--valuetransformer)
|
|
15
|
+
* [TypeDeclarationValidator < Value::Validator](#typedeclarationvalidator--valuevalidator)
|
|
16
|
+
* [in general:](#in-general)
|
|
17
|
+
* [types and type declarations:](#types-and-type-declarations)
|
|
18
|
+
|
|
19
|
+
<!-- TOC -->
|
|
20
|
+
|
|
21
|
+
These are notes about some things conceptual.
|
|
22
|
+
|
|
23
|
+
# Command
|
|
24
|
+
|
|
25
|
+
* A command is an encapsulation of a high-level business operation and is intended to be the public
|
|
26
|
+
interface of a system or subsystem.
|
|
27
|
+
|
|
28
|
+
# Type < Value::Processor
|
|
29
|
+
|
|
30
|
+
A type is an instance of the Types::Type class.
|
|
31
|
+
|
|
32
|
+
It (the instance) is a namespace.
|
|
33
|
+
|
|
34
|
+
It is a Value::Processor
|
|
35
|
+
|
|
36
|
+
* reflection
|
|
37
|
+
* can give a type declaration value (formal or informal/sugary or strict) for this type
|
|
38
|
+
* can give the list of possible errors that could result from processing a value of this type
|
|
39
|
+
and the types for their context schemas
|
|
40
|
+
* can answer what value processors are supported for values of this type
|
|
41
|
+
* can answer which value processors are automatically applied for values of this type
|
|
42
|
+
* can serve as a base type for another type
|
|
43
|
+
* can process a value of this type
|
|
44
|
+
* can answer if a value needs to be cast
|
|
45
|
+
* can answer if a value can be cast
|
|
46
|
+
* can cast a value into an value of this type
|
|
47
|
+
* can transform a value of this type
|
|
48
|
+
* can validate a value of this type
|
|
49
|
+
* processor registry operations
|
|
50
|
+
* can register a supported value processor
|
|
51
|
+
* can register a value caster
|
|
52
|
+
|
|
53
|
+
# type declaration value
|
|
54
|
+
|
|
55
|
+
* Something that defines/declares a type in a declarative fashion.
|
|
56
|
+
* Can have a sugary form for human expression/readability/writability
|
|
57
|
+
* Is easily serializable for cross-system metaprogramming
|
|
58
|
+
* example:
|
|
59
|
+
```ruby
|
|
60
|
+
{
|
|
61
|
+
foo: :integer,
|
|
62
|
+
bar: [:integer, :optional, :allow_blank, min: 1]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
* In this example, we are using a sugary declaration to specify a new type of
|
|
66
|
+
attributes type that can represent a value like `{ foo: -20, bar: 10 }`
|
|
67
|
+
|
|
68
|
+
# Type reference
|
|
69
|
+
|
|
70
|
+
* References a "registered" type. A registered type has a type symbol and belongs to a domain.
|
|
71
|
+
* An unresolved type reference doesn't have to be absolute and is looked up in the current
|
|
72
|
+
Foobara namespace.
|
|
73
|
+
* A resolved type is absolute.
|
|
74
|
+
* A type reference can be used as a type declaration.
|
|
75
|
+
|
|
76
|
+
# Domain
|
|
77
|
+
|
|
78
|
+
* A namespace for Commands and Types
|
|
79
|
+
* can depend on other domains in a unidirectional way
|
|
80
|
+
|
|
81
|
+
# Organization
|
|
82
|
+
|
|
83
|
+
* namespace for collecting domains
|
|
84
|
+
|
|
85
|
+
# Domain mapper
|
|
86
|
+
|
|
87
|
+
* Translates models (or types or commands inputs/results) to models (or types or command inputs/results) in
|
|
88
|
+
another domain.
|
|
89
|
+
|
|
90
|
+
# Value::Processor
|
|
91
|
+
|
|
92
|
+
* Has a process_value method that receives a value and returns an Outcome
|
|
93
|
+
* Can have an applicable?(value) method
|
|
94
|
+
* Answers what errors are possible
|
|
95
|
+
* Including the type of their context
|
|
96
|
+
|
|
97
|
+
## Value::Caster < Value::Processor
|
|
98
|
+
|
|
99
|
+
* gives #cast instead of #transform but same idea, takes value returns value
|
|
100
|
+
* like ValueProcessor, never gives errors
|
|
101
|
+
* only one value caster per type should be #applicable? for a given value.
|
|
102
|
+
* Therefore doesn't have to play nicely with other Casters, unlike Transformers/Validators
|
|
103
|
+
|
|
104
|
+
## Value::Validator < Value::Processor
|
|
105
|
+
|
|
106
|
+
* gives #validation_errors that takes value and returns errors
|
|
107
|
+
* never gives new value
|
|
108
|
+
|
|
109
|
+
## Value::Transformer < Value::Processor
|
|
110
|
+
|
|
111
|
+
* gives #transfomer that takes value and returns value
|
|
112
|
+
* never gives errors
|
|
113
|
+
|
|
114
|
+
## Desugarizer < Value::Transformer
|
|
115
|
+
|
|
116
|
+
* takes sugary type declaration and returns strict type declaration
|
|
117
|
+
|
|
118
|
+
## TypeDeclarationValidator < Value::Validator
|
|
119
|
+
|
|
120
|
+
* Validates type declarations
|
|
121
|
+
|
|
122
|
+
A way to think about the interfaces/concepts involved here, if helpful:
|
|
123
|
+
|
|
124
|
+
### in general:
|
|
125
|
+
|
|
126
|
+
* Processor, Multi, Selection, Pipeline: value -> outcome
|
|
127
|
+
* Multi < Processor: value -> outcome
|
|
128
|
+
* Selection < Multi (chooses 1 processor among many to run): value -> outcome
|
|
129
|
+
* Pipeline < Multi (chains a collection of processors together): value -> outcome
|
|
130
|
+
* Processor, Multi, Selection, Pipeline: value -> outcome
|
|
131
|
+
* Transformer: value -> value
|
|
132
|
+
* Validator: value -> error[]
|
|
133
|
+
|
|
134
|
+
Maybe not helpful, but, you could think of Processor/Multi/Selection/Pipeline as monads
|
|
135
|
+
and Validator and Transformer as monads but with convenience methods that make assumptions
|
|
136
|
+
about the context (transformer assumes there are no errors and validator assumes
|
|
137
|
+
no transformation of the value.)
|
|
138
|
+
|
|
139
|
+
### types and type declarations:
|
|
140
|
+
|
|
141
|
+
* TypeDeclarationHandler: type declaration -> Type instance
|
|
142
|
+
* TypeDeclarationHandlerRegistry: type declaration -> outcome<TypeDeclarationHandler>
|
|
143
|
+
* Desugarizer: type declaration -> strict(er) type declaration
|
|
144
|
+
* TypeDeclarationValidator: strict type declaration -> error[]
|
|
145
|
+
* Type instance: value -> outcome
|
|
146
|
+
* Type casting (is a Value::Pipeline of casters): value -> value
|
|
147
|
+
* Caster: value -> value
|
|
148
|
+
* Type transformers: value -> value
|
|
149
|
+
* Type validators: value -> error[]
|
|
150
|
+
* Type processors: value -> outcome
|
|
151
|
+
* Supported type processors: value -> outcome
|
|
152
|
+
* Supported type transformers: value -> value
|
|
153
|
+
* Supported type validators: value -> error[]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require "date"
|
|
2
|
+
require "time"
|
|
3
|
+
require "bigdecimal"
|
|
4
|
+
|
|
5
|
+
module Foobara
|
|
6
|
+
module BuiltinTypes
|
|
7
|
+
class << self
|
|
8
|
+
def builtin_types
|
|
9
|
+
@builtin_types ||= Set.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def builtin?(type)
|
|
13
|
+
builtin_types.include?(type)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def [](symbol)
|
|
17
|
+
builtin_types.find do |type|
|
|
18
|
+
type.type_symbol == symbol
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def install!
|
|
23
|
+
duck = build_and_register!(:duck, nil, ::Object)
|
|
24
|
+
# TODO: should we ban ::Object that are ::Enumerable from atomic_duck?
|
|
25
|
+
atomic_duck = build_and_register!(:atomic_duck, duck, ::Object)
|
|
26
|
+
build_and_register!(:symbol, atomic_duck)
|
|
27
|
+
# TODO: wtf why pass ::Object? It's to avoid casting? Do we need a way to flag abstract types?
|
|
28
|
+
number = build_and_register!(:number, atomic_duck, ::Object)
|
|
29
|
+
build_and_register!(:integer, number)
|
|
30
|
+
build_and_register!(:float, number)
|
|
31
|
+
build_and_register!(:big_decimal, number)
|
|
32
|
+
# Let's skip these for now since they rarely come up in business contexts and both could be
|
|
33
|
+
# represented by a tuple of numbers.
|
|
34
|
+
# build_and_register!(:rational, number)
|
|
35
|
+
# build_and_register!(:complex, number)
|
|
36
|
+
string = build_and_register!(:string, atomic_duck)
|
|
37
|
+
build_and_register!(:date, atomic_duck)
|
|
38
|
+
build_and_register!(:datetime, atomic_duck, ::Time)
|
|
39
|
+
build_and_register!(:boolean, atomic_duck, [::TrueClass, ::FalseClass])
|
|
40
|
+
build_and_register!(:email, string, ::String)
|
|
41
|
+
# TODO: not urgent and derisked already via :email
|
|
42
|
+
# phone_number = build_and_register!(:phone_number, string)
|
|
43
|
+
# TODO: wtf
|
|
44
|
+
duckture = build_and_register!(:duckture, duck, ::Object)
|
|
45
|
+
array = build_and_register!(:array, duckture)
|
|
46
|
+
build_and_register!(:tuple, array, ::Array)
|
|
47
|
+
associative_array = build_and_register!(:associative_array, duckture, ::Hash)
|
|
48
|
+
# TODO: uh oh... we do some translations in the casting here...
|
|
49
|
+
build_and_register!(:attributes, associative_array, nil)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def reset_all
|
|
53
|
+
builtin_types.each do |builtin_type|
|
|
54
|
+
builtin_type.foobara_each do |scoped|
|
|
55
|
+
if scoped.scoped_namespace == builtin_type
|
|
56
|
+
scoped.scoped_namespace = nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
builtin_types.clear
|
|
62
|
+
|
|
63
|
+
install!
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Adding a new builtin type
|
|
2
|
+
|
|
3
|
+
Note that adding a custom type is a different process involving writing handlers/desugarizers/declaration validators.
|
|
4
|
+
TODO: add information to either this document or another about adding desugarizers, type declaration handlers,
|
|
5
|
+
and type declaration validators.
|
|
6
|
+
|
|
7
|
+
Let's go through the steps of adding a String builtin type
|
|
8
|
+
|
|
9
|
+
## Create a directory for the new type
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mkdir lib/foobara/builtin_types/string
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Add Casters if needed
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
mkdir lib/foobara/builtin_types/string/casters
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
in `lib/foobara/builtin_types/string/casters/symbol.rb`
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
|
|
25
|
+
module Foobara
|
|
26
|
+
module BuiltinTypes
|
|
27
|
+
module String
|
|
28
|
+
module Casters
|
|
29
|
+
class Symbol < Value::Caster
|
|
30
|
+
def applicable?(value)
|
|
31
|
+
value.is_a?(::Symbol)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def applies_message
|
|
35
|
+
"be a Symbol"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def cast(string)
|
|
39
|
+
string.to_s
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Creating SupportedProcessors/SupportedTransformers/SupportedValidators
|
|
49
|
+
|
|
50
|
+
Let's make a validator for length
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
mkdir lib/foobara/builtin_types/string/supported_validators
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
in `lib/foobara/builtin_types/string/supported_validators/max_length.rb`
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
|
|
60
|
+
module Foobara
|
|
61
|
+
module BuiltinTypes
|
|
62
|
+
module String
|
|
63
|
+
module SupportedValidators
|
|
64
|
+
class MaxLength < TypeDeclarations::Validator
|
|
65
|
+
class MaxLengthExceededError < Foobara::Value::DataError
|
|
66
|
+
class << self
|
|
67
|
+
def context_type_declaration
|
|
68
|
+
{
|
|
69
|
+
value: :string,
|
|
70
|
+
max_length: :integer
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def validation_errors(string)
|
|
77
|
+
if string.length > max_length
|
|
78
|
+
build_error(string)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def error_message(_value)
|
|
83
|
+
"Max length exceeded. Cannot be longer than #{max_length} characters"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def error_context(value)
|
|
87
|
+
{
|
|
88
|
+
value:,
|
|
89
|
+
max_length:
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Let's create a supported transformer
|
|
100
|
+
|
|
101
|
+
in `lib/foobara/builtin_types/string/supported_transformers/downcase.rb`
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
|
|
105
|
+
module Foobara
|
|
106
|
+
module BuiltinTypes
|
|
107
|
+
module String
|
|
108
|
+
module SupportedTransformers
|
|
109
|
+
class Downcase < Value::Transformer
|
|
110
|
+
def transform(string)
|
|
111
|
+
string.downcase
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Assemble our new type on boot by adding it to builtin_types.rb
|
|
121
|
+
|
|
122
|
+
in `build_and_register_all_builtins_and_install_type_declaration_extensions!` in `lib/foobara/builtin_types.rb`
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
string = build_and_register!(:string, atomic_duck)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Trying it out...
|
|
129
|
+
|
|
130
|
+
You could test this in a console with:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
$ bin / console
|
|
134
|
+
irb(main) : 001 : 0 > type = Foobara::TypeDeclarations::TypeBuilder.type_for_declaration(:string, :downcase, max_length: 10)
|
|
135
|
+
=> #<Foobara::Types::Type:0x00007fb12f5ca160 ...>
|
|
136
|
+
irb(main) : 002 : 0 > type.process_value!("Foo Bar")
|
|
137
|
+
=> "foo bar"
|
|
138
|
+
irb(main) : 003 : 0 > type.process_value("Foo Bar Baz").errors.first.message
|
|
139
|
+
=> "Max length exceeded. Cannot be longer than 10"
|
|
140
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module Array
|
|
4
|
+
module Casters
|
|
5
|
+
class Arrayable < Value::Caster
|
|
6
|
+
def applicable?(value)
|
|
7
|
+
!value.is_a?(::Array) && value.respond_to?(:to_a)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def applies_message
|
|
11
|
+
"respond to :to_a"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def cast(object)
|
|
15
|
+
# TODO: This is probably too lenient
|
|
16
|
+
object.to_a
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module Array
|
|
4
|
+
module SupportedProcessors
|
|
5
|
+
class ElementTypeDeclaration < TypeDeclarations::ElementProcessor
|
|
6
|
+
def element_type
|
|
7
|
+
@element_type ||= type_for_declaration(element_type_declaration)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def process_value(array)
|
|
11
|
+
errors = []
|
|
12
|
+
|
|
13
|
+
array.each.with_index do |element, index|
|
|
14
|
+
element_outcome = element_type.process_value(element)
|
|
15
|
+
|
|
16
|
+
if element_outcome.success?
|
|
17
|
+
array[index] = element_outcome.result
|
|
18
|
+
else
|
|
19
|
+
element_outcome.each_error do |error|
|
|
20
|
+
error.prepend_path!(index)
|
|
21
|
+
|
|
22
|
+
errors << error
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Outcome.new(result: array, errors:)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def possible_errors
|
|
31
|
+
super + element_type.possible_errors.map do |possible_error|
|
|
32
|
+
possible_error = possible_error.dup
|
|
33
|
+
possible_error.prepend_path!(:"#")
|
|
34
|
+
possible_error
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module Array
|
|
4
|
+
module SupportedValidators
|
|
5
|
+
class Size < TypeDeclarations::Validator
|
|
6
|
+
class IncorrectTupleSizeError < Value::DataError
|
|
7
|
+
class << self
|
|
8
|
+
def context_type_declaration
|
|
9
|
+
{
|
|
10
|
+
expected_size: :integer,
|
|
11
|
+
actual_size: :integer,
|
|
12
|
+
value: :array
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def expected_size
|
|
19
|
+
size
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validation_errors(array)
|
|
23
|
+
if array.size != expected_size
|
|
24
|
+
build_error(array)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def error_message(array)
|
|
29
|
+
"Invalid tuple size. #{array.inspect} should have had #{expected_size} elements but had #{array.size}."
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def error_context(array)
|
|
33
|
+
{
|
|
34
|
+
expected_size:,
|
|
35
|
+
actual_size: array.size,
|
|
36
|
+
value: array
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
# TODO: rename to Map to avoid thinking of it as an array of pairs which isn't quite the right mental model.
|
|
4
|
+
module AssociativeArray
|
|
5
|
+
module Casters
|
|
6
|
+
class Array < Value::Caster
|
|
7
|
+
def applicable?(value)
|
|
8
|
+
value.is_a?(::Array) && value.all? { |element| element.is_a?(::Array) && element.size == 2 }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def applies_message
|
|
12
|
+
"be a an array of pairs"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def cast(array)
|
|
16
|
+
array.to_h
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/projects/builtin_types/src/associative_array/supported_processors/key_type_declaration.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module AssociativeArray
|
|
4
|
+
module SupportedProcessors
|
|
5
|
+
class KeyTypeDeclaration < TypeDeclarations::ElementProcessor
|
|
6
|
+
def key_type
|
|
7
|
+
@key_type ||= type_for_declaration(key_type_declaration)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def process_value(attributes_hash)
|
|
11
|
+
errors = []
|
|
12
|
+
|
|
13
|
+
attributes_hash = attributes_hash.to_a.map.with_index do |(key, value), index|
|
|
14
|
+
key_outcome = key_type.process_value(key)
|
|
15
|
+
|
|
16
|
+
if key_outcome.success?
|
|
17
|
+
key = key_outcome.result
|
|
18
|
+
else
|
|
19
|
+
key_outcome.each_error do |error|
|
|
20
|
+
# Can' prepend path since we dont know if key is a symbolizable type...
|
|
21
|
+
error.prepend_path!(index, :key)
|
|
22
|
+
|
|
23
|
+
errors << error
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
[key, value]
|
|
28
|
+
end.to_h
|
|
29
|
+
|
|
30
|
+
Outcome.new(result: attributes_hash, errors:)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def possible_errors
|
|
34
|
+
super + key_type.possible_errors.map do |possible_error|
|
|
35
|
+
possible_error = possible_error.dup
|
|
36
|
+
possible_error.prepend_path!(:"#", :key)
|
|
37
|
+
possible_error
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/projects/builtin_types/src/associative_array/supported_processors/value_type_declaration.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module AssociativeArray
|
|
4
|
+
module SupportedProcessors
|
|
5
|
+
class ValueTypeDeclaration < TypeDeclarations::ElementProcessor
|
|
6
|
+
def value_type
|
|
7
|
+
@value_type ||= type_for_declaration(value_type_declaration)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def process_value(attributes_hash)
|
|
11
|
+
errors = []
|
|
12
|
+
|
|
13
|
+
attributes_hash = attributes_hash.to_a.map.with_index do |(key, value), index|
|
|
14
|
+
value_outcome = value_type.process_value(value)
|
|
15
|
+
|
|
16
|
+
if value_outcome.success?
|
|
17
|
+
value = value_outcome.result
|
|
18
|
+
else
|
|
19
|
+
value_outcome.each_error do |error|
|
|
20
|
+
# Can' prepend path since we dont know if key is a symbolizable type...
|
|
21
|
+
error.prepend_path!(index, :value)
|
|
22
|
+
|
|
23
|
+
errors << error
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
[key, value]
|
|
28
|
+
end.to_h
|
|
29
|
+
|
|
30
|
+
Outcome.new(result: attributes_hash, errors:)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def possible_errors
|
|
34
|
+
super + value_type.possible_errors.map do |possible_error|
|
|
35
|
+
possible_error = possible_error.dup
|
|
36
|
+
possible_error.prepend_path!(:"#", :value)
|
|
37
|
+
possible_error
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Foobara
|
|
2
|
+
module BuiltinTypes
|
|
3
|
+
module Attributes
|
|
4
|
+
module Casters
|
|
5
|
+
class Array < AssociativeArray::Casters::Array
|
|
6
|
+
def applicable?(value)
|
|
7
|
+
if super
|
|
8
|
+
hash_caster.applicable?(to_h(value))
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def applies_message
|
|
13
|
+
"be a an array of pairs"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def cast(array)
|
|
17
|
+
hash_caster.cast(super)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def hash_caster
|
|
23
|
+
@hash_caster ||= Hash.instance
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_h(value)
|
|
27
|
+
method(:cast).super_method.call(value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|