brut 0.5.0 → 0.9.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.
Files changed (564) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +13 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Dockerfile.dx +27 -1
  5. data/Gemfile.lock +33 -1
  6. data/README.md +19 -0
  7. data/assets/YouTubeThumb.pxd +0 -0
  8. data/bin/build +86 -0
  9. data/bin/ci +40 -0
  10. data/bin/docs +40 -10
  11. data/bin/generate-and-run-rubocop +52 -0
  12. data/bin/publish +61 -0
  13. data/bin/rubocop +27 -0
  14. data/bin/setup +52 -0
  15. data/bin/test +18 -0
  16. data/brut-css/bin/build +19 -0
  17. data/brut-css/bin/ci +19 -0
  18. data/brut-css/bin/docs +19 -0
  19. data/brut-css/bin/publish +21 -0
  20. data/brut-css/bin/setup +1 -0
  21. data/brut-css/package-lock.json +2 -2
  22. data/brut-css/package.json +1 -1
  23. data/brut-js/bin/build +15 -6
  24. data/brut-js/bin/docs +25 -0
  25. data/brut-js/bin/publish +21 -0
  26. data/brut-js/bin/setup +1 -0
  27. data/brut-js/dx +1 -0
  28. data/brut-js/package-lock.json +2 -2
  29. data/brut-js/package.json +1 -1
  30. data/brut.gemspec +34 -28
  31. data/brutrb.com/.vitepress/config.mjs +3 -0
  32. data/brutrb.com/bin/setup +1 -0
  33. data/brutrb.com/database-schema.md +1 -1
  34. data/brutrb.com/getting-started.md +3 -0
  35. data/brutrb.com/overview.md +6 -0
  36. data/brutrb.com/recipes/migrations.md +1 -1
  37. data/brutrb.com/tutorial.md +7 -3
  38. data/docker-compose.dx.yml +3 -0
  39. data/docs/404.html +2 -2
  40. data/docs/adrs.html +3 -3
  41. data/docs/ai.html +3 -3
  42. data/docs/api/Brut/BackEnd/SeedData.html +2 -2
  43. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +2 -2
  44. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +2 -2
  45. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +2 -2
  46. data/docs/api/Brut/BackEnd/Sidekiq.html +2 -2
  47. data/docs/api/Brut/BackEnd/Validators/FormValidator.html +2 -2
  48. data/docs/api/Brut/BackEnd/Validators.html +2 -2
  49. data/docs/api/Brut/BackEnd.html +2 -2
  50. data/docs/api/Brut/CLI/App.html +2 -2
  51. data/docs/api/Brut/CLI/AppRunner.html +2 -2
  52. data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +2 -2
  53. data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +2 -2
  54. data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +2 -2
  55. data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +2 -2
  56. data/docs/api/Brut/CLI/Apps/BuildAssets.html +2 -2
  57. data/docs/api/Brut/CLI/Apps/DB/Create.html +2 -2
  58. data/docs/api/Brut/CLI/Apps/DB/Drop.html +2 -2
  59. data/docs/api/Brut/CLI/Apps/DB/Migrate.html +2 -2
  60. data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +2 -2
  61. data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +2 -2
  62. data/docs/api/Brut/CLI/Apps/DB/Seed.html +2 -2
  63. data/docs/api/Brut/CLI/Apps/DB/Status.html +2 -2
  64. data/docs/api/Brut/CLI/Apps/DB.html +2 -2
  65. data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +2 -2
  66. data/docs/api/Brut/CLI/Apps/DeployBase.html +2 -2
  67. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +3 -3
  68. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +2 -2
  69. data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +2 -2
  70. data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +2 -2
  71. data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +2 -2
  72. data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +2 -2
  73. data/docs/api/Brut/CLI/Apps/Scaffold/DbModel.html +2 -2
  74. data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +2 -2
  75. data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +2 -2
  76. data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +2 -2
  77. data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +2 -2
  78. data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +2 -2
  79. data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +3 -3
  80. data/docs/api/Brut/CLI/Apps/Scaffold.html +2 -2
  81. data/docs/api/Brut/CLI/Apps/Test/Audit.html +2 -2
  82. data/docs/api/Brut/CLI/Apps/Test/E2e.html +2 -2
  83. data/docs/api/Brut/CLI/Apps/Test/JS.html +2 -2
  84. data/docs/api/Brut/CLI/Apps/Test/Run.html +2 -2
  85. data/docs/api/Brut/CLI/Apps/Test.html +2 -2
  86. data/docs/api/Brut/CLI/Apps.html +2 -2
  87. data/docs/api/Brut/CLI/Command.html +2 -2
  88. data/docs/api/Brut/CLI/Error.html +2 -2
  89. data/docs/api/Brut/CLI/ExecutionResults/Result.html +2 -2
  90. data/docs/api/Brut/CLI/ExecutionResults.html +2 -2
  91. data/docs/api/Brut/CLI/Executor.html +2 -2
  92. data/docs/api/Brut/CLI/InvalidOption.html +2 -2
  93. data/docs/api/Brut/CLI/Options.html +80 -2
  94. data/docs/api/Brut/CLI/Output.html +2 -2
  95. data/docs/api/Brut/CLI/SystemExecError.html +2 -2
  96. data/docs/api/Brut/CLI.html +2 -2
  97. data/docs/api/Brut/FactoryBot.html +3 -3
  98. data/docs/api/Brut/Framework/App.html +3 -3
  99. data/docs/api/Brut/Framework/Config.html +25 -3
  100. data/docs/api/Brut/Framework/Container.html +2 -2
  101. data/docs/api/Brut/Framework/Error.html +2 -2
  102. data/docs/api/Brut/Framework/Errors/AbstractMethod.html +2 -2
  103. data/docs/api/Brut/Framework/Errors/Bug.html +2 -2
  104. data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +2 -2
  105. data/docs/api/Brut/Framework/Errors/MissingParameter.html +2 -2
  106. data/docs/api/Brut/Framework/Errors/NoClassForPath.html +2 -2
  107. data/docs/api/Brut/Framework/Errors/NotFound.html +2 -2
  108. data/docs/api/Brut/Framework/Errors/NotImplemented.html +2 -2
  109. data/docs/api/Brut/Framework/Errors.html +2 -2
  110. data/docs/api/Brut/Framework/FussyTypeEnforcement.html +2 -2
  111. data/docs/api/Brut/Framework/MCP.html +21 -11
  112. data/docs/api/Brut/Framework/ProjectEnvironment.html +2 -2
  113. data/docs/api/Brut/Framework.html +2 -2
  114. data/docs/api/Brut/FrontEnd/AssetPathResolver.html +2 -2
  115. data/docs/api/Brut/FrontEnd/Component/Helpers.html +2 -2
  116. data/docs/api/Brut/FrontEnd/Component.html +2 -2
  117. data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +2 -2
  118. data/docs/api/Brut/FrontEnd/Components/FormTag.html +4 -4
  119. data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +2 -2
  120. data/docs/api/Brut/FrontEnd/Components/Input.html +2 -2
  121. data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +2 -2
  122. data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +2 -2
  123. data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +2 -2
  124. data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +2 -2
  125. data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +2 -2
  126. data/docs/api/Brut/FrontEnd/Components/Inputs.html +2 -2
  127. data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +2 -2
  128. data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +2 -2
  129. data/docs/api/Brut/FrontEnd/Components/TimeTag.html +2 -2
  130. data/docs/api/Brut/FrontEnd/Components/Traceparent.html +2 -2
  131. data/docs/api/Brut/FrontEnd/Components.html +2 -2
  132. data/docs/api/Brut/FrontEnd/CsrfProtector.html +250 -0
  133. data/docs/api/Brut/FrontEnd/Download.html +2 -2
  134. data/docs/api/Brut/FrontEnd/Flash.html +2 -2
  135. data/docs/api/Brut/FrontEnd/Form.html +6 -6
  136. data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +2 -2
  137. data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +2 -2
  138. data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +2 -2
  139. data/docs/api/Brut/FrontEnd/Forms/Input.html +2 -2
  140. data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +2 -2
  141. data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +2 -2
  142. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +2 -2
  143. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +2 -2
  144. data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +2 -2
  145. data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +2 -2
  146. data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +2 -2
  147. data/docs/api/Brut/FrontEnd/Forms.html +2 -2
  148. data/docs/api/Brut/FrontEnd/GenericResponse.html +2 -2
  149. data/docs/api/Brut/FrontEnd/Handler.html +2 -2
  150. data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +2 -2
  151. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +2 -2
  152. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +2 -2
  153. data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +2 -2
  154. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +2 -2
  155. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +2 -2
  156. data/docs/api/Brut/FrontEnd/Handlers.html +2 -2
  157. data/docs/api/Brut/FrontEnd/HandlingResults.html +2 -2
  158. data/docs/api/Brut/FrontEnd/HttpMethod.html +2 -2
  159. data/docs/api/Brut/FrontEnd/HttpStatus.html +2 -2
  160. data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +2 -2
  161. data/docs/api/Brut/FrontEnd/Layout.html +2 -2
  162. data/docs/api/Brut/FrontEnd/Middleware.html +2 -2
  163. data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +2 -2
  164. data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +2 -2
  165. data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +2 -2
  166. data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +2 -2
  167. data/docs/api/Brut/FrontEnd/Middlewares.html +2 -2
  168. data/docs/api/Brut/FrontEnd/Page.html +2 -2
  169. data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +2 -2
  170. data/docs/api/Brut/FrontEnd/Pages.html +2 -2
  171. data/docs/api/Brut/FrontEnd/RequestContext.html +2 -2
  172. data/docs/api/Brut/FrontEnd/RouteHook.html +2 -2
  173. data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +2 -2
  174. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +2 -2
  175. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +2 -2
  176. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +2 -2
  177. data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +2 -2
  178. data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +2 -2
  179. data/docs/api/Brut/FrontEnd/RouteHooks.html +2 -2
  180. data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +2 -2
  181. data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +2 -2
  182. data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +2 -2
  183. data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +2 -2
  184. data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +2 -2
  185. data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +2 -2
  186. data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +2 -2
  187. data/docs/api/Brut/FrontEnd/Routing/Route.html +2 -2
  188. data/docs/api/Brut/FrontEnd/Routing.html +2 -2
  189. data/docs/api/Brut/FrontEnd/Session.html +2 -2
  190. data/docs/api/Brut/FrontEnd.html +3 -3
  191. data/docs/api/Brut/I18n/BaseMethods.html +3 -3
  192. data/docs/api/Brut/I18n/ForBackEnd.html +2 -2
  193. data/docs/api/Brut/I18n/ForCLI.html +2 -2
  194. data/docs/api/Brut/I18n/ForHTML.html +2 -2
  195. data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +2 -2
  196. data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +2 -2
  197. data/docs/api/Brut/I18n.html +2 -2
  198. data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +2 -2
  199. data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +2 -2
  200. data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +2 -2
  201. data/docs/api/Brut/Instrumentation/OpenTelemetry.html +2 -2
  202. data/docs/api/Brut/Instrumentation.html +2 -2
  203. data/docs/api/Brut/RubocopConfig.html +237 -0
  204. data/docs/api/Brut/SinatraHelpers/ClassMethods.html +2 -2
  205. data/docs/api/Brut/SinatraHelpers.html +2 -2
  206. data/docs/api/Brut/SpecSupport/ClockSupport.html +2 -2
  207. data/docs/api/Brut/SpecSupport/ComponentSupport.html +7 -13
  208. data/docs/api/Brut/SpecSupport/E2ETestServer.html +2 -2
  209. data/docs/api/Brut/SpecSupport/E2eSupport.html +2 -2
  210. data/docs/api/Brut/SpecSupport/EnhancedNode.html +2 -2
  211. data/docs/api/Brut/SpecSupport/FlashSupport.html +2 -2
  212. data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +2 -2
  213. data/docs/api/Brut/SpecSupport/GeneralSupport.html +2 -2
  214. data/docs/api/Brut/SpecSupport/HandlerSupport.html +2 -2
  215. data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +2 -2
  216. data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +2 -2
  217. data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +2 -2
  218. data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +2 -2
  219. data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +2 -2
  220. data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +2 -2
  221. data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +2 -2
  222. data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +2 -2
  223. data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +2 -2
  224. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +2 -2
  225. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +2 -2
  226. data/docs/api/Brut/SpecSupport/Matchers.html +2 -2
  227. data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +2 -2
  228. data/docs/api/Brut/SpecSupport/RSpecSetup.html +4 -4
  229. data/docs/api/Brut/SpecSupport/SessionSupport.html +2 -2
  230. data/docs/api/Brut/SpecSupport.html +2 -2
  231. data/docs/api/Brut.html +128 -12
  232. data/docs/api/Clock.html +2 -2
  233. data/docs/api/ModuleName.html +28 -28
  234. data/docs/api/RichString.html +22 -22
  235. data/docs/api/SemanticLogger/Appender/Async.html +2 -2
  236. data/docs/api/Sequel/Extensions/BrutInstrumentation.html +2 -2
  237. data/docs/api/Sequel/Extensions/BrutMigrations.html +2 -2
  238. data/docs/api/Sequel/Extensions.html +2 -2
  239. data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +2 -2
  240. data/docs/api/Sequel/Plugins/CreatedAt.html +2 -2
  241. data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +2 -2
  242. data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +2 -2
  243. data/docs/api/Sequel/Plugins/ExternalId.html +2 -2
  244. data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +2 -2
  245. data/docs/api/Sequel/Plugins/FindBang.html +2 -2
  246. data/docs/api/Sequel/Plugins.html +2 -2
  247. data/docs/api/Sequel.html +2 -2
  248. data/docs/api/_index.html +16 -2
  249. data/docs/api/class_list.html +1 -1
  250. data/docs/api/file.README.html +28 -2
  251. data/docs/api/index.html +28 -2
  252. data/docs/api/method_list.html +192 -168
  253. data/docs/api/top-level-namespace.html +2 -2
  254. data/docs/assets/{app.D6BuVHo9.js → app.CmkhEsw7.js} +1 -1
  255. data/docs/assets/chunks/@localSearchIndexroot.DUha-mf5.js +1 -0
  256. data/docs/assets/chunks/{VPLocalSearchBox.BpvHMbx6.js → VPLocalSearchBox.CDh583Oj.js} +1 -1
  257. data/docs/assets/chunks/{theme.wlAOvi2f.js → theme.B0_7GeW8.js} +2 -2
  258. data/docs/assets/{components.md.iLiv2E9X.js → components.md.-22ecBxM.js} +3 -3
  259. data/docs/assets/{configuration.md.DmuAdsli.js → configuration.md.CLKL1lFf.js} +1 -1
  260. data/docs/assets/{database-schema.md.C5gXexJi.js → database-schema.md.LpmBPVEU.js} +1 -1
  261. data/docs/assets/{forms.md.D8aa_qI-.js → forms.md.CBI5--o2.js} +1 -1
  262. data/docs/assets/{getting-started.md.DLplsDUd.js → getting-started.md.D5nzBZ4J.js} +6 -3
  263. data/docs/assets/{getting-started.md.DLplsDUd.lean.js → getting-started.md.D5nzBZ4J.lean.js} +1 -1
  264. data/docs/assets/overview.md.DlKiRRG_.js +1 -0
  265. data/docs/assets/overview.md.DlKiRRG_.lean.js +1 -0
  266. data/docs/assets/{recipes_migrations.md.DPN3gQE3.js → recipes_migrations.md.CTcnWDJF.js} +1 -1
  267. data/docs/assets/tutorial.md.BIb7XT6j.js +1 -0
  268. data/docs/assets/tutorial.md.BIb7XT6j.lean.js +1 -0
  269. data/docs/assets.html +3 -3
  270. data/docs/brut-js/api/AjaxSubmit.html +1 -1
  271. data/docs/brut-js/api/AjaxSubmit.js.html +1 -1
  272. data/docs/brut-js/api/Autosubmit.html +1 -1
  273. data/docs/brut-js/api/Autosubmit.js.html +1 -1
  274. data/docs/brut-js/api/BaseCustomElement.html +1 -1
  275. data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
  276. data/docs/brut-js/api/BrutCustomElements.html +1 -1
  277. data/docs/brut-js/api/BufferedLogger.html +1 -1
  278. data/docs/brut-js/api/ConfirmSubmit.html +1 -1
  279. data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
  280. data/docs/brut-js/api/ConfirmationDialog.html +1 -1
  281. data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
  282. data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
  283. data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
  284. data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
  285. data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
  286. data/docs/brut-js/api/CopyToClipboard.html +1 -1
  287. data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
  288. data/docs/brut-js/api/Form.html +1 -1
  289. data/docs/brut-js/api/Form.js.html +1 -1
  290. data/docs/brut-js/api/I18nTranslation.html +1 -1
  291. data/docs/brut-js/api/I18nTranslation.js.html +1 -1
  292. data/docs/brut-js/api/LocaleDetection.html +1 -1
  293. data/docs/brut-js/api/LocaleDetection.js.html +1 -1
  294. data/docs/brut-js/api/Logger.html +1 -1
  295. data/docs/brut-js/api/Logger.js.html +1 -1
  296. data/docs/brut-js/api/Message.html +1 -1
  297. data/docs/brut-js/api/Message.js.html +1 -1
  298. data/docs/brut-js/api/PrefixedLogger.html +1 -1
  299. data/docs/brut-js/api/RichString.html +1 -1
  300. data/docs/brut-js/api/RichString.js.html +1 -1
  301. data/docs/brut-js/api/Tabs.html +1 -1
  302. data/docs/brut-js/api/Tabs.js.html +1 -1
  303. data/docs/brut-js/api/Tracing.html +1 -1
  304. data/docs/brut-js/api/Tracing.js.html +1 -1
  305. data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
  306. data/docs/brut-js/api/external-Performance.html +1 -1
  307. data/docs/brut-js/api/external-Promise.html +1 -1
  308. data/docs/brut-js/api/external-ValidityState.html +1 -1
  309. data/docs/brut-js/api/external-Window.html +1 -1
  310. data/docs/brut-js/api/external-fetch.html +1 -1
  311. data/docs/brut-js/api/global.html +1 -1
  312. data/docs/brut-js/api/index.html +1 -1
  313. data/docs/brut-js/api/index.js.html +1 -1
  314. data/docs/brut-js/api/module-testing.html +1 -1
  315. data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
  316. data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
  317. data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
  318. data/docs/brut-js/api/testing.DOMCreator.html +1 -1
  319. data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
  320. data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
  321. data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
  322. data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
  323. data/docs/brut-js/api/testing_index.js.html +1 -1
  324. data/docs/brut-js.html +3 -3
  325. data/docs/business-logic.html +3 -3
  326. data/docs/cli.html +3 -3
  327. data/docs/components.html +7 -7
  328. data/docs/configuration.html +5 -5
  329. data/docs/css.html +3 -3
  330. data/docs/custom-element-tests.html +3 -3
  331. data/docs/database-access.html +3 -3
  332. data/docs/database-schema.html +5 -5
  333. data/docs/deployment.html +3 -3
  334. data/docs/dev-environment.html +3 -3
  335. data/docs/dir-structure.html +3 -3
  336. data/docs/doc-conventions.html +3 -3
  337. data/docs/end-to-end-tests.html +3 -3
  338. data/docs/features.html +3 -3
  339. data/docs/flash-and-session.html +3 -3
  340. data/docs/form-constraints.html +3 -3
  341. data/docs/forms.html +5 -5
  342. data/docs/getting-started.html +9 -6
  343. data/docs/handlers.html +3 -3
  344. data/docs/hashmap.json +1 -1
  345. data/docs/hooks.html +3 -3
  346. data/docs/i18n.html +3 -3
  347. data/docs/index.html +3 -3
  348. data/docs/instrumentation.html +3 -3
  349. data/docs/javascript.html +3 -3
  350. data/docs/jobs.html +3 -3
  351. data/docs/keyword-injection.html +3 -3
  352. data/docs/layouts.html +3 -3
  353. data/docs/lsp.html +3 -3
  354. data/docs/markdown-examples.html +3 -3
  355. data/docs/middleware.html +3 -3
  356. data/docs/overview.html +5 -5
  357. data/docs/pages.html +3 -3
  358. data/docs/recipes/alternate-layouts.html +3 -3
  359. data/docs/recipes/authentication.html +3 -3
  360. data/docs/recipes/blank-layouts.html +3 -3
  361. data/docs/recipes/custom-flash.html +3 -3
  362. data/docs/recipes/indexed-forms.html +3 -3
  363. data/docs/recipes/migrations.html +5 -5
  364. data/docs/recipes/text-field-component.html +3 -3
  365. data/docs/roadmap.html +3 -3
  366. data/docs/routes.html +3 -3
  367. data/docs/security.html +3 -3
  368. data/docs/seed-data.html +3 -3
  369. data/docs/space-time-continuum.html +3 -3
  370. data/docs/tutorial.html +5 -5
  371. data/docs/unit-tests.html +3 -3
  372. data/docs/why.html +3 -3
  373. data/dx/build +45 -9
  374. data/lib/brut/cli/app.rb +1 -1
  375. data/lib/brut/cli/apps/heroku_container_based_deploy.rb +1 -1
  376. data/lib/brut/cli/apps/scaffold.rb +1 -1
  377. data/lib/brut/cli/options.rb +4 -0
  378. data/lib/brut/factory_bot.rb +1 -1
  379. data/lib/brut/framework/app.rb +1 -1
  380. data/lib/brut/framework/config.rb +11 -0
  381. data/lib/brut/framework/mcp.rb +13 -8
  382. data/lib/brut/front_end/components/form_tag.rb +2 -2
  383. data/lib/brut/front_end/csrf_protector.rb +30 -0
  384. data/lib/brut/front_end/form.rb +4 -4
  385. data/lib/brut/front_end/page.rb +1 -1
  386. data/lib/brut/front_end/routing.rb +1 -1
  387. data/lib/brut/front_end.rb +1 -0
  388. data/lib/brut/i18n/base_methods.rb +1 -1
  389. data/lib/brut/instrumentation/logger_span_exporter.rb +1 -1
  390. data/lib/brut/junk_drawer.rb +3 -1
  391. data/lib/brut/rubocop_config.rb +123 -0
  392. data/lib/brut/spec_support/component_support.rb +0 -3
  393. data/lib/brut/spec_support/rspec_setup.rb +2 -2
  394. data/lib/brut/version.rb +1 -1
  395. data/mkbrut/.gitignore +16 -0
  396. data/mkbrut/CODE_OF_CONDUCT.txt +100 -0
  397. data/mkbrut/Gemfile +3 -0
  398. data/mkbrut/Gemfile.lock +19 -0
  399. data/mkbrut/LICENSE.txt +370 -0
  400. data/mkbrut/README.md +145 -0
  401. data/mkbrut/Rakefile +2 -0
  402. data/mkbrut/bin/build +36 -0
  403. data/mkbrut/bin/ci +19 -0
  404. data/mkbrut/bin/docs +19 -0
  405. data/mkbrut/bin/publish +129 -0
  406. data/mkbrut/bin/rake +16 -0
  407. data/mkbrut/bin/setup +30 -0
  408. data/mkbrut/brut-welcome.png +0 -0
  409. data/mkbrut/deploy/.dockerignore +2 -0
  410. data/mkbrut/deploy/Dockerfile +25 -0
  411. data/mkbrut/dx +1 -0
  412. data/mkbrut/exe/mkbrut +5 -0
  413. data/mkbrut/lib/mkbrut/app.rb +79 -0
  414. data/mkbrut/lib/mkbrut/app_id.rb +8 -0
  415. data/mkbrut/lib/mkbrut/app_name.rb +29 -0
  416. data/mkbrut/lib/mkbrut/app_options.rb +36 -0
  417. data/mkbrut/lib/mkbrut/base.rb +57 -0
  418. data/mkbrut/lib/mkbrut/cli.rb +107 -0
  419. data/mkbrut/lib/mkbrut/erb_binding_delegate.rb +20 -0
  420. data/mkbrut/lib/mkbrut/internet_identifier.rb +32 -0
  421. data/mkbrut/lib/mkbrut/invalid_identifier.rb +4 -0
  422. data/mkbrut/lib/mkbrut/ops/add_css_import.rb +42 -0
  423. data/mkbrut/lib/mkbrut/ops/add_i18n_message.rb +74 -0
  424. data/mkbrut/lib/mkbrut/ops/add_method.rb +48 -0
  425. data/mkbrut/lib/mkbrut/ops/append_to_file.rb +20 -0
  426. data/mkbrut/lib/mkbrut/ops/base_op.rb +21 -0
  427. data/mkbrut/lib/mkbrut/ops/copy_file.rb +12 -0
  428. data/mkbrut/lib/mkbrut/ops/insert_code_in_method.rb +58 -0
  429. data/mkbrut/lib/mkbrut/ops/insert_route.rb +52 -0
  430. data/mkbrut/lib/mkbrut/ops/mkdir.rb +13 -0
  431. data/mkbrut/lib/mkbrut/ops/prism_parsing_op.rb +70 -0
  432. data/mkbrut/lib/mkbrut/ops/render_template.rb +26 -0
  433. data/mkbrut/lib/mkbrut/ops/skip_file.rb +10 -0
  434. data/mkbrut/lib/mkbrut/ops.rb +16 -0
  435. data/mkbrut/lib/mkbrut/organization.rb +5 -0
  436. data/mkbrut/lib/mkbrut/prefix.rb +26 -0
  437. data/mkbrut/lib/mkbrut/prefixed_io.rb +16 -0
  438. data/mkbrut/lib/mkbrut/segments/bare_bones.rb +185 -0
  439. data/mkbrut/lib/mkbrut/segments/demo.rb +121 -0
  440. data/mkbrut/lib/mkbrut/segments/heroku.rb +30 -0
  441. data/mkbrut/lib/mkbrut/segments/sidekiq.rb +3 -0
  442. data/mkbrut/lib/mkbrut/segments.rb +8 -0
  443. data/mkbrut/lib/mkbrut/version.rb +3 -0
  444. data/mkbrut/lib/mkbrut/versions.rb +13 -0
  445. data/mkbrut/lib/mkbrut.rb +18 -0
  446. data/mkbrut/mkbrut.gemspec +34 -0
  447. data/mkbrut/templates/Base/.dockerignore +25 -0
  448. data/mkbrut/templates/Base/.env.development.erb +60 -0
  449. data/mkbrut/templates/Base/.env.test.erb +8 -0
  450. data/mkbrut/templates/Base/.gitignore +31 -0
  451. data/mkbrut/templates/Base/.projections.json +59 -0
  452. data/mkbrut/templates/Base/Dockerfile.dx +205 -0
  453. data/mkbrut/templates/Base/Gemfile.erb +53 -0
  454. data/mkbrut/templates/Base/Procfile.development +5 -0
  455. data/mkbrut/templates/Base/Procfile.test +1 -0
  456. data/mkbrut/templates/Base/README.md +4 -0
  457. data/mkbrut/templates/Base/README.md.erb +40 -0
  458. data/mkbrut/templates/Base/app/bootstrap.rb +61 -0
  459. data/mkbrut/templates/Base/app/config/i18n/en/1_defaults.rb +128 -0
  460. data/mkbrut/templates/Base/app/config/i18n/en/2_app.rb +24 -0
  461. data/mkbrut/templates/Base/app/public/static/manifest.json.erb +33 -0
  462. data/mkbrut/templates/Base/app/src/app.rb.erb +37 -0
  463. data/mkbrut/templates/Base/app/src/back_end/data_models/app_data_model.rb +5 -0
  464. data/mkbrut/templates/Base/app/src/back_end/data_models/db.rb +19 -0
  465. data/mkbrut/templates/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb +6 -0
  466. data/mkbrut/templates/Base/app/src/back_end/data_models/seed/seed_data.rb +9 -0
  467. data/mkbrut/templates/Base/app/src/front_end/components/app_component.rb +8 -0
  468. data/mkbrut/templates/Base/app/src/front_end/components/custom_element_registration.rb.erb +7 -0
  469. data/mkbrut/templates/Base/app/src/front_end/css/index.css +2 -0
  470. data/mkbrut/templates/Base/app/src/front_end/css/svgs.css +12 -0
  471. data/mkbrut/templates/Base/app/src/front_end/forms/app_form.rb +4 -0
  472. data/mkbrut/templates/Base/app/src/front_end/handlers/app_handler.rb +4 -0
  473. data/mkbrut/templates/Base/app/src/front_end/images/LogoPylon.png +0 -0
  474. data/mkbrut/templates/Base/app/src/front_end/images/LogoTransit.png +0 -0
  475. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-120x120.png +0 -0
  476. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-152x152.png +0 -0
  477. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-167x167.png +0 -0
  478. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-180x180.png +0 -0
  479. data/mkbrut/templates/Base/app/src/front_end/images/favicon.ico +0 -0
  480. data/mkbrut/templates/Base/app/src/front_end/images/icon.png +0 -0
  481. data/mkbrut/templates/Base/app/src/front_end/images/mkicons.sh +6 -0
  482. data/mkbrut/templates/Base/app/src/front_end/js/index.js +6 -0
  483. data/mkbrut/templates/Base/app/src/front_end/layouts/default_layout.rb.erb +73 -0
  484. data/mkbrut/templates/Base/app/src/front_end/pages/app_page.rb +11 -0
  485. data/mkbrut/templates/Base/app/src/front_end/pages/home_page.rb +62 -0
  486. data/mkbrut/templates/Base/app/src/front_end/support/app_session.rb +6 -0
  487. data/mkbrut/templates/Base/app/src/front_end/svgs/README.md +5 -0
  488. data/mkbrut/templates/Base/app/src/front_end/svgs/comment-button.svg +59 -0
  489. data/mkbrut/templates/Base/bin/README.md.erb +5 -0
  490. data/mkbrut/templates/Base/bin/build-assets +7 -0
  491. data/mkbrut/templates/Base/bin/ci +39 -0
  492. data/mkbrut/templates/Base/bin/console +31 -0
  493. data/mkbrut/templates/Base/bin/db +9 -0
  494. data/mkbrut/templates/Base/bin/dbconsole +51 -0
  495. data/mkbrut/templates/Base/bin/dev +25 -0
  496. data/mkbrut/templates/Base/bin/release +26 -0
  497. data/mkbrut/templates/Base/bin/run +86 -0
  498. data/mkbrut/templates/Base/bin/scaffold +9 -0
  499. data/mkbrut/templates/Base/bin/setup +256 -0
  500. data/mkbrut/templates/Base/bin/startup-message +65 -0
  501. data/mkbrut/templates/Base/bin/test +9 -0
  502. data/mkbrut/templates/Base/bin/test-server +29 -0
  503. data/mkbrut/templates/Base/bin/watch-and-build-assets +37 -0
  504. data/mkbrut/templates/Base/config.ru +16 -0
  505. data/mkbrut/templates/Base/docker-compose.dx.yml +92 -0
  506. data/mkbrut/templates/Base/dx/README.md +28 -0
  507. data/mkbrut/templates/Base/dx/bash_customizations +12 -0
  508. data/mkbrut/templates/Base/dx/bash_customizations.local +8 -0
  509. data/mkbrut/templates/Base/dx/build +107 -0
  510. data/mkbrut/templates/Base/dx/docker-compose.env.erb +25 -0
  511. data/mkbrut/templates/Base/dx/dx.sh.lib +137 -0
  512. data/mkbrut/templates/Base/dx/exec +68 -0
  513. data/mkbrut/templates/Base/dx/prune +19 -0
  514. data/mkbrut/templates/Base/dx/show-help-in-app-container-then-wait.sh +38 -0
  515. data/mkbrut/templates/Base/dx/start +30 -0
  516. data/mkbrut/templates/Base/dx/stop +23 -0
  517. data/mkbrut/templates/Base/package.json.erb +37 -0
  518. data/mkbrut/templates/Base/puma.config.rb +53 -0
  519. data/mkbrut/templates/Base/specs/e2e/home_page.spec.rb.erb +23 -0
  520. data/mkbrut/templates/Base/specs/front_end/js/SpecHelper.js +24 -0
  521. data/mkbrut/templates/Base/specs/front_end/pages/home_page.spec.rb +22 -0
  522. data/mkbrut/templates/Base/specs/lint_factories.spec.rb +7 -0
  523. data/mkbrut/templates/Base/specs/spec_helper.rb +78 -0
  524. data/mkbrut/templates/Base/specs/support.rb +2 -0
  525. data/mkbrut/templates/segments/BareBones/app/src/front_end/handlers/trigger_exception_handler.rb +24 -0
  526. data/mkbrut/templates/segments/BareBones/app/src/front_end/js/Example.js.erb +49 -0
  527. data/mkbrut/templates/segments/BareBones/specs/front_end/handlers/trigger_exception_handler.spec.rb +41 -0
  528. data/mkbrut/templates/segments/BareBones/specs/front_end/js/Example.spec.js.erb +38 -0
  529. data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/db/guestbook_message.rb +3 -0
  530. data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/migrations/20250628194124_guestbook.rb +14 -0
  531. data/mkbrut/templates/segments/Demo/app/src/front_end/components/flash_component.rb +36 -0
  532. data/mkbrut/templates/segments/Demo/app/src/front_end/css/constraint-violations.css +18 -0
  533. data/mkbrut/templates/segments/Demo/app/src/front_end/css/fonts.css +19 -0
  534. data/mkbrut/templates/segments/Demo/app/src/front_end/fonts/monaspace-xenon.ttf +0 -0
  535. data/mkbrut/templates/segments/Demo/app/src/front_end/forms/guestbook_message_form.rb +4 -0
  536. data/mkbrut/templates/segments/Demo/app/src/front_end/handlers/guestbook_message_handler.rb +64 -0
  537. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page/message_component.rb +41 -0
  538. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page.rb +43 -0
  539. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/new_guestbook_message_page.rb +64 -0
  540. data/mkbrut/templates/segments/Demo/specs/back_end/data_models/db/guestbook_message.spec.rb +5 -0
  541. data/mkbrut/templates/segments/Demo/specs/e2e/guest_message.spec.rb +54 -0
  542. data/mkbrut/templates/segments/Demo/specs/factories/db/guestbook_message.factory.rb +7 -0
  543. data/mkbrut/templates/segments/Demo/specs/front_end/components/flash_component.spec.rb +5 -0
  544. data/mkbrut/templates/segments/Demo/specs/front_end/handlers/guestbook_message_handler.spec.rb +122 -0
  545. data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb +5 -0
  546. data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb +52 -0
  547. data/mkbrut/templates/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb +5 -0
  548. data/mkbrut/templates/segments/Heroku/bin/deploy +11 -0
  549. data/mkbrut/templates/segments/Heroku/deploy/Dockerfile +125 -0
  550. data/mkbrut/templates/segments/Heroku/deploy/docker-entrypoint +15 -0
  551. data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +26 -0
  552. data/specs/brut/junk_drawer.spec.rb +4 -0
  553. metadata +242 -41
  554. data/.rspec +0 -3
  555. data/docs/assets/chunks/@localSearchIndexroot.COP2Bcmp.js +0 -1
  556. data/docs/assets/overview.md.iMnwLO4x.js +0 -1
  557. data/docs/assets/overview.md.iMnwLO4x.lean.js +0 -1
  558. data/docs/assets/tutorial.md.BYXj4cOu.js +0 -1
  559. data/docs/assets/tutorial.md.BYXj4cOu.lean.js +0 -1
  560. /data/docs/assets/{components.md.iLiv2E9X.lean.js → components.md.-22ecBxM.lean.js} +0 -0
  561. /data/docs/assets/{configuration.md.DmuAdsli.lean.js → configuration.md.CLKL1lFf.lean.js} +0 -0
  562. /data/docs/assets/{database-schema.md.C5gXexJi.lean.js → database-schema.md.LpmBPVEU.lean.js} +0 -0
  563. /data/docs/assets/{forms.md.D8aa_qI-.lean.js → forms.md.CBI5--o2.lean.js} +0 -0
  564. /data/docs/assets/{recipes_migrations.md.DPN3gQE3.lean.js → recipes_migrations.md.CTcnWDJF.lean.js} +0 -0
