brut 0.0.28 → 0.0.29

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 (369) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.projections.json +10 -0
  4. data/.rspec +3 -0
  5. data/Dockerfile.dx +32 -14
  6. data/Gemfile.lock +1 -1
  7. data/assets/Logo-Square.pxd +0 -0
  8. data/assets/LogoPylon.pxd +0 -0
  9. data/assets/LogoStop.pxd +0 -0
  10. data/assets/LogoTall.pxd +0 -0
  11. data/bin/docs +24 -2
  12. data/bin/rspec +27 -0
  13. data/bin/setup +3 -3
  14. data/brutrb.com/.vitepress/theme/custom.css +7 -0
  15. data/brutrb.com/.vitepress/theme/style.css +26 -15
  16. data/brutrb.com/deployment.md +123 -45
  17. data/brutrb.com/images/LogoPylon.png +0 -0
  18. data/brutrb.com/images/LogoSquare.png +0 -0
  19. data/brutrb.com/images/LogoStop.png +0 -0
  20. data/brutrb.com/images/LogoTall.png +0 -0
  21. data/brutrb.com/images/OverviewMetro.graffle +0 -0
  22. data/brutrb.com/images/OverviewMetro.png +0 -0
  23. data/brutrb.com/index.md +4 -3
  24. data/brutrb.com/overview.md +6 -6
  25. data/docker-compose.dx.yml +5 -2
  26. data/docs/404.html +3 -3
  27. data/docs/ai.html +4 -4
  28. data/docs/api/Brut/BackEnd/SeedData.html +1 -1
  29. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +1 -1
  30. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +1 -1
  31. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +1 -1
  32. data/docs/api/Brut/BackEnd/Sidekiq.html +1 -1
  33. data/docs/api/Brut/BackEnd/Validators/FormValidator.html +1 -1
  34. data/docs/api/Brut/BackEnd/Validators.html +1 -1
  35. data/docs/api/Brut/BackEnd.html +1 -1
  36. data/docs/api/Brut/CLI/App.html +1 -1
  37. data/docs/api/Brut/CLI/AppRunner.html +1 -1
  38. data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +1 -1
  39. data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +1 -1
  40. data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +1 -1
  41. data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +1 -1
  42. data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
  43. data/docs/api/Brut/CLI/Apps/DB/Create.html +1 -1
  44. data/docs/api/Brut/CLI/Apps/DB/Drop.html +1 -1
  45. data/docs/api/Brut/CLI/Apps/DB/Migrate.html +1 -1
  46. data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +1 -1
  47. data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +1 -1
  48. data/docs/api/Brut/CLI/Apps/DB/Seed.html +1 -1
  49. data/docs/api/Brut/CLI/Apps/DB/Status.html +1 -1
  50. data/docs/api/Brut/CLI/Apps/DB.html +1 -1
  51. data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +1 -1
  52. data/docs/api/Brut/CLI/Apps/DeployBase.html +1 -1
  53. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +1 -1
  54. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +1 -1
  55. data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
  56. data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +1 -1
  57. data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +1 -1
  58. data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +1 -1
  59. data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +1 -1
  60. data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +1 -1
  61. data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
  62. data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +1 -1
  63. data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
  64. data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +1 -1
  65. data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
  66. data/docs/api/Brut/CLI/Apps/Test/Audit.html +1 -1
  67. data/docs/api/Brut/CLI/Apps/Test/E2e.html +1 -1
  68. data/docs/api/Brut/CLI/Apps/Test/JS.html +1 -1
  69. data/docs/api/Brut/CLI/Apps/Test/Run.html +1 -1
  70. data/docs/api/Brut/CLI/Apps/Test.html +1 -1
  71. data/docs/api/Brut/CLI/Apps.html +1 -1
  72. data/docs/api/Brut/CLI/Command.html +1 -1
  73. data/docs/api/Brut/CLI/Error.html +1 -1
  74. data/docs/api/Brut/CLI/ExecutionResults/Result.html +1 -1
  75. data/docs/api/Brut/CLI/ExecutionResults.html +1 -1
  76. data/docs/api/Brut/CLI/Executor.html +1 -1
  77. data/docs/api/Brut/CLI/InvalidOption.html +1 -1
  78. data/docs/api/Brut/CLI/Options.html +1 -1
  79. data/docs/api/Brut/CLI/Output.html +1 -1
  80. data/docs/api/Brut/CLI/SystemExecError.html +1 -1
  81. data/docs/api/Brut/CLI.html +1 -1
  82. data/docs/api/Brut/FactoryBot.html +1 -1
  83. data/docs/api/Brut/Framework/App.html +1 -1
  84. data/docs/api/Brut/Framework/Config.html +1 -1
  85. data/docs/api/Brut/Framework/Container.html +1 -1
  86. data/docs/api/Brut/Framework/Error.html +1 -1
  87. data/docs/api/Brut/Framework/Errors/AbstractMethod.html +1 -1
  88. data/docs/api/Brut/Framework/Errors/Bug.html +1 -1
  89. data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +1 -1
  90. data/docs/api/Brut/Framework/Errors/MissingParameter.html +1 -1
  91. data/docs/api/Brut/Framework/Errors/NoClassForPath.html +1 -1
  92. data/docs/api/Brut/Framework/Errors/NotFound.html +1 -1
  93. data/docs/api/Brut/Framework/Errors/NotImplemented.html +1 -1
  94. data/docs/api/Brut/Framework/Errors.html +1 -1
  95. data/docs/api/Brut/Framework/FussyTypeEnforcement.html +1 -1
  96. data/docs/api/Brut/Framework/MCP.html +1 -1
  97. data/docs/api/Brut/Framework/ProjectEnvironment.html +1 -1
  98. data/docs/api/Brut/Framework.html +1 -1
  99. data/docs/api/Brut/FrontEnd/AssetPathResolver.html +1 -1
  100. data/docs/api/Brut/FrontEnd/Component/Helpers.html +1 -1
  101. data/docs/api/Brut/FrontEnd/Component.html +1 -1
  102. data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
  103. data/docs/api/Brut/FrontEnd/Components/FormTag.html +1 -1
  104. data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +1 -1
  105. data/docs/api/Brut/FrontEnd/Components/Input.html +1 -1
  106. data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +1 -1
  107. data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +1 -1
  108. data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +1 -1
  109. data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +1 -1
  110. data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +1 -1
  111. data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
  112. data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +1 -1
  113. data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +1 -1
  114. data/docs/api/Brut/FrontEnd/Components/TimeTag.html +1 -1
  115. data/docs/api/Brut/FrontEnd/Components/Traceparent.html +1 -1
  116. data/docs/api/Brut/FrontEnd/Components.html +1 -1
  117. data/docs/api/Brut/FrontEnd/Download.html +1 -1
  118. data/docs/api/Brut/FrontEnd/Flash.html +1 -1
  119. data/docs/api/Brut/FrontEnd/Form.html +1 -1
  120. data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +1 -1
  121. data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +201 -0
  122. data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +535 -0
  123. data/docs/api/Brut/FrontEnd/Forms/Input.html +983 -35
  124. data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +1 -1
  125. data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +29 -19
  126. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +9 -3
  127. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
  128. data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +9 -3
  129. data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
  130. data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +1 -1
  131. data/docs/api/Brut/FrontEnd/Forms.html +1 -1
  132. data/docs/api/Brut/FrontEnd/GenericResponse.html +1 -1
  133. data/docs/api/Brut/FrontEnd/Handler.html +1 -1
  134. data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +1 -1
  135. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +1 -1
  136. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +1 -1
  137. data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +1 -1
  138. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +1 -1
  139. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +1 -1
  140. data/docs/api/Brut/FrontEnd/Handlers.html +1 -1
  141. data/docs/api/Brut/FrontEnd/HandlingResults.html +1 -1
  142. data/docs/api/Brut/FrontEnd/HttpMethod.html +1 -1
  143. data/docs/api/Brut/FrontEnd/HttpStatus.html +1 -1
  144. data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +1 -1
  145. data/docs/api/Brut/FrontEnd/Layout.html +1 -1
  146. data/docs/api/Brut/FrontEnd/Middleware.html +1 -1
  147. data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +1 -1
  148. data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +1 -1
  149. data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +1 -1
  150. data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +1 -1
  151. data/docs/api/Brut/FrontEnd/Middlewares.html +1 -1
  152. data/docs/api/Brut/FrontEnd/Page.html +1 -1
  153. data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +1 -1
  154. data/docs/api/Brut/FrontEnd/Pages.html +1 -1
  155. data/docs/api/Brut/FrontEnd/RequestContext.html +1 -1
  156. data/docs/api/Brut/FrontEnd/RouteHook.html +1 -1
  157. data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +1 -1
  158. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +1 -1
  159. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +1 -1
  160. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +1 -1
  161. data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +1 -1
  162. data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +1 -1
  163. data/docs/api/Brut/FrontEnd/RouteHooks.html +1 -1
  164. data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +1 -1
  165. data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +1 -1
  166. data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +1 -1
  167. data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +1 -1
  168. data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +1 -1
  169. data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +1 -1
  170. data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +1 -1
  171. data/docs/api/Brut/FrontEnd/Routing/Route.html +1 -1
  172. data/docs/api/Brut/FrontEnd/Routing.html +1 -1
  173. data/docs/api/Brut/FrontEnd/Session.html +1 -1
  174. data/docs/api/Brut/FrontEnd.html +1 -1
  175. data/docs/api/Brut/I18n/BaseMethods.html +1 -1
  176. data/docs/api/Brut/I18n/ForBackEnd.html +1 -1
  177. data/docs/api/Brut/I18n/ForCLI.html +1 -1
  178. data/docs/api/Brut/I18n/ForHTML.html +1 -1
  179. data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +1 -1
  180. data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +1 -1
  181. data/docs/api/Brut/I18n.html +1 -1
  182. data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +1 -1
  183. data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +1 -1
  184. data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +1 -1
  185. data/docs/api/Brut/Instrumentation/OpenTelemetry.html +1 -1
  186. data/docs/api/Brut/Instrumentation.html +1 -1
  187. data/docs/api/Brut/SinatraHelpers/ClassMethods.html +1 -1
  188. data/docs/api/Brut/SinatraHelpers.html +1 -1
  189. data/docs/api/Brut/SpecSupport/ClockSupport.html +1 -1
  190. data/docs/api/Brut/SpecSupport/ComponentSupport.html +1 -1
  191. data/docs/api/Brut/SpecSupport/E2ETestServer.html +1 -1
  192. data/docs/api/Brut/SpecSupport/E2eSupport.html +1 -1
  193. data/docs/api/Brut/SpecSupport/EnhancedNode.html +1 -1
  194. data/docs/api/Brut/SpecSupport/FlashSupport.html +1 -1
  195. data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +1 -1
  196. data/docs/api/Brut/SpecSupport/GeneralSupport.html +1 -1
  197. data/docs/api/Brut/SpecSupport/HandlerSupport.html +1 -1
  198. data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +1 -1
  199. data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +1 -1
  200. data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +1 -1
  201. data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +1 -1
  202. data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +1 -1
  203. data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +1 -1
  204. data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +1 -1
  205. data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +1 -1
  206. data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +1 -1
  207. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +1 -1
  208. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +1 -1
  209. data/docs/api/Brut/SpecSupport/Matchers.html +1 -1
  210. data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +1 -1
  211. data/docs/api/Brut/SpecSupport/RSpecSetup.html +1 -1
  212. data/docs/api/Brut/SpecSupport/SessionSupport.html +1 -1
  213. data/docs/api/Brut/SpecSupport.html +1 -1
  214. data/docs/api/Brut.html +1 -1
  215. data/docs/api/Clock.html +1 -1
  216. data/docs/api/RichString.html +1 -1
  217. data/docs/api/SemanticLogger/Appender/Async.html +1 -1
  218. data/docs/api/Sequel/Extensions/BrutInstrumentation.html +1 -1
  219. data/docs/api/Sequel/Extensions/BrutMigrations.html +1 -1
  220. data/docs/api/Sequel/Extensions.html +1 -1
  221. data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +1 -1
  222. data/docs/api/Sequel/Plugins/CreatedAt.html +1 -1
  223. data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +1 -1
  224. data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +1 -1
  225. data/docs/api/Sequel/Plugins/ExternalId.html +1 -1
  226. data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +1 -1
  227. data/docs/api/Sequel/Plugins/FindBang.html +1 -1
  228. data/docs/api/Sequel/Plugins.html +1 -1
  229. data/docs/api/Sequel.html +1 -1
  230. data/docs/api/_index.html +15 -1
  231. data/docs/api/class_list.html +1 -1
  232. data/docs/api/css/full_list.css +2 -1
  233. data/docs/api/css/style.css +14 -13
  234. data/docs/api/file.README.html +1 -1
  235. data/docs/api/index.html +1 -1
  236. data/docs/api/method_list.html +419 -275
  237. data/docs/api/top-level-namespace.html +1 -1
  238. data/docs/assets/LogoStop.X8x-4riz.png +0 -0
  239. data/docs/assets/OverviewMetro.DUS-5fUZ.png +0 -0
  240. data/docs/assets/{app.BX81XO4N.js → app.BhrfSt68.js} +1 -1
  241. data/docs/assets/chunks/@localSearchIndexroot.CeRAdP1K.js +1 -0
  242. data/docs/assets/chunks/{VPLocalSearchBox.gABXcTWp.js → VPLocalSearchBox.Dpot_2H4.js} +1 -1
  243. data/docs/assets/chunks/{theme.DwUXXAL3.js → theme.N2SNVLgU.js} +2 -2
  244. data/docs/assets/{configuration.md.BGHl8oRC.js → configuration.md.LG-zIBww.js} +1 -1
  245. data/docs/assets/deployment.md.BLseERGV.js +48 -0
  246. data/docs/assets/deployment.md.BLseERGV.lean.js +1 -0
  247. data/docs/assets/{getting-started.md.Ciz82L0m.js → getting-started.md.Dj0qtZI2.js} +2 -2
  248. data/docs/assets/index.md.CuBB-BdM.js +1 -0
  249. data/docs/assets/index.md.CuBB-BdM.lean.js +1 -0
  250. data/docs/assets/{overview.md.C5wlBcR5.js → overview.md.DVKRM8zl.js} +4 -4
  251. data/docs/assets/overview.md.DVKRM8zl.lean.js +1 -0
  252. data/docs/assets/{style.D73IYGCX.css → style.B2o1L9eN.css} +1 -1
  253. data/docs/assets.html +4 -4
  254. data/docs/brut-js/api/AjaxSubmit.html +1 -1
  255. data/docs/brut-js/api/AjaxSubmit.js.html +1 -1
  256. data/docs/brut-js/api/Autosubmit.html +1 -1
  257. data/docs/brut-js/api/Autosubmit.js.html +1 -1
  258. data/docs/brut-js/api/BaseCustomElement.html +1 -1
  259. data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
  260. data/docs/brut-js/api/BrutCustomElements.html +1 -1
  261. data/docs/brut-js/api/BufferedLogger.html +1 -1
  262. data/docs/brut-js/api/ConfirmSubmit.html +1 -1
  263. data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
  264. data/docs/brut-js/api/ConfirmationDialog.html +1 -1
  265. data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
  266. data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
  267. data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
  268. data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
  269. data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
  270. data/docs/brut-js/api/CopyToClipboard.html +1 -1
  271. data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
  272. data/docs/brut-js/api/Form.html +1 -1
  273. data/docs/brut-js/api/Form.js.html +1 -1
  274. data/docs/brut-js/api/I18nTranslation.html +1 -1
  275. data/docs/brut-js/api/I18nTranslation.js.html +1 -1
  276. data/docs/brut-js/api/LocaleDetection.html +1 -1
  277. data/docs/brut-js/api/LocaleDetection.js.html +1 -1
  278. data/docs/brut-js/api/Logger.html +1 -1
  279. data/docs/brut-js/api/Logger.js.html +1 -1
  280. data/docs/brut-js/api/Message.html +1 -1
  281. data/docs/brut-js/api/Message.js.html +1 -1
  282. data/docs/brut-js/api/PrefixedLogger.html +1 -1
  283. data/docs/brut-js/api/RichString.html +1 -1
  284. data/docs/brut-js/api/RichString.js.html +1 -1
  285. data/docs/brut-js/api/Tabs.html +1 -1
  286. data/docs/brut-js/api/Tabs.js.html +1 -1
  287. data/docs/brut-js/api/Tracing.html +1 -1
  288. data/docs/brut-js/api/Tracing.js.html +1 -1
  289. data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
  290. data/docs/brut-js/api/external-Performance.html +1 -1
  291. data/docs/brut-js/api/external-Promise.html +1 -1
  292. data/docs/brut-js/api/external-ValidityState.html +1 -1
  293. data/docs/brut-js/api/external-Window.html +1 -1
  294. data/docs/brut-js/api/external-fetch.html +1 -1
  295. data/docs/brut-js/api/global.html +1 -1
  296. data/docs/brut-js/api/index.html +1 -1
  297. data/docs/brut-js/api/index.js.html +1 -1
  298. data/docs/brut-js/api/module-testing.html +1 -1
  299. data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
  300. data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
  301. data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
  302. data/docs/brut-js/api/testing.DOMCreator.html +1 -1
  303. data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
  304. data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
  305. data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
  306. data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
  307. data/docs/brut-js/api/testing_index.js.html +1 -1
  308. data/docs/brut-js.html +4 -4
  309. data/docs/business-logic.html +4 -4
  310. data/docs/cli.html +4 -4
  311. data/docs/components.html +4 -4
  312. data/docs/configuration.html +6 -6
  313. data/docs/css.html +4 -4
  314. data/docs/custom-element-tests.html +4 -4
  315. data/docs/database-access.html +4 -4
  316. data/docs/database-schema.html +4 -4
  317. data/docs/deployment.html +53 -6
  318. data/docs/dev-environment.html +4 -4
  319. data/docs/doc-conventions.html +4 -4
  320. data/docs/end-to-end-tests.html +4 -4
  321. data/docs/flash-and-session.html +4 -4
  322. data/docs/forms.html +4 -4
  323. data/docs/getting-started.html +7 -7
  324. data/docs/handlers.html +4 -4
  325. data/docs/hashmap.json +1 -1
  326. data/docs/hooks.html +4 -4
  327. data/docs/i18n.html +4 -4
  328. data/docs/index.html +6 -6
  329. data/docs/instrumentation.html +4 -4
  330. data/docs/javascript.html +4 -4
  331. data/docs/jobs.html +4 -4
  332. data/docs/keyword-injection.html +4 -4
  333. data/docs/layouts.html +4 -4
  334. data/docs/lsp.html +4 -4
  335. data/docs/markdown-examples.html +4 -4
  336. data/docs/middleware.html +4 -4
  337. data/docs/not-released.html +4 -4
  338. data/docs/overview.html +9 -9
  339. data/docs/pages.html +4 -4
  340. data/docs/recipes/authentication.html +4 -4
  341. data/docs/routes.html +4 -4
  342. data/docs/security.html +4 -4
  343. data/docs/seed-data.html +4 -4
  344. data/docs/space-time-continuum.html +4 -4
  345. data/docs/tutorial.html +4 -4
  346. data/docs/unit-tests.html +4 -4
  347. data/dx/bash_customizations +7 -0
  348. data/dx/build +13 -2
  349. data/dx/docker-compose.env +1 -1
  350. data/dx/exec +25 -8
  351. data/lib/brut/front_end/forms/input.rb +253 -20
  352. data/lib/brut/front_end/forms/input_definition.rb +15 -12
  353. data/lib/brut/front_end.rb +1 -0
  354. data/lib/brut/version.rb +1 -1
  355. data/specs/brut/front_end/forms/input.spec.rb +978 -0
  356. data/specs/spec_helper.rb +27 -0
  357. data/specs/support/matchers/have_constraint_violation.rb +23 -0
  358. data/specs/support/matchers.rb +5 -0
  359. data/specs/support.rb +3 -0
  360. metadata +39 -17
  361. data/docs/assets/chunks/@localSearchIndexroot.CoYzciVi.js +0 -1
  362. data/docs/assets/deployment.md.Dbka4OTr.js +0 -1
  363. data/docs/assets/deployment.md.Dbka4OTr.lean.js +0 -1
  364. data/docs/assets/index.md.B28EwVpq.js +0 -1
  365. data/docs/assets/index.md.B28EwVpq.lean.js +0 -1
  366. data/docs/assets/overview.Da81cB9R.png +0 -0
  367. data/docs/assets/overview.md.C5wlBcR5.lean.js +0 -1
  368. /data/docs/assets/{configuration.md.BGHl8oRC.lean.js → configuration.md.LG-zIBww.lean.js} +0 -0
  369. /data/docs/assets/{getting-started.md.Ciz82L0m.lean.js → getting-started.md.Dj0qtZI2.lean.js} +0 -0
