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
@@ -0,0 +1,114 @@
1
+ module Foobara
2
+ module Persistence
3
+ class EntityBase
4
+ attr_accessor :tables, :name, :entity_attributes_crud_driver
5
+
6
+ class << self
7
+ def using_transactions(existing_transactions, &block)
8
+ if existing_transactions.empty?
9
+ block.call
10
+ elsif existing_transactions.size == 1
11
+ existing_transaction = existing_transactions.first
12
+
13
+ existing_transaction.entity_base.using_transaction(existing_transaction, &block)
14
+ else
15
+ existing_transactions.inject(block) do |nested_proc, existing_transaction|
16
+ proc do
17
+ existing_transaction.entity_base.using_transaction(existing_transaction, &nested_proc)
18
+ end
19
+ end.call
20
+ end
21
+ end
22
+ end
23
+
24
+ def initialize(name, entity_attributes_crud_driver:)
25
+ self.entity_attributes_crud_driver = entity_attributes_crud_driver
26
+ self.tables = {}
27
+ self.name = name
28
+ # TODO: a smell?
29
+ end
30
+
31
+ def register_entity_class(entity_class, table_name: entity_class.full_entity_name)
32
+ table = EntityBase::Table.new(table_name, self)
33
+
34
+ register_table(table)
35
+ end
36
+
37
+ def register_table(table)
38
+ tables[table.table_name] = table
39
+ end
40
+
41
+ def transaction_key
42
+ @transaction_key ||= "foobara:tx:#{name}"
43
+ end
44
+
45
+ def current_transaction
46
+ Thread.foobara_var_get(transaction_key)
47
+ end
48
+
49
+ def set_current_transaction(transaction)
50
+ Thread.foobara_var_set(transaction_key, transaction)
51
+ end
52
+
53
+ VALID_MODES = [:use_existing, :open_nested, :open_new, nil].freeze
54
+
55
+ def using_transaction(existing_transaction, &)
56
+ transaction(existing_transaction:, &)
57
+ end
58
+
59
+ def transaction(mode = nil, existing_transaction: nil)
60
+ unless VALID_MODES.include?(mode)
61
+ # :nocov:
62
+ raise ArgumentError, "Mode was #{mode} but expected one of #{VALID_MODES}"
63
+ # :nocov:
64
+ end
65
+
66
+ old_transaction = current_transaction
67
+
68
+ if old_transaction&.closed?
69
+ old_transaction = nil
70
+ end
71
+
72
+ if old_transaction&.currently_open?
73
+ if mode == :use_existing || existing_transaction == old_transaction
74
+ if block_given?
75
+ return yield old_transaction
76
+ else
77
+ return old_transaction
78
+ end
79
+ elsif mode != :open_nested && mode != :open_new
80
+ # :nocov:
81
+ raise "Transaction already open. " \
82
+ "Use mode :use_existing if you want to make use of the existing transaction. " \
83
+ "Use mode :open_nested if you are actually trying to nest transactions."
84
+ # :nocov:
85
+ end
86
+ end
87
+
88
+ unless block_given?
89
+ return existing_transaction || Transaction.new(self)
90
+ end
91
+
92
+ begin
93
+ if existing_transaction
94
+ tx = existing_transaction
95
+ else
96
+ tx = Transaction.new(self)
97
+ tx.open!
98
+ end
99
+
100
+ set_current_transaction(tx)
101
+ result = yield tx
102
+ tx.commit! if tx.currently_open? && !existing_transaction
103
+ result
104
+ rescue Foobara::Persistence::EntityBase::Transaction::RolledBack # rubocop:disable Lint/SuppressedException
105
+ rescue => e
106
+ tx.rollback!(e) if tx.currently_open?
107
+ raise
108
+ ensure
109
+ set_current_transaction(old_transaction)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,172 @@
1
+ module Foobara
2
+ module Persistence
3
+ class NoTableOrCrudDriverError < StandardError; end
4
+ class NoTransactionOpenError < StandardError; end
5
+
6
+ class << self
7
+ attr_reader :default_crud_driver
8
+
9
+ def default_crud_driver=(crud_driver)
10
+ if default_crud_driver
11
+ # :nocov:
12
+ raise "Default crud driver already set."
13
+ # :nocov:
14
+ end
15
+
16
+ @default_crud_driver = crud_driver
17
+ end
18
+
19
+ def default_base
20
+ @default_base ||= if default_crud_driver
21
+ base = EntityBase.new(
22
+ "default_entity_base",
23
+ entity_attributes_crud_driver: default_crud_driver
24
+ )
25
+ register_base(base)
26
+ end
27
+ end
28
+
29
+ # TODO: automatically order these by dependency...
30
+ # TODO: also, consider automatically opening transactions for dependent entities automatically...
31
+ def transaction(*objects, mode: nil, &block)
32
+ # def transaction(mode = nil, existing_transaction: nil)
33
+ bases = objects_to_bases(objects)
34
+
35
+ if bases.empty?
36
+ # :nocov:
37
+ raise "No bases found for #{objects}"
38
+ # :nocov:
39
+ end
40
+
41
+ if bases.size == 1
42
+ bases.first.transaction(mode, &block)
43
+ else
44
+ bases.inject(block) do |nested_proc, base|
45
+ proc do
46
+ base.transaction(mode, &nested_proc)
47
+ end
48
+ end.call
49
+ end
50
+ end
51
+
52
+ # TODO: support transactions across multiple bases
53
+ def current_transaction(object)
54
+ base = to_base(object)
55
+ base.current_transaction
56
+ end
57
+
58
+ def current_transaction!(object)
59
+ base = to_base(object)
60
+ tx = base.current_transaction
61
+
62
+ unless tx
63
+ # :nocov:
64
+ raise NoTransactionOpenError
65
+ # :nocov:
66
+ end
67
+
68
+ tx
69
+ end
70
+
71
+ def current_transaction_table!(object)
72
+ current_transaction!(object).table_for(object)
73
+ end
74
+
75
+ def current_transaction_table(object)
76
+ current_transaction(object).table_for(object)
77
+ end
78
+
79
+ def to_base(object)
80
+ bases = to_bases(object)
81
+
82
+ if bases.empty?
83
+ # :nocov:
84
+ raise "Could not find a base for #{object}"
85
+ # :nocov:
86
+ end
87
+
88
+ if bases.size > 1
89
+ # :nocov:
90
+ raise "Expected to only find 1 base for #{object} but found #{bases.size}"
91
+ # :nocov:
92
+ end
93
+
94
+ bases.first
95
+ end
96
+
97
+ def to_bases(object)
98
+ objects_to_bases(Util.array(object))
99
+ end
100
+
101
+ def objects_to_bases(objects)
102
+ objects.map do |object|
103
+ object_to_base(object)
104
+ end.uniq
105
+ end
106
+
107
+ def object_to_base(object)
108
+ case object
109
+ when EntityBase
110
+ object
111
+ when ::String
112
+ bases[object]
113
+ when ::Symbol
114
+ bases[object.to_s]
115
+ when Class
116
+ base_for_entity_class(object)
117
+ when Entity
118
+ base_for_entity_class(object.class)
119
+ else
120
+ # :nocov:
121
+ raise ArgumentError, "Not able to convert #{object} to an entity base"
122
+ # :nocov:
123
+ end
124
+ end
125
+
126
+ def bases
127
+ @bases ||= {}
128
+ end
129
+
130
+ def base_for_entity_class_name(entity_class_name)
131
+ table_for_entity_class_name(entity_class_name).entity_base
132
+ end
133
+
134
+ def base_for_entity_class(entity_class)
135
+ table_for_entity_class_name(entity_class.full_entity_name).entity_base
136
+ end
137
+
138
+ def table_for_entity_class_name(entity_class_name)
139
+ table = tables_for_entity_class_name[entity_class_name]
140
+
141
+ return table if table
142
+
143
+ if default_base
144
+ table = EntityBase::Table.new(entity_class_name, default_base)
145
+ default_base.register_table(table)
146
+ tables_for_entity_class_name[entity_class_name] = table
147
+ else
148
+ # :nocov:
149
+ raise NoTableOrCrudDriverError,
150
+ "Can't find table for #{entity_class_name} and can't dynamically build one without default crud driver."
151
+ # :nocov:
152
+ end
153
+ end
154
+
155
+ def register_base(base)
156
+ # TODO: add some validations here
157
+ bases[base.name] = base
158
+ end
159
+
160
+ def register_entity(base, entity_class, table_name: entity_class.full_entity_name)
161
+ base = to_base(base)
162
+
163
+ table = base.register_entity_class(entity_class, table_name:)
164
+ tables_for_entity_class_name[entity_class.full_entity_name] = table
165
+ end
166
+
167
+ def tables_for_entity_class_name
168
+ @tables_for_entity_class_name ||= {}
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1 @@
1
+ class Foobara::StateMachine; end
@@ -0,0 +1,158 @@
1
+ module Foobara
2
+ class StateMachine
3
+ module Callbacks
4
+ include Concern
5
+
6
+ # owner helps with determining the relevant object when running class-registered state transition callbacks
7
+ attr_accessor :callback_registry, :owner
8
+
9
+ def initialize(owner: nil)
10
+ self.owner = owner
11
+ self.callback_registry = Callback::Registry::ChainedConditioned.new(self.class.class_callback_registry)
12
+ end
13
+
14
+ foobara_delegate :callbacks_for,
15
+ :has_callbacks?,
16
+ :has_before_callbacks?,
17
+ :has_after_callbacks?,
18
+ :has_around_callbacks?,
19
+ :has_error_callbacks?,
20
+ :has_failure_callbacks?,
21
+ to: :callback_registry
22
+
23
+ def register_transition_callback(type, **, &)
24
+ callback_registry.register_callback(type, **, &)
25
+ end
26
+
27
+ module ClassMethods
28
+ def class_callback_registry
29
+ @class_callback_registry ||= Callback::Registry::Conditioned.new(
30
+ from: states,
31
+ transition: transitions,
32
+ to: states
33
+ )
34
+ end
35
+
36
+ def remove_all_callbacks
37
+ @class_callback_registry = nil
38
+ end
39
+
40
+ def register_transition_callback(type, **, &)
41
+ class_callback_registry.register_callback(type, **, &)
42
+ end
43
+
44
+ attr_reader :register_callback_methods
45
+
46
+ # 0 before_any_transition
47
+ # 1 before_transition_to_<state>
48
+ # 2 before_transition_from_<state>
49
+ # 3 before_transition_from_<state>_to_<state>
50
+ # 4 before_<transition>_transition
51
+ # 5 before_<transition>_transition_to_<state>
52
+ # 6 before_<transition>_transition_from_<state>
53
+ def create_register_callback_methods
54
+ if register_callback_methods
55
+ # :nocov:
56
+ raise "Do not create register callback methods twice"
57
+ # :nocov:
58
+ end
59
+
60
+ callback_methods = @register_callback_methods = []
61
+
62
+ tos = Set.new
63
+ transitions = Set.new
64
+ froms = Set.new
65
+
66
+ froms_to_tos = Set.new
67
+ transitions_to_tos = Set.new
68
+ froms_to_transitions = Set.new
69
+ froms_transitions_tos = Set.new
70
+
71
+ transition_map.each_pair do |from, to_map|
72
+ froms << from
73
+ to_map.each_pair do |transition, to|
74
+ transitions << transition
75
+ tos << to
76
+ froms_to_tos << [from, to]
77
+ transitions_to_tos << [transition, to]
78
+ froms_to_transitions << [from, transition]
79
+ froms_transitions_tos << [from, transition, to]
80
+ end
81
+ end
82
+
83
+ Foobara::Callback::Block.types.each do |type|
84
+ method_name = "#{type}_any_transition"
85
+ callback_methods << method_name
86
+
87
+ define_method method_name do |&block|
88
+ register_transition_callback(type, &block)
89
+ end
90
+
91
+ froms.each do |from|
92
+ method_name = "#{type}_transition_from_#{from}"
93
+ callback_methods << method_name
94
+
95
+ define_method method_name do |&block|
96
+ register_transition_callback(type, from:, &block)
97
+ end
98
+ end
99
+
100
+ transitions.each do |transition|
101
+ method_name = "#{type}_#{transition}"
102
+ callback_methods << method_name
103
+
104
+ define_method method_name do |&block|
105
+ register_transition_callback(type, transition:, &block)
106
+ end
107
+ end
108
+
109
+ tos.each do |to|
110
+ method_name = "#{type}_transition_to_#{to}"
111
+ callback_methods << method_name
112
+
113
+ define_method method_name do |&block|
114
+ register_transition_callback(type, to:, &block)
115
+ end
116
+ end
117
+
118
+ froms_to_tos.each do |(from, to)|
119
+ method_name = "#{type}_transition_from_#{from}_to_#{to}"
120
+ callback_methods << method_name
121
+
122
+ define_method method_name do |&block|
123
+ register_transition_callback(type, to:, from:, &block)
124
+ end
125
+ end
126
+
127
+ transitions_to_tos.each do |(transition, to)|
128
+ method_name = "#{type}_#{transition}_to_#{to}"
129
+ callback_methods << method_name
130
+
131
+ define_method method_name do |&block|
132
+ register_transition_callback(type, transition:, to:, &block)
133
+ end
134
+ end
135
+
136
+ froms_to_transitions.each do |(from, transition)|
137
+ method_name = "#{type}_#{transition}_from_#{from}"
138
+ callback_methods << method_name
139
+
140
+ define_method method_name do |&block|
141
+ register_transition_callback(type, transition:, from:, &block)
142
+ end
143
+ end
144
+
145
+ froms_transitions_tos.each do |(from, transition, to)|
146
+ method_name = "#{type}_#{transition}_from_#{from}_to_#{to}"
147
+ callback_methods << method_name
148
+
149
+ define_method method_name do |&block|
150
+ register_transition_callback(type, transition:, from:, to:, &block)
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,13 @@
1
+ module Foobara
2
+ class StateMachine
3
+ class LogEntry
4
+ attr_accessor :from, :transition, :to
5
+
6
+ def initialize(from:, transition:, to:)
7
+ self.from = from
8
+ self.transition = transition
9
+ self.to = to
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,91 @@
1
+ module Foobara
2
+ require_project_file("state_machine", "sugar")
3
+ require_project_file("state_machine", "callbacks")
4
+ require_project_file("state_machine", "validations")
5
+
6
+ class StateMachine
7
+ include Sugar
8
+ include Callbacks
9
+ include Validations
10
+ include TransitionLog
11
+
12
+ class InvalidTransition < StandardError; end
13
+
14
+ class << self
15
+ attr_accessor :transitions, :initial_state, :states, :non_terminal_states, :terminal_states, :transition_map,
16
+ :raw_transition_map, :state, :transition
17
+
18
+ def set_transition_map(transition_map, initial_state: nil, states: nil, terminal_states: nil, transitions: nil)
19
+ self.raw_transition_map = transition_map
20
+
21
+ self.initial_state = initial_state
22
+ self.states = states
23
+ self.terminal_states = terminal_states
24
+ self.transitions = transitions
25
+
26
+ desugarize_transition_map
27
+ determine_states_and_transitions
28
+
29
+ create_enums
30
+ create_state_predicate_methods
31
+ create_transition_methods
32
+ create_can_methods
33
+ create_register_callback_methods
34
+ end
35
+ end
36
+
37
+ attr_accessor :current_state
38
+
39
+ def initialize(*args, **options)
40
+ super
41
+
42
+ self.current_state = self.class.initial_state
43
+ end
44
+
45
+ def perform_transition!(transition, &block)
46
+ from = current_state
47
+
48
+ transition_map = self.class.transition_map
49
+
50
+ if in_terminal_state?
51
+ raise InvalidTransition,
52
+ "#{current_state} is a terminal state so no transitions from here are allowed."
53
+ end
54
+
55
+ unless transition_map[current_state].key?(transition)
56
+ raise InvalidTransition,
57
+ "Cannot perform #{transition} from #{current_state}. Expected one of #{allowed_transitions}."
58
+ end
59
+
60
+ to = transition_map[current_state][transition]
61
+
62
+ conditions = { from:, transition:, to: }
63
+
64
+ callback_registry.runner(**conditions).callback_data(state_machine: self, **conditions).run do
65
+ block.call if block_given?
66
+ update_current_state(**conditions)
67
+ end
68
+ end
69
+
70
+ def allowed_transitions
71
+ if in_terminal_state?
72
+ []
73
+ else
74
+ self.class.transition_map[current_state].keys
75
+ end
76
+ end
77
+
78
+ def can?(transition)
79
+ self.class.transition_map[current_state].key?(transition)
80
+ end
81
+
82
+ def update_current_state(**conditions)
83
+ self.current_state = conditions[:to]
84
+ log_transition(**conditions)
85
+ end
86
+
87
+ def in_terminal_state?
88
+ self.class.terminal_states.include?(current_state)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,125 @@
1
+ module Foobara
2
+ class StateMachine
3
+ module Sugar
4
+ class TransitionAlreadyDefinedError < StandardError; end
5
+ class BadInitialState < StandardError; end
6
+
7
+ include Concern
8
+
9
+ module ClassMethods
10
+ def desugarize_transition_map
11
+ self.transition_map = {}
12
+
13
+ raw_transition_map.each_pair do |from_state, transitions|
14
+ Util.array(from_state).each do |state|
15
+ state = state.to_sym
16
+
17
+ transitions.each_pair do |transition, next_state|
18
+ transition = transition.to_sym
19
+ next_state = next_state.to_sym
20
+
21
+ transitions_for_state = transition_map[state] ||= {}
22
+
23
+ if transitions_for_state.key?(transition)
24
+ # :nocov:
25
+ raise TransitionAlreadyDefinedError, "There's already a #{transition} for #{state}"
26
+ # :nocov:
27
+ end
28
+
29
+ transitions_for_state[transition] = next_state
30
+ end
31
+ end
32
+ end
33
+
34
+ transition_map.freeze
35
+ end
36
+
37
+ def determine_states_and_transitions
38
+ computed_non_terminal_states = transition_map.keys.uniq
39
+ computed_terminal_states = []
40
+ computed_transitions = []
41
+
42
+ transition_map.each_value do |transitions|
43
+ transitions.each_pair do |transition, to_state|
44
+ computed_transitions << transition unless computed_transitions.include?(transition)
45
+
46
+ if !computed_non_terminal_states.include?(to_state) && !computed_terminal_states.include?(to_state)
47
+ computed_terminal_states << to_state
48
+ end
49
+ end
50
+ end
51
+
52
+ if terminal_states
53
+ all_states = computed_non_terminal_states + computed_terminal_states
54
+ validate_terminal_states(computed_terminal_states, all_states)
55
+ # User has marked states as explicitly terminal even though they might have transitions
56
+ # This is allowed. So fix any such computations.
57
+ computed_non_terminal_states -= terminal_states
58
+ computed_terminal_states |= terminal_states
59
+ else
60
+ self.terminal_states = computed_terminal_states.freeze
61
+ end
62
+
63
+ self.non_terminal_states = computed_non_terminal_states.freeze
64
+
65
+ computed_states = computed_non_terminal_states + computed_terminal_states
66
+
67
+ if states
68
+ validate_states(computed_states)
69
+ else
70
+ self.states = computed_states.freeze
71
+ end
72
+
73
+ if transitions
74
+ validate_transitions(computed_transitions)
75
+ else
76
+ self.transitions = computed_transitions.freeze
77
+ end
78
+
79
+ if initial_state
80
+ unless states.include?(initial_state)
81
+ raise BadInitialState, "Initial state explicitly set to #{
82
+ initial_state
83
+ } but should have been one of #{states}"
84
+ end
85
+ else
86
+ self.initial_state = states.first
87
+ end
88
+ end
89
+
90
+ def create_enums
91
+ self.state = Enumerated::Values.new(states)
92
+ self.transition = Enumerated::Values.new(transitions)
93
+ end
94
+
95
+ def create_state_predicate_methods
96
+ states.each do |state|
97
+ define_method "currently_#{state}?" do
98
+ current_state == state
99
+ end
100
+
101
+ define_method "ever_#{state}?" do
102
+ current_state == state || log.any? { |log_entry| log_entry.from == state }
103
+ end
104
+ end
105
+ end
106
+
107
+ def create_can_methods
108
+ transitions.each do |transition|
109
+ define_method "can_#{transition}?" do
110
+ can?(transition)
111
+ end
112
+ end
113
+ end
114
+
115
+ def create_transition_methods
116
+ transitions.each do |transition|
117
+ define_method "#{transition}!" do |&block|
118
+ perform_transition!(transition, &block)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,19 @@
1
+ module Foobara
2
+ class StateMachine
3
+ module TransitionLog
4
+ include Concern
5
+
6
+ attr_accessor :log
7
+
8
+ def initialize(*args, **options)
9
+ super
10
+
11
+ self.log = []
12
+ end
13
+
14
+ def log_transition(**)
15
+ log << LogEntry.new(**)
16
+ end
17
+ end
18
+ end
19
+ end