@@ -51,7 +51,7 @@ class Brut::CLI::Apps::Scaffold < Brut::CLI::App
51
51
  files_to_test_files.each do |source,destination|
52
52
  result = Prism.parse_file(source.to_s)
53
53
  if !result
54
- raise "For some reason Prism did not parse #{source.to_s}"
54
+ raise "For some reason Prism did not parse #{source}"
55
55
  end
56
56
  classes = find_classes(result.value).map { |(module_nodes,class_node)|
57
57
  (module_nodes.map(&:constant_path).map(&:full_name).map(&:to_s) + [class_node.constant_path.full_name.to_s]).compact.join("::")
@@ -74,4 +74,8 @@ class Brut::CLI::Options
74
74
  value
75
75
  end
76
76
  end
77
+ def respond_to_missing?(sym, include_private = false)
78
+ # XXX: Maybe this should not
79
+ true
80
+ end
77
81
  end
@@ -7,7 +7,7 @@ class Brut::FactoryBot
7
7
  def setup!
8
8
  Faker::Config.locale = :en
9
9
  FactoryBot.definition_file_paths = [
10
- Brut.container.app_specs_dir / "factories"
10
+ Brut.container.app_specs_dir / "factories",
11
11
  ]
12
12
  FactoryBot.define do
13
13
  to_create { |instance| instance.save }
@@ -89,7 +89,7 @@ class Brut::Framework::App
89
89
  raise ArgumentError, "Your error handler block may only accept exception: and http_status_code: as required keyword parameters. The following parameters were found:\n #{messages.join("\n ")}"
90
90
  end
91
91
  if @error_blocks[condition]
92
- raise ArgumentError, "You have already configured error handling for condition '#{condition.to_s}'"
92
+ raise ArgumentError, "You have already configured error handling for condition '#{condition}'"
93
93
  end
94
94
  @error_blocks[condition] = block
95
95
  end
@@ -319,6 +319,17 @@ class Brut::Framework::Config
319
319
  allow_app_override: true,
320
320
  )