@@ -1,11 +1,11 @@
1
- import{_ as i,c as a,o as e,ag as t}from"./chunks/framework.1L-BeKqY.js";const n="/assets/overview.Da81cB9R.png",g=JSON.parse('{"title":"Conceptual Overview","description":"","frontmatter":{},"headers":[],"relativePath":"overview.md","filePath":"overview.md"}'),l={name:"overview.md"};function h(p,s,r,d,o,k){return e(),a("div",null,s[0]||(s[0]=[t('<h1 id="conceptual-overview" tabindex="-1">Conceptual Overview <a class="header-anchor" href="#conceptual-overview" aria-label="Permalink to &quot;Conceptual Overview&quot;">​</a></h1><p>Brut is a web framework that provides the ability to receive HTTP requests and respond to them. It includes facilities for generating HTML, interacting with a database, managing assets and more. Pretty much everything you need, though not much that you don&#39;t.</p><p>Brut&#39;s approach and design are built on three core values:</p><ul><li><strong>Leverage Standards</strong> - The web platform is great, and Brut wants you to use it.</li><li><strong>There&#39;s One Best Way To Do It</strong> - Flexibility leads to chaos.</li><li><strong>Simple over Easy</strong> - Verbose code that can be quickly understood beats impenetrable compact DSLs every day.</li></ul><p>As such, Brut&#39;s API and concepts are intended to mirror concepts that exist in the domain of building web sites. For example, when you go to a URL, you are viewing a web page. In Brut, a page is rendered by using a subclass of <a href="/api/Brut/FrontEnd/Page.html" target="_self" rel="noopener" data-no-router><code>Brut::FrontEnd::Page</code></a>, called a <em>page</em>.</p><p>Brut also avoids creating abstractions on top of existing standards you already need to know to build websites. For example, instead of creating a resource/verb abstraction on top of submitting forms over HTTP, Brut instead has you implement a <a href="/api/Brut/FrontEnd/Form.html" target="_self" rel="noopener" data-no-router><code>Brut::FrontEnd::Form</code></a> that describes the form&#39;s inputs—just like you&#39;d have in HTML.</p><h2 id="basic-elements-of-a-brut-powered-app" tabindex="-1">Basic Elements of a Brut-Powered App <a class="header-anchor" href="#basic-elements-of-a-brut-powered-app" aria-label="Permalink to &quot;Basic Elements of a Brut-Powered App&quot;">​</a></h2><p>Below is a diagram showing the high level parts of a Brut app. It shows four important terms with respect to how Brut is organized:</p><ul><li><em>Client</em> or <em>Client Side</em> is the web browser (or HTTP client). This is where CSS is applied to HTML and where JavaScript is executed. HTTP requests are initiated here.</li><li><em>Server</em> or <em>Server Side</em> is where any code not in the browser runs. In Brut, this includes HTML generation, SQL queries, and everything in between.</li><li><em>Front End</em> is the code that deals with producing your user interface or HTTP API. A lot of this code runs on the <em>server side</em>, however it exists to provide a user interface of some sort.</li><li><em>Back End</em> is the code that deals with everything else, such as accessing a database, executing business logic, or managing background jobs.</li></ul><p><img src="'+n+`" alt="Architectural Overview"></p><ul><li><strong>Browser</strong> is, well, a web browser</li><li><a href="/pages.html"><strong>Pages</strong></a> generate web pages, which is what happens when a browser&#39;s UI navigates to a URL.</li><li><a href="/components.html"><strong>Components</strong></a> generate HTML fragments and are used to generate the HTML of a page or for re-use across pages.</li><li><a href="/forms.html"><strong>Forms</strong></a> describe the inputs of an HTML <code>&lt;form&gt;</code> element, and hold a form&#39;s submitted data for server-side processing.</li><li><a href="/handlers.html"><strong>Handlers</strong></a> receive non-GET HTTP requests from the browser, notably form submissions.</li><li><a href="/javascript.html"><strong>JS</strong></a> and <a href="/assets.html"><strong>Assets</strong></a> (including <a href="/css.html">CSS</a>) are bundled on the server and sent to the client.</li><li><a href="/database-access.html"><strong>DB Models</strong></a> are objects that provide access to your database.</li><li><a href="/business-logic.html"><strong>Domain Logic</strong></a> as where your business and domain logic lives and can be implemented however you like.</li></ul><h2 id="brut-is-not-a-resource-oriented-mvc-framework" tabindex="-1">Brut is Not a Resource-Oriented MVC Framework. <a class="header-anchor" href="#brut-is-not-a-resource-oriented-mvc-framework" aria-label="Permalink to &quot;Brut is Not a Resource-Oriented MVC Framework.&quot;">​</a></h2><p>You will note that Brut is <em>not</em> an MVC framework. Rather than creating an often confusing abstraction on top of HTTP, browsers, and HTML, Brut provides a more direct set of primitives.</p><p>Further, Brut is not <em>resource-oriented</em>. While HTTP does include the concept of resources and verbs to operate on those resources, in the context of building a web application, these two abstractions cause more problems than they solve.</p><p>Although Brut can can certainly respond to any URL and any verb, the core set of abstractions mirror the observed behavior of a web browser: <em>Pages</em> generate HTML (with the help of <em>Components</em>). <em>Forms</em> describe data to collect from the user, which is submitted to <em>Handlers</em> for processing by the back-end. Ajax requests (and arbitrary HTTP requests) can also be responded-to by <em>Handlers</em>.</p><p>In practice, this means that you do not have to perform mental gymnastics to decide exactly what verb and/or resource best represents the use-case you are trying to build. When your partners want to build an &quot;account management page&quot;, you will be able to implement this with a class named <code>AccountManagementPage</code>. When discussing enhancements to the &quot;user settings form&quot;, you will making changes to the <code>UserSettingsForm</code> and <code>UserSettingsHandler</code>. If that form is on the page everyone calls the &quot;preferences page&quot;, you&#39;ll be dealing with <code>PreferencesPage</code>, and not &quot;the index method of the <code>UserSettingsController</code>.</p><p>Let&#39;s go one step deeper to see how these primitives work.</p><h2 id="quick-tour-of-brut-s-primitives" tabindex="-1">Quick Tour of Brut&#39;s Primitives <a class="header-anchor" href="#quick-tour-of-brut-s-primitives" aria-label="Permalink to &quot;Quick Tour of Brut&#39;s Primitives&quot;">​</a></h2><h3 id="pages" tabindex="-1">Pages <a class="header-anchor" href="#pages" aria-label="Permalink to &quot;Pages&quot;">​</a></h3><p>The <em>Page</em> is the best example of Brut&#39;s value system. When you fetch a URL in a web browser, that is referred to as a web page. Thus, in Brut, a route accessed via an HTTP <code>GET</code> is managed by an instance of a <em>page class</em>.</p><p>Instead of a routing system where you must map http-like verbs to resource, Brut&#39;s routes are more direct. For a page, you&#39;d use the <code>page</code> method (we&#39;ll explain more what <code>class App</code> and <code>routes do</code> are doing later):</p><div class="language-ruby vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> App</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> Brut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">Framework</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">App</span></span>
1
+ import{_ as i,c as a,o as e,ag as t}from"./chunks/framework.1L-BeKqY.js";const n="/assets/OverviewMetro.DUS-5fUZ.png",g=JSON.parse('{"title":"Conceptual Overview","description":"","frontmatter":{},"headers":[],"relativePath":"overview.md","filePath":"overview.md"}'),l={name:"overview.md"};function h(p,s,r,o,d,k){return e(),a("div",null,s[0]||(s[0]=[t('<h1 id="conceptual-overview" tabindex="-1">Conceptual Overview <a class="header-anchor" href="#conceptual-overview" aria-label="Permalink to &quot;Conceptual Overview&quot;">​</a></h1><p>Brut is a web framework that provides the ability to receive HTTP requests and respond to them. It includes facilities for generating HTML, interacting with a database, managing assets and more. Pretty much everything you need, though not much that you don&#39;t.</p><p>Brut&#39;s approach and design are built on three core values:</p><ul><li><strong>Leverage Standards</strong> - The web platform is great, and Brut wants you to use it.</li><li><strong>There&#39;s One Best Way To Do It</strong> - Flexibility leads to chaos.</li><li><strong>Simple over Easy</strong> - Verbose code that can be quickly understood beats impenetrable compact DSLs every day.</li></ul><p>As such, Brut&#39;s API and concepts are intended to mirror concepts that exist in the domain of building web sites. For example, when you go to a URL, you are viewing a web page. In Brut, a page is rendered by using a subclass of <a href="/api/Brut/FrontEnd/Page.html" target="_self" rel="noopener" data-no-router><code>Brut::FrontEnd::Page</code></a>, called a <em>page</em>.</p><p>Brut also avoids creating abstractions on top of existing standards you already need to know to build websites. For example, instead of creating a resource/verb abstraction on top of submitting forms over HTTP, Brut instead has you implement a <a href="/api/Brut/FrontEnd/Form.html" target="_self" rel="noopener" data-no-router><code>Brut::FrontEnd::Form</code></a> that describes the form&#39;s inputs—just like you&#39;d have in HTML.</p><h2 id="basic-elements-of-a-brut-powered-app" tabindex="-1">Basic Elements of a Brut-Powered App <a class="header-anchor" href="#basic-elements-of-a-brut-powered-app" aria-label="Permalink to &quot;Basic Elements of a Brut-Powered App&quot;">​</a></h2><p>Below is a diagram showing the high level parts of a Brut app. It shows four important terms with respect to how Brut is organized:</p><ul><li><em>Client</em> or <em>Client Side</em> is the web browser (or HTTP client). This is where CSS is applied to HTML and where JavaScript is executed. HTTP requests are initiated here.</li><li><em>Server</em> or <em>Server Side</em> is where any code not in the browser runs. In Brut, this includes HTML generation, SQL queries, and everything in between.</li><li><em>Front End</em> is the code that deals with producing your user interface or HTTP API. A lot of this code runs on the <em>server side</em>, however it exists to provide a user interface of some sort.</li><li><em>Back End</em> is the code that deals with everything else, such as accessing a database, executing business logic, or managing background jobs.</li></ul><p><img src="'+n+`" alt="Architectural Overview"></p><ul><li><strong>Visitor</strong> is someone visiting your web site or app.</li><li><strong>Browser</strong> is, well, a web browser</li><li><a href="/pages.html"><strong>Pages</strong></a> generate web pages, which is what happens when a browser&#39;s UI navigates to a URL.</li><li><a href="/forms.html"><strong>Forms</strong></a> describe the inputs of an HTML <code>&lt;form&gt;</code> element, and hold a form&#39;s submitted data for server-side processing. Browser submit forms to the server.</li><li><a href="/components.html"><strong>Components</strong></a> generate HTML fragments and are used to generate the HTML of a page or for re-use across pages.</li><li><a href="/handlers.html"><strong>Handlers</strong></a> receive non-GET HTTP requests from the browser, notably form submissions.</li><li><a href="/javascript.html"><strong>JavaScript</strong></a> and <a href="/assets.html"><strong>Assets</strong></a> (including <a href="/css.html">CSS</a>) are bundled on the server and sent to the client.</li><li><a href="/business-logic.html"><strong>Domain Logic</strong></a> as where your business and domain logic lives and can be implemented however you like.</li><li><a href="/database-access.html"><strong>DB Models</strong></a> are objects that provide access to your database.</li><li><strong>Relational Database</strong> is your database, where data is stored.</li></ul><h2 id="brut-is-not-a-resource-oriented-mvc-framework" tabindex="-1">Brut is Not a Resource-Oriented MVC Framework. <a class="header-anchor" href="#brut-is-not-a-resource-oriented-mvc-framework" aria-label="Permalink to &quot;Brut is Not a Resource-Oriented MVC Framework.&quot;">​</a></h2><p>You will note that Brut is <em>not</em> an MVC framework. Rather than creating an often confusing abstraction on top of HTTP, browsers, and HTML, Brut provides a more direct set of primitives.</p><p>Further, Brut is not <em>resource-oriented</em>. While HTTP does include the concept of resources and verbs to operate on those resources, in the context of building a web application, these two abstractions cause more problems than they solve.</p><p>Although Brut can can certainly respond to any URL and any verb, the core set of abstractions mirror the observed behavior of a web browser: <em>Pages</em> generate HTML (with the help of <em>Components</em>). <em>Forms</em> describe data to collect from the user, which is submitted to <em>Handlers</em> for processing by the back-end. Ajax requests (and arbitrary HTTP requests) can also be responded-to by <em>Handlers</em>.</p><p>In practice, this means that you do not have to perform mental gymnastics to decide exactly what verb and/or resource best represents the use-case you are trying to build. When your partners want to build an &quot;account management page&quot;, you will be able to implement this with a class named <code>AccountManagementPage</code>. When discussing enhancements to the &quot;user settings form&quot;, you will making changes to the <code>UserSettingsForm</code> and <code>UserSettingsHandler</code>. If that form is on the page everyone calls the &quot;preferences page&quot;, you&#39;ll be dealing with <code>PreferencesPage</code>, and not &quot;the index method of the <code>UserSettingsController</code>.</p><p>Let&#39;s go one step deeper to see how these primitives work.</p><h2 id="quick-tour-of-brut-s-primitives" tabindex="-1">Quick Tour of Brut&#39;s Primitives <a class="header-anchor" href="#quick-tour-of-brut-s-primitives" aria-label="Permalink to &quot;Quick Tour of Brut&#39;s Primitives&quot;">​</a></h2><h3 id="pages" tabindex="-1">Pages <a class="header-anchor" href="#pages" aria-label="Permalink to &quot;Pages&quot;">​</a></h3><p>The <em>Page</em> is the best example of Brut&#39;s value system. When you fetch a URL in a web browser, that is referred to as a web page. Thus, in Brut, a route accessed via an HTTP <code>GET</code> is managed by an instance of a <em>page class</em>.</p><p>Instead of a routing system where you must map http-like verbs to resource, Brut&#39;s routes are more direct. For a page, you&#39;d use the <code>page</code> method (we&#39;ll explain more what <code>class App</code> and <code>routes do</code> are doing later):</p><div class="language-ruby vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> App</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> Brut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">Framework</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">::</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">App</span></span>
2
2
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;my-app&quot;</span></span>
3
3
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> organization</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;my-org&quot;</span></span>
4
4
  <span class="line"></span>
5
5
  <span class="line highlighted"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">do</span></span>
6
6
  <span class="line highlighted"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> page </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;/dashboard&quot;</span></span>
7
7
  <span class="line highlighted"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span>
8
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div><p>Brut is convention-based, so when this route is requested by the browser, Brut will instantiate the class <code>DashboardPage</code> to handle the request. The page is an enhanced Phlex component that supports layouts. You implement <code>page_template</code> and make calls to Phlex&#39;s API to generate your page&#39;s HTML.</p><p>You will write an initializer (using keyword arguments) that describes all the data your page needs in order to generate its HTML. Brut will instantiate your page class into an object and use Phlex&#39;s API to generate HTML.</p><p>There is great variety in what your initializer can be given by Brut. For example, if we want to show the current time as well as respond to the query-string parameter &quot;compact&quot;, we&#39;d write our class like so:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-_dRKF" id="tab-zuR4a5p" checked><label data-title="pages/dashboard_page.rb" for="tab-zuR4a5p">pages/dashboard_page.rb</label><input type="radio" name="group-_dRKF" id="tab-GxeCb9M"><label data-title="layouts/default_layout.rb" for="tab-GxeCb9M">layouts/default_layout.rb</label></div><div class="blocks"><div class="language-ruby vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> DashboardPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AppPage</span></span>
8
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div><p>Brut is convention-based, so when this route is requested by the browser, Brut will instantiate the class <code>DashboardPage</code> to handle the request. The page is an enhanced Phlex component that supports layouts. You implement <code>page_template</code> and make calls to Phlex&#39;s API to generate your page&#39;s HTML.</p><p>You will write an initializer (using keyword arguments) that describes all the data your page needs in order to generate its HTML. Brut will instantiate your page class into an object and use Phlex&#39;s API to generate HTML.</p><p>There is great variety in what your initializer can be given by Brut. For example, if we want to show the current time as well as respond to the query-string parameter &quot;compact&quot;, we&#39;d write our class like so:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group--qXMx" id="tab-KZvr-oY" checked><label data-title="pages/dashboard_page.rb" for="tab-KZvr-oY">pages/dashboard_page.rb</label><input type="radio" name="group--qXMx" id="tab-cgtxeqq"><label data-title="layouts/default_layout.rb" for="tab-cgtxeqq">layouts/default_layout.rb</label></div><div class="blocks"><div class="language-ruby vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> DashboardPage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AppPage</span></span>
9
9
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> initialize</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">clock:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">compact:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
10
10
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> @now </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> clock.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">now</span></span>
11
11
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> @compact </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> compact </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;true&quot;</span></span>
@@ -37,7 +37,7 @@ import{_ as i,c as a,o as e,ag as t}from"./chunks/framework.1L-BeKqY.js";const n
37
37
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span>
38
38
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span>
39
39
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span>
40
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div></div></div><p>This would all produce HTML like so:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-8BLf8" id="tab-WY0h1rb" checked><label data-title="/dashboard" for="tab-WY0h1rb">/dashboard</label><input type="radio" name="group-8BLf8" id="tab-Z8iuD-2"><label data-title="/dashboard?compact=true" for="tab-Z8iuD-2">/dashboard?compact=true</label></div><div class="blocks"><div class="language-html vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;!</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">DOCTYPE</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> html</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
40
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div></div></div><p>This would all produce HTML like so:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-eDHyu" id="tab-f9HHgvF" checked><label data-title="/dashboard" for="tab-f9HHgvF">/dashboard</label><input type="radio" name="group-eDHyu" id="tab-LFQcgeQ"><label data-title="/dashboard?compact=true" for="tab-LFQcgeQ">/dashboard?compact=true</label></div><div class="blocks"><div class="language-html vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;!</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">DOCTYPE</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> html</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
41
41
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">html</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
42
42
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">head</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
43
43
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">title</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;My Awesome Site&lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">title</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
@@ -97,7 +97,7 @@ import{_ as i,c as a,o as e,ag as t}from"./chunks/framework.1L-BeKqY.js";const n
97
97
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span>
98
98
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div><h3 id="forms" tabindex="-1">Forms <a class="header-anchor" href="#forms" aria-label="Permalink to &quot;Forms&quot;">​</a></h3><p>To allow data to be submitted from the browser, you&#39;d use an HTML <code>&lt;form&gt;</code> that contains many <code>&lt;inputs&gt;</code>, as has been the case since the birth of the web. To declare a form that will be submitted, use <code>form</code>:</p><div class="language-ruby vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">do</span></span>
99
99
  <span class="line highlighted"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> form </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;/login&quot;</span></span>
100
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span></code></pre></div><p>Brut is convention-based, so it will expect a class named <code>LoginForm</code> to exist to hold a programmatic description of the form. This description allows the form&#39;s data to be managed during the submission process. That form is passed to an instance of <code>LoginHandler</code>, which contains the logic for processing the submission.</p><p>The idea behind form classes is to avoid dealing with Hashes containing magical strings or symbols and instead deal with a more strictly defined type. This means, among other benefits, you don&#39;t have maintain a separate list of allowed parameters. Your form defines them and is used to generate HTML, so it&#39;s all just one list of parameters. Forms aren&#39;t that fancy, though. Just as HTML <code>FormData</code> is string keys and string values, so it is with Brut forms.</p><p>To define the inputs, class methods are used in the form class&#39; definition. When the form is submitted <code>LoginHandler#handle</code> is called, and passed an instance of the form. The form has methods to access the inputs&#39; values</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-IRcL-" id="tab-wr0wsvL" checked><label data-title="forms/login_form.rb" for="tab-wr0wsvL">forms/login_form.rb</label><input type="radio" name="group-IRcL-" id="tab-zQiBzCH"><label data-title="handlers/login_handler.rb" for="tab-zQiBzCH">handlers/login_handler.rb</label></div><div class="blocks"><div class="language-ruby vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> LoginForm</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AppForm</span></span>
100
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> end</span></span></code></pre></div><p>Brut is convention-based, so it will expect a class named <code>LoginForm</code> to exist to hold a programmatic description of the form. This description allows the form&#39;s data to be managed during the submission process. That form is passed to an instance of <code>LoginHandler</code>, which contains the logic for processing the submission.</p><p>The idea behind form classes is to avoid dealing with Hashes containing magical strings or symbols and instead deal with a more strictly defined type. This means, among other benefits, you don&#39;t have maintain a separate list of allowed parameters. Your form defines them and is used to generate HTML, so it&#39;s all just one list of parameters. Forms aren&#39;t that fancy, though. Just as HTML <code>FormData</code> is string keys and string values, so it is with Brut forms.</p><p>To define the inputs, class methods are used in the form class&#39; definition. When the form is submitted <code>LoginHandler#handle</code> is called, and passed an instance of the form. The form has methods to access the inputs&#39; values</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-N0YMR" id="tab-p_t9M_a" checked><label data-title="forms/login_form.rb" for="tab-p_t9M_a">forms/login_form.rb</label><input type="radio" name="group-N0YMR" id="tab--3a9l7j"><label data-title="handlers/login_handler.rb" for="tab--3a9l7j">handlers/login_handler.rb</label></div><div class="blocks"><div class="language-ruby vp-adaptive-theme active"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> LoginForm</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AppForm</span></span>
101
101
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> input </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">:email</span></span>
102
102
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> input </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">:password</span></span>
103
103
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">end</span></span></code></pre></div><div class="language-ruby vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ruby</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">class</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> LoginHandler</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AppHandler</span></span>
@@ -0,0 +1 @@
1
+ import{_ as i,c as a,o as e,ag as t}from"./chunks/framework.1L-BeKqY.js";const n="/assets/OverviewMetro.DUS-5fUZ.png",g=JSON.parse('{"title":"Conceptual Overview","description":"","frontmatter":{},"headers":[],"relativePath":"overview.md","filePath":"overview.md"}'),l={name:"overview.md"};function h(p,s,r,o,d,k){return e(),a("div",null,s[0]||(s[0]=[t("",79)]))}const E=i(l,[["render",h]]);export{g as __pageData,E as default};