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.
- 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/theme/custom.css +7 -0
- data/brutrb.com/.vitepress/theme/style.css +26 -15
- data/brutrb.com/deployment.md +123 -45
- 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/overview.md +6 -6
- data/docker-compose.dx.yml +5 -2
- data/docs/404.html +3 -3
- data/docs/ai.html +4 -4
- 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 +1 -1
- data/docs/api/Brut/CLI/AppRunner.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +1 -1
- data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Create.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Drop.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Migrate.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Seed.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB/Status.html +1 -1
- data/docs/api/Brut/CLI/Apps/DB.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +1 -1
- data/docs/api/Brut/CLI/Apps/DeployBase.html +1 -1
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +1 -1
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Audit.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/E2e.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/JS.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test/Run.html +1 -1
- data/docs/api/Brut/CLI/Apps/Test.html +1 -1
- data/docs/api/Brut/CLI/Apps.html +1 -1
- data/docs/api/Brut/CLI/Command.html +1 -1
- 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 +1 -1
- data/docs/api/Brut/CLI/InvalidOption.html +1 -1
- data/docs/api/Brut/CLI/Options.html +1 -1
- 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 +1 -1
- data/docs/api/Brut/Framework/Error.html +1 -1
- data/docs/api/Brut/Framework/Errors/AbstractMethod.html +1 -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 +1 -1
- 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 +1 -1
- data/docs/api/Brut/FrontEnd/Component.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +1 -1
- 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 +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +1 -1
- data/docs/api/Brut/SpecSupport/Matchers.html +1 -1
- data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +1 -1
- data/docs/api/Brut/SpecSupport/RSpecSetup.html +1 -1
- 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 +1 -1
- data/docs/api/Sequel/Extensions/BrutMigrations.html +1 -1
- 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/_index.html +15 -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 +419 -275
- 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/{app.BX81XO4N.js → app.BhrfSt68.js} +1 -1
- data/docs/assets/chunks/@localSearchIndexroot.CeRAdP1K.js +1 -0
- data/docs/assets/chunks/{VPLocalSearchBox.gABXcTWp.js → VPLocalSearchBox.Dpot_2H4.js} +1 -1
- data/docs/assets/chunks/{theme.DwUXXAL3.js → theme.N2SNVLgU.js} +2 -2
- data/docs/assets/{configuration.md.BGHl8oRC.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/{getting-started.md.Ciz82L0m.js → getting-started.md.Dj0qtZI2.js} +2 -2
- data/docs/assets/index.md.CuBB-BdM.js +1 -0
- data/docs/assets/index.md.CuBB-BdM.lean.js +1 -0
- data/docs/assets/{overview.md.C5wlBcR5.js → overview.md.DVKRM8zl.js} +4 -4
- data/docs/assets/overview.md.DVKRM8zl.lean.js +1 -0
- data/docs/assets/{style.D73IYGCX.css → style.B2o1L9eN.css} +1 -1
- data/docs/assets.html +4 -4
- 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 +4 -4
- data/docs/business-logic.html +4 -4
- data/docs/cli.html +4 -4
- data/docs/components.html +4 -4
- data/docs/configuration.html +6 -6
- data/docs/css.html +4 -4
- data/docs/custom-element-tests.html +4 -4
- data/docs/database-access.html +4 -4
- data/docs/database-schema.html +4 -4
- data/docs/deployment.html +53 -6
- data/docs/dev-environment.html +4 -4
- data/docs/doc-conventions.html +4 -4
- data/docs/end-to-end-tests.html +4 -4
- data/docs/flash-and-session.html +4 -4
- data/docs/forms.html +4 -4
- data/docs/getting-started.html +7 -7
- data/docs/handlers.html +4 -4
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +4 -4
- data/docs/i18n.html +4 -4
- data/docs/index.html +6 -6
- data/docs/instrumentation.html +4 -4
- data/docs/javascript.html +4 -4
- data/docs/jobs.html +4 -4
- data/docs/keyword-injection.html +4 -4
- data/docs/layouts.html +4 -4
- data/docs/lsp.html +4 -4
- data/docs/markdown-examples.html +4 -4
- data/docs/middleware.html +4 -4
- data/docs/not-released.html +4 -4
- data/docs/overview.html +9 -9
- data/docs/pages.html +4 -4
- data/docs/recipes/authentication.html +4 -4
- data/docs/routes.html +4 -4
- data/docs/security.html +4 -4
- data/docs/seed-data.html +4 -4
- data/docs/space-time-continuum.html +4 -4
- data/docs/tutorial.html +4 -4
- data/docs/unit-tests.html +4 -4
- 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/front_end/forms/input.rb +253 -20
- data/lib/brut/front_end/forms/input_definition.rb +15 -12
- data/lib/brut/front_end.rb +1 -0
- data/lib/brut/version.rb +1 -1
- 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 +39 -17
- data/docs/assets/chunks/@localSearchIndexroot.CoYzciVi.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/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.C5wlBcR5.lean.js +0 -1
- /data/docs/assets/{configuration.md.BGHl8oRC.lean.js → configuration.md.LG-zIBww.lean.js} +0 -0
- /data/docs/assets/{getting-started.md.Ciz82L0m.lean.js → getting-started.md.Dj0qtZI2.lean.js} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b77e4a2a30122b1805ecf5cb52a5313bb137c188364a6baac62270918cd1640
|
4
|
+
data.tar.gz: 393ad694666d889d5672fb592e7f188e19f78f519f19fbd4a5edb1af32ef5d21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 769c54918d2cb9a3e40e007d954c70ef6ec4033bb1a159d616cc4680aaf5b5d650e0335d729a5acc10b0d9f96574c4dfe5ec5f563bbd82828c6878ea4a532338
|
7
|
+
data.tar.gz: 510b4299c42f476f61110382afdb26c1c71ae8f6aecf16f95bebcf30bb5ac14b0817b08bb0787e3b9b541be59add9e35d4d60df78debbe0627b371aa4639ce00
|
data/.gitignore
CHANGED
@@ -32,3 +32,9 @@
|
|
32
32
|
/brut-css/dist
|
33
33
|
# This is where the CSS lives temporarily while docs are being built
|
34
34
|
/brut-css/src/docs/brut.css
|
35
|
+
|
36
|
+
# Per-developer Bash customizations that could contain secrets
|
37
|
+
/dx/bash_customizations.local
|
38
|
+
|
39
|
+
# Gems are installed here for LSP convienience
|
40
|
+
/local-gems
|
data/.projections.json
ADDED
data/.rspec
ADDED
data/Dockerfile.dx
CHANGED
@@ -10,28 +10,46 @@ RUN apt-get -y clean && \
|
|
10
10
|
apt-get -y update && \
|
11
11
|
apt-get install --quiet --yes ca-certificates curl gnupg rsync
|
12
12
|
|
13
|
-
# Install NODE per https://github.com/nodesource/distributions?tab=readme-ov-file#using-debian-as-root-nodejs-22
|
14
|
-
RUN curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh && \
|
15
|
-
bash /tmp/nodesource_setup.sh && \
|
16
|
-
apt-get install -y nodejs
|
17
|
-
|
18
|
-
# Install Postgres client per https://www.postgresql.org/download/linux/debian/ - note that the
|
19
|
-
# automated configuration doesn't work, I think because it assumes non-root.
|
20
|
-
RUN apt-get -y install lsb-release && \
|
21
|
-
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
|
22
|
-
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
|
23
|
-
apt-get update && \
|
24
|
-
apt-get -y install postgresql-client-16
|
25
|
-
|
26
13
|
RUN echo "gem: --no-document" >> ~/.gemrc && \
|
27
14
|
gem update --system && \
|
28
15
|
gem install bundler
|
29
|
-
|
30
16
|
# Need vim at all times
|
31
17
|
ENV EDITOR=vim
|
32
18
|
RUN apt-get install -y vim && \
|
33
19
|
echo "set -o vi" >> /root/.bashrc
|
34
20
|
|
21
|
+
|
22
|
+
# Setup a non-root user
|
23
|
+
|
24
|
+
# Their user id, which ideally matches their user id on the host
|
25
|
+
ARG user_uid=10001
|
26
|
+
# Their group id, which ideally matches their group id on the host
|
27
|
+
ARG user_gid=10002
|
28
|
+
|
29
|
+
# Create the user's group ID if it does not exist
|
30
|
+
RUN getent group ${user_gid} || groupadd --gid ${user_gid} appgroup
|
31
|
+
# Create the user. Note that we put bash_customizations in both .profile and .bashrc
|
32
|
+
# to increase the chances they are used when running bash in various configurations
|
33
|
+
RUN useradd --uid ${user_uid} --gid ${user_gid} --create-home --home-dir /home/appuser appuser && \
|
34
|
+
echo ". ~/.bash_customizations" >> /home/appuser/.profile && \
|
35
|
+
echo ". ~/.bash_customizations.local" >> /home/appuser/.profile && \
|
36
|
+
echo ". ~/.bash_customizations" >> /home/appuser/.bashrc && \
|
37
|
+
echo ". ~/.bash_customizations.local" >> /home/appuser/.bashrc
|
38
|
+
|
39
|
+
COPY --chown=appuser:${user_gid} dx/show-help-in-app-container-then-wait.sh /home/appuser
|
40
|
+
COPY --chown=appuser:${user_gid} dx/bash_customizations /home/appuser/.bash_customizations
|
41
|
+
COPY --chown=appuser:${user_gid} dx/bash_customizations.local /home/appuser/.bash_customizations.local
|
42
|
+
|
43
|
+
# NOT including the group here as that will place the user's environment
|
44
|
+
# ONLY in that group and not in all the groups in which they are a part.
|
45
|
+
USER appuser
|
46
|
+
|
47
|
+
# Install NodeJS, per https://nodejs.org/en/download
|
48
|
+
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \
|
49
|
+
\. "$HOME/.nvm/nvm.sh" && \
|
50
|
+
nvm install 22 && \
|
51
|
+
node -v && nvm current && npm -v
|
52
|
+
|
35
53
|
# Node's colors are hand-crafted to always look bad and render at least some text unreadable
|
36
54
|
# no matter what your setup. Cool.
|
37
55
|
ENV NODE_DISABLE_COLORS=1
|
data/Gemfile.lock
CHANGED
Binary file
|
Binary file
|
data/assets/LogoStop.pxd
ADDED
Binary file
|
data/assets/LogoTall.pxd
ADDED
Binary file
|
data/bin/docs
CHANGED
@@ -14,14 +14,36 @@ OptionParser.new do |opts|
|
|
14
14
|
end
|
15
15
|
end.parse!
|
16
16
|
|
17
|
-
public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path
|
18
|
-
docs_dir = public_dir
|
17
|
+
public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path
|
18
|
+
docs_dir = public_dir / "api"
|
19
19
|
brutjs_dir = (Pathname(__FILE__).dirname / ".." / "brut-js" ).expand_path.to_s
|
20
20
|
|
21
21
|
system(
|
22
22
|
"bundle exec yard doc -o '#{docs_dir}' -m markdown -M rdiscount --backtrace"
|
23
23
|
)
|
24
24
|
|
25
|
+
puts "Hacking CSS"
|
26
|
+
[
|
27
|
+
docs_dir / "css" / "style.css",
|
28
|
+
docs_dir / "css" / "full_list.css"
|
29
|
+
].each do |css_file_to_hack|
|
30
|
+
lines = File.read(css_file_to_hack).split(/\n/)
|
31
|
+
File.open(css_file_to_hack, "w") do |f|
|
32
|
+
lines.each do |line|
|
33
|
+
if line =~ /\"Lucida Sans"/
|
34
|
+
f.puts line.gsub(/\"Lucida Sans\"/, '"Helvetica Neue", "Lucida Sans"')
|
35
|
+
elsif line =~ / Monaco,/
|
36
|
+
f.puts line.gsub(/ Monaco,/, '"Courier New", Monaco,')
|
37
|
+
elsif line =~ /font-family: monospace;/
|
38
|
+
f.puts line.gsub(/font-family: monospace;/, 'font-family: "Courier New", monospace;')
|
39
|
+
else
|
40
|
+
f.puts line
|
41
|
+
end
|
42
|
+
end
|
43
|
+
f.puts "code { font-family: 'Courier New', monospace; font-weight: 600; }"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
FileUtils.chdir brutjs_dir do
|
26
48
|
system("bin/build")
|
27
49
|
end
|
data/bin/rspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/setup
CHANGED
@@ -83,7 +83,7 @@ def setup(update_gems:,setup_credentials:)
|
|
83
83
|
system! "ssh-add #{key_file}"
|
84
84
|
end
|
85
85
|
|
86
|
-
known_hosts_dest = Pathname("/") / "
|
86
|
+
known_hosts_dest = Pathname("/") / "home" / "appuser" / ".ssh" / "known_hosts"
|
87
87
|
if known_hosts_dest.exist?
|
88
88
|
log "#{known_hosts_dest} exists, your ssh key should work with GitHub"
|
89
89
|
else
|
@@ -117,7 +117,7 @@ def setup(update_gems:,setup_credentials:)
|
|
117
117
|
end
|
118
118
|
log "Your ssh key looks good"
|
119
119
|
|
120
|
-
gem_credentials_dest = Pathname("/") / "
|
120
|
+
gem_credentials_dest = Pathname("/") / "home" / "appuser" / ".gem" / "credentials"
|
121
121
|
if gem_credentials_dest.exist?
|
122
122
|
log "Gem credentials look good"
|
123
123
|
else
|
@@ -139,7 +139,7 @@ def setup(update_gems:,setup_credentials:)
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
npm_credentials_dest = Pathname("/") / "
|
142
|
+
npm_credentials_dest = Pathname("/") / "home" / "appuser" / ".npmrc"
|
143
143
|
if npm_credentials_dest.exist?
|
144
144
|
log "NPM credentials look good"
|
145
145
|
else
|
@@ -51,13 +51,14 @@
|
|
51
51
|
|
52
52
|
--blue-vp-c-brand-1: #0C00A7;
|
53
53
|
--blue-vp-c-brand-2: #6357FF;
|
54
|
-
--blue-vp-c-brand-3: #
|
55
|
-
--blue-vp-c-brand-soft: #
|
54
|
+
--blue-vp-c-brand-3: #4C0606;
|
55
|
+
--blue-vp-c-brand-soft: #FFF9F9;
|
56
|
+
|
57
|
+
--vp-c-brand-1: #362400;
|
58
|
+
--vp-c-brand-2: #F1A100;
|
59
|
+
--vp-c-brand-3: #281B00;
|
60
|
+
--vp-c-brand-soft: #FFF1D6;
|
56
61
|
|
57
|
-
--vp-c-brand-1: #A70C00;
|
58
|
-
--vp-c-brand-2: #FF6357;
|
59
|
-
--vp-c-brand-3: #e21000;
|
60
|
-
--vp-c-brand-soft: #FFE7E5;
|
61
62
|
|
62
63
|
--xvp-c-brand-1: var(--vp-c-indigo-1);
|
63
64
|
--xvp-c-brand-2: var(--vp-c-indigo-2);
|
@@ -69,15 +70,25 @@
|
|
69
70
|
--vp-c-tip-3: var(--vp-c-brand-3);
|
70
71
|
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
71
72
|
|
72
|
-
--
|
73
|
-
--
|
74
|
-
--
|
75
|
-
--
|
76
|
-
|
77
|
-
--vp-c-
|
78
|
-
--vp-c-
|
79
|
-
--vp-c-
|
80
|
-
--vp-c-
|
73
|
+
--xvp-c-warning-1: var(--vp-c-yellow-1);
|
74
|
+
--xvp-c-warning-2: var(--vp-c-yellow-2);
|
75
|
+
--xvp-c-warning-3: var(--vp-c-yellow-3);
|
76
|
+
--xvp-c-warning-soft: var(--vp-c-yellow-soft);
|
77
|
+
|
78
|
+
--vp-c-warning-1: #9E5601;
|
79
|
+
--vp-c-warning-2: #FDAF53;
|
80
|
+
--vp-c-warning-3: #5E3301;
|
81
|
+
--vp-c-warning-soft: #FFF3E5;
|
82
|
+
|
83
|
+
--vp-c-danger-1: #AC0E0E;
|
84
|
+
--vp-c-danger-2: #F14E4E;
|
85
|
+
--vp-c-danger-3: #4C0606;
|
86
|
+
--vp-c-danger-soft: #FFF9F9;
|
87
|
+
|
88
|
+
--xvp-c-danger-1: var(--vp-c-red-1);
|
89
|
+
--xvp-c-danger-2: var(--vp-c-red-2);
|
90
|
+
--xvp-c-danger-3: var(--vp-c-red-3);
|
91
|
+
--xvp-c-danger-soft: var(--vp-c-red-soft);
|
81
92
|
}
|
82
93
|
|
83
94
|
/**
|
data/brutrb.com/deployment.md
CHANGED
@@ -1,66 +1,144 @@
|
|
1
1
|
# Deployment
|
2
2
|
|
3
3
|
Brut apps are Rack apps, so they can be deployed in conventional
|
4
|
-
ways.
|
5
|
-
development are inteded to work for production as well.
|
4
|
+
ways.
|
6
5
|
|
7
6
|
## Overview
|
8
7
|
|
9
|
-
|
10
|
-
simple solution for all deployment setups, so this document will
|
11
|
-
outline considerations when setting up deployment.
|
8
|
+
There are just too many ways to deploy. Brut attempts to address this by adhering to [12-factor principles](https://12factor.net). Brut also tries not to create artifacts like `Procfile` or `Dockerfile` that would conflict with the artifacts you'd need to manage deployment.
|
12
9
|
|
13
|
-
|
14
|
-
at `deploy/Dockerfile`, which is the foundation of a `Dockerfile`
|
15
|
-
you can use. In particular, it shows you the commands needed to
|
16
|
-
setup and run the app in production:
|
10
|
+
That said, Brut includes first-class support for deploying to Heroku using containers. More options will be included as necessary, either through direct support in code/tooling, or documentation here.
|
17
11
|
|
18
|
-
|
19
|
-
as whatever is needed for NodeJS and Postgres, the Brut-specific
|
20
|
-
parts look like so:
|
12
|
+
### Heroku Container-based Deployment
|
21
13
|
|
22
|
-
|
23
|
-
2. Install Node modules with `npm clean-install`
|
24
|
-
3. Build all assets with `bin/build-assets` (this will bundle all
|
25
|
-
CSS and Javascript, plus copy over any other [assets](/assets)
|
26
|
-
to the locations from where the Brut app will serve them)
|
27
|
-
4. Run the app with `bin/run`
|
14
|
+
When creating your Brut app with `mkbrut`, the Heroku segment can be used to create files and scripts for a [Heroku container-based deployment](https://devcenter.heroku.com/articles/container-registry-and-runtime).
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
| File | Purpose | Notes |
|
17
|
+
|------|---------|-------|
|
18
|
+
| `bin/deploy` | Script to use to perform the deployment | This wraps `HerokuContainerBasedDeploy` in `Brut::CLI::Apps` |
|
19
|
+
| `deploy/Dockerfile` | Template `Dockerfile` used to create a `Dockerfile` for each process type | Heroku requires each process (web, worker, release, etc.) to have its own `Dockerfile` and own image |
|
20
|
+
| `deploy/heroku_config.rb` | Class that exports optional processes | By default, your app has a web and release process. `HerokuConfig` can export others, like Sidekiq |
|
21
|
+
| `deploy/docker-entrypoint` | The [`ENTRYPOINT`](https://docs.docker.com/reference/dockerfile/#entrypoint) for production Docker images, which is set up to use jemalloc | You can modify or remove this as needed |
|
22
|
+
|
23
|
+
How to deploy:
|
24
|
+
|
25
|
+
1. Auth to Heroku from inside your dev container:
|
26
|
+
|
27
|
+
```
|
28
|
+
your-computer> dx/exec bash
|
29
|
+
devcontainer> heroku auth:login
|
30
|
+
# You will need to copy/paste the URL to log in
|
31
|
+
devcontainer> heroku container:login
|
32
|
+
```
|
33
|
+
|
34
|
+
2. Create your app using the container stack:
|
35
|
+
|
36
|
+
```
|
37
|
+
> heroku create --stack container -a «your heroku app name»
|
38
|
+
```
|
39
|
+
3. Ensure your app's source code is all checked in, there are no uncommitted or unadded files, and you have pushed to main.
|
40
|
+
4. `bin/deploy`
|
41
|
+
|
42
|
+
This will generate a `Dockerfile` for each process (by default, `Dockerfile.web` and `Dockerfile.release`), build images, push those images to Heroku, and ask Heroku to release them.
|
43
|
+
|
44
|
+
Debugging Tips:
|
45
|
+
|
46
|
+
* Keep in mind it's hard to make general deployment tools. You are expected to understand your deployment and be capable of deploying an arbitrary Rack app manually. Brut's tooling automates what you need to know.
|
47
|
+
* `bin/deploy` runs the `deploy` subcommand, so `bin/deploy help deploy` can provide
|
48
|
+
some options for debugging issues:
|
49
|
+
|
50
|
+
```
|
51
|
+
devcontainer> bin/deploy help deploy
|
52
|
+
Usage: bin/deploy [global options] deploy [command options]
|
53
|
+
|
54
|
+
Build images, push them to Heroku, and deploy them
|
55
|
+
|
56
|
+
Manages a deploy process based on using Heroku's Container Registry. See
|
57
|
+
|
58
|
+
https://devcenter.heroku.com/articles/container-registry-and-runtime
|
59
|
+
|
60
|
+
for details. You are assumed to understand this.
|
61
|
+
This command will make the process somewhat easier.
|
62
|
+
|
63
|
+
This will use deploy/Dockerfile as a template to create
|
64
|
+
one Dockerfile for each process you want to run in Heroku.
|
65
|
+
deploy/heroku_config.rb is where the processes and their
|
66
|
+
commands are configured.
|
67
|
+
|
68
|
+
The release phase is included automatically, based on bin/release.
|
69
|
+
|
70
|
+
GLOBAL OPTIONS
|
71
|
+
|
72
|
+
-h, --help Get help
|
73
|
+
--log-level=LEVEL Set log level. Allowed values: debug,
|
74
|
+
info, warn, error, fatal. Default 'fatal'
|
75
|
+
--verbose Set log level to 'debug', which will produce
|
76
|
+
maximum output
|
77
|
+
|
78
|
+
ENVIRONMENT VARIABLES
|
79
|
+
|
80
|
+
BRUT_CLI_RAISE_ON_ERROR - if set, shows backtrace on errors
|
81
|
+
LOG_LEVEL - log level if --log-level or --verbose is omitted
|
82
|
+
|
83
|
+
|
84
|
+
COMMAND OPTIONS
|
85
|
+
|
86
|
+
--platform=PLATFORM Override default platform. Can be any Docker
|
87
|
+
platform.
|
88
|
+
--[no-]dry-run Print the commands that would be run and
|
89
|
+
don't actually do anything. Implies --skip-checks
|
90
|
+
--[no-]skip-checks Skip checks for code having been
|
91
|
+
committed and pushed
|
92
|
+
--[no-]deploy After images are pushed, actually deploy them
|
93
|
+
--[no-]push After images are created, push them
|
94
|
+
to Heroku's registry. If false,
|
95
|
+
implies --no-deploy
|
96
|
+
```
|
97
|
+
* Try building images first: `bin/deploy deploy --no-push --skip-checks`
|
98
|
+
* It's possible to run the images locally. If you are on Apple Silicon, you'll
|
99
|
+
need to set --platform:
|
100
|
+
|
101
|
+
* `bin/deploy deploy --no-push --skip-checks --platform linux/arm64`
|
102
|
+
* Create `docker-compose.yml` for your image and any other services e.g. databases
|
103
|
+
* Set required environment variables in `docker-compose.yml`
|
104
|
+
* Start up Docker compose and poke around
|
105
|
+
|
106
|
+
You'll need to have a better understanding of Docker to do this, however if you
|
107
|
+
are deploying with Docker, this is an understanding you hopefully already have.
|
108
|
+
|
109
|
+
|
110
|
+
### Other Mechanisms for Deployment
|
111
|
+
|
112
|
+
As a Rack app, other deployments should be possible. To make the app work, you'll need to make sure a few things are dealt with:
|
113
|
+
|
114
|
+
* `RACK_ENV` **must** be `"production"`
|
115
|
+
* `bin/build-assets` will build all assets by default. This must either be done on production servers or done ahead of time and the results packaged with the app.
|
116
|
+
* `bin/build-assets` outputs files in `app/public` and `app/config`. Those files are used at runtime. Brut **will not** initiate the build of any assets.
|
117
|
+
* If you are going to build assets on production servers, you *must* included developer tooling. This means NodeJS, all modules in `package.json` and all RubyGems in `Gemfile`.
|
118
|
+
|
119
|
+
The `deploy/Dockerfile` created by `mkbrut --segment-heroku` is not very Heroku-specific and could serve as a reference.
|
33
120
|
|
34
121
|
## Testing
|
35
122
|
|
36
|
-
|
37
|
-
them locally to see how they work. You will need to have local
|
38
|
-
versions of all infrastructure (database, Redis, etc.), but if
|
39
|
-
these work locally, there is a high chance they work in
|
40
|
-
production.
|
123
|
+
Testing deployments is a bit out of scope, but in general:
|
41
124
|
|
42
|
-
|
43
|
-
|
125
|
+
* A container-based deployment can theoretically be run on your computer as a test.
|
126
|
+
* Non-production, but production-like environments can be used to validate production configurations.
|
127
|
+
* You own the means of production…not Brut.
|
44
128
|
|
45
129
|
## Recommended Practices
|
46
130
|
|
47
|
-
|
48
|
-
|
49
|
-
|
131
|
+
* Avoid a lot of code that checks `Brut.container.project_env`. Try to consolidate all prod/test/dev differences in environment variables.
|
132
|
+
* Have a way to get a shell into your production environment for debugging.
|
133
|
+
* Brut doesn't log much, but if you remove the `OTEL_*` environment variables, Brut will log OTel telemetry to the console, which may be useful.
|
134
|
+
* Setting `OTEL_LOG_LEVEL=debug` is advised if the app isn't starting or you aren't seeing any telemetry or logging
|
50
135
|
|
51
|
-
|
52
|
-
of surprises. That all being said, here are some recommendations:
|
136
|
+
## Technical Notes
|
53
137
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
card you charge and refund.
|
58
|
-
* Configure observability so you know what your app is doing at
|
59
|
-
all times.
|
60
|
-
* Configure a URL that, when accessed, produces an error. This
|
61
|
-
allows you to check your error reporting system.
|
62
|
-
* Create a page somewhere that shows the git SHA of your
|
63
|
-
deployment, or some other unique, unambiguous version number. This
|
64
|
-
will clarify what version of the code is actually running.
|
138
|
+
> [!IMPORTANT]
|
139
|
+
> Technical Notes are for deeper understanding and debugging. While we will try to keep them up-to-date with changes to Brut's
|
140
|
+
> internals, the source code is always more correct.
|
65
141
|
|
142
|
+
_Last Updated July 3, 2025_
|
66
143
|
|
144
|
+
None at this time.
|
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
|
+

|
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\":\"_6HCDL6d\",\"assets.md\":\"D3wunzLx\",\"brut-js.md\":\"o2DAO2s2\",\"business-logic.md\":\"BY4hGy0m\",\"cli.md\":\"RmeA2b0i\",\"components.md\":\"CRUMdRoN\",\"configuration.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>
|