321
321
 
322
+ c.store(
323
+ "csrf_protector",
324
+ Brut::FrontEnd::CsrfProtector,
325
+ "Object to allow custom logic related to CSRF protection",
326
+ allow_app_override: true
327
+ ) do
328
+ Brut::FrontEnd::CsrfProtector.new
329
+ end
330
+
331
+
332
+
322
333
  c.store(
323
334
  "semantic_logger_appenders",
324
335
  { Hash => "if only one appender is needed", Array => "to configure multiple appenders" },
@@ -131,9 +131,9 @@ class Brut::Framework::MCP
131
131
  exception: ex)
132
132
  rescue => ex2
133
133
  $stderr.puts "While handling an error recording an exception, we get another error from SemanticLogger." + [
134
- [ :original_exception, exception, ].join(": "),
135
- [ :exception_from_recording_exception, ex, ].join(": "),
136
- [ :exception_from_semantic_logger, ex2 ].join(": "),
134
+ [ :original_exception, exception ].join(": "),
135
+ [ :exception_from_recording_exception, ex ].join(": "),
136
+ [ :exception_from_semantic_logger, ex2 ].join(": "),
137
137
 
138
138
  ].join(", ")
139
139
  end
@@ -174,7 +174,7 @@ class Brut::Framework::MCP
174
174
  end
