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.
Files changed (359) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +5 -0
  3. data/.rubocop.yml +20 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +10 -0
  6. data/DECISION_LOG.md +220 -0
  7. data/Guardfile +9 -0
  8. data/LICENSE-AGPL.txt +666 -0
  9. data/LICENSE.txt +4 -0
  10. data/README.md +50 -0
  11. data/Rakefile +10 -0
  12. data/concepts.md +153 -0
  13. data/projects/builtin_types/lib/foobara/builtin_types.rb +67 -0
  14. data/projects/builtin_types/src/README.md +140 -0
  15. data/projects/builtin_types/src/array/casters/arrayable.rb +22 -0
  16. data/projects/builtin_types/src/array/supported_processors/element_type_declaration.rb +41 -0
  17. data/projects/builtin_types/src/array/supported_validators/size.rb +43 -0
  18. data/projects/builtin_types/src/associative_array/casters/array.rb +22 -0
  19. data/projects/builtin_types/src/associative_array/supported_processors/key_type_declaration.rb +44 -0
  20. data/projects/builtin_types/src/associative_array/supported_processors/value_type_declaration.rb +44 -0
  21. data/projects/builtin_types/src/atomic_duck.rb +6 -0
  22. data/projects/builtin_types/src/attributes/casters/array.rb +33 -0
  23. data/projects/builtin_types/src/attributes/casters/hash.rb +28 -0
  24. data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb +89 -0
  25. 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
  26. data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/desugarizers/symbolize_defaults.rb +31 -0
  27. 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
  28. 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
  29. data/projects/builtin_types/src/attributes/supported_transformers/defaults.rb +41 -0
  30. 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
  31. 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
  32. 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
  33. data/projects/builtin_types/src/attributes/supported_validators/required.rb +51 -0
  34. data/projects/builtin_types/src/big_decimal/casters/integer.rb +21 -0
  35. data/projects/builtin_types/src/big_decimal/casters/string.rb +24 -0
  36. data/projects/builtin_types/src/boolean/casters/numeric.rb +21 -0
  37. data/projects/builtin_types/src/boolean/casters/string_or_symbol.rb +27 -0
  38. data/projects/builtin_types/src/builtin_types.rb +189 -0
  39. data/projects/builtin_types/src/date/casters/hash.rb +23 -0
  40. data/projects/builtin_types/src/date/casters/string.rb +40 -0
  41. data/projects/builtin_types/src/datetime/casters/date.rb +21 -0
  42. data/projects/builtin_types/src/datetime/casters/hash.rb +77 -0
  43. data/projects/builtin_types/src/datetime/casters/seconds_since_epoch.rb +21 -0
  44. data/projects/builtin_types/src/datetime/casters/string.rb +31 -0
  45. data/projects/builtin_types/src/duck/supported_casters/allow_nil.rb +38 -0
  46. data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_desugarizer.rb +29 -0
  47. 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
  48. 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
  49. 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
  50. data/projects/builtin_types/src/duck/supported_validators/instance_of.rb +42 -0
  51. data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/cast_one_of.rb +37 -0
  52. data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/module_desugarizer.rb +41 -0
  53. data/projects/builtin_types/src/duck/supported_validators/one_of.rb +41 -0
  54. data/projects/builtin_types/src/duck.rb +6 -0
  55. data/projects/builtin_types/src/duckture.rb +6 -0
  56. data/projects/builtin_types/src/email/transformers/downcase.rb +15 -0
  57. data/projects/builtin_types/src/email/validator_base.rb +94 -0
  58. data/projects/builtin_types/src/float/casters/integer.rb +21 -0
  59. data/projects/builtin_types/src/float/casters/string.rb +24 -0
  60. data/projects/builtin_types/src/integer/casters/string.rb +23 -0
  61. data/projects/builtin_types/src/number/supported_validators/max.rb +41 -0
  62. data/projects/builtin_types/src/number/supported_validators/min.rb +41 -0
  63. data/projects/builtin_types/src/string/casters/numeric.rb +21 -0
  64. data/projects/builtin_types/src/string/casters/symbol.rb +21 -0
  65. data/projects/builtin_types/src/string/supported_transformers/downcase.rb +11 -0
  66. data/projects/builtin_types/src/string/supported_validators/matches.rb +41 -0
  67. data/projects/builtin_types/src/string/supported_validators/max_length.rb +37 -0
  68. data/projects/builtin_types/src/symbol/casters/string.rb +21 -0
  69. data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations/type_declaration_extension/extend_tuple_type_declaration/desugarizers/set_size.rb +32 -0
  70. 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
  71. data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations.rb +59 -0
  72. data/projects/callback/lib/foobara/callback.rb +1 -0
  73. data/projects/callback/src/block/after.rb +10 -0
  74. data/projects/callback/src/block/around.rb +10 -0
  75. data/projects/callback/src/block/before.rb +10 -0
  76. data/projects/callback/src/block/concerns/block_parameter_not_allowed.rb +21 -0
  77. data/projects/callback/src/block/concerns/block_parameter_required.rb +21 -0
  78. data/projects/callback/src/block/concerns/keyword_argumentable_block.rb +31 -0
  79. data/projects/callback/src/block/concerns/single_argument_block.rb +22 -0
  80. data/projects/callback/src/block/concerns/type.rb +17 -0
  81. data/projects/callback/src/block/error.rb +10 -0
  82. data/projects/callback/src/block.rb +83 -0
  83. data/projects/callback/src/registry/base.rb +90 -0
  84. data/projects/callback/src/registry/chained_conditioned.rb +24 -0
  85. data/projects/callback/src/registry/chained_multiple_action.rb +24 -0
  86. data/projects/callback/src/registry/conditioned.rb +101 -0
  87. data/projects/callback/src/registry/multiple_action.rb +110 -0
  88. data/projects/callback/src/registry/single_action.rb +15 -0
  89. data/projects/callback/src/runner.rb +89 -0
  90. data/projects/callback/src/set.rb +56 -0
  91. data/projects/command/lib/foobara/command.rb +9 -0
  92. data/projects/command/src/command/entity_helpers.rb +145 -0
  93. data/projects/command/src/command.rb +36 -0
  94. data/projects/command/src/concerns/callbacks.rb +93 -0
  95. data/projects/command/src/concerns/description.rb +23 -0
  96. data/projects/command/src/concerns/domain_mappers.rb +35 -0
  97. data/projects/command/src/concerns/entities.rb +88 -0
  98. data/projects/command/src/concerns/errors.rb +181 -0
  99. data/projects/command/src/concerns/errors_type.rb +124 -0
  100. data/projects/command/src/concerns/inputs.rb +59 -0
  101. data/projects/command/src/concerns/inputs_type.rb +58 -0
  102. data/projects/command/src/concerns/namespace.rb +49 -0
  103. data/projects/command/src/concerns/reflection.rb +137 -0
  104. data/projects/command/src/concerns/result.rb +25 -0
  105. data/projects/command/src/concerns/result_type.rb +29 -0
  106. data/projects/command/src/concerns/runtime.rb +119 -0
  107. data/projects/command/src/concerns/state_machine.rb +12 -0
  108. data/projects/command/src/concerns/subcommands.rb +102 -0
  109. data/projects/command/src/concerns/transactions.rb +81 -0
  110. data/projects/command/src/state_machine.rb +57 -0
  111. data/projects/command/src/transformed_command.rb +459 -0
  112. data/projects/command_connectors/lib/foobara/command_connectors.rb +12 -0
  113. data/projects/command_connectors/src/command_connector.rb +401 -0
  114. data/projects/command_connectors/src/command_registry/allowed_rule.rb +29 -0
  115. data/projects/command_connectors/src/command_registry/exposed_command.rb +140 -0
  116. data/projects/command_connectors/src/command_registry/exposed_domain.rb +30 -0
  117. data/projects/command_connectors/src/command_registry/exposed_organization.rb +30 -0
  118. data/projects/command_connectors/src/command_registry.rb +257 -0
  119. data/projects/command_connectors/src/commands/describe.rb +36 -0
  120. data/projects/command_connectors/src/commands/list_commands.rb +51 -0
  121. data/projects/command_connectors/src/commands/ping.rb +21 -0
  122. data/projects/command_connectors/src/commands/query_git_commit_info.rb +81 -0
  123. data/projects/command_connectors/src/request.rb +99 -0
  124. data/projects/command_connectors/src/response.rb +17 -0
  125. data/projects/command_connectors/src/serializer.rb +25 -0
  126. data/projects/command_connectors/src/serializers/aggregate_serializer.rb +32 -0
  127. data/projects/command_connectors/src/serializers/atomic_serializer.rb +25 -0
  128. data/projects/command_connectors/src/serializers/entities_to_primary_keys_serializer.rb +28 -0
  129. data/projects/command_connectors/src/serializers/errors_serializer.rb +18 -0
  130. data/projects/command_connectors/src/serializers/json_serializer.rb +20 -0
  131. data/projects/command_connectors/src/serializers/noop_serializer.rb +20 -0
  132. data/projects/command_connectors/src/serializers/record_store_serializer.rb +31 -0
  133. data/projects/command_connectors/src/serializers/success_serializer.rb +14 -0
  134. data/projects/command_connectors/src/serializers/yaml_serializer.rb +20 -0
  135. data/projects/command_connectors/src/transformers/auth_errors_transformer.rb +35 -0
  136. data/projects/command_connectors/src/transformers/load_aggregates_pre_commit_transformer.rb +36 -0
  137. data/projects/command_connectors_http/lib/foobara/command_connectors_http.rb +6 -0
  138. data/projects/command_connectors_http/src/http/commands/get_options.rb +16 -0
  139. data/projects/command_connectors_http/src/http/commands/help/presenter/command.rb +14 -0
  140. data/projects/command_connectors_http/src/http/commands/help/presenter/domain.rb +14 -0
  141. data/projects/command_connectors_http/src/http/commands/help/presenter/entity.rb +14 -0
  142. data/projects/command_connectors_http/src/http/commands/help/presenter/error.rb +14 -0
  143. data/projects/command_connectors_http/src/http/commands/help/presenter/model.rb +14 -0
  144. data/projects/command_connectors_http/src/http/commands/help/presenter/organization.rb +14 -0
  145. data/projects/command_connectors_http/src/http/commands/help/presenter/processor.rb +14 -0
  146. data/projects/command_connectors_http/src/http/commands/help/presenter/processor_class.rb +14 -0
  147. data/projects/command_connectors_http/src/http/commands/help/presenter/root.rb +14 -0
  148. data/projects/command_connectors_http/src/http/commands/help/presenter/type.rb +14 -0
  149. data/projects/command_connectors_http/src/http/commands/help/presenter.rb +162 -0
  150. data/projects/command_connectors_http/src/http/commands/help/templates/command.html.erb +11 -0
  151. data/projects/command_connectors_http/src/http/commands/help/templates/domain.html.erb +1 -0
  152. data/projects/command_connectors_http/src/http/commands/help/templates/entity.html.erb +1 -0
  153. data/projects/command_connectors_http/src/http/commands/help/templates/error.html.erb +1 -0
  154. data/projects/command_connectors_http/src/http/commands/help/templates/model.html.erb +1 -0
  155. data/projects/command_connectors_http/src/http/commands/help/templates/organization.html.erb +1 -0
  156. data/projects/command_connectors_http/src/http/commands/help/templates/processor.html.erb +1 -0
  157. data/projects/command_connectors_http/src/http/commands/help/templates/processor_class.html.erb +1 -0
  158. data/projects/command_connectors_http/src/http/commands/help/templates/root.html.erb +3 -0
  159. data/projects/command_connectors_http/src/http/commands/help/templates/type.html.erb +1 -0
  160. data/projects/command_connectors_http/src/http/commands/help.rb +98 -0
  161. data/projects/command_connectors_http/src/http/request.rb +98 -0
  162. data/projects/command_connectors_http/src/http/response.rb +14 -0
  163. data/projects/command_connectors_http/src/http.rb +84 -0
  164. data/projects/common/lib/foobara/common.rb +11 -0
  165. data/projects/common/src/data_path.rb +272 -0
  166. data/projects/common/src/error.rb +215 -0
  167. data/projects/common/src/error_collection.rb +97 -0
  168. data/projects/common/src/error_key.rb +168 -0
  169. data/projects/common/src/outcome.rb +101 -0
  170. data/projects/common/src/possible_error.rb +80 -0
  171. data/projects/common/src/runtime_error.rb +24 -0
  172. data/projects/concerns/lib/foobara/concerns.rb +1 -0
  173. data/projects/concerns/src/concern.rb +93 -0
  174. data/projects/delegate/lib/foobara/delegate.rb +1 -0
  175. data/projects/delegate/src/extensions/module.rb +12 -0
  176. data/projects/domain/lib/foobara/domain.rb +25 -0
  177. data/projects/domain/src/domain.rb +65 -0
  178. data/projects/domain/src/domain_mapper/registry.rb +47 -0
  179. data/projects/domain/src/domain_mapper.rb +162 -0
  180. data/projects/domain/src/domain_module_extension.rb +510 -0
  181. data/projects/domain/src/extensions/foobara.rb +69 -0
  182. data/projects/domain/src/global_domain.rb +14 -0
  183. data/projects/domain/src/global_organization.rb +12 -0
  184. data/projects/domain/src/is_manifestable.rb +68 -0
  185. data/projects/domain/src/manifestable.rb +12 -0
  186. data/projects/domain/src/module_extension.rb +122 -0
  187. data/projects/domain/src/organization.rb +52 -0
  188. data/projects/domain/src/organization_module_extension.rb +50 -0
  189. data/projects/entity/lib/foobara/entity.rb +27 -0
  190. data/projects/entity/src/concerns/associations.rb +241 -0
  191. data/projects/entity/src/concerns/attributes.rb +170 -0
  192. data/projects/entity/src/concerns/callbacks.rb +97 -0
  193. data/projects/entity/src/concerns/initialization.rb +127 -0
  194. data/projects/entity/src/concerns/persistence.rb +142 -0
  195. data/projects/entity/src/concerns/primary_key.rb +43 -0
  196. data/projects/entity/src/concerns/queries.rb +96 -0
  197. data/projects/entity/src/concerns/reflection.rb +51 -0
  198. data/projects/entity/src/concerns/transactions.rb +31 -0
  199. data/projects/entity/src/concerns/types.rb +31 -0
  200. data/projects/entity/src/entity.rb +61 -0
  201. data/projects/entity/src/extensions/builtin_types/entity/casters/hash.rb +33 -0
  202. data/projects/entity/src/extensions/builtin_types/entity/validators/attributes_declaration.rb +32 -0
  203. data/projects/entity/src/extensions/builtin_types/entity.rb +6 -0
  204. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/attributes_handler_desugarizer.rb +14 -0
  205. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/hash_desugarizer.rb +43 -0
  206. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/model_class_desugarizer.rb +21 -0
  207. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/primary_key_desugarizer.rb +19 -0
  208. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/to_type_transformer.rb +64 -0
  209. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_is_symbol.rb +35 -0
  210. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_present.rb +27 -0
  211. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_references_attribute.rb +36 -0
  212. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration.rb +11 -0
  213. data/projects/entity/src/new_prepend.rb +21 -0
  214. data/projects/entity/src/not_found_error.rb +72 -0
  215. data/projects/enumerated/lib/foobara/enumerated.rb +1 -0
  216. data/projects/enumerated/src/accessors.rb +61 -0
  217. data/projects/enumerated/src/values.rb +121 -0
  218. data/projects/foobara/lib/foobara/all.rb +44 -0
  219. data/projects/in_memory_crud_driver/lib/foobara/in_memory_crud_driver.rb +3 -0
  220. data/projects/in_memory_crud_driver/src/in_memory.rb +10 -0
  221. data/projects/in_memory_crud_driver_minimal/lib/foobara/in_memory_crud_driver_minimal.rb +1 -0
  222. data/projects/in_memory_crud_driver_minimal/src/in_memory_minimal.rb +113 -0
  223. data/projects/manifest/lib/foobara/manifest.rb +4 -0
  224. data/projects/manifest/src/foobara/manifest/array.rb +13 -0
  225. data/projects/manifest/src/foobara/manifest/attributes.rb +40 -0
  226. data/projects/manifest/src/foobara/manifest/base_manifest.rb +161 -0
  227. data/projects/manifest/src/foobara/manifest/command.rb +59 -0
  228. data/projects/manifest/src/foobara/manifest/domain.rb +43 -0
  229. data/projects/manifest/src/foobara/manifest/entity.rb +35 -0
  230. data/projects/manifest/src/foobara/manifest/error.rb +33 -0
  231. data/projects/manifest/src/foobara/manifest/model.rb +43 -0
  232. data/projects/manifest/src/foobara/manifest/organization.rb +45 -0
  233. data/projects/manifest/src/foobara/manifest/possible_error.rb +30 -0
  234. data/projects/manifest/src/foobara/manifest/processor.rb +11 -0
  235. data/projects/manifest/src/foobara/manifest/processor_class.rb +11 -0
  236. data/projects/manifest/src/foobara/manifest/root_manifest.rb +112 -0
  237. data/projects/manifest/src/foobara/manifest/type.rb +86 -0
  238. data/projects/manifest/src/foobara/manifest/type_declaration.rb +117 -0
  239. data/projects/model/lib/foobara/model.rb +23 -0
  240. data/projects/model/src/concerns/reflection.rb +22 -0
  241. data/projects/model/src/concerns/types.rb +104 -0
  242. data/projects/model/src/extensions/builtin_types/model/casters/hash.rb +23 -0
  243. data/projects/model/src/extensions/builtin_types/model/transformers/mutable.rb +26 -0
  244. data/projects/model/src/extensions/builtin_types/model/validators/attributes_declaration.rb +33 -0
  245. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/attributes_handler_desugarizer.rb +24 -0
  246. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/hash_desugarizer.rb +32 -0
  247. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +119 -0
  248. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +57 -0
  249. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration.rb +21 -0
  250. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/hash_desugarizer.rb +37 -0
  251. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/model_class_type_desugarizer.rb +25 -0
  252. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/mutable_validator.rb +46 -0
  253. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/normalize_mutable_attributes_desugarizer.rb +28 -0
  254. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/to_type_transformer.rb +27 -0
  255. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +31 -0
  256. data/projects/model/src/extensions/type_declarations/handlers/registered_type_declaration/model_class_desugarizer.rb +23 -0
  257. data/projects/model/src/model.rb +320 -0
  258. data/projects/monorepo/lib/foobara/monorepo/project.rb +52 -0
  259. data/projects/monorepo/lib/foobara/monorepo.rb +63 -0
  260. data/projects/namespace/lib/foobara/namespace.rb +4 -0
  261. data/projects/namespace/src/ambiguous_registry.rb +104 -0
  262. data/projects/namespace/src/base_registry.rb +66 -0
  263. data/projects/namespace/src/extensions/module.rb +5 -0
  264. data/projects/namespace/src/is_namespace.rb +352 -0
  265. data/projects/namespace/src/namespace/lookup_mode.rb +41 -0
  266. data/projects/namespace/src/namespace.rb +61 -0
  267. data/projects/namespace/src/namespace_helpers.rb +273 -0
  268. data/projects/namespace/src/prefixless_registry.rb +54 -0
  269. data/projects/namespace/src/scoped.rb +113 -0
  270. data/projects/namespace/src/unambiguous_registry.rb +65 -0
  271. data/projects/persistence/lib/foobara/persistence.rb +22 -0
  272. data/projects/persistence/src/entity_attributes_crud_driver.rb +241 -0
  273. data/projects/persistence/src/entity_base/table.rb +14 -0
  274. data/projects/persistence/src/entity_base/transaction/concerns/entity_callback_handling.rb +157 -0
  275. data/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +83 -0
  276. data/projects/persistence/src/entity_base/transaction/concerns/transaction_tracking.rb +53 -0
  277. data/projects/persistence/src/entity_base/transaction/state_machine.rb +27 -0
  278. data/projects/persistence/src/entity_base/transaction.rb +163 -0
  279. data/projects/persistence/src/entity_base/transaction_table/concerns/queries.rb +42 -0
  280. data/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +134 -0
  281. data/projects/persistence/src/entity_base/transaction_table.rb +620 -0
  282. data/projects/persistence/src/entity_base.rb +114 -0
  283. data/projects/persistence/src/persistence.rb +172 -0
  284. data/projects/state_machine/lib/foobara/state_machine.rb +1 -0
  285. data/projects/state_machine/src/callbacks.rb +158 -0
  286. data/projects/state_machine/src/log_entry.rb +13 -0
  287. data/projects/state_machine/src/state_machine.rb +91 -0
  288. data/projects/state_machine/src/sugar.rb +125 -0
  289. data/projects/state_machine/src/transition_log.rb +19 -0
  290. data/projects/state_machine/src/validations.rb +69 -0
  291. data/projects/thread_parent/lib/foobara/thread_parent.rb +1 -0
  292. data/projects/thread_parent/src/thread_parent.rb +38 -0
  293. data/projects/type_declarations/lib/foobara/type_declarations.rb +131 -0
  294. data/projects/type_declarations/src/attributes.rb +34 -0
  295. data/projects/type_declarations/src/caster.rb +7 -0
  296. data/projects/type_declarations/src/desugarizer.rb +25 -0
  297. data/projects/type_declarations/src/dsl/attributes.rb +199 -0
  298. data/projects/type_declarations/src/element_processor.rb +7 -0
  299. data/projects/type_declarations/src/error_extension.rb +73 -0
  300. data/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb +31 -0
  301. data/projects/type_declarations/src/handlers/extend_array_type_declaration/element_type_declaration_desugarizer.rb +37 -0
  302. data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb +22 -0
  303. data/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +36 -0
  304. data/projects/type_declarations/src/handlers/extend_array_type_declaration.rb +14 -0
  305. data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration/to_type_transformer.rb +28 -0
  306. data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration.rb +20 -0
  307. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/dsl_desugarizer.rb +25 -0
  308. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/element_type_declarations_desugarizer.rb +34 -0
  309. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb +60 -0
  310. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +21 -0
  311. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration.rb +16 -0
  312. data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +75 -0
  313. data/projects/type_declarations/src/handlers/extend_registered_type_declaration.rb +23 -0
  314. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb +30 -0
  315. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb +24 -0
  316. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration.rb +13 -0
  317. data/projects/type_declarations/src/handlers/registered_type_declaration/desugarizer_metadata_cleanup_desugarizer.rb +29 -0
  318. data/projects/type_declarations/src/handlers/registered_type_declaration/short_type_name_desugarizer.rb +65 -0
  319. data/projects/type_declarations/src/handlers/registered_type_declaration/strict_desugarizer.rb +32 -0
  320. data/projects/type_declarations/src/handlers/registered_type_declaration/strict_stringified_desugarizer.rb +39 -0
  321. data/projects/type_declarations/src/handlers/registered_type_declaration/symbol_desugarizer.rb +26 -0
  322. data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb +28 -0
  323. data/projects/type_declarations/src/handlers/registered_type_declaration/type_desugarizer.rb +24 -0
  324. data/projects/type_declarations/src/handlers/registered_type_declaration.rb +26 -0
  325. data/projects/type_declarations/src/processor.rb +7 -0
  326. data/projects/type_declarations/src/to_type_transformer.rb +11 -0
  327. data/projects/type_declarations/src/transformer.rb +7 -0
  328. data/projects/type_declarations/src/type_builder.rb +112 -0
  329. data/projects/type_declarations/src/type_declaration_error.rb +9 -0
  330. data/projects/type_declarations/src/type_declaration_handler.rb +120 -0
  331. data/projects/type_declarations/src/type_declaration_handler_registry.rb +27 -0
  332. data/projects/type_declarations/src/type_declaration_validator.rb +19 -0
  333. data/projects/type_declarations/src/type_declarations.rb +128 -0
  334. data/projects/type_declarations/src/typed_transformer.rb +89 -0
  335. data/projects/type_declarations/src/validator.rb +7 -0
  336. data/projects/type_declarations/src/with_registries.rb +41 -0
  337. data/projects/types/lib/foobara/types.rb +11 -0
  338. data/projects/types/src/element_processor.rb +7 -0
  339. data/projects/types/src/extensions/error.rb +32 -0
  340. data/projects/types/src/type/concerns/reflection.rb +79 -0
  341. data/projects/types/src/type/concerns/supported_processor_registration.rb +56 -0
  342. data/projects/types/src/type.rb +375 -0
  343. data/projects/types/src/types.rb +4 -0
  344. data/projects/value/lib/foobara/value.rb +7 -0
  345. data/projects/value/src/caster.rb +84 -0
  346. data/projects/value/src/data_error.rb +27 -0
  347. data/projects/value/src/processor/casting.rb +123 -0
  348. data/projects/value/src/processor/multi.rb +63 -0
  349. data/projects/value/src/processor/pipeline.rb +27 -0
  350. data/projects/value/src/processor/runner.rb +38 -0
  351. data/projects/value/src/processor/selection.rb +90 -0
  352. data/projects/value/src/processor.rb +358 -0
  353. data/projects/value/src/transformer.rb +84 -0
  354. data/projects/value/src/validator.rb +53 -0
  355. data/projects/version/lib/foobara/version.rb +4 -0
  356. data/projects/version/src/version.rb +5 -0
  357. data/projects/weak_object_set/lib/foobara/weak_object_set.rb +3 -0
  358. data/projects/weak_object_set/src/weak_object_set.rb +163 -0
  359. 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
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require "rubocop/rake_task"
7
+
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[spec rubocop]
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
@@ -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
@@ -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,6 @@
1
+ module Foobara
2
+ module BuiltinTypes
3
+ module AtomicDuck
4
+ end
5
+ end
6
+ 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