brut 0.4.0 → 0.8.0
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 +4 -0
- data/CHANGELOG.md +36 -1
- data/Dockerfile.dx +19 -0
- data/Gemfile.lock +1 -1
- data/README.md +19 -0
- data/assets/MetroIcon.graffle +0 -0
- data/assets/YouTubeThumb.pxd +0 -0
- data/bin/build +86 -0
- data/bin/ci +36 -0
- data/bin/docs +39 -9
- data/bin/publish +61 -0
- data/bin/setup +6 -0
- data/brut-css/bin/build +19 -0
- data/brut-css/bin/ci +19 -0
- data/brut-css/bin/docs +19 -0
- data/brut-css/bin/publish +21 -0
- data/brut-css/bin/setup +1 -0
- data/brut-css/package-lock.json +2 -2
- data/brut-css/package.json +1 -1
- data/brut-css/src/css/flex.css +1 -1
- data/brut-css/src/docs/includes/body-and-header.html.ejs +1 -1
- data/brut-js/bin/build +15 -6
- data/brut-js/bin/docs +25 -0
- data/brut-js/bin/publish +21 -0
- data/brut-js/bin/setup +1 -0
- data/brut-js/dx +1 -0
- data/brut-js/package-lock.json +2 -2
- data/brut-js/package.json +1 -1
- data/brut-js/specs/AjaxSubmit.spec.js +100 -7
- data/brut-js/src/AjaxSubmit.js +76 -40
- data/brut.gemspec +2 -2
- data/brutrb.com/adrs.md +1 -0
- data/brutrb.com/bin/setup +1 -0
- data/brutrb.com/getting-started.md +3 -0
- data/brutrb.com/overview.md +6 -0
- data/brutrb.com/tutorial.md +7 -3
- data/docs/404.html +2 -2
- data/docs/adrs.html +5 -5
- data/docs/ai.html +3 -3
- 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/DbModel.html +2 -2
- 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 +86 -2
- data/docs/api/Brut/FrontEnd/Component.html +78 -9
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Input.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
- data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/TimeTag.html +3 -3
- data/docs/api/Brut/FrontEnd/Components/Traceparent.html +3 -3
- 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 +1 -1
- data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/Input.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
- data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +1 -1
- 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 +3 -3
- 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 +31 -23
- data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +3 -3
- 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 +13 -11
- 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/ModuleName.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 +1 -1
- data/docs/api/file.README.html +1 -1
- data/docs/api/index.html +1 -1
- data/docs/api/method_list.html +92 -76
- data/docs/api/top-level-namespace.html +1 -1
- data/docs/assets/{adrs.md.JRxZ5uYE.js → adrs.md.BxjHi9-8.js} +1 -1
- data/docs/assets/adrs.md.BxjHi9-8.lean.js +1 -0
- data/docs/assets/{app.AkS4fHzI.js → app.DyQLb4Ot.js} +1 -1
- data/docs/assets/chunks/@localSearchIndexroot.CmtZyrFA.js +1 -0
- data/docs/assets/chunks/{VPLocalSearchBox.By6un1FD.js → VPLocalSearchBox.T1iA-eJx.js} +1 -1
- data/docs/assets/chunks/{theme.DwiUPdci.js → theme.ChwsbWjK.js} +2 -2
- data/docs/assets/{components.md.BfeWD9sX.js → components.md.DHh-NwKs.js} +3 -3
- data/docs/assets/{configuration.md.DoSBNc0H.js → configuration.md.D8Wz3oJU.js} +1 -1
- data/docs/assets/{forms.md.DFveP5g_.js → forms.md.BRE85eju.js} +1 -1
- data/docs/assets/{getting-started.md.DZWjCVC0.js → getting-started.md.2ioiTe-B.js} +6 -3
- data/docs/assets/{getting-started.md.DZWjCVC0.lean.js → getting-started.md.2ioiTe-B.lean.js} +1 -1
- data/docs/assets/overview.md.DlKiRRG_.js +1 -0
- data/docs/assets/overview.md.DlKiRRG_.lean.js +1 -0
- data/docs/assets/tutorial.md.BIb7XT6j.js +1 -0
- data/docs/assets/tutorial.md.BIb7XT6j.lean.js +1 -0
- data/docs/assets.html +3 -3
- data/docs/brut-css/brut.max.css +1 -1
- data/docs/brut-css/classes/appearances.html +1 -1
- data/docs/brut-css/classes/background-colors.html +1 -1
- data/docs/brut-css/classes/border-colors.html +1 -1
- data/docs/brut-css/classes/borders.html +1 -1
- data/docs/brut-css/classes/dimensions.html +1 -1
- data/docs/brut-css/classes/flex.html +3 -3
- data/docs/brut-css/classes/foreground-colors.html +1 -1
- data/docs/brut-css/classes/junk-drawer.html +1 -1
- data/docs/brut-css/classes/layout.html +1 -1
- data/docs/brut-css/classes/lists.html +1 -1
- data/docs/brut-css/classes/positioning.html +1 -1
- data/docs/brut-css/classes/spacings.html +1 -1
- data/docs/brut-css/classes/typography.html +1 -1
- data/docs/brut-css/customization/advanced-configuration.html +1 -1
- data/docs/brut-css/customization/breakpoints.html +1 -1
- data/docs/brut-css/customization/design-system.html +1 -1
- data/docs/brut-css/customization/pseudo-classes.html +1 -1
- data/docs/brut-css/getting-started/core-concepts.html +1 -1
- data/docs/brut-css/getting-started/installation.html +1 -1
- data/docs/brut-css/getting-started/overview.html +1 -1
- data/docs/brut-css/getting-started/simple-example.html +1 -1
- data/docs/brut-css/index.html +1 -1
- data/docs/brut-css/properties/colors.html +1 -1
- data/docs/brut-css/properties/spacings.html +1 -1
- data/docs/brut-css/properties/typography.html +1 -1
- data/docs/brut-js/api/AjaxSubmit.html +56 -7
- data/docs/brut-js/api/AjaxSubmit.js.html +77 -41
- 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 +3 -3
- data/docs/business-logic.html +3 -3
- data/docs/cli.html +3 -3
- data/docs/components.html +7 -7
- data/docs/configuration.html +5 -5
- data/docs/css.html +3 -3
- data/docs/custom-element-tests.html +3 -3
- data/docs/database-access.html +3 -3
- data/docs/database-schema.html +3 -3
- data/docs/deployment.html +3 -3
- data/docs/dev-environment.html +3 -3
- data/docs/dir-structure.html +3 -3
- data/docs/doc-conventions.html +3 -3
- data/docs/end-to-end-tests.html +3 -3
- data/docs/features.html +3 -3
- data/docs/flash-and-session.html +3 -3
- data/docs/form-constraints.html +3 -3
- data/docs/forms.html +5 -5
- data/docs/getting-started.html +9 -6
- data/docs/handlers.html +3 -3
- data/docs/hashmap.json +1 -1
- data/docs/hooks.html +3 -3
- data/docs/i18n.html +3 -3
- data/docs/index.html +3 -3
- data/docs/instrumentation.html +3 -3
- data/docs/javascript.html +3 -3
- data/docs/jobs.html +3 -3
- data/docs/keyword-injection.html +3 -3
- data/docs/layouts.html +3 -3
- data/docs/lsp.html +3 -3
- data/docs/markdown-examples.html +3 -3
- data/docs/middleware.html +3 -3
- data/docs/overview.html +5 -5
- data/docs/pages.html +3 -3
- data/docs/recipes/alternate-layouts.html +3 -3
- data/docs/recipes/authentication.html +3 -3
- data/docs/recipes/blank-layouts.html +3 -3
- data/docs/recipes/custom-flash.html +3 -3
- data/docs/recipes/indexed-forms.html +3 -3
- data/docs/recipes/migrations.html +3 -3
- data/docs/recipes/text-field-component.html +3 -3
- data/docs/roadmap.html +3 -3
- data/docs/routes.html +3 -3
- data/docs/security.html +3 -3
- data/docs/seed-data.html +3 -3
- data/docs/space-time-continuum.html +3 -3
- data/docs/tutorial.html +5 -5
- data/docs/unit-tests.html +3 -3
- data/docs/why.html +3 -3
- data/lib/brut/cli/apps/scaffold.rb +1 -1
- data/lib/brut/framework/mcp.rb +1 -1
- data/lib/brut/front_end/component.rb +19 -0
- data/lib/brut/front_end/components/form_tag.rb +2 -2
- data/lib/brut/front_end/page.rb +11 -7
- data/lib/brut/sinatra_helpers.rb +1 -0
- data/lib/brut/version.rb +1 -1
- data/mkbrut/.gitignore +16 -0
- data/mkbrut/CODE_OF_CONDUCT.txt +100 -0
- data/mkbrut/Gemfile +3 -0
- data/mkbrut/Gemfile.lock +19 -0
- data/mkbrut/LICENSE.txt +370 -0
- data/mkbrut/README.md +145 -0
- data/mkbrut/Rakefile +2 -0
- data/mkbrut/bin/build +36 -0
- data/mkbrut/bin/ci +19 -0
- data/mkbrut/bin/docs +19 -0
- data/mkbrut/bin/publish +129 -0
- data/mkbrut/bin/rake +16 -0
- data/mkbrut/bin/setup +30 -0
- data/mkbrut/brut-welcome.png +0 -0
- data/mkbrut/deploy/.dockerignore +2 -0
- data/mkbrut/deploy/Dockerfile +25 -0
- data/mkbrut/exe/mkbrut +5 -0
- data/mkbrut/lib/mkbrut/app.rb +79 -0
- data/mkbrut/lib/mkbrut/app_id.rb +8 -0
- data/mkbrut/lib/mkbrut/app_name.rb +29 -0
- data/mkbrut/lib/mkbrut/app_options.rb +36 -0
- data/mkbrut/lib/mkbrut/base.rb +57 -0
- data/mkbrut/lib/mkbrut/cli.rb +107 -0
- data/mkbrut/lib/mkbrut/erb_binding_delegate.rb +20 -0
- data/mkbrut/lib/mkbrut/internet_identifier.rb +32 -0
- data/mkbrut/lib/mkbrut/invalid_identifier.rb +4 -0
- data/mkbrut/lib/mkbrut/ops/add_css_import.rb +42 -0
- data/mkbrut/lib/mkbrut/ops/add_i18n_message.rb +74 -0
- data/mkbrut/lib/mkbrut/ops/add_method.rb +48 -0
- data/mkbrut/lib/mkbrut/ops/append_to_file.rb +20 -0
- data/mkbrut/lib/mkbrut/ops/base_op.rb +21 -0
- data/mkbrut/lib/mkbrut/ops/copy_file.rb +12 -0
- data/mkbrut/lib/mkbrut/ops/insert_code_in_method.rb +58 -0
- data/mkbrut/lib/mkbrut/ops/insert_route.rb +52 -0
- data/mkbrut/lib/mkbrut/ops/mkdir.rb +13 -0
- data/mkbrut/lib/mkbrut/ops/prism_parsing_op.rb +70 -0
- data/mkbrut/lib/mkbrut/ops/render_template.rb +26 -0
- data/mkbrut/lib/mkbrut/ops/skip_file.rb +10 -0
- data/mkbrut/lib/mkbrut/ops.rb +16 -0
- data/mkbrut/lib/mkbrut/organization.rb +5 -0
- data/mkbrut/lib/mkbrut/prefix.rb +26 -0
- data/mkbrut/lib/mkbrut/prefixed_io.rb +16 -0
- data/mkbrut/lib/mkbrut/segments/bare_bones.rb +185 -0
- data/mkbrut/lib/mkbrut/segments/demo.rb +121 -0
- data/mkbrut/lib/mkbrut/segments/heroku.rb +30 -0
- data/mkbrut/lib/mkbrut/segments/sidekiq.rb +3 -0
- data/mkbrut/lib/mkbrut/segments.rb +8 -0
- data/mkbrut/lib/mkbrut/version.rb +3 -0
- data/mkbrut/lib/mkbrut/versions.rb +13 -0
- data/mkbrut/lib/mkbrut.rb +18 -0
- data/mkbrut/mkbrut.gemspec +32 -0
- data/mkbrut/templates/Base/.dockerignore +25 -0
- data/mkbrut/templates/Base/.env.development.erb +60 -0
- data/mkbrut/templates/Base/.env.test.erb +8 -0
- data/mkbrut/templates/Base/.gitignore +31 -0
- data/mkbrut/templates/Base/.projections.json +59 -0
- data/mkbrut/templates/Base/Dockerfile.dx +205 -0
- data/mkbrut/templates/Base/Gemfile.erb +53 -0
- data/mkbrut/templates/Base/Procfile.development +5 -0
- data/mkbrut/templates/Base/Procfile.test +1 -0
- data/mkbrut/templates/Base/README.md +4 -0
- data/mkbrut/templates/Base/README.md.erb +40 -0
- data/mkbrut/templates/Base/app/bootstrap.rb +61 -0
- data/mkbrut/templates/Base/app/config/i18n/en/1_defaults.rb +128 -0
- data/mkbrut/templates/Base/app/config/i18n/en/2_app.rb +24 -0
- data/mkbrut/templates/Base/app/public/static/manifest.json.erb +33 -0
- data/mkbrut/templates/Base/app/src/app.rb.erb +37 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/app_data_model.rb +5 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/db.rb +19 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb +6 -0
- data/mkbrut/templates/Base/app/src/back_end/data_models/seed/seed_data.rb +9 -0
- data/mkbrut/templates/Base/app/src/front_end/components/app_component.rb +8 -0
- data/mkbrut/templates/Base/app/src/front_end/components/custom_element_registration.rb.erb +7 -0
- data/mkbrut/templates/Base/app/src/front_end/css/index.css +2 -0
- data/mkbrut/templates/Base/app/src/front_end/css/svgs.css +12 -0
- data/mkbrut/templates/Base/app/src/front_end/forms/app_form.rb +4 -0
- data/mkbrut/templates/Base/app/src/front_end/handlers/app_handler.rb +4 -0
- data/mkbrut/templates/Base/app/src/front_end/images/LogoPylon.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/LogoTransit.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-120x120.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-152x152.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-167x167.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-180x180.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/favicon.ico +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/icon.png +0 -0
- data/mkbrut/templates/Base/app/src/front_end/images/mkicons.sh +6 -0
- data/mkbrut/templates/Base/app/src/front_end/js/index.js +6 -0
- data/mkbrut/templates/Base/app/src/front_end/layouts/default_layout.rb.erb +73 -0
- data/mkbrut/templates/Base/app/src/front_end/pages/app_page.rb +11 -0
- data/mkbrut/templates/Base/app/src/front_end/pages/home_page.rb +62 -0
- data/mkbrut/templates/Base/app/src/front_end/support/app_session.rb +6 -0
- data/mkbrut/templates/Base/app/src/front_end/svgs/README.md +5 -0
- data/mkbrut/templates/Base/app/src/front_end/svgs/comment-button.svg +59 -0
- data/mkbrut/templates/Base/bin/README.md.erb +5 -0
- data/mkbrut/templates/Base/bin/build-assets +7 -0
- data/mkbrut/templates/Base/bin/ci +39 -0
- data/mkbrut/templates/Base/bin/console +31 -0
- data/mkbrut/templates/Base/bin/db +9 -0
- data/mkbrut/templates/Base/bin/dbconsole +51 -0
- data/mkbrut/templates/Base/bin/dev +25 -0
- data/mkbrut/templates/Base/bin/release +26 -0
- data/mkbrut/templates/Base/bin/run +86 -0
- data/mkbrut/templates/Base/bin/scaffold +9 -0
- data/mkbrut/templates/Base/bin/setup +256 -0
- data/mkbrut/templates/Base/bin/startup-message +65 -0
- data/mkbrut/templates/Base/bin/test +9 -0
- data/mkbrut/templates/Base/bin/test-server +29 -0
- data/mkbrut/templates/Base/bin/watch-and-build-assets +37 -0
- data/mkbrut/templates/Base/config.ru +16 -0
- data/mkbrut/templates/Base/docker-compose.dx.yml +92 -0
- data/mkbrut/templates/Base/dx/README.md +28 -0
- data/mkbrut/templates/Base/dx/bash_customizations +12 -0
- data/mkbrut/templates/Base/dx/bash_customizations.local +8 -0
- data/mkbrut/templates/Base/dx/build +107 -0
- data/mkbrut/templates/Base/dx/docker-compose.env.erb +25 -0
- data/mkbrut/templates/Base/dx/dx.sh.lib +137 -0
- data/mkbrut/templates/Base/dx/exec +68 -0
- data/mkbrut/templates/Base/dx/prune +19 -0
- data/mkbrut/templates/Base/dx/show-help-in-app-container-then-wait.sh +38 -0
- data/mkbrut/templates/Base/dx/start +30 -0
- data/mkbrut/templates/Base/dx/stop +23 -0
- data/mkbrut/templates/Base/package.json.erb +37 -0
- data/mkbrut/templates/Base/puma.config.rb +53 -0
- data/mkbrut/templates/Base/specs/e2e/home_page.spec.rb.erb +23 -0
- data/mkbrut/templates/Base/specs/front_end/js/SpecHelper.js +24 -0
- data/mkbrut/templates/Base/specs/front_end/pages/home_page.spec.rb +22 -0
- data/mkbrut/templates/Base/specs/lint_factories.spec.rb +7 -0
- data/mkbrut/templates/Base/specs/spec_helper.rb +78 -0
- data/mkbrut/templates/Base/specs/support.rb +2 -0
- data/mkbrut/templates/segments/BareBones/app/src/front_end/handlers/trigger_exception_handler.rb +24 -0
- data/mkbrut/templates/segments/BareBones/app/src/front_end/js/Example.js.erb +49 -0
- data/mkbrut/templates/segments/BareBones/specs/front_end/handlers/trigger_exception_handler.spec.rb +41 -0
- data/mkbrut/templates/segments/BareBones/specs/front_end/js/Example.spec.js.erb +38 -0
- data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/db/guestbook_message.rb +3 -0
- data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/migrations/20250628194124_guestbook.rb +14 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/components/flash_component.rb +36 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/css/constraint-violations.css +18 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/css/fonts.css +19 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/fonts/monaspace-xenon.ttf +0 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/forms/guestbook_message_form.rb +4 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/handlers/guestbook_message_handler.rb +64 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page/message_component.rb +41 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page.rb +43 -0
- data/mkbrut/templates/segments/Demo/app/src/front_end/pages/new_guestbook_message_page.rb +64 -0
- data/mkbrut/templates/segments/Demo/specs/back_end/data_models/db/guestbook_message.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/e2e/guest_message.spec.rb +54 -0
- data/mkbrut/templates/segments/Demo/specs/factories/db/guestbook_message.factory.rb +7 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/components/flash_component.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/handlers/guestbook_message_handler.spec.rb +122 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb +5 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb +52 -0
- data/mkbrut/templates/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb +5 -0
- data/mkbrut/templates/segments/Heroku/bin/deploy +11 -0
- data/mkbrut/templates/segments/Heroku/deploy/Dockerfile +125 -0
- data/mkbrut/templates/segments/Heroku/deploy/docker-entrypoint +15 -0
- data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +26 -0
- metadata +188 -24
- data/brut-js/CHANGELOG.md +0 -5
- data/docs/assets/adrs.md.JRxZ5uYE.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.C9FqcQxD.js +0 -1
- data/docs/assets/overview.md.iMnwLO4x.js +0 -1
- data/docs/assets/overview.md.iMnwLO4x.lean.js +0 -1
- data/docs/assets/tutorial.md.BYXj4cOu.js +0 -1
- data/docs/assets/tutorial.md.BYXj4cOu.lean.js +0 -1
- /data/docs/assets/{components.md.BfeWD9sX.lean.js → components.md.DHh-NwKs.lean.js} +0 -0
- /data/docs/assets/{configuration.md.DoSBNc0H.lean.js → configuration.md.D8Wz3oJU.lean.js} +0 -0
- /data/docs/assets/{forms.md.DFveP5g_.lean.js → forms.md.BRE85eju.lean.js} +0 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
class MKBrut::Ops::AddCSSImport < MKBrut::Ops::BaseOp
|
2
|
+
def initialize(project_root:, import:)
|
3
|
+
@file = project_root / "app" / "src" / "front_end" / "css" / "index.css"
|
4
|
+
@import = import
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
if dry_run?
|
9
|
+
puts "Would add import '#{@import}'; to '#{@file}'"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
contents = File.read(@file).split(/\n/)
|
14
|
+
|
15
|
+
inserted_import = false
|
16
|
+
previous_line_was_import = false
|
17
|
+
new_contents = []
|
18
|
+
contents.each do |line|
|
19
|
+
if line =~ /^\s*@import\s+["']/
|
20
|
+
previous_line_was_import = true
|
21
|
+
new_contents << line
|
22
|
+
else
|
23
|
+
if previous_line_was_import && !inserted_import
|
24
|
+
new_contents << "@import '#{@import}';"
|
25
|
+
inserted_import = true
|
26
|
+
end
|
27
|
+
previous_line_was_import = false
|
28
|
+
new_contents << line
|
29
|
+
end
|
30
|
+
end
|
31
|
+
if !inserted_import && previous_line_was_import
|
32
|
+
new_contents << "@import \"#{@import}\";"
|
33
|
+
inserted_import = true
|
34
|
+
end
|
35
|
+
if !inserted_import
|
36
|
+
raise "Did not find any other @imports in '#{@file}' - was expecting at least one to exist"
|
37
|
+
end
|
38
|
+
File.open(@file, "w") do |file|
|
39
|
+
file.puts new_contents.join("\n")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class MKBrut::Ops::AddI18nMessage < MKBrut::Ops::PrismParsingOp
|
2
|
+
def initialize(project_root:, hash:)
|
3
|
+
@file = project_root / "app" / "config" / "i18n" / "en" / "2_app.rb"
|
4
|
+
@hash = hash
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
if dry_run?
|
9
|
+
puts "Would merge:\n#{@hash}\ninto #{@file}"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
parse_file!
|
13
|
+
|
14
|
+
hash_node = @tree.value.statements.body.detect { it.is_a?(Prism::HashNode) }
|
15
|
+
if !hash_node
|
16
|
+
raise "'#{@file}' did not have a hash node, so we cannot insert a new i18n message"
|
17
|
+
end
|
18
|
+
|
19
|
+
# eval the source to get a real hash of the contents
|
20
|
+
start_offset = hash_node.location.start_offset
|
21
|
+
end_offset = hash_node.location.end_offset
|
22
|
+
original_code = @source[start_offset...end_offset]
|
23
|
+
original_hash = eval(original_code, binding, @file.to_s)
|
24
|
+
|
25
|
+
new_hash = deep_merge(original_hash,@hash)
|
26
|
+
|
27
|
+
formatted_hash = format_hash(new_hash)
|
28
|
+
|
29
|
+
new_source = @source.dup
|
30
|
+
new_source[start_offset...end_offset] = formatted_hash
|
31
|
+
|
32
|
+
File.open(@file, "w") do |file|
|
33
|
+
file.puts new_source
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def deep_merge(a, b)
|
40
|
+
a.merge(b) do |_key, old_val, new_val|
|
41
|
+
if old_val.is_a?(Hash) && new_val.is_a?(Hash)
|
42
|
+
deep_merge(old_val, new_val)
|
43
|
+
else
|
44
|
+
new_val
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# NASTY, but not currently sure a better what do it.
|
50
|
+
def format_hash(hash, trailing_comma = "", indent = "")
|
51
|
+
string = "{\n"
|
52
|
+
hash.each do |key, value|
|
53
|
+
key_code = if key.kind_of?(Symbol)
|
54
|
+
if key =~ /^[A-Za-z_][A-Za-z0-9_]*$/
|
55
|
+
"#{key}:"
|
56
|
+
else
|
57
|
+
"'#{key}':"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
"#{key} =>"
|
61
|
+
end
|
62
|
+
value_code = case value
|
63
|
+
when String
|
64
|
+
then "\"#{value}\",\n"
|
65
|
+
when Hash
|
66
|
+
format_hash(value, ",", indent + " ")
|
67
|
+
end
|
68
|
+
string << "#{indent} #{key_code} #{value_code}"
|
69
|
+
end
|
70
|
+
string << "#{indent}}#{trailing_comma}\n"
|
71
|
+
string
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class MKBrut::Ops::AddMethod < MKBrut::Ops::PrismParsingOp
|
2
|
+
def initialize(file:, class_name:, code:)
|
3
|
+
@file = file
|
4
|
+
@class_name = class_name
|
5
|
+
@code = code.gsub(/^\n\s*$/,"").gsub(/\n$/,"")
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
if dry_run?
|
10
|
+
puts "Would add method:\n#{@code}\nto #{@class_name} in '#{@file}'"
|
11
|
+
return
|
12
|
+
end
|
13
|
+
class_node = find_class(class_name: @class_name, assumed_body: false)
|
14
|
+
|
15
|
+
insert_offset = nil
|
16
|
+
class_body_nodes = case class_node.body
|
17
|
+
when Prism::StatementsNode
|
18
|
+
class_node.body.body
|
19
|
+
when nil
|
20
|
+
[]
|
21
|
+
else
|
22
|
+
[class_node.body]
|
23
|
+
end
|
24
|
+
|
25
|
+
class_body_nodes.each do |node|
|
26
|
+
if node.is_a?(Prism::CallNode) && node.name == "private"
|
27
|
+
insert_offset = node.location.start_offset
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if insert_offset.nil?
|
33
|
+
# Use the final end of the class
|
34
|
+
insert_offset = class_node.location.end_offset - 3
|
35
|
+
end
|
36
|
+
|
37
|
+
class_start_line = class_node.location.start_line
|
38
|
+
class_indent = @source.lines[class_start_line - 1][/^\s*/] || ""
|
39
|
+
method_indent = class_indent + " "
|
40
|
+
|
41
|
+
indented_method_code = @code.lines.map { |line| method_indent + line }.join
|
42
|
+
insert_text = "\n" + indented_method_code + "\n"
|
43
|
+
|
44
|
+
updated_source = @source.dup.insert(insert_offset, insert_text)
|
45
|
+
File.write(@file, updated_source)
|
46
|
+
updated_source
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class MKBrut::Ops::AppendToFile < MKBrut::Ops::BaseOp
|
2
|
+
def initialize(file:, content:)
|
3
|
+
@file = file
|
4
|
+
@content = content
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
if dry_run?
|
9
|
+
puts "Would append to #{@file}:\n#{@content}\n"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
contents = File.read(@file)
|
14
|
+
File.open(@file, "w") do |file|
|
15
|
+
file.puts contents
|
16
|
+
file.puts "\n"
|
17
|
+
file.puts @content
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class MKBrut::Ops::BaseOp
|
2
|
+
@dry_run = false
|
3
|
+
|
4
|
+
def self.dry_run=(value)
|
5
|
+
MKBrut::Ops::BaseOp.instance_variable_set(:@dry_run, value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.dry_run? = !!MKBrut::Ops::BaseOp.instance_variable_get(:@dry_run)
|
9
|
+
def dry_run? = self.class.dry_run?
|
10
|
+
|
11
|
+
def call = raise "Subclass must implement"
|
12
|
+
|
13
|
+
def self.fileutils_args
|
14
|
+
if self.dry_run?
|
15
|
+
{ noop: true, verbose: true }
|
16
|
+
else
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def fileutils_args = self.class.fileutils_args
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
class MKBrut::Ops::CopyFile < MKBrut::Ops::BaseOp
|
4
|
+
def initialize(source, destination_root:)
|
5
|
+
@source = source
|
6
|
+
@destination_root = destination_root
|
7
|
+
end
|
8
|
+
def call
|
9
|
+
FileUtils.cp(@source, @destination_root / @source.basename, **fileutils_args)
|
10
|
+
end
|
11
|
+
def to_s = "Copy '#{@source}' to '#{@destination_root}'"
|
12
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class MKBrut::Ops::InsertCodeInMethod < MKBrut::Ops::PrismParsingOp
|
2
|
+
def initialize(file:, class_name:, method_name:, code:, where: :end)
|
3
|
+
@file = file
|
4
|
+
@class_name = class_name
|
5
|
+
@method_name = method_name.to_sym
|
6
|
+
@code = code
|
7
|
+
@where = where
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
method_node = find_method(class_name: @class_name, method_name: @method_name)
|
12
|
+
|
13
|
+
insertion_point = if @where == :start
|
14
|
+
insertion_point_for_code_at_start_of_method(method_node: method_node)
|
15
|
+
else
|
16
|
+
insertion_point_for_code_at_end_of_method(method_node: method_node)
|
17
|
+
end
|
18
|
+
indented_code = indent_code_for_method(method_node: method_node)
|
19
|
+
|
20
|
+
new_source = @source.dup.insert(insertion_point, indented_code)
|
21
|
+
File.write(@file, new_source)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def indent_code_for_method(method_node:)
|
27
|
+
|
28
|
+
method_start_line = method_node.location.start_line
|
29
|
+
spaces_before_def = @source.lines[method_start_line - 1][/^\s*/] || ""
|
30
|
+
spaces_for_code_in_method = spaces_before_def + " "
|
31
|
+
|
32
|
+
post_indent = if @where == :start
|
33
|
+
"\n#{spaces_before_def}"
|
34
|
+
else
|
35
|
+
""
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
"\n" +
|
40
|
+
@code.split(/\n/).map { |line|
|
41
|
+
spaces_for_code_in_method + line
|
42
|
+
}.join("\n") + post_indent
|
43
|
+
end
|
44
|
+
|
45
|
+
def insertion_point_for_code_at_end_of_method(method_node:)
|
46
|
+
line_number_of_method_end = method_node.location.end_line - 1
|
47
|
+
length_of_method_end = @source.lines[line_number_of_method_end].length
|
48
|
+
|
49
|
+
method_node.location.end_offset - length_of_method_end
|
50
|
+
end
|
51
|
+
|
52
|
+
def insertion_point_for_code_at_start_of_method(method_node:)
|
53
|
+
line_number_of_method_start = method_node.location.start_line - 1
|
54
|
+
length_of_method_start = @source.lines[line_number_of_method_start].length
|
55
|
+
|
56
|
+
method_node.location.start_offset + length_of_method_start
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class MKBrut::Ops::InsertRoute < MKBrut::Ops::PrismParsingOp
|
2
|
+
def initialize(project_root:, code:)
|
3
|
+
@file = project_root / "app" / "src" / "app.rb"
|
4
|
+
@code = code
|
5
|
+
end
|
6
|
+
|
7
|
+
def call
|
8
|
+
if dry_run?
|
9
|
+
puts "Would insert route:\n#{@code}\ninto #{@file}"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
app_class_node = find_class(class_name: "App")
|
13
|
+
|
14
|
+
routes_block = find_routes_block(app_class_node)
|
15
|
+
|
16
|
+
if !routes_block
|
17
|
+
raise "'App' in '#{@file}' did not have a routes block, so we cannot insert a new route"
|
18
|
+
end
|
19
|
+
|
20
|
+
end_offset = routes_block.block.location.end_offset
|
21
|
+
indented_line = " #{@code}\n "
|
22
|
+
new_source = @source.dup.insert(end_offset - 3, indented_line)
|
23
|
+
|
24
|
+
File.open(@file, "w") do |file|
|
25
|
+
file.puts new_source
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_routes_block(class_node)
|
30
|
+
statements = case class_node.body
|
31
|
+
when Prism::StatementsNode
|
32
|
+
class_node.body.body
|
33
|
+
when nil
|
34
|
+
[]
|
35
|
+
else
|
36
|
+
[class_node.body]
|
37
|
+
end
|
38
|
+
|
39
|
+
statements.detect do |statement|
|
40
|
+
if statement.is_a?(Prism::CallNode)
|
41
|
+
if statement.name == :routes
|
42
|
+
statement.block
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
else
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "prism"
|
2
|
+
class MKBrut::Ops::PrismParsingOp < MKBrut::Ops::BaseOp
|
3
|
+
def initialize(file:)
|
4
|
+
@file = file
|
5
|
+
end
|
6
|
+
|
7
|
+
class ClassNotInSource < StandardError
|
8
|
+
def initialize(file:, class_name:)
|
9
|
+
super("Could not find the class '#{class_name}' inside '#{file}'")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class MethodNotInClass < StandardError
|
14
|
+
def initialize(file:, class_name:, method_name:)
|
15
|
+
super("Could not find the method '#{method_name}' in class '#{class_name}' inside '#{file}'")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class SourceNotParseable < StandardError
|
20
|
+
def initialize(tree_errors:, file:)
|
21
|
+
error_message = tree_errors.map { |error|
|
22
|
+
"#{error.message} (line #{error.location.start_line}, column #{error.location.start_column})"
|
23
|
+
}.join(", ")
|
24
|
+
super("Failed to parse file '#{file}': #{error_message}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def parse_file!
|
31
|
+
source = File.read(@file)
|
32
|
+
tree = Prism.parse(source)
|
33
|
+
|
34
|
+
if !tree.success?
|
35
|
+
raise SourceNotParseable.new(tree_errors: tree.errors, file: @file)
|
36
|
+
end
|
37
|
+
@tree = tree
|
38
|
+
@source = source
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_class(class_name:, assumed_body: true)
|
42
|
+
if !@tree
|
43
|
+
parse_file!
|
44
|
+
end
|
45
|
+
class_node = @tree.value.statements.body.detect { |node|
|
46
|
+
node.is_a?(Prism::ClassNode) && node.constant_path.slice == class_name
|
47
|
+
}
|
48
|
+
|
49
|
+
if !class_node
|
50
|
+
raise ClassNotInSource.new(file: @file, class_name: class_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
if !class_node.body.respond_to?(:body) && assumed_body
|
54
|
+
raise "The class '#{class_name}' in '#{file}' does not have any methods"
|
55
|
+
end
|
56
|
+
class_node
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_method(class_name:, method_name:)
|
60
|
+
class_node = find_class(class_name:)
|
61
|
+
method_node = class_node.body.body.detect { |node|
|
62
|
+
node.is_a?(Prism::DefNode) && node.name == @method_name
|
63
|
+
}
|
64
|
+
|
65
|
+
if !method_node
|
66
|
+
raise MethodNotInClass.new(file: @file, class_name: class_name, method_name: @method_name)
|
67
|
+
end
|
68
|
+
method_node
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "erb"
|
2
|
+
class MKBrut::Ops::RenderTemplate < MKBrut::Ops::BaseOp
|
3
|
+
|
4
|
+
def initialize(source, destination_root:, erb_binding:)
|
5
|
+
@erb = source
|
6
|
+
@destination_file = destination_root / @erb.basename.sub_ext("")
|
7
|
+
@erb_binding = erb_binding
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
if dry_run?
|
12
|
+
puts "Render '#{@destination_file}'"
|
13
|
+
return
|
14
|
+
end
|
15
|
+
template = File.read(@erb)
|
16
|
+
File.open(@destination_file, "w") do |file|
|
17
|
+
file.puts ERB.new(
|
18
|
+
template,
|
19
|
+
trim_mode: "-"
|
20
|
+
).result(
|
21
|
+
@erb_binding.instance_eval { binding }
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
def to_s = "ERB '#{@erb}' to '#{@destination_file}'"
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MKBrut
|
2
|
+
module Ops
|
3
|
+
autoload :BaseOp, "mkbrut/ops/base_op"
|
4
|
+
autoload :Mkdir, "mkbrut/ops/mkdir"
|
5
|
+
autoload :CopyFile, "mkbrut/ops/copy_file"
|
6
|
+
autoload :RenderTemplate, "mkbrut/ops/render_template"
|
7
|
+
autoload :SkipFile, "mkbrut/ops/skip_file"
|
8
|
+
autoload :InsertRoute, "mkbrut/ops/insert_route"
|
9
|
+
autoload :InsertCodeInMethod, "mkbrut/ops/insert_code_in_method"
|
10
|
+
autoload :AppendToFile, "mkbrut/ops/append_to_file"
|
11
|
+
autoload :PrismParsingOp, "mkbrut/ops/prism_parsing_op"
|
12
|
+
autoload :AddI18nMessage, "mkbrut/ops/add_i18n_message"
|
13
|
+
autoload :AddCSSImport, "mkbrut/ops/add_css_import"
|
14
|
+
autoload :AddMethod, "mkbrut/ops/add_method"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MKBrut
|
2
|
+
class Prefix
|
3
|
+
def self.from_app_id(app_id)
|
4
|
+
app_id = app_id.to_s
|
5
|
+
prefix = if app_id =~ /^[^-]+[a-z]-[a-z]/
|
6
|
+
app_id.split("-")[0..1].map { it[0] }.join("")
|
7
|
+
else
|
8
|
+
app_id[0..1]
|
9
|
+
end
|
10
|
+
self.new(prefix)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(identifier)
|
14
|
+
@identifier = identifier.to_s
|
15
|
+
if @identifier.length != 2
|
16
|
+
raise InvalidIdentifier, "prefix '#{@identifier}' must be 2 characters"
|
17
|
+
end
|
18
|
+
if @identifier !~ /^[a-z]+$/
|
19
|
+
raise InvalidIdentifier, "prefix must be only lower case ASCII letters"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s = @identifier
|
24
|
+
alias to_str to_s
|
25
|
+
end
|
26
|
+
end
|