175
175
 
176
176
  message = if Brut.container.project_env.development?
177
- "Form submission did not include an authenticity token. All forms must include one. To add one, use the `form_tag` helper, or include Brut::FrontEnd::Components::Inputs::CsrfToken somewhere inside your <form> tag"
177
+ "Form submission did not include an authenticity token. All forms must include one. To add one, use the `Brut::FrontEnd::Components::FormTag` component, or include Brut::FrontEnd::Components::Inputs::CsrfToken somewhere inside your <form> tag"
178
178
  else
179
179
  "Forbidden"
180
180
  end
@@ -186,10 +186,15 @@ class Brut::Framework::MCP
186
186
  Rack::Protection::AuthenticityToken,
187
187
  [
188
188
  {
189
- allow_if: ->(env) { env["brut.owned_path"] },
189
+ allow_if: ->(env) {
190
+ brut_owned_path = env["brut.owned_path"]
191
+ app_allowed = Brut.container.csrf_protector.tap {|_| puts _.class.name }.allowed?(env)
192
+
193
+ brut_owned_path || app_allowed
194
+ },
190
195
  message: message,
191
- }
192
- ]
196
+ },
197
+ ],
193
198
  ],
194
199
  ]
195
200
  if Brut.container.auto_reload_classes?
@@ -275,7 +280,7 @@ class Brut::Framework::MCP
275
280
  in TrueClass
