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,12 +1,54 @@
|
|
1
|
+
require "uri"
|
2
|
+
|
1
3
|
# An Input is a stateful object representing a specific input and its value
|
2
4
|
# during the course of a form submission process. In particular, it wraps a value
|
3
|
-
# and a {Brut::FrontEnd::Forms::ValidityState}. These are mutable, whereas
|
5
|
+
# and a {Brut::FrontEnd::Forms::ValidityState}. These are mutable, whereas
|
6
|
+
# the wrapped {Brut::FrontEnd::Forms::InputDefinition} is not.
|
7
|
+
#
|
8
|
+
# Of note, this class also initiates the server-execution of the
|
9
|
+
# client-side validations. When a form is posted, and you ask the form
|
10
|
+
# to validate itself, this class examines the value for the inputs
|
11
|
+
# and determines if a client-side violation should've happened in the browser.
|
12
|
+
#
|
13
|
+
# It does its best to mimic the browser's behavior, however there will be
|
14
|
+
# some subtle differences.
|
15
|
+
#
|
16
|
+
# An important considering is that everything is a string. The browser wants
|
17
|
+
# strings and its internal API is string-based. So is this. That said,
|
18
|
+
# this will convert strings into richer types in order to perform constraint
|
19
|
+
# analysis.
|
20
|
+
#
|
21
|
+
# Where possible, standard library classes are used, but in some cases -
|
22
|
+
# colors and times - there is no standard library class.
|
23
|
+
#
|
24
|
+
# See {#typed_value}.
|
4
25
|
class Brut::FrontEnd::Forms::Input
|
5
26
|
|
6
27
|
extend Forwardable
|
7
28
|
|
8
|
-
# @return [String] the input's value
|
29
|
+
# @return [String] the input's value. **DO NOTE** this returns a string. This is
|
30
|
+
# because HTML stores these values as Strings. When using a checkbox, in
|
31
|
+
# particular, the value will *not* be a boolean. You cannot do `if
|
32
|
+
# input.value` and expect that work. See {#typed_value} instead.
|
9
33
|
attr_reader :value
|
34
|
+
|
35
|
+
# @return [Date|Time|BigDecimal|String|true|false|nil] the value of the input,
|
36
|
+
# as coerced to the type used to evaluate constraints.
|
37
|
+
# Returns `nil` if the value could not be coerced (which likely means
|
38
|
+
# there is or will be a constraint violation), **or**
|
39
|
+
# if it is a blank String.
|
40
|
+
#
|
41
|
+
# Of note, `type=color` will return a String here, but that String
|
42
|
+
# should be parseable into a hex code, i.e. #XXXXXX, where each "X"
|
43
|
+
# is 0-9 or a-f. Further, `type=time` will also return a string
|
44
|
+
# in the format HH:MM or HH:MM:SS, where the time is in 24 hour
|
45
|
+
# time. Lastly, `type=datetime-local` will return a `Time`, even
|
46
|
+
# though the control allows the visitor to choose an invalid time.
|
47
|
+
# If there is no `valueMissing` constraint violation, but this
|
48
|
+
# attribute returns `nil`, {#value} *will* return the string sent by
|
49
|
+
# the browser, even if it's not a real timestamp.
|
50
|
+
attr_reader :typed_value
|
51
|
+
|
10
52
|
# @return [Brut::FrontEnd::Forms::ValidityState] Validity state that captures the current constraint violations, if any
|
11
53
|
attr_reader :validity_state
|
12
54
|
|
@@ -20,6 +62,46 @@ class Brut::FrontEnd::Forms::Input
|
|
20
62
|
self.value=(value)
|
21
63
|
end
|
22
64
|
|
65
|
+
# @!method max
|
66
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
67
|
+
# initializer
|
68
|
+
|
69
|
+
# @!method maxlength
|
70
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
71
|
+
# initializer
|
72
|
+
|
73
|
+
# @!method min
|
74
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
75
|
+
# initializer
|
76
|
+
|
77
|
+
# @!method minlength
|
78
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
79
|
+
# initializer
|
80
|
+
|
81
|
+
# @!method name
|
82
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
83
|
+
# initializer
|
84
|
+
|
85
|
+
# @!method pattern
|
86
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
87
|
+
# initializer
|
88
|
+
|
89
|
+
# @!method required
|
90
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
91
|
+
# initializer
|
92
|
+
|
93
|
+
# @!method step
|
94
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
95
|
+
# initializer
|
96
|
+
|
97
|
+
# @!method type
|
98
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
99
|
+
# initializer
|
100
|
+
|
101
|
+
# @!method array?
|
102
|
+
# @return [String|nil] the value from the `input_definition` given to the
|
103
|
+
# initializer
|
104
|
+
|
23
105
|
def_delegators :"@input_definition", :max,
|
24
106
|
:maxlength,
|
25
107
|
:min,
|
@@ -37,14 +119,52 @@ class Brut::FrontEnd::Forms::Input
|
|
37
119
|
#
|
38
120
|
# When this method completes, the value of {#validity_state} could change.
|
39
121
|
#
|
40
|
-
# @param [String] new_value the value for the input.
|
122
|
+
# @param [String] new_value the value for the input. Any non-String value will
|
123
|
+
# be coerced to a String via `to_s`.
|
41
124
|
def value=(new_value)
|
42
|
-
|
43
|
-
|
125
|
+
new_value = new_value.to_s
|
126
|
+
@typed_value = case self.type
|
127
|
+
when "number"
|
128
|
+
BigDecimal(new_value, exception: false)
|
129
|
+
when "range"
|
130
|
+
BigDecimal(new_value, exception: false)
|
131
|
+
when "checkbox"
|
132
|
+
new_value == "true"
|
133
|
+
when "color"
|
134
|
+
Color.from_hex_string(new_value)&.to_s
|
135
|
+
when "date"
|
136
|
+
begin
|
137
|
+
Date.parse(new_value)
|
138
|
+
rescue
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
when "time"
|
142
|
+
TimeOfDay.from_string(new_value)
|
143
|
+
when "datetime-local"
|
144
|
+
begin
|
145
|
+
Time.parse(new_value)
|
146
|
+
rescue
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
when "url"
|
150
|
+
begin
|
151
|
+
URI(new_value)
|
152
|
+
rescue
|
153
|
+
nil
|
154
|
+
end
|
155
|
+
else
|
156
|
+
new_value.strip == "" ? nil : new_value
|
157
|
+
end
|
158
|
+
|
159
|
+
if type == "hidden" || type == "file"
|
160
|
+
@value = new_value
|
161
|
+
return
|
44
162
|
end
|
45
|
-
|
163
|
+
|
164
|
+
value_missing = new_value.strip == "" || @typed_value.nil?
|
165
|
+
|
46
166
|
missing = if self.required
|
47
|
-
value_missing
|
167
|
+
value_missing || @typed_value == false
|
48
168
|
else
|
49
169
|
false
|
50
170
|
end
|
@@ -60,38 +180,81 @@ class Brut::FrontEnd::Forms::Input
|
|
60
180
|
false
|
61
181
|
end
|
62
182
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
183
|
+
range_overflow = if self.max && !value_missing
|
184
|
+
if type == "date"
|
185
|
+
max_date = Date.parse(self.max)
|
186
|
+
@typed_value > max_date
|
187
|
+
elsif type == "datetime-local"
|
188
|
+
max_date = Time.parse(self.max)
|
189
|
+
@typed_value > max_date
|
190
|
+
elsif type == "time"
|
191
|
+
max_time = TimeOfDay.from_string(self.max)
|
192
|
+
@typed_value > max_time
|
193
|
+
else
|
194
|
+
new_value.to_i > self.max
|
195
|
+
end
|
67
196
|
else
|
68
197
|
false
|
69
198
|
end
|
70
199
|
|
71
|
-
range_underflow = if self.min && !value_missing
|
72
|
-
|
200
|
+
range_underflow = if self.min && !value_missing
|
201
|
+
if type == "date"
|
202
|
+
min_date = Date.parse(self.min)
|
203
|
+
@typed_value < min_date
|
204
|
+
elsif type == "datetime-local"
|
205
|
+
min_date = Time.parse(self.min)
|
206
|
+
@typed_value < min_date
|
207
|
+
elsif type == "time"
|
208
|
+
min_time = TimeOfDay.from_string(self.min)
|
209
|
+
@typed_value < min_time
|
210
|
+
else
|
211
|
+
new_value.to_i < self.min
|
212
|
+
end
|
73
213
|
else
|
74
214
|
false
|
75
215
|
end
|
76
216
|
|
77
|
-
pattern_mismatch = if self.pattern && !value_missing
|
217
|
+
pattern_mismatch = if self.pattern && !value_missing
|
78
218
|
!new_value.match?(Regexp.new(self.pattern))
|
79
|
-
|
80
|
-
|
219
|
+
elsif type == "url" && !value_missing
|
220
|
+
@typed_value.nil? || !@typed_value.absolute
|
81
221
|
end
|
82
|
-
step_mismatch =
|
222
|
+
step_mismatch = if self.step && !value_missing
|
223
|
+
step_big_decimal = BigDecimal(self.step.to_s)
|
224
|
+
if type == "date"
|
225
|
+
basis_date = self.min ? Date.parse(self.min) : Date.parse("1970-01-01")
|
226
|
+
num_days = (@typed_value - basis_date)
|
227
|
+
num_days % step_big_decimal != 0
|
228
|
+
elsif type == "datetime-local"
|
229
|
+
basis_time = self.min ? Time.parse(self.min) : Time.parse("1970-01-01T00:00:00")
|
230
|
+
num_seconds = (@typed_value - basis_time)
|
231
|
+
num_seconds % step_big_decimal != 0
|
232
|
+
elsif type == "time"
|
233
|
+
basis_time = self.min ? TimeOfDay.from_string(self.min) : TimeOfDay.new(hour: 0, minute: 0, second: 0)
|
234
|
+
num_seconds = (@typed_value - basis_time)
|
235
|
+
num_seconds % step_big_decimal != 0
|
236
|
+
else
|
237
|
+
@typed_value % step_big_decimal != 0
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
if type == "range" || type == "color"
|
242
|
+
missing = false
|
243
|
+
elsif type == "time"
|
244
|
+
@typed_value = @typed_value&.to_s
|
245
|
+
end
|
83
246
|
|
84
247
|
@validity_state = Brut::FrontEnd::Forms::ValidityState.new(
|
85
248
|
valueMissing: missing,
|
86
249
|
tooShort: too_short,
|
87
|
-
tooLong:
|
250
|
+
tooLong: too_long,
|
88
251
|
rangeOverflow: range_overflow,
|
89
252
|
rangeUnderflow: range_underflow,
|
90
253
|
patternMismatch: pattern_mismatch,
|
91
254
|
stepMismatch: step_mismatch,
|
92
|
-
typeMismatch:
|
255
|
+
typeMismatch: false,
|
93
256
|
)
|
94
|
-
@value = new_value
|
257
|
+
@value = value_missing ? nil : new_value
|
95
258
|
end
|
96
259
|
|
97
260
|
# Set a server-side constraint violation on this input. This is essentially arbitrary, but note
|
@@ -105,4 +268,74 @@ class Brut::FrontEnd::Forms::Input
|
|
105
268
|
|
106
269
|
# @return [true|false] true if the underlying {#validity_state} has no constraint violations
|
107
270
|
def valid? = @validity_state.valid?
|
271
|
+
|
272
|
+
class Color
|
273
|
+
def self.from_hex_string(string)
|
274
|
+
string = string.to_s
|
275
|
+
if string.match?(/\A#[0-9a-fA-F]{6}\z/)
|
276
|
+
string.downcase
|
277
|
+
else
|
278
|
+
nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class TimeOfDay
|
284
|
+
include Comparable
|
285
|
+
def self.from_string(string)
|
286
|
+
match_data = string.match(/\A([01]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?\z/)
|
287
|
+
if match_data
|
288
|
+
hour = match_data[1].to_i
|
289
|
+
minute = match_data[2].to_i
|
290
|
+
second = match_data[4] ? match_data[4].to_i : nil
|
291
|
+
self.new(hour:, minute:, second:)
|
292
|
+
else
|
293
|
+
nil
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def initialize(hour:, minute:, second:)
|
298
|
+
@hour = in_range!(hour, 0, 23, "hour")
|
299
|
+
@minute = in_range!(minute, 0, 59, "minute")
|
300
|
+
@second = second.nil? ? nil : in_range!(second, 0, 59, "second")
|
301
|
+
end
|
302
|
+
|
303
|
+
def to_s
|
304
|
+
if @second.nil?
|
305
|
+
sprintf("%02d:%02d", @hour, @minute)
|
306
|
+
else
|
307
|
+
sprintf("%02d:%02d:%02d", @hour, @minute, @second)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def to_seconds
|
312
|
+
(@second || 0) +
|
313
|
+
(@minute * 60) +
|
314
|
+
(@hour * 3600)
|
315
|
+
end
|
316
|
+
|
317
|
+
def -(other)
|
318
|
+
if other.kind_of?(self.class)
|
319
|
+
self.to_seconds - other.to_seconds
|
320
|
+
else
|
321
|
+
raise ArgumentError, "Cannot subtract #{other.class} from TimeOfDay"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def <=>(other)
|
326
|
+
return -1 if !other.kind_of?(self.class)
|
327
|
+
self.to_seconds <=> other.to_seconds
|
328
|
+
end
|
329
|
+
|
330
|
+
private
|
331
|
+
|
332
|
+
def in_range!(value, min, max, name)
|
333
|
+
if value < min || value > max
|
334
|
+
raise ArgumentError, "Invalid #{name} '#{value}' (must be between #{min} and #{max})"
|
335
|
+
end
|
336
|
+
value
|
337
|
+
rescue ArgumentError => e
|
338
|
+
raise ArgumentError, "Invalid TimeOfDay: #{e.message}"
|
339
|
+
end
|
340
|
+
end
|
108
341
|
end
|
@@ -22,12 +22,11 @@ class Brut::FrontEnd::Forms::InputDefinition
|
|
22
22
|
INPUT_TYPES_TO_CLASS = {
|
23
23
|
"checkbox" => String,
|
24
24
|
"color" => String,
|
25
|
-
"date" =>
|
26
|
-
"datetime-local" =>
|
25
|
+
"date" => Date,
|
26
|
+
"datetime-local" => Time,
|
27
27
|
"email" => String,
|
28
28
|
"file" => String,
|
29
29
|
"hidden" => String,
|
30
|
-
"month" => String,
|
31
30
|
"number" => Numeric,
|
32
31
|
"password" => String,
|
33
32
|
"radio" => String,
|
@@ -35,9 +34,8 @@ class Brut::FrontEnd::Forms::InputDefinition
|
|
35
34
|
"search" => String,
|
36
35
|
"tel" => String,
|
37
36
|
"text" => String,
|
38
|
-
"time" =>
|
37
|
+
"time" => Time, # XXX
|
39
38
|
"url" => String,
|
40
|
-
"week" => String,
|
41
39
|
}
|
42
40
|
|
43
41
|
# Create an InputDefinition. This should very closely mirror
|
@@ -65,7 +63,7 @@ class Brut::FrontEnd::Forms::InputDefinition
|
|
65
63
|
min: nil,
|
66
64
|
minlength: nil,
|
67
65
|
name: nil,
|
68
|
-
pattern:
|
66
|
+
pattern: :based_on_type,
|
69
67
|
required: :based_on_type,
|
70
68
|
step: nil,
|
71
69
|
type: nil,
|
@@ -89,20 +87,25 @@ class Brut::FrontEnd::Forms::InputDefinition
|
|
89
87
|
required = type != "checkbox"
|
90
88
|
end
|
91
89
|
|
92
|
-
@max =
|
90
|
+
@max = max
|
93
91
|
@maxlength = type!( maxlength , Numeric , "maxlength")
|
94
|
-
@min =
|
92
|
+
@min = min
|
95
93
|
@minlength = type!( minlength , Numeric , "minlength")
|
96
94
|
@name = type!( name , String , "name", required: true)
|
97
|
-
@pattern = type!( pattern , String , "pattern")
|
98
95
|
@required = type!( required , [true, false] , "required", required: true)
|
99
96
|
@step = type!( step , Numeric , "step")
|
100
97
|
@type = type!( type , INPUT_TYPES_TO_CLASS.keys , "type", required: true)
|
101
98
|
@array = type!( array , [true, false] , "array", required: true)
|
102
99
|
|
103
|
-
|
104
|
-
|
105
|
-
|
100
|
+
@pattern = if pattern == :based_on_type
|
101
|
+
if type == "email"
|
102
|
+
/^[^@]+@[^@]+\.[^@]+$/.source
|
103
|
+
else
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
else
|
107
|
+
type!( pattern, String, "pattern" )
|
108
|
+
end
|
106
109
|
end
|
107
110
|
|
108
111
|
def array? = @array
|
@@ -28,6 +28,8 @@ class Brut::FrontEnd::Middlewares::ReloadApp < Brut::FrontEnd::Middleware
|
|
28
28
|
span.add_event("Routing reloaded")
|
29
29
|
Brut.container.asset_path_resolver.reload
|
30
30
|
span.add_event("Asset Path Resolver reloaded")
|
31
|
+
Brut.container.reload
|
32
|
+
span.add_event("Brut.container reloaded")
|
31
33
|
::I18n.reload!
|
32
34
|
span.add_event("I18n reloaded")
|
33
35
|
rescue => ex
|
data/lib/brut/front_end.rb
CHANGED
@@ -12,6 +12,7 @@ module Brut::FrontEnd
|
|
12
12
|
autoload(:Download, "brut/front_end/download")
|
13
13
|
autoload(:Flash, "brut/front_end/flash")
|
14
14
|
autoload(:Form, "brut/front_end/form")
|
15
|
+
autoload(:Forms, "brut/front_end/form")
|
15
16
|
autoload(:GenericResponse, "brut/front_end/generic_response")
|
16
17
|
autoload(:Handler, "brut/front_end/handler")
|
17
18
|
autoload(:Handlers, "brut/front_end/handler")
|
@@ -43,8 +43,16 @@ class Brut::SpecSupport::RSpecSetup
|
|
43
43
|
# Create the setup with the given RSpec configuration.
|
44
44
|
#
|
45
45
|
# @param [RSpec::Core::Configuration] rspec_config yielded from `RSpec.configure`
|
46
|
-
|
47
|
-
|
46
|
+
# @param [boolean] monkey_patch_summary_notification if true (the default),
|
47
|
+
# RSpec's Notifications::SumaryNotification will be monkey-patched to show
|
48
|
+
# `bin/test` in the summary instead of `./rspec`, as that is how you would
|
49
|
+
# re-run a test. But, it's still monkey-patching.
|
50
|
+
def initialize(rspec_config:,
|
51
|
+
monkey_patch_summary_notification: true)
|
52
|
+
|
53
|
+
@config = rspec_config
|
54
|
+
@monkey_patch_summary_notification = monkey_patch_summary_notification
|
55
|
+
|
48
56
|
SemanticLogger.default_level = ENV.fetch("LOGGER_LEVEL_FOR_TESTS","warn")
|
49
57
|
end
|
50
58
|
|
@@ -155,6 +163,9 @@ class Brut::SpecSupport::RSpecSetup
|
|
155
163
|
@config.after(:suite) do
|
156
164
|
Brut::SpecSupport::E2ETestServer.instance.stop
|
157
165
|
end
|
166
|
+
if @monkey_patch_summary_notification
|
167
|
+
monkey_patch_summary_notification!
|
168
|
+
end
|
158
169
|
end
|
159
170
|
|
160
171
|
class OptionalSidekiqSupport
|
@@ -181,4 +192,33 @@ class Brut::SpecSupport::RSpecSetup
|
|
181
192
|
end
|
182
193
|
end
|
183
194
|
|
195
|
+
private
|
196
|
+
|
197
|
+
def monkey_patch_summary_notification!
|
198
|
+
require "rspec/core/notifications"
|
199
|
+
klass = RSpec::Core::Notifications::SummaryNotification
|
200
|
+
if !klass.instance_variable_get("@_brut_has_monkeypatched")
|
201
|
+
klass.class_eval do
|
202
|
+
# Slightly reformatted, but the only line that's different
|
203
|
+
# is the one that said to use './rspec'. Now it says 'bin/test run'
|
204
|
+
def colorized_rerun_commands(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
205
|
+
"\nFailed examples:\n\n" +
|
206
|
+
failed_examples.map do |example|
|
207
|
+
rerun_argument = rerun_argument_for(example)
|
208
|
+
colorizer.wrap(
|
209
|
+
"bin/test run #{rerun_argument}", # <--- this is the only difference
|
210
|
+
RSpec.configuration.failure_color
|
211
|
+
) +
|
212
|
+
" " +
|
213
|
+
colorizer.wrap(
|
214
|
+
"# #{example.full_description}",
|
215
|
+
RSpec.configuration.detail_color
|
216
|
+
)
|
217
|
+
end.join("\n")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
klass.instance_variable_set("@_brut_has_monkeypatched",true)
|
221
|
+
end
|
222
|
+
end
|
184
223
|
end
|
224
|
+
|
data/lib/brut/version.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Extensions
|
3
3
|
# Instruments all SQL executions.
|
4
|
+
#
|
5
|
+
# *NOTE* this will include the actual SQL query text in the
|
6
|
+
# span, so any literal values in the query will be in the observability
|
7
|
+
# platforms.
|
4
8
|
module BrutInstrumentation
|
5
9
|
# @!visibility private
|
6
10
|
def log_connection_yield(sql,conn,args=nil)
|