brut 0.0.27 → 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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.projections.json +10 -0
- data/.rspec +3 -0
- data/Dockerfile.dx +32 -14
- data/Gemfile.lock +1 -1
- data/assets/Logo-Square.pxd +0 -0
- data/assets/LogoPylon.pxd +0 -0
- data/assets/LogoStop.pxd +0 -0
- data/assets/LogoTall.pxd +0 -0
- data/bin/docs +24 -2
- data/bin/rspec +27 -0
- data/bin/setup +3 -3
- data/brutrb.com/.vitepress/config.mjs +1 -0
- data/brutrb.com/.vitepress/theme/custom.css +7 -0
- data/brutrb.com/.vitepress/theme/style.css +26 -15
- data/brutrb.com/deployment.md +123 -45
- data/brutrb.com/dev-environment.md +6 -5
- data/brutrb.com/doc-conventions.md +1 -1
- data/brutrb.com/getting-started.md +64 -28
- data/brutrb.com/images/LogoPylon.png +0 -0
- data/brutrb.com/images/LogoSquare.png +0 -0
- data/brutrb.com/images/LogoStop.png +0 -0
- data/brutrb.com/images/LogoTall.png +0 -0
- data/brutrb.com/images/OverviewMetro.graffle +0 -0
- data/brutrb.com/images/OverviewMetro.png +0 -0
- data/brutrb.com/index.md +4 -3
- data/brutrb.com/instrumentation.md +12 -0
- data/brutrb.com/layouts.md +130 -0
- data/brutrb.com/overview.md +6 -6
- data/docker-compose.dx.yml +5 -2
- data/docs/404.html +3 -3
- data/docs/ai.html +6 -6
- data/docs/api/Brut/BackEnd/SeedData.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +1 -1
- data/docs/api/Brut/BackEnd/Sidekiq.html +1 -1
- data/docs/api/Brut/BackEnd/Validators/FormValidator.html +1 -1
- data/docs/api/Brut/BackEnd/Validators.html +1 -1
- data/docs/api/Brut/BackEnd.html +1 -1
- data/docs/api/Brut/CLI/App.html +38 -13
- data/docs/api/Brut/CLI/AppRunner.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +2 -2
- data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Create.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Drop.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Migrate.html +9 -3
- data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +11 -11
- data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Seed.html +2 -2
- data/docs/api/Brut/CLI/Apps/DB/Status.html +12 -12
- data/docs/api/Brut/CLI/Apps/DB.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +270 -0
- data/docs/api/Brut/CLI/Apps/DeployBase.html +257 -0
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +585 -0
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +196 -0
- data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +2 -2
- data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Audit.html +12 -10
- data/docs/api/Brut/CLI/Apps/Test/E2e.html +8 -8
- data/docs/api/Brut/CLI/Apps/Test/JS.html +9 -9
- data/docs/api/Brut/CLI/Apps/Test/Run.html +18 -18
- data/docs/api/Brut/CLI/Apps/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps.html +2 -2
- data/docs/api/Brut/CLI/Command.html +113 -28
- data/docs/api/Brut/CLI/Error.html +1 -1
- data/docs/api/Brut/CLI/ExecutionResults/Result.html +1 -1
- data/docs/api/Brut/CLI/ExecutionResults.html +1 -1
- data/docs/api/Brut/CLI/Executor.html +169 -38
- data/docs/api/Brut/CLI/InvalidOption.html +1 -1
- data/docs/api/Brut/CLI/Options.html +68 -19
- data/docs/api/Brut/CLI/Output.html +1 -1
- data/docs/api/Brut/CLI/SystemExecError.html +1 -1
- data/docs/api/Brut/CLI.html +1 -1
- data/docs/api/Brut/FactoryBot.html +1 -1
- data/docs/api/Brut/Framework/App.html +1 -1
- data/docs/api/Brut/Framework/Config.html +1 -1
- data/docs/api/Brut/Framework/Container.html +110 -29
- data/docs/api/Brut/Framework/Error.html +1 -1
- data/docs/api/Brut/Framework/Errors/AbstractMethod.html +89 -1
- data/docs/api/Brut/Framework/Errors/Bug.html +1 -1
- data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +1 -1
- data/docs/api/Brut/Framework/Errors/MissingParameter.html +1 -1
- data/docs/api/Brut/Framework/Errors/NoClassForPath.html +1 -1
- data/docs/api/Brut/Framework/Errors/NotFound.html +1 -1
- data/docs/api/Brut/Framework/Errors/NotImplemented.html +1 -1
- data/docs/api/Brut/Framework/Errors.html +31 -8
- data/docs/api/Brut/Framework/FussyTypeEnforcement.html +1 -1
- data/docs/api/Brut/Framework/MCP.html +1 -1
- data/docs/api/Brut/Framework/ProjectEnvironment.html +1 -1
- data/docs/api/Brut/Framework.html +1 -1
- data/docs/api/Brut/FrontEnd/AssetPathResolver.html +1 -1
- data/docs/api/Brut/FrontEnd/Component/Helpers.html +36 -26
- data/docs/api/Brut/FrontEnd/Component.html +7 -7
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +37 -29
- data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Input.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +20 -117
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +25 -23
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +73 -380
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +22 -138
- data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/TimeTag.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Traceparent.html +1 -1
- data/docs/api/Brut/FrontEnd/Components.html +23 -2
- data/docs/api/Brut/FrontEnd/Download.html +1 -1
- data/docs/api/Brut/FrontEnd/Flash.html +1 -1
- data/docs/api/Brut/FrontEnd/Form.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +24 -68
- data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +201 -0
- data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +535 -0
- data/docs/api/Brut/FrontEnd/Forms/Input.html +983 -35
- data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +4 -4
- data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +29 -19
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +9 -3
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +9 -3
- data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +72 -22
- data/docs/api/Brut/FrontEnd/Forms.html +1 -1
- data/docs/api/Brut/FrontEnd/GenericResponse.html +1 -1
- data/docs/api/Brut/FrontEnd/Handler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Handlers.html +1 -1
- data/docs/api/Brut/FrontEnd/HandlingResults.html +1 -1
- data/docs/api/Brut/FrontEnd/HttpMethod.html +1 -1
- data/docs/api/Brut/FrontEnd/HttpStatus.html +1 -1
- data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +1 -1
- data/docs/api/Brut/FrontEnd/Layout.html +1 -1
- data/docs/api/Brut/FrontEnd/Middleware.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +1 -1
- data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +6 -2
- data/docs/api/Brut/FrontEnd/Middlewares.html +1 -1
- data/docs/api/Brut/FrontEnd/Page.html +1 -1
- data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +1 -1
- data/docs/api/Brut/FrontEnd/Pages.html +1 -1
- data/docs/api/Brut/FrontEnd/RequestContext.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHook.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +1 -1
- data/docs/api/Brut/FrontEnd/RouteHooks.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing/Route.html +1 -1
- data/docs/api/Brut/FrontEnd/Routing.html +1 -1
- data/docs/api/Brut/FrontEnd/Session.html +1 -1
- data/docs/api/Brut/FrontEnd.html +1 -1
- data/docs/api/Brut/I18n/BaseMethods.html +1 -1
- data/docs/api/Brut/I18n/ForBackEnd.html +1 -1
- data/docs/api/Brut/I18n/ForCLI.html +1 -1
- data/docs/api/Brut/I18n/ForHTML.html +1 -1
- data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +1 -1
- data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +1 -1
- data/docs/api/Brut/I18n.html +1 -1
- data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +1 -1
- data/docs/api/Brut/Instrumentation/OpenTelemetry.html +1 -1
- data/docs/api/Brut/Instrumentation.html +1 -1
- data/docs/api/Brut/SinatraHelpers/ClassMethods.html +1 -1
- data/docs/api/Brut/SinatraHelpers.html +1 -1
- data/docs/api/Brut/SpecSupport/ClockSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/ComponentSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/E2ETestServer.html +20 -20
- data/docs/api/Brut/SpecSupport/E2eSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/EnhancedNode.html +1 -1
- data/docs/api/Brut/SpecSupport/FlashSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +1 -1
- data/docs/api/Brut/SpecSupport/GeneralSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/HandlerSupport.html +2 -2
- data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +142 -0
- data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +142 -0
- data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +155 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +55 -25
- data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +46 -19
- data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +149 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +165 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +158 -0
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +156 -0
- data/docs/api/Brut/SpecSupport/Matchers.html +2 -2
- data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +24 -24
- data/docs/api/Brut/SpecSupport/RSpecSetup.html +55 -20
- data/docs/api/Brut/SpecSupport/SessionSupport.html +1 -1
- data/docs/api/Brut/SpecSupport.html +1 -1
- data/docs/api/Brut.html +1 -1
- data/docs/api/Clock.html +1 -1
- data/docs/api/RichString.html +1 -1
- data/docs/api/SemanticLogger/Appender/Async.html +1 -1
- data/docs/api/Sequel/Extensions/BrutInstrumentation.html +5 -1
- data/docs/api/Sequel/Extensions/BrutMigrations.html +36 -28
- data/docs/api/Sequel/Extensions.html +1 -1
- data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +1 -1
- data/docs/api/Sequel/Plugins/CreatedAt.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +1 -1
- data/docs/api/Sequel/Plugins/ExternalId.html +1 -1
- data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +1 -1
- data/docs/api/Sequel/Plugins/FindBang.html +1 -1
- data/docs/api/Sequel/Plugins.html +1 -1
- data/docs/api/Sequel.html +1 -1
- data/docs/api/SpecSupport/Matchers/BeABug.html +143 -0
- data/docs/api/_index.html +106 -1
- data/docs/api/class_list.html +1 -1
- data/docs/api/css/full_list.css +2 -1
- data/docs/api/css/style.css +14 -13
- data/docs/api/file.README.html +1 -1
- data/docs/api/index.html +1 -1
- data/docs/api/method_list.html +530 -330
- data/docs/api/top-level-namespace.html +1 -1
- data/docs/assets/LogoStop.X8x-4riz.png +0 -0
- data/docs/assets/OverviewMetro.DUS-5fUZ.png +0 -0
- data/docs/assets/{ai.md.tZrjP9im.js → ai.md._6HCDL6d.js} +1 -1
- data/docs/assets/ai.md._6HCDL6d.lean.js +1 -0
- data/docs/assets/{app.D_yaTITQ.js → app.BhrfSt68.js} +1 -1
- data/docs/assets/chunks/@localSearchIndexroot.CeRAdP1K.js +1 -0
- data/docs/assets/chunks/{VPLocalSearchBox.B2-ZzyTY.js → VPLocalSearchBox.Dpot_2H4.js} +1 -1
- data/docs/assets/chunks/{theme.CfGFVRvE.js → theme.N2SNVLgU.js} +2 -2
- data/docs/assets/{components.md.eCttGlN-.js → components.md.CRUMdRoN.js} +1 -1
- data/docs/assets/{configuration.md.BRriU0cL.js → configuration.md.LG-zIBww.js} +1 -1
- data/docs/assets/deployment.md.BLseERGV.js +48 -0
- data/docs/assets/deployment.md.BLseERGV.lean.js +1 -0
- data/docs/assets/{dev-environment.md.BNc8AYiK.js → dev-environment.md.GZv6xvi9.js} +1 -1
- data/docs/assets/doc-conventions.md.-kN3Xo5C.js +1 -0
- data/docs/assets/{doc-conventions.md.DCfRXXi-.lean.js → doc-conventions.md.-kN3Xo5C.lean.js} +1 -1
- data/docs/assets/{forms.md.CBTYQ_Cz.js → forms.md.B-koVgyw.js} +23 -23
- data/docs/assets/{forms.md.CBTYQ_Cz.lean.js → forms.md.B-koVgyw.lean.js} +1 -1
- data/docs/assets/getting-started.md.Dj0qtZI2.js +25 -0
- data/docs/assets/getting-started.md.Dj0qtZI2.lean.js +1 -0
- data/docs/assets/index.md.CuBB-BdM.js +1 -0
- data/docs/assets/index.md.CuBB-BdM.lean.js +1 -0
- data/docs/assets/{instrumentation.md.CL6ax7nT.js → instrumentation.md.a9Pjps4P.js} +2 -2
- data/docs/assets/{instrumentation.md.CL6ax7nT.lean.js → instrumentation.md.a9Pjps4P.lean.js} +1 -1
- data/docs/assets/layouts.md.cPnh3NId.js +51 -0
- data/docs/assets/layouts.md.cPnh3NId.lean.js +1 -0
- data/docs/assets/lsp.md.Bsu-f6VU.js +1 -0
- data/docs/assets/lsp.md.Bsu-f6VU.lean.js +1 -0
- data/docs/assets/{overview.md.CDalkuxV.js → overview.md.DVKRM8zl.js} +4 -4
- data/docs/assets/overview.md.DVKRM8zl.lean.js +1 -0
- data/docs/assets/recipes_authentication.md.CAsXf7hk.js +1 -0
- data/docs/assets/recipes_authentication.md.CAsXf7hk.lean.js +1 -0
- data/docs/assets/{style.D73IYGCX.css → style.B2o1L9eN.css} +1 -1
- data/docs/assets.html +5 -5
- data/docs/brut-js/api/AjaxSubmit.html +1 -1
- data/docs/brut-js/api/AjaxSubmit.js.html +1 -1
- data/docs/brut-js/api/Autosubmit.html +1 -1
- data/docs/brut-js/api/Autosubmit.js.html +1 -1
- data/docs/brut-js/api/BaseCustomElement.html +1 -1
- data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
- data/docs/brut-js/api/BrutCustomElements.html +1 -1
- data/docs/brut-js/api/BufferedLogger.html +1 -1
- data/docs/brut-js/api/ConfirmSubmit.html +1 -1
- data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
- data/docs/brut-js/api/ConfirmationDialog.html +1 -1
- data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
- data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
- data/docs/brut-js/api/CopyToClipboard.html +1 -1
- data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
- data/docs/brut-js/api/Form.html +1 -1
- data/docs/brut-js/api/Form.js.html +1 -1
- data/docs/brut-js/api/I18nTranslation.html +1 -1
- data/docs/brut-js/api/I18nTranslation.js.html +1 -1
- data/docs/brut-js/api/LocaleDetection.html +1 -1
- data/docs/brut-js/api/LocaleDetection.js.html +1 -1
- data/docs/brut-js/api/Logger.html +1 -1
- data/docs/brut-js/api/Logger.js.html +1 -1
- data/docs/brut-js/api/Message.html +1 -1
- data/docs/brut-js/api/Message.js.html +1 -1
- data/docs/brut-js/api/PrefixedLogger.html +1 -1
- data/docs/brut-js/api/RichString.html +1 -1
- data/docs/brut-js/api/RichString.js.html +1 -1
- data/docs/brut-js/api/Tabs.html +1 -1
- data/docs/brut-js/api/Tabs.js.html +1 -1
- data/docs/brut-js/api/Tracing.html +1 -1
- data/docs/brut-js/api/Tracing.js.html +1 -1
- data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
- data/docs/brut-js/api/external-Performance.html +1 -1
- data/docs/brut-js/api/external-Promise.html +1 -1
- data/docs/brut-js/api/external-ValidityState.html +1 -1
- data/docs/brut-js/api/external-Window.html +1 -1
- data/docs/brut-js/api/external-fetch.html +1 -1
- data/docs/brut-js/api/global.html +1 -1
- data/docs/brut-js/api/index.html +1 -1
- data/docs/brut-js/api/index.js.html +1 -1
- data/docs/brut-js/api/module-testing.html +1 -1
- data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
- data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
- data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
- data/docs/brut-js/api/testing.DOMCreator.html +1 -1
- data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
- data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
- data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
- data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
- data/docs/brut-js/api/testing_index.js.html +1 -1
- data/docs/brut-js.html +5 -5
- data/docs/business-logic.html +5 -5
- data/docs/cli.html +5 -5
- data/docs/components.html +7 -7
- data/docs/configuration.html +6 -6
- data/docs/css.html +5 -5
- data/docs/custom-element-tests.html +5 -5
- data/docs/database-access.html +5 -5
- data/docs/database-schema.html +5 -5
- data/docs/deployment.html +53 -6
- data/docs/dev-environment.html +6 -6
- data/docs/doc-conventions.html +6 -6
- data/docs/end-to-end-tests.html +5 -5
- data/docs/flash-and-session.html +5 -5
- data/docs/forms.html +28 -28
- data/docs/getting-started.html +30 -7
- data/docs/handlers.html +5 -5
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +5 -5
- data/docs/i18n.html +5 -5
- data/docs/index.html +6 -6
- data/docs/instrumentation.html +6 -6
- data/docs/javascript.html +5 -5
- data/docs/jobs.html +5 -5
- data/docs/keyword-injection.html +5 -5
- data/docs/layouts.html +74 -0
- data/docs/lsp.html +24 -0
- data/docs/markdown-examples.html +5 -5
- data/docs/middleware.html +5 -5
- data/docs/not-released.html +5 -5
- data/docs/overview.html +9 -9
- data/docs/pages.html +6 -6
- data/docs/recipes/authentication.html +24 -0
- data/docs/routes.html +5 -5
- data/docs/security.html +5 -5
- data/docs/seed-data.html +5 -5
- data/docs/space-time-continuum.html +5 -5
- data/docs/tutorial.html +5 -5
- data/docs/unit-tests.html +5 -5
- data/dx/bash_customizations +7 -0
- data/dx/build +13 -2
- data/dx/docker-compose.env +1 -1
- data/dx/exec +25 -8
- data/lib/brut/cli/app.rb +7 -2
- data/lib/brut/cli/apps/deploy_base.rb +86 -0
- data/lib/brut/cli/apps/heroku_container_based_deploy.rb +194 -0
- data/lib/brut/cli/command.rb +7 -13
- data/lib/brut/cli/executor.rb +31 -5
- data/lib/brut/cli/options.rb +4 -0
- data/lib/brut/cli.rb +4 -3
- data/lib/brut/framework/container.rb +25 -7
- data/lib/brut/framework/errors/abstract_method.rb +7 -0
- data/lib/brut/framework/errors.rb +4 -2
- data/lib/brut/front_end/forms/input.rb +253 -20
- data/lib/brut/front_end/forms/input_definition.rb +15 -12
- data/lib/brut/front_end/middlewares/reload_app.rb +2 -0
- data/lib/brut/front_end.rb +1 -0
- data/lib/brut/spec_support/rspec_setup.rb +42 -2
- data/lib/brut/version.rb +1 -1
- data/lib/sequel/extensions/brut_instrumentation.rb +4 -0
- data/specs/brut/front_end/forms/input.spec.rb +978 -0
- data/specs/spec_helper.rb +27 -0
- data/specs/support/matchers/have_constraint_violation.rb +23 -0
- data/specs/support/matchers.rb +5 -0
- data/specs/support.rb +3 -0
- metadata +77 -29
- data/docs/assets/ai.md.tZrjP9im.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.BsN5i0Fi.js +0 -1
- data/docs/assets/deployment.md.Dbka4OTr.js +0 -1
- data/docs/assets/deployment.md.Dbka4OTr.lean.js +0 -1
- data/docs/assets/doc-conventions.md.DCfRXXi-.js +0 -1
- data/docs/assets/getting-started.md.Bz2s1Vjb.js +0 -2
- data/docs/assets/getting-started.md.Bz2s1Vjb.lean.js +0 -1
- data/docs/assets/index.md.B28EwVpq.js +0 -1
- data/docs/assets/index.md.B28EwVpq.lean.js +0 -1
- data/docs/assets/overview.Da81cB9R.png +0 -0
- data/docs/assets/overview.md.CDalkuxV.lean.js +0 -1
- /data/docs/assets/{components.md.eCttGlN-.lean.js → components.md.CRUMdRoN.lean.js} +0 -0
- /data/docs/assets/{configuration.md.BRriU0cL.lean.js → configuration.md.LG-zIBww.lean.js} +0 -0
- /data/docs/assets/{dev-environment.md.BNc8AYiK.lean.js → dev-environment.md.GZv6xvi9.lean.js} +0 -0
@@ -1,21 +1,26 @@
|
|
1
1
|
# Getting Started
|
2
2
|
|
3
3
|
Brut is developed alongside a separate gem called `mkbrut`, which allows you to
|
4
|
-
create a new Brut app. It will set up
|
4
|
+
create a new Brut app. It will set up your dev environment as well.
|
5
5
|
|
6
6
|
## Get `mkbrut`
|
7
7
|
|
8
|
-
|
9
|
-
RubyGems:
|
8
|
+
The simplest way to use `mkbrut` is to use an existing [Docker image](https://hub.docker.com/repository/docker/thirdtank/mkbrut/general). You don't have to install or configure Ruby:
|
10
9
|
|
11
10
|
```
|
12
|
-
|
11
|
+
docker run \
|
12
|
+
-v "$PWD":"$PWD" \
|
13
|
+
-w "$PWD" \
|
14
|
+
-it \
|
15
|
+
thirdtank/mkbrut \
|
16
|
+
mkbrut my-new-app
|
13
17
|
```
|
14
18
|
|
15
|
-
If
|
19
|
+
If you already have Ruby 3.4 installed, you can install `mkbrut` directly:
|
16
20
|
|
17
21
|
```
|
18
|
-
|
22
|
+
> gem install mkbrut
|
23
|
+
> mkbrut my-new-app
|
19
24
|
```
|
20
25
|
|
21
26
|
## Init Your App
|
@@ -23,16 +28,44 @@ docker pull XXXX
|
|
23
28
|
A Brut app just needs a name, which will be used to derive a few more useful values.
|
24
29
|
For now:
|
25
30
|
|
31
|
+
::: code-group
|
32
|
+
|
33
|
+
``` [Docker-based]
|
34
|
+
docker run \
|
35
|
+
-v "$PWD":"$PWD" \
|
36
|
+
-w "$PWD" \
|
37
|
+
-it \
|
38
|
+
thirdtank/mkbrut \
|
39
|
+
mkbrut my-new-app
|
26
40
|
```
|
41
|
+
|
42
|
+
``` [RubyGems-based]
|
27
43
|
mkbrut my-new-app
|
28
44
|
```
|
29
45
|
|
30
|
-
|
46
|
+
:::
|
47
|
+
|
48
|
+
This will create your new app, along with some demo routes, components, handlers, and tests. If this is your first time using Brut, we recommend you examine these demo components.
|
49
|
+
|
50
|
+
To create your app without the demo components:
|
31
51
|
|
52
|
+
::: code-group
|
53
|
+
|
54
|
+
``` [Docker-based]
|
55
|
+
docker run \
|
56
|
+
-v "$PWD":"$PWD" \
|
57
|
+
-w "$PWD" \
|
58
|
+
-it \
|
59
|
+
thirdtank/mkbrut \
|
60
|
+
mkbrut my-new-app --no-demo
|
32
61
|
```
|
33
|
-
|
62
|
+
|
63
|
+
``` [RubyGems-based]
|
64
|
+
mkbrut my-new-app --no-demo
|
34
65
|
```
|
35
66
|
|
67
|
+
:::
|
68
|
+
|
36
69
|
## Start Your Dev Environment
|
37
70
|
|
38
71
|
Brut includes a dev environment based on Docker. It uses Docker compose to run a
|
@@ -50,49 +83,52 @@ Docker container for local observability via OpenTelemetry.
|
|
50
83
|
```
|
51
84
|
> dx/start
|
52
85
|
```
|
53
|
-
4.
|
86
|
+
4. Now, "log in" to the container where your app and its tests will run:
|
54
87
|
|
55
88
|
```
|
56
|
-
> dx/exec
|
89
|
+
> dx/exec login
|
57
90
|
```
|
58
91
|
|
59
|
-
|
92
|
+
5. Set everything up:
|
60
93
|
|
61
94
|
```
|
62
|
-
> dx/exec bash
|
63
95
|
inside-container> bin/setup
|
64
96
|
```
|
65
97
|
|
66
|
-
Now, you're ready to go
|
98
|
+
Now, you're ready to go. See [Dev Environemnt](/dev-environment) for details on how
|
99
|
+
this all works.
|
67
100
|
|
68
101
|
## Run the App
|
69
102
|
|
70
103
|
```
|
71
|
-
>
|
72
|
-
```
|
73
|
-
|
74
|
-
OR
|
75
|
-
|
76
|
-
```
|
77
|
-
> dx/exec bash
|
78
|
-
> bin/dev
|
104
|
+
inside-container> bin/dev
|
79
105
|
```
|
80
106
|
|
81
107
|
You can now visit your app at `localhost:6502`
|
82
108
|
|
83
|
-
|
109
|
+
You can make changes and see them when you reload. Open up `app/src/front_end/pages/home_page.rb` *in your editor running on your computer* and change the `h1` to look like so:
|
84
110
|
|
85
|
-
|
111
|
+
```ruby {6}
|
112
|
+
class HomePage < AppPage
|
113
|
+
def page_template
|
114
|
+
div(class: "flex flex-column items-center justify-center h-80vh") do
|
115
|
+
img(src: "/static/images/icon.png", class: "h-50")
|
116
|
+
h1(class: "ff-sans ma-0 lh-title f-5") do
|
117
|
+
"Welcome to My New App!"
|
118
|
+
end
|
86
119
|
|
120
|
+
# ...
|
87
121
|
```
|
88
|
-
> dx/exec bin/ci
|
89
|
-
```
|
90
122
|
|
91
|
-
|
123
|
+
When you reload your browser, you'll see your change
|
124
|
+
|
125
|
+
## Run the Tests
|
126
|
+
|
127
|
+
There are a few tests you can run, as well as some checks that you aren't using
|
128
|
+
RubyGems with security vulnerabilities. Run it all now with `bin/ci`:
|
92
129
|
|
93
130
|
```
|
94
|
-
>
|
95
|
-
> bin/ci
|
131
|
+
inside-container> bin/dev
|
96
132
|
```
|
97
133
|
|
98
134
|
## Now Build The Rest of Your App 🦉
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/brutrb.com/index.md
CHANGED
@@ -6,8 +6,8 @@ hero:
|
|
6
6
|
name: "Brut RB"
|
7
7
|
text: "Raw Ruby Web Apps"
|
8
8
|
tagline: Standards-based, No-nonsense, HTML-first, Low Ceremony
|
9
|
-
|
10
|
-
src: /images/
|
9
|
+
ximage:
|
10
|
+
src: /images/LogoTall.png
|
11
11
|
alt: "A Ruby gemstone embedded into a concrete, brutalist building"
|
12
12
|
actions:
|
13
13
|
- theme: brand
|
@@ -20,7 +20,7 @@ hero:
|
|
20
20
|
text: Conceptual Overview
|
21
21
|
link: /overview
|
22
22
|
|
23
|
-
|
23
|
+
xfeatures:
|
24
24
|
- title: Standards-Based
|
25
25
|
icon: 📄
|
26
26
|
details: "Brut leverages HTML, HTTP, SQL, and the Ruby standard library to let you write apps using standards you already know…or could quickly learn"
|
@@ -34,3 +34,4 @@ features:
|
|
34
34
|
icon: 🏘️
|
35
35
|
details: "Sequel, Phlex, I18n, RSpec. They do it best"
|
36
36
|
---
|
37
|
+

|
@@ -66,6 +66,17 @@ Here is a non-exhaustive list of what Brut automatically instruments:
|
|
66
66
|
* Ignored parameters on all form submissions
|
67
67
|
* How long reloading takes in development
|
68
68
|
* CSP reporting results
|
69
|
+
* SQL Statements
|
70
|
+
|
71
|
+
> [!WARNING]
|
72
|
+
> `Sequel::Extensions::BrutInstrumentation` sets up telemetry for
|
73
|
+
> Sequel, and it does it in a relatively simplistic way. The result
|
74
|
+
> is that *all* SQL statements are part of the telemetry, including
|
75
|
+
> the actual values inserted or used in `WHERE` clauses.
|
76
|
+
> While you should not be putting sensitive data into your database,
|
77
|
+
> be warned that this is happening. There are plans to improve this
|
78
|
+
> to be more flexible and reduce the Schance of sensitive data
|
79
|
+
> being sent in traces.
|
69
80
|
|
70
81
|
### Adding Your Own Instrumentation
|
71
82
|
|
@@ -175,6 +186,7 @@ specific issues.
|
|
175
186
|
|
176
187
|
_Last Updated June 12, 2025_
|
177
188
|
|
189
|
+
|
178
190
|
Brut does not have plans to support non-OTel instrumentation, nor does it have plans to provide hooks to
|
179
191
|
use proprietary formats. This could change of course.
|
180
192
|
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# Layouts
|
2
|
+
|
3
|
+
Brut supports *layouts*, which are a way to centralizing common HTML amongst many
|
4
|
+
different pages. Conceptually, they are the same as a Rails layout. Technically, they are a Phlex component designed to render a page from a `yield` block.
|
5
|
+
|
6
|
+
## Overview
|
7
|
+
|
8
|
+
Your app should include `app/src/front_end/layouts/default_layout.rb`. The name
|
9
|
+
"default" is special, in that all pages will use this layout by default.
|
10
|
+
|
11
|
+
Since a layout is a Phlex component, its HTML is generated from `view_template`, and
|
12
|
+
it is expected to have exactly one `yield`, where the page's content will be
|
13
|
+
inserted.
|
14
|
+
|
15
|
+
```ruby {33}
|
16
|
+
class DefaultLayout < Brut::FrontEnd::Layout
|
17
|
+
include Brut::FrontEnd::Components
|
18
|
+
|
19
|
+
def initialize(page_name:)
|
20
|
+
@page_name = page_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def view_template
|
24
|
+
doctype
|
25
|
+
html(lang: "en") do
|
26
|
+
head do
|
27
|
+
meta(charset: "utf-8")
|
28
|
+
meta(content: "width=device-width,initial-scale=1", name:"viewport")
|
29
|
+
meta(content: "website", property:"og:type")
|
30
|
+
link(rel: "manifest", href: "/static/manifest.json")
|
31
|
+
link(rel: "preload", as: "style", href: asset_path("/css/styles.css"))
|
32
|
+
link(rel: "stylesheet", href: asset_path("/css/styles.css"))
|
33
|
+
script(defer: true, src: asset_path("/js/app.js"))
|
34
|
+
title { app_name }
|
35
|
+
PageIdentifier(@page_name)
|
36
|
+
I18nTranslations("cv.fe")
|
37
|
+
I18nTranslations("cv.this_field")
|
38
|
+
Traceparent()
|
39
|
+
render(
|
40
|
+
Brut::FrontEnd::RequestContext.inject(
|
41
|
+
Brut::FrontEnd::Components::LocaleDetection
|
42
|
+
)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
body do
|
46
|
+
brut_tracing url: "/__brut/instrumentation", show_warnings: true
|
47
|
+
main class: @page_name do
|
48
|
+
yield
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
### Maintaining Layouts
|
57
|
+
|
58
|
+
You are free to manage this how you like, however a few components inside the
|
59
|
+
`<head>` and `<body>` that are important to keep:
|
60
|
+
|
61
|
+
* `Brut::FrontEnd::Components::PageIdentifier` includes a `<meta>` tag with the page's name in it, which is handy for managing your end-to-end tests.
|
62
|
+
* `Brut::FrontEnd::Components::I18nTranslations` includes translatsion for common client-side constraint violations. See [Forms](/forms), [I18n](/i18n), and [JavaScript](/javascript) for more details on how this is used.
|
63
|
+
* `Brut::FrontEnd::Components::Traceparent` ensures that the OpenTelemetry *traceparent* is available so when client-side telemetry is reported back to the server, it can be connected to the request that initiated it.
|
64
|
+
* The `<brut-tracing>` element collects the client-side telemetry and sends it back
|
65
|
+
to the server.
|
66
|
+
|
67
|
+
### Creating Alternate Layouts
|
68
|
+
|
69
|
+
The way each page knows to use `DefaultLayout` is due to the `layout` method of
|
70
|
+
`Brut::FrontEnd::Page`, which returns `"default"`. The return value of `layout` is
|
71
|
+
used to figure out the name of the layout class.
|
72
|
+
|
73
|
+
You can set up your own by overriding `layout`:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class MyOtherPage < AppPage
|
77
|
+
def layout = "other_design"
|
78
|
+
|
79
|
+
# ...
|
80
|
+
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
Brut will expect the class `OtherDesignLayout` to exist and provide HTML. Based on
|
85
|
+
Zeitwerk's conventions, that class should be in
|
86
|
+
`app/src/front_end/layouts/other_design_layout.rb`.
|
87
|
+
|
88
|
+
### No Layout
|
89
|
+
|
90
|
+
If you don't want a layout, you are encouraged to creat a blank layout, for example:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class BlankLayout < Brut::FrontEnd::Layout
|
94
|
+
def view_template
|
95
|
+
yield
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# use like so:
|
100
|
+
|
101
|
+
def layout = "blank"
|
102
|
+
```
|
103
|
+
|
104
|
+
## Testing
|
105
|
+
|
106
|
+
You generally don't test a layout, aside from end-to-end tests. If your layout
|
107
|
+
needs complex logic, you are encouraged to extract that to a
|
108
|
+
[component](/components) and test that instead.
|
109
|
+
|
110
|
+
## Recommended Practices
|
111
|
+
|
112
|
+
Keep your layouts as simple as you can.
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
## Technical Notes
|
117
|
+
|
118
|
+
> [!IMPORTANT]
|
119
|
+
> Technical Notes are for deeper understanding and debugging. While we will try to keep them up-to-date with changes to Brut's
|
120
|
+
> internals, the source code is always more correct.
|
121
|
+
|
122
|
+
_Last Updated July 1, 2025_
|
123
|
+
|
124
|
+
Layouts work due to the implementation of the method `view_template` in `Brut::FrontEnd::Page`. This is why a page class must provide `page_template` instead.
|
125
|
+
|
126
|
+
While you could override `view_template` in your page to provide a "blank layout",
|
127
|
+
this is discouraged, as the use of `view_template` should be considered a
|
128
|
+
private implementation detail.
|
129
|
+
|
130
|
+
|
data/brutrb.com/overview.md
CHANGED
@@ -24,18 +24,18 @@ the *server side*, however it exists to provide a user interface of some sort.
|
|
24
24
|
* *Back End* is the code that deals with everything else, such as accessing a database, executing business logic, or managing background jobs.
|
25
25
|
|
26
26
|
|
27
|
-

|
28
28
|
|
29
|
+
* **Visitor** is someone visiting your web site or app.
|
29
30
|
* **Browser** is, well, a web browser
|
30
31
|
* [**Pages**](/pages) generate web pages, which is what happens when a browser's UI navigates to a URL.
|
32
|
+
* [**Forms**](/forms) describe the inputs of an HTML `<form>` element, and hold a form's submitted data for server-side processing. Browser submit forms to the server.
|
31
33
|
* [**Components**](/components) generate HTML fragments and are used to generate the HTML of a page or for re-use across pages.
|
32
|
-
* [**Forms**](/forms) describe the inputs of an HTML `<form>` element, and hold a form's submitted data for server-side
|
33
|
-
processing.
|
34
34
|
* [**Handlers**](/handlers) receive non-GET HTTP requests from the browser, notably form submissions.
|
35
|
-
* [**
|
35
|
+
* [**JavaScript**](/javascript) and [**Assets**](/assets) (including [CSS](/css)) are bundled on the server and sent to the client.
|
36
|
+
* [**Domain Logic**](/business-logic) as where your business and domain logic lives and can be implemented however you like.
|
36
37
|
* [**DB Models**](/database-access) are objects that provide access to your database.
|
37
|
-
*
|
38
|
-
however you like.
|
38
|
+
* **Relational Database** is your database, where data is stored.
|
39
39
|
|
40
40
|
## Brut is Not a Resource-Oriented MVC Framework.
|
41
41
|
|
data/docker-compose.dx.yml
CHANGED
@@ -8,11 +8,14 @@ services:
|
|
8
8
|
source: ${PWD}
|
9
9
|
target: ${PWD}
|
10
10
|
consistency: "consistent"
|
11
|
+
# This allows access to Git configuration so Git commands work
|
11
12
|
- type: bind
|
12
13
|
source: ${GIT_CONFIG}
|
13
|
-
target: "/
|
14
|
-
|
14
|
+
target: "/home/appuser/.gitconfig"
|
15
|
+
command: /home/appuser/show-help-in-app-container-then-wait.sh
|
15
16
|
working_dir: ${PWD}
|
17
|
+
environment:
|
18
|
+
PROJECT_ROOT: ${PWD}
|
16
19
|
ports:
|
17
20
|
- "8086:8086"
|
18
21
|
- "8087:8087"
|
data/docs/404.html
CHANGED
@@ -6,16 +6,16 @@
|
|
6
6
|
<title>404 | Brut RB</title>
|
7
7
|
<meta name="description" content="Not Found">
|
8
8
|
<meta name="generator" content="VitePress v1.6.3">
|
9
|
-
<link rel="preload stylesheet" href="/assets/style.
|
9
|
+
<link rel="preload stylesheet" href="/assets/style.B2o1L9eN.css" as="style">
|
10
10
|
<link rel="preload stylesheet" href="/vp-icons.css" as="style">
|
11
11
|
|
12
|
-
<script type="module" src="/assets/app.
|
12
|
+
<script type="module" src="/assets/app.BhrfSt68.js"></script>
|
13
13
|
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
|
14
14
|
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
|
15
15
|
</head>
|
16
16
|
<body>
|
17
17
|
<div id="app"></div>
|
18
|
-
<script>window.__VP_HASH_MAP__=JSON.parse("{\"ai.md\":\"
|
18
|
+
<script>window.__VP_HASH_MAP__=JSON.parse("{\"ai.md\":\"_6HCDL6d\",\"assets.md\":\"D3wunzLx\",\"brut-js.md\":\"o2DAO2s2\",\"business-logic.md\":\"BY4hGy0m\",\"cli.md\":\"RmeA2b0i\",\"components.md\":\"CRUMdRoN\",\"configuration.md\":\"LG-zIBww\",\"css.md\":\"DJgj2clw\",\"custom-element-tests.md\":\"BrYJQEl3\",\"database-access.md\":\"C7l-Vuvb\",\"database-schema.md\":\"BUjR0VS1\",\"deployment.md\":\"BLseERGV\",\"dev-environment.md\":\"GZv6xvi9\",\"doc-conventions.md\":\"-kN3Xo5C\",\"end-to-end-tests.md\":\"yfQHC0b5\",\"flash-and-session.md\":\"BXY8RvT0\",\"forms.md\":\"B-koVgyw\",\"getting-started.md\":\"Dj0qtZI2\",\"handlers.md\":\"089DVD3v\",\"hooks.md\":\"C4-moMny\",\"i18n.md\":\"Do9i1qWl\",\"index.md\":\"CuBB-BdM\",\"instrumentation.md\":\"a9Pjps4P\",\"javascript.md\":\"GWbhRS51\",\"jobs.md\":\"S-2amAYp\",\"keyword-injection.md\":\"Dt2tKREs\",\"layouts.md\":\"cPnh3NId\",\"lsp.md\":\"Bsu-f6VU\",\"markdown-examples.md\":\"CCFEQO44\",\"middleware.md\":\"Czz_UlJN\",\"not-released.md\":\"BBy28McC\",\"overview.md\":\"DVKRM8zl\",\"pages.md\":\"BE3kfOc5\",\"recipes_authentication.md\":\"CAsXf7hk\",\"routes.md\":\"BMM7peut\",\"security.md\":\"C668yXCi\",\"seed-data.md\":\"BvFZlqIk\",\"space-time-continuum.md\":\"KPUIKysQ\",\"tutorial.md\":\"BnoGjrdK\",\"unit-tests.md\":\"DUGrnLj5\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Brut RB\",\"description\":\"Documentation for the Brut.RB web framework.\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"search\":{\"provider\":\"local\"},\"nav\":[{\"text\":\"Home\",\"link\":\"/\"},{\"text\":\"Getting Started\",\"link\":\"/getting-started\"},{\"text\":\"Overview\",\"link\":\"/overview\"},{\"text\":\"Brut API\",\"link\":\"/api/index.html\",\"target\":\"_self\"},{\"text\":\"BrutJS\",\"link\":\"/brut-js/api/index.html\",\"target\":\"_self\"},{\"text\":\"BrutCSS\",\"link\":\"/brut-css/index.html\",\"target\":\"_self\"}],\"outline\":[2,3],\"sidebar\":[{\"text\":\"Overview\",\"collapsed\":false,\"items\":[{\"text\":\"Getting Started\",\"link\":\"/getting-started\"},{\"text\":\"Concepts\",\"link\":\"/overview\"},{\"text\":\"Documentation Conventions\",\"link\":\"/doc-conventions\"},{\"text\":\"Tutorial\",\"link\":\"/tutorial\"},{\"text\":\"Dev Environment\",\"link\":\"/dev-environment\"},{\"text\":\"AI Declaration\",\"link\":\"/ai\"}]},{\"text\":\"Front-End\",\"collapsed\":false,\"items\":[{\"text\":\"Routes\",\"link\":\"/routes\"},{\"text\":\"Pages\",\"link\":\"/pages\"},{\"text\":\"Layouts\",\"link\":\"/layouts\"},{\"text\":\"Forms\",\"link\":\"/forms\"},{\"text\":\"Handlers and Actions\",\"link\":\"/handlers\"},{\"text\":\"Components\",\"link\":\"/components\"},{\"text\":\"Flash and Session\",\"link\":\"/flash-and-session\"},{\"text\":\"Space/Time Continuum\",\"link\":\"/space-time-continuum\"},{\"text\":\"JavaScript\",\"link\":\"/javascript\"},{\"text\":\"CSS\",\"link\":\"/css\"},{\"text\":\"Assets\",\"link\":\"/assets\"},{\"text\":\"BrutJS\",\"link\":\"/brut-js\"}]},{\"text\":\"Back-End\",\"collapsed\":false,\"items\":[{\"text\":\"Database Schema\",\"link\":\"/database-schema\"},{\"text\":\"Database Access\",\"link\":\"/database-access\"},{\"text\":\"Seed Data\",\"link\":\"/seed-data\"},{\"text\":\"Jobs\",\"link\":\"/jobs\"},{\"text\":\"Business Logic\",\"link\":\"/business-logic\"}]},{\"text\":\"Framework\",\"collapsed\":false,\"items\":[{\"text\":\"Configuration\",\"link\":\"/configuration\"},{\"text\":\"Keyword Injection\",\"link\":\"/keyword-injection\"},{\"text\":\"I18n\",\"link\":\"/i18n\"},{\"text\":\"CLI / Tasks\",\"link\":\"/cli\"},{\"text\":\"Deployment\",\"link\":\"/deployment\"}]},{\"text\":\"Testing\",\"collapsed\":false,\"items\":[{\"text\":\"Unit Tests\",\"link\":\"/unit-tests\"},{\"text\":\"End-to-End Tests\",\"link\":\"/end-to-end-tests\"},{\"text\":\"Testing Custom Elements\",\"link\":\"/custom-element-tests\"}]},{\"text\":\"Advanced Topics\",\"collapsed\":true,\"items\":[{\"text\":\"Route Hooks\",\"link\":\"/hooks\"},{\"text\":\"Middleware\",\"link\":\"/middleware\"},{\"text\":\"Instrumentation\",\"link\":\"/instrumentation\"},{\"text\":\"Security\",\"link\":\"/security\"},{\"text\":\"LSP Support\",\"link\":\"/lsp\"}]},{\"text\":\"Recipes\",\"collapsed\":true,\"items\":[{\"text\":\"Authentication\",\"link\":\"/recipes/authentication\"},{\"text\":\"Form Validations\",\"link\":\"/recipes/form-validations\"},{\"text\":\"Database Migrations\",\"link\":\"/recipes/database-migrations\"},{\"text\":\"Ajax Form Submission\",\"link\":\"/recipes/ajax-form\"},{\"text\":\"Custom Telemetry\",\"link\":\"/recipes/telemetry\"},{\"text\":\"CLI App/Task\",\"link\":\"/recipes/cli-app\"}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/thirdtank/brut\"}]},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
|
19
19
|
|
20
20
|
</body>
|
21
21
|
</html>
|