276
281
  nil
277
282
  else
278
- raise NoMatchingPatternError, "Result from #{method} hook #{klass}'s #{method} method was a #{result.class} (#{result.to_s} as a string), which cannot be used to understand the response to generate. Return nil or true if processing should proceed"
283
+ raise NoMatchingPatternError, "Result from #{method} hook #{klass}'s #{method} method was a #{result.class} (#{result} as a string), which cannot be used to understand the response to generate. Return nil or true if processing should proceed"
279
284
  end
280
285
  end
281
286
  end
@@ -36,10 +36,10 @@ class Brut::FrontEnd::Components::FormTag < Brut::FrontEnd::Component
36
36
  form_class = form_class.class
37
37
  end
38
38
  if html_attributes[:action]
39
- raise ArgumentError, "You cannot specify both for: (#{form_class}) and and action: (#{html_attributes[:action]}) to a form_tag"
39
+ raise ArgumentError, "You cannot specify both for: (#{form_class}) and and action: (#{html_attributes[:action]}) to #{self.class}"
40
40
  end
41
41
  if html_attributes[:method]
42
- raise ArgumentError, "You cannot specify both for: (#{form_class}) and and method: (#{html_attributes[:method]}) to a form_tag"
42
+ raise ArgumentError, "You cannot specify both for: (#{form_class}) and and method: (#{html_attributes[:method]}) to #{self.class}"
43
43
  end
44
44
  begin
45
45
  route = Brut.container.routing.route(form_class)
@@ -0,0 +1,30 @@
1
+ # Base for custom logic around CSRF protection. Brut configures `Rack::Protection::AuthenticityToken` for all requests, and
2
+ # this happens early in the request. The idea is that no real POST should be missing a CSRF token. That said, there are times
3
+ # when it must be skipped, such as for webhooks. In that case, you can extend this class and configure it via
4
+ # `Brut.container.override("csrf_protector", YourCustomCsrfProtector.new)` in your `App` class' initializer.
5
+ #
6
+ # @example
7
+ # class CsrfProtector < Brut::FrontEnd::CsrfProtector
8
+ # def allowed?(env)
9
+ # !!env["PATH_INFO"].to_s.match?(/^\/webhooks\//)
10
+ # end
11
+ # end
12
+ # # Then, in app.rb
13
+ # class App < Brut::Framework::App
14
+ # def id = "some-id"
15
+ # def organization = "some-org"
16
+ #
17
+ # def initialize
18
+ # Brut.container.override("csrf_protector") do
19
+ # CsrfProtector.new
20
+ # end
21
+ #
22
+ # # ...
23
+ #
24
+ class Brut::FrontEnd::CsrfProtector
25
+
26
+ # Return true if the request should be allowed without a CSRF token. This implementation returns false.
27
+ def allowed?(env)
28
+ false
29
+ end
30
+ end
@@ -73,7 +73,7 @@ class Brut::FrontEnd::Form
73
73
  }
74
74
  else
75
75
  [
76
- input_definition.make_input(value:, index: nil)
76
+ input_definition.make_input(value:, index: nil),
77
77
  ]
78
78
  end
79
79
 
@@ -109,7 +109,7 @@ class Brut::FrontEnd::Form
109
109
  # @return [Brut::FrontEnd::Forms::Input]
110
110
  def inputs(input_name)
111
111
  @inputs.fetch(input_name.to_s)
112
- rescue KeyError => ex
112
+ rescue KeyError
113
113
  raise Brut::Framework::Errors::Bug, "Form does not define the input '#{input_name}'. You must add this to your form. Found these inputs: #{@inputs.keys.join(', ')}"
114
114
  end
115
115
 
@@ -164,8 +164,8 @@ class Brut::FrontEnd::Form
164
164
  true
165
165
  end
166
166
  },
167
- index
168
- ]
167
+ index,
168
+ ],
169
169
  ]
170
170
  end
171
171
  }.compact
@@ -86,7 +86,7 @@ private
86
86
  layout_class = Module.const_get(
87
87
  layout_class = RichString.new([
88
88
  self.layout,
89
- "layout"
89
+ "layout",
90
90
  ].join("_")).camelize
91
91
  )
92
92
  Brut.container.instrumentation.add_prefixed_attributes("brut", layout_class: layout_class)
@@ -276,7 +276,7 @@ private
276
276
  }
277
277
  part_names[-1] += suffix
278
278
  begin
279
- part_names.inject(Module) { |mod,path_element|
279
+ part_names.reduce(Module) { |mod,path_element|
280
280
  mod.const_get(path_element,mod == Module)
281
281
  }
282
282
  rescue NameError => ex
@@ -9,6 +9,7 @@ module Brut::FrontEnd
9
9
  autoload(:AssetPathResolver, "brut/front_end/asset_path_resolver")
10
10
  autoload(:Component, "brut/front_end/component")
11
11
  autoload(:Components, "brut/front_end/component")
12
+ autoload(:CsrfProtector, "brut/front_end/csrf_protector")
12
13
  autoload(:Download, "brut/front_end/download")
13
14
  autoload(:Flash, "brut/front_end/flash")
14
15
  autoload(:Form, "brut/front_end/form")
@@ -211,7 +211,7 @@ module Brut::I18n::BaseMethods
211
211
  block_contents = safe(capture(&block))
212
212
  interpolated_values[:block] = block_contents
213
213
  end
214
- t_direct(keys_to_check,**interpolated_values.merge(key_given: key))
214
+ t_direct(keys_to_check,**interpolated_values, key_given: key)
215
215
  rescue I18n::MissingInterpolationArgument => ex
216
216
  if ex.key.to_s == "block"
217
217
  raise ArgumentError,"One of the keys #{key.join(", ")} contained a %{block} interpolation value: '#{ex.string}'. This means you must yield a block to `t`"
@@ -58,7 +58,7 @@ private
58
58
  (span.events || []).each do |event|
59
59
  event_message = (" " * (indent + 2)) + "event:#{event.name}"
60
60
  event_params = {
61
- timing: ((event.timestamp - previous_timestamp)/1_000.0).to_i/1_000.0
61
+ timing: ((event.timestamp - previous_timestamp)/1_000.0).to_i/1_000.0,
62
62
  }.merge(event.attributes).merge(synthetic_attributes)
63
63
  SemanticLogger[self.class].info(event_message,event_params)
64
64
  previous_timestamp = event.timestamp
@@ -96,7 +96,9 @@ class RichString
96
96
  }.
97
97
  join.gsub("-","_").
98
98
  gsub(/[_]+/,"_").
99
- gsub(/^_+/,"").
99
+ split(/::/).
100
+ map { |it| it.gsub(/^_+/,"") }.
101
+ join("/").
100
102
  gsub(/_+$/,"")
101
103
  )
102
104
  end
@@ -0,0 +1,123 @@
1
+ require "pathname"
2
+ require "yaml"
3
+ # Not here:
4
+ # - prevent use of postfix conditonals entirely
5
+ module Brut
6
+ IM_NOT_CALLING_THEM_COPS = {
7
+ "Gemspec/AddRuntimeDependency" => true,
8
+ "Lint/AmbiguousAssignment" => true,
9
+ "Lint/AmbiguousOperator" => true,
10
+ "Lint/AmbiguousOperatorPrecedence" => true,
11
+ "Lint/AmbiguousRange" => true,
12
+ "Lint/AmbiguousRegexpLiteral" => true,
13
+ "Lint/DuplicateCaseCondition" => true,
14
+ "Lint/DuplicateElsifCondition" => true,
15
+ "Lint/Loop" => true,
16
+ "Lint/RedundantSplatExpansion" => true,
17
+ "Lint/RedundantStringCoercion" => true,
18
+ "Lint/RedundantTypeConversion" => true,
19
+ "Lint/ToJSON" => true,
20
+ "Style/ColonMethodDefinition" => true,
21
+ "Style/DefWithParentheses" => true,
22
+ "Style/InvertibleUnlessCondition" => true,
23
+ "Style/KeywordArgumentsMerging" => true,
24
+ "Style/MethodDefParentheses" => true,
25
+ "Style/MissingRespondToMissing" => true,
26
+ "Style/MultilineTernaryOperator" => true,
27
+ "Style/NegatedUnless" => true,
28
+ "Style/NestedTernaryOperator" => true,
29
+ "Style/PreferredHashMethods" => true,
30
+ "Style/UnlessElse" => true,
31
+ "Style/UnlessLogicalOperators" => true,
32
+ "Layout/DotPosition" => {
33
+ "EnforcedStyle" => "trailing",
34
+ },
35
+ "Lint/AssignmentInCondition" => {
36
+ "AllowSafeAssignment" => "false",
37
+ },
38
+ "Style/ClassMethodsDefinitions" => {
39
+ "EnforcedStyle" => "def_self",
40
+ },
41
+ "Style/CollectionMethods" => {
42
+ "PreferredMethods" => {
43
+ "find" => "detect",
44
+ "collect" => "map",
45
+ "find_all" => "select",
46
+ "member?" => "include?",
47
+ },
48
+ },
49
+ "Style/EndlessMethod" => {
50
+ "EnforcedStyle" => "allow_single_line",
51
+ },
52
+ "Style/For" => {
53
+ "EnforcedStyle" => "each",
54
+ },
55
+ "Style/YodaCondition" => {
56
+ "EnforcedStyle" => "forbid_for_all_comparison_operators",
57
+ },
58
+ "Style/DisableSyntax" => {
59
+ "DisableSyntax" => [
60
+ "unless",
61
+ "and_or_not",
62
+ "until",
63
+ ],
64
+ },
65
+ "Style/TrailingCommaInArrayLiteral" => {
66
+ "EnforcedStyleForMultiline" => "consistent_comma",
67
+ },
68
+ "Style/TrailingCommaInHashLiteral" => {
69
+ "EnforcedStyleForMultiline" => "consistent_comma",
70
+ },
71
+ # Documented, but nonexistent
72
+ #"Style/ItBlockParameter" => {
73
+ # "EnforcedStyle" => "allow_single_line",
74
+ #},
75
+ }
76
+ PREAMBLE = {
77
+ "inherit_mode" => {
78
+ "merge" => [ "Exclude" ],
79
+ },
80
+ "plugins" => [
81
+ "rubocop-disable_syntax",
82
+ ],
83
+ "AllCops" => {
84
+ "DisabledByDefault" => true,
85
+ "TargetRubyVersion" => RUBY_VERSION.split(".")[0..1].join("."),
86
+ "SuggestExtensions" => false,
87
+ "Exclude" => [
88
+ "local-gems/**/*",
89
+ "**/local-gems/**/*",
90
+ "node_modules/**/*",
91
+ "**/node_modules/**/*",
92
+ ],
93
+ },
94
+ }
95
+ class RubocopConfig
96
+ def create_ridiculous_yaml
97
+ if !ARGV[0]
98
+ raise "You must supply the file where the config will be written"
99
+ end
100
+ filename = Pathname(ARGV[0])
101
+ my_big_yaml_hash_of_doom = {}.merge(PREAMBLE)
102
+ IM_NOT_CALLING_THEM_COPS.each do |not_a_cop, config|
103
+ body = case config
104
+ when Hash
105
+ config
106
+ when Array
107
+ config
108
+ when true
109
+ {}
110
+ else
111
+ raise "#{config.class}/#{config} is not handled by this contraption"
112
+ end
113
+ body["Enabled"] = true
114
+ my_big_yaml_hash_of_doom[not_a_cop] = body
115
+ end
116
+ File.open(filename,"w") do |file|
117
+ file.puts "# This file is generated! DO NOT EDIT (not that you'd want to - it's YAML!)"
118
+ file.puts "# The configuration is canonically stored in lib/brut/rubocop_config.rb"
119
+ file.puts my_big_yaml_hash_of_doom.to_yaml
120
+ end
121
+ end
122
+ end
123
+ end
@@ -51,9 +51,6 @@ module Brut::SpecSupport::ComponentSupport
51
51
  # result = generate_and_parse(HeaderComponent.new(title: "Hello!")
52
52
  # expect(result.e!("h1").text).to eq("Hello!")
53
53
  #
54
- # @example Using context
55
- # result = generate_and_parse(TableRow.new([ "one", "two" ]), context: "tbody")
56
- #
57
54
  # @param [Brut::FrontEnd::Component] component the component instance you wish to generate. This should be set up to simulate the test
58
55
  # you are running.
59
56
  # @yield if the component requires or accepts a yielded block, this is how you do that in the test.
@@ -100,10 +100,10 @@ class Brut::SpecSupport::RSpecSetup
100
100
  if needs_request_context
101
101
  session = {
102
102
  "session_id" => "test-session-id",
103
- "csrf" => "test-csrf-token"
103
+ "csrf" => "test-csrf-token",
104
104
  }
105
105
  env = {
106
- "rack.session" => session
106
+ "rack.session" => session,
107
107
  }
108
108
  app_session = Brut.container.session_class.new(rack_session: session)
109
109
  request_context = Brut::FrontEnd::RequestContext.new(
data/lib/brut/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Brut
2
2
  # @!visibility private
3
- VERSION = "0.5.0"
3
+ VERSION = "0.9.0"
4
4
  end
data/mkbrut/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ # AI droppings
2
+ /.cursor
3
+ # Local gem cache
4
+ /local-gems
5
+ # Forever banned from ringside
6
+ /node_modules
7
+
8
+ # Local developer credentials - should not be checked in!
9
+ /dx/credentials
10
+ /dx/build.args
11
+
12
+ # Bundler uses this for locally-built gems.
13
+ /pkg
14
+
15
+ # From hell’s heart I stab at thee; for hate’s sake I spit my last breath at thee.
16
+ .DS_Store
@@ -0,0 +1,100 @@
1
+ Contributor Covenant Code of Conduct
2
+
3
+ Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+ We pledge to act and interact in ways that contribute to an open, welcoming,
12
+ diverse, inclusive, and healthy community.
13
+ Our Standards
14
+ Examples of behavior that contributes to a positive environment for our
15
+ community include:
16
+
17
+ * Demonstrating empathy and kindness toward other people
18
+ * Being respectful of differing opinions, viewpoints, and experiences
19
+ * Giving and gracefully accepting constructive feedback
20
+ * Accepting responsibility and apologizing to those affected by our mistakes,
21
+ and learning from the experience
22
+ * Focusing on what is best not just for us as individuals, but for the overall
23
+ community
24
+
25
+ Examples of unacceptable behavior include:
26
+
27
+ * The use of sexualized language or imagery, and sexual attention or advances of
28
+ any kind
29
+ * Trolling, insulting or derogatory comments, and personal or political attacks
30
+ * Public or private harassment
31
+ * Publishing others’ private information, such as a physical or email address,
32
+ without their explicit permission
33
+ * Other conduct which could reasonably be considered inappropriate in a
34
+ professional setting
35
+
36
+ Enforcement Responsibilities
37
+ Community leaders are responsible for clarifying and enforcing our standards of
38
+ acceptable behavior and will take appropriate and fair corrective action in
39
+ response to any behavior that they deem inappropriate, threatening, offensive,
40
+ or harmful.
41
+ Community leaders have the right and responsibility to remove, edit, or reject
42
+ comments, commits, code, wiki edits, issues, and other contributions that are
43
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
44
+ decisions when appropriate.
45
+ Scope
46
+ This Code of Conduct applies within all community spaces, and also applies when
47
+ an individual is officially representing the community in public spaces.
48
+ Examples of representing our community include using an official email address,
49
+ posting via an official social media account, or acting as an appointed
50
+ representative at an online or offline event.
51
+ Enforcement
52
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
53
+ reported to the community leaders responsible for enforcement at
54
+ abuse@thirdtank.com
55
+
56
+ All complaints will be reviewed and investigated promptly and fairly.
57
+ All community leaders are obligated to respect the privacy and security of the
58
+ reporter of any incident.
59
+ Enforcement Guidelines
60
+ Community leaders will follow these Community Impact Guidelines in determining
61
+ the consequences for any action they deem in violation of this Code of Conduct:
62
+ 1. Correction
63
+ Community Impact: Use of inappropriate language or other behavior deemed
64
+ unprofessional or unwelcome in the community.
65
+ Consequence: A private, written warning from community leaders, providing
66
+ clarity around the nature of the violation and an explanation of why the
67
+ behavior was inappropriate. A public apology may be requested.
68
+ 2. Warning
69
+ Community Impact: A violation through a single incident or series of
70
+ actions.
71
+ Consequence: A warning with consequences for continued behavior. No
72
+ interaction with the people involved, including unsolicited interaction with
73
+ those enforcing the Code of Conduct, for a specified period of time. This
74
+ includes avoiding interactions in community spaces as well as external channels
75
+ like social media. Violating these terms may lead to a temporary or permanent
76
+ ban.
77
+ 3. Temporary Ban
78
+ Community Impact: A serious violation of community standards, including
79
+ sustained inappropriate behavior.
80
+ Consequence: A temporary ban from any sort of interaction or public
81
+ communication with the community for a specified period of time. No public or
82
+ private interaction with the people involved, including unsolicited interaction
83
+ with those enforcing the Code of Conduct, is allowed during this period.
84
+ Violating these terms may lead to a permanent ban.
85
+ 4. Permanent Ban
86
+ Community Impact: Demonstrating a pattern of violation of community
87
+ standards, including sustained inappropriate behavior, harassment of an
88
+ individual, or aggression toward or disparagement of classes of individuals.
89
+ Consequence: A permanent ban from any sort of public interaction within the
90
+ community.
91
+ Attribution
92
+ This Code of Conduct is adapted from the Contributor Covenant,
93
+ version 2.1, available at
94
+ https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
95
+ Community Impact Guidelines were inspired by
96
+ Mozilla’s code of conduct enforcement ladder.
97
+ For answers to common questions about this code of conduct, see the FAQ at
98
+ https://www.contributor-covenant.org/faq. Translations are available at
99
+ https://www.contributor-covenant.org/translations.
100
+
data/mkbrut/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,19 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mkbrut (0.9.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (13.3.0)
10
+
11
+ PLATFORMS
12
+ aarch64-linux
13
+
14
+ DEPENDENCIES
15
+ mkbrut!
16
+ rake
17
+
18
+ BUNDLED WITH
19
+ 2.7.1