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.
Files changed (568) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/CHANGELOG.md +36 -1
  4. data/Dockerfile.dx +19 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +19 -0
  7. data/assets/MetroIcon.graffle +0 -0
  8. data/assets/YouTubeThumb.pxd +0 -0
  9. data/bin/build +86 -0
  10. data/bin/ci +36 -0
  11. data/bin/docs +39 -9
  12. data/bin/publish +61 -0
  13. data/bin/setup +6 -0
  14. data/brut-css/bin/build +19 -0
  15. data/brut-css/bin/ci +19 -0
  16. data/brut-css/bin/docs +19 -0
  17. data/brut-css/bin/publish +21 -0
  18. data/brut-css/bin/setup +1 -0
  19. data/brut-css/package-lock.json +2 -2
  20. data/brut-css/package.json +1 -1
  21. data/brut-css/src/css/flex.css +1 -1
  22. data/brut-css/src/docs/includes/body-and-header.html.ejs +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-js/specs/AjaxSubmit.spec.js +100 -7
  31. data/brut-js/src/AjaxSubmit.js +76 -40
  32. data/brut.gemspec +2 -2
  33. data/brutrb.com/adrs.md +1 -0
  34. data/brutrb.com/bin/setup +1 -0
  35. data/brutrb.com/getting-started.md +3 -0
  36. data/brutrb.com/overview.md +6 -0
  37. data/brutrb.com/tutorial.md +7 -3
  38. data/docs/404.html +2 -2
  39. data/docs/adrs.html +5 -5
  40. data/docs/ai.html +3 -3
  41. data/docs/api/Brut/BackEnd/SeedData.html +1 -1
  42. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +1 -1
  43. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +1 -1
  44. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +1 -1
  45. data/docs/api/Brut/BackEnd/Sidekiq.html +1 -1
  46. data/docs/api/Brut/BackEnd/Validators/FormValidator.html +1 -1
  47. data/docs/api/Brut/BackEnd/Validators.html +1 -1
  48. data/docs/api/Brut/BackEnd.html +1 -1
  49. data/docs/api/Brut/CLI/App.html +1 -1
  50. data/docs/api/Brut/CLI/AppRunner.html +1 -1
  51. data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +1 -1
  52. data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +1 -1
  53. data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +1 -1
  54. data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +1 -1
  55. data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
  56. data/docs/api/Brut/CLI/Apps/DB/Create.html +1 -1
  57. data/docs/api/Brut/CLI/Apps/DB/Drop.html +1 -1
  58. data/docs/api/Brut/CLI/Apps/DB/Migrate.html +1 -1
  59. data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +1 -1
  60. data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +1 -1
  61. data/docs/api/Brut/CLI/Apps/DB/Seed.html +1 -1
  62. data/docs/api/Brut/CLI/Apps/DB/Status.html +1 -1
  63. data/docs/api/Brut/CLI/Apps/DB.html +1 -1
  64. data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +1 -1
  65. data/docs/api/Brut/CLI/Apps/DeployBase.html +1 -1
  66. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +1 -1
  67. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +1 -1
  68. data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
  69. data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +1 -1
  70. data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +1 -1
  71. data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +1 -1
  72. data/docs/api/Brut/CLI/Apps/Scaffold/DbModel.html +2 -2
  73. data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +1 -1
  74. data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +1 -1
  75. data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
  76. data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +1 -1
  77. data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
  78. data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +1 -1
  79. data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
  80. data/docs/api/Brut/CLI/Apps/Test/Audit.html +1 -1
  81. data/docs/api/Brut/CLI/Apps/Test/E2e.html +1 -1
  82. data/docs/api/Brut/CLI/Apps/Test/JS.html +1 -1
  83. data/docs/api/Brut/CLI/Apps/Test/Run.html +1 -1
  84. data/docs/api/Brut/CLI/Apps/Test.html +1 -1
  85. data/docs/api/Brut/CLI/Apps.html +1 -1
  86. data/docs/api/Brut/CLI/Command.html +1 -1
  87. data/docs/api/Brut/CLI/Error.html +1 -1
  88. data/docs/api/Brut/CLI/ExecutionResults/Result.html +1 -1
  89. data/docs/api/Brut/CLI/ExecutionResults.html +1 -1
  90. data/docs/api/Brut/CLI/Executor.html +1 -1
  91. data/docs/api/Brut/CLI/InvalidOption.html +1 -1
  92. data/docs/api/Brut/CLI/Options.html +1 -1
  93. data/docs/api/Brut/CLI/Output.html +1 -1
  94. data/docs/api/Brut/CLI/SystemExecError.html +1 -1
  95. data/docs/api/Brut/CLI.html +1 -1
  96. data/docs/api/Brut/FactoryBot.html +1 -1
  97. data/docs/api/Brut/Framework/App.html +1 -1
  98. data/docs/api/Brut/Framework/Config.html +1 -1
  99. data/docs/api/Brut/Framework/Container.html +1 -1
  100. data/docs/api/Brut/Framework/Error.html +1 -1
  101. data/docs/api/Brut/Framework/Errors/AbstractMethod.html +1 -1
  102. data/docs/api/Brut/Framework/Errors/Bug.html +1 -1
  103. data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +1 -1
  104. data/docs/api/Brut/Framework/Errors/MissingParameter.html +1 -1
  105. data/docs/api/Brut/Framework/Errors/NoClassForPath.html +1 -1
  106. data/docs/api/Brut/Framework/Errors/NotFound.html +1 -1
  107. data/docs/api/Brut/Framework/Errors/NotImplemented.html +1 -1
  108. data/docs/api/Brut/Framework/Errors.html +1 -1
  109. data/docs/api/Brut/Framework/FussyTypeEnforcement.html +1 -1
  110. data/docs/api/Brut/Framework/MCP.html +1 -1
  111. data/docs/api/Brut/Framework/ProjectEnvironment.html +1 -1
  112. data/docs/api/Brut/Framework.html +1 -1
  113. data/docs/api/Brut/FrontEnd/AssetPathResolver.html +1 -1
  114. data/docs/api/Brut/FrontEnd/Component/Helpers.html +86 -2
  115. data/docs/api/Brut/FrontEnd/Component.html +78 -9
  116. data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +3 -3
  117. data/docs/api/Brut/FrontEnd/Components/FormTag.html +3 -3
  118. data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +3 -3
  119. data/docs/api/Brut/FrontEnd/Components/Input.html +3 -3
  120. data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +3 -3
  121. data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +3 -3
  122. data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +3 -3
  123. data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +3 -3
  124. data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +3 -3
  125. data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
  126. data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +3 -3
  127. data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +3 -3
  128. data/docs/api/Brut/FrontEnd/Components/TimeTag.html +3 -3
  129. data/docs/api/Brut/FrontEnd/Components/Traceparent.html +3 -3
  130. data/docs/api/Brut/FrontEnd/Components.html +1 -1
  131. data/docs/api/Brut/FrontEnd/Download.html +1 -1
  132. data/docs/api/Brut/FrontEnd/Flash.html +1 -1
  133. data/docs/api/Brut/FrontEnd/Form.html +1 -1
  134. data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +1 -1
  135. data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +1 -1
  136. data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +1 -1
  137. data/docs/api/Brut/FrontEnd/Forms/Input.html +1 -1
  138. data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +1 -1
  139. data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +1 -1
  140. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +1 -1
  141. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
  142. data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +1 -1
  143. data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
  144. data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +1 -1
  145. data/docs/api/Brut/FrontEnd/Forms.html +1 -1
  146. data/docs/api/Brut/FrontEnd/GenericResponse.html +1 -1
  147. data/docs/api/Brut/FrontEnd/Handler.html +1 -1
  148. data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +1 -1
  149. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +1 -1
  150. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +1 -1
  151. data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +1 -1
  152. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +1 -1
  153. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +1 -1
  154. data/docs/api/Brut/FrontEnd/Handlers.html +1 -1
  155. data/docs/api/Brut/FrontEnd/HandlingResults.html +1 -1
  156. data/docs/api/Brut/FrontEnd/HttpMethod.html +1 -1
  157. data/docs/api/Brut/FrontEnd/HttpStatus.html +1 -1
  158. data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +1 -1
  159. data/docs/api/Brut/FrontEnd/Layout.html +3 -3
  160. data/docs/api/Brut/FrontEnd/Middleware.html +1 -1
  161. data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +1 -1
  162. data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +1 -1
  163. data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +1 -1
  164. data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +1 -1
  165. data/docs/api/Brut/FrontEnd/Middlewares.html +1 -1
  166. data/docs/api/Brut/FrontEnd/Page.html +31 -23
  167. data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +3 -3
  168. data/docs/api/Brut/FrontEnd/Pages.html +1 -1
  169. data/docs/api/Brut/FrontEnd/RequestContext.html +1 -1
  170. data/docs/api/Brut/FrontEnd/RouteHook.html +1 -1
  171. data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +1 -1
  172. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +1 -1
  173. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +1 -1
  174. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +1 -1
  175. data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +1 -1
  176. data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +1 -1
  177. data/docs/api/Brut/FrontEnd/RouteHooks.html +1 -1
  178. data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +1 -1
  179. data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +1 -1
  180. data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +1 -1
  181. data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +1 -1
  182. data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +1 -1
  183. data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +1 -1
  184. data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +1 -1
  185. data/docs/api/Brut/FrontEnd/Routing/Route.html +1 -1
  186. data/docs/api/Brut/FrontEnd/Routing.html +1 -1
  187. data/docs/api/Brut/FrontEnd/Session.html +1 -1
  188. data/docs/api/Brut/FrontEnd.html +1 -1
  189. data/docs/api/Brut/I18n/BaseMethods.html +1 -1
  190. data/docs/api/Brut/I18n/ForBackEnd.html +1 -1
  191. data/docs/api/Brut/I18n/ForCLI.html +1 -1
  192. data/docs/api/Brut/I18n/ForHTML.html +1 -1
  193. data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +1 -1
  194. data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +1 -1
  195. data/docs/api/Brut/I18n.html +1 -1
  196. data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +1 -1
  197. data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +1 -1
  198. data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +1 -1
  199. data/docs/api/Brut/Instrumentation/OpenTelemetry.html +1 -1
  200. data/docs/api/Brut/Instrumentation.html +1 -1
  201. data/docs/api/Brut/SinatraHelpers/ClassMethods.html +13 -11
  202. data/docs/api/Brut/SinatraHelpers.html +1 -1
  203. data/docs/api/Brut/SpecSupport/ClockSupport.html +1 -1
  204. data/docs/api/Brut/SpecSupport/ComponentSupport.html +1 -1
  205. data/docs/api/Brut/SpecSupport/E2ETestServer.html +1 -1
  206. data/docs/api/Brut/SpecSupport/E2eSupport.html +1 -1
  207. data/docs/api/Brut/SpecSupport/EnhancedNode.html +1 -1
  208. data/docs/api/Brut/SpecSupport/FlashSupport.html +1 -1
  209. data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +1 -1
  210. data/docs/api/Brut/SpecSupport/GeneralSupport.html +1 -1
  211. data/docs/api/Brut/SpecSupport/HandlerSupport.html +1 -1
  212. data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +1 -1
  213. data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +1 -1
  214. data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +1 -1
  215. data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +1 -1
  216. data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +1 -1
  217. data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +1 -1
  218. data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +1 -1
  219. data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +1 -1
  220. data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +1 -1
  221. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +1 -1
  222. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +1 -1
  223. data/docs/api/Brut/SpecSupport/Matchers.html +1 -1
  224. data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +1 -1
  225. data/docs/api/Brut/SpecSupport/RSpecSetup.html +1 -1
  226. data/docs/api/Brut/SpecSupport/SessionSupport.html +1 -1
  227. data/docs/api/Brut/SpecSupport.html +1 -1
  228. data/docs/api/Brut.html +1 -1
  229. data/docs/api/Clock.html +1 -1
  230. data/docs/api/ModuleName.html +1 -1
  231. data/docs/api/RichString.html +1 -1
  232. data/docs/api/SemanticLogger/Appender/Async.html +1 -1
  233. data/docs/api/Sequel/Extensions/BrutInstrumentation.html +1 -1
  234. data/docs/api/Sequel/Extensions/BrutMigrations.html +1 -1
  235. data/docs/api/Sequel/Extensions.html +1 -1
  236. data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +1 -1
  237. data/docs/api/Sequel/Plugins/CreatedAt.html +1 -1
  238. data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +1 -1
  239. data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +1 -1
  240. data/docs/api/Sequel/Plugins/ExternalId.html +1 -1
  241. data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +1 -1
  242. data/docs/api/Sequel/Plugins/FindBang.html +1 -1
  243. data/docs/api/Sequel/Plugins.html +1 -1
  244. data/docs/api/Sequel.html +1 -1
  245. data/docs/api/_index.html +1 -1
  246. data/docs/api/file.README.html +1 -1
  247. data/docs/api/index.html +1 -1
  248. data/docs/api/method_list.html +92 -76
  249. data/docs/api/top-level-namespace.html +1 -1
  250. data/docs/assets/{adrs.md.JRxZ5uYE.js → adrs.md.BxjHi9-8.js} +1 -1
  251. data/docs/assets/adrs.md.BxjHi9-8.lean.js +1 -0
  252. data/docs/assets/{app.AkS4fHzI.js → app.DyQLb4Ot.js} +1 -1
  253. data/docs/assets/chunks/@localSearchIndexroot.CmtZyrFA.js +1 -0
  254. data/docs/assets/chunks/{VPLocalSearchBox.By6un1FD.js → VPLocalSearchBox.T1iA-eJx.js} +1 -1
  255. data/docs/assets/chunks/{theme.DwiUPdci.js → theme.ChwsbWjK.js} +2 -2
  256. data/docs/assets/{components.md.BfeWD9sX.js → components.md.DHh-NwKs.js} +3 -3
  257. data/docs/assets/{configuration.md.DoSBNc0H.js → configuration.md.D8Wz3oJU.js} +1 -1
  258. data/docs/assets/{forms.md.DFveP5g_.js → forms.md.BRE85eju.js} +1 -1
  259. data/docs/assets/{getting-started.md.DZWjCVC0.js → getting-started.md.2ioiTe-B.js} +6 -3
  260. data/docs/assets/{getting-started.md.DZWjCVC0.lean.js → getting-started.md.2ioiTe-B.lean.js} +1 -1
  261. data/docs/assets/overview.md.DlKiRRG_.js +1 -0
  262. data/docs/assets/overview.md.DlKiRRG_.lean.js +1 -0
  263. data/docs/assets/tutorial.md.BIb7XT6j.js +1 -0
  264. data/docs/assets/tutorial.md.BIb7XT6j.lean.js +1 -0
  265. data/docs/assets.html +3 -3
  266. data/docs/brut-css/brut.max.css +1 -1
  267. data/docs/brut-css/classes/appearances.html +1 -1
  268. data/docs/brut-css/classes/background-colors.html +1 -1
  269. data/docs/brut-css/classes/border-colors.html +1 -1
  270. data/docs/brut-css/classes/borders.html +1 -1
  271. data/docs/brut-css/classes/dimensions.html +1 -1
  272. data/docs/brut-css/classes/flex.html +3 -3
  273. data/docs/brut-css/classes/foreground-colors.html +1 -1
  274. data/docs/brut-css/classes/junk-drawer.html +1 -1
  275. data/docs/brut-css/classes/layout.html +1 -1
  276. data/docs/brut-css/classes/lists.html +1 -1
  277. data/docs/brut-css/classes/positioning.html +1 -1
  278. data/docs/brut-css/classes/spacings.html +1 -1
  279. data/docs/brut-css/classes/typography.html +1 -1
  280. data/docs/brut-css/customization/advanced-configuration.html +1 -1
  281. data/docs/brut-css/customization/breakpoints.html +1 -1
  282. data/docs/brut-css/customization/design-system.html +1 -1
  283. data/docs/brut-css/customization/pseudo-classes.html +1 -1
  284. data/docs/brut-css/getting-started/core-concepts.html +1 -1
  285. data/docs/brut-css/getting-started/installation.html +1 -1
  286. data/docs/brut-css/getting-started/overview.html +1 -1
  287. data/docs/brut-css/getting-started/simple-example.html +1 -1
  288. data/docs/brut-css/index.html +1 -1
  289. data/docs/brut-css/properties/colors.html +1 -1
  290. data/docs/brut-css/properties/spacings.html +1 -1
  291. data/docs/brut-css/properties/typography.html +1 -1
  292. data/docs/brut-js/api/AjaxSubmit.html +56 -7
  293. data/docs/brut-js/api/AjaxSubmit.js.html +77 -41
  294. data/docs/brut-js/api/Autosubmit.html +1 -1
  295. data/docs/brut-js/api/Autosubmit.js.html +1 -1
  296. data/docs/brut-js/api/BaseCustomElement.html +1 -1
  297. data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
  298. data/docs/brut-js/api/BrutCustomElements.html +1 -1
  299. data/docs/brut-js/api/BufferedLogger.html +1 -1
  300. data/docs/brut-js/api/ConfirmSubmit.html +1 -1
  301. data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
  302. data/docs/brut-js/api/ConfirmationDialog.html +1 -1
  303. data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
  304. data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
  305. data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
  306. data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
  307. data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
  308. data/docs/brut-js/api/CopyToClipboard.html +1 -1
  309. data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
  310. data/docs/brut-js/api/Form.html +1 -1
  311. data/docs/brut-js/api/Form.js.html +1 -1
  312. data/docs/brut-js/api/I18nTranslation.html +1 -1
  313. data/docs/brut-js/api/I18nTranslation.js.html +1 -1
  314. data/docs/brut-js/api/LocaleDetection.html +1 -1
  315. data/docs/brut-js/api/LocaleDetection.js.html +1 -1
  316. data/docs/brut-js/api/Logger.html +1 -1
  317. data/docs/brut-js/api/Logger.js.html +1 -1
  318. data/docs/brut-js/api/Message.html +1 -1
  319. data/docs/brut-js/api/Message.js.html +1 -1
  320. data/docs/brut-js/api/PrefixedLogger.html +1 -1
  321. data/docs/brut-js/api/RichString.html +1 -1
  322. data/docs/brut-js/api/RichString.js.html +1 -1
  323. data/docs/brut-js/api/Tabs.html +1 -1
  324. data/docs/brut-js/api/Tabs.js.html +1 -1
  325. data/docs/brut-js/api/Tracing.html +1 -1
  326. data/docs/brut-js/api/Tracing.js.html +1 -1
  327. data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
  328. data/docs/brut-js/api/external-Performance.html +1 -1
  329. data/docs/brut-js/api/external-Promise.html +1 -1
  330. data/docs/brut-js/api/external-ValidityState.html +1 -1
  331. data/docs/brut-js/api/external-Window.html +1 -1
  332. data/docs/brut-js/api/external-fetch.html +1 -1
  333. data/docs/brut-js/api/global.html +1 -1
  334. data/docs/brut-js/api/index.html +1 -1
  335. data/docs/brut-js/api/index.js.html +1 -1
  336. data/docs/brut-js/api/module-testing.html +1 -1
  337. data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
  338. data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
  339. data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
  340. data/docs/brut-js/api/testing.DOMCreator.html +1 -1
  341. data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
  342. data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
  343. data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
  344. data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
  345. data/docs/brut-js/api/testing_index.js.html +1 -1
  346. data/docs/brut-js.html +3 -3
  347. data/docs/business-logic.html +3 -3
  348. data/docs/cli.html +3 -3
  349. data/docs/components.html +7 -7
  350. data/docs/configuration.html +5 -5
  351. data/docs/css.html +3 -3
  352. data/docs/custom-element-tests.html +3 -3
  353. data/docs/database-access.html +3 -3
  354. data/docs/database-schema.html +3 -3
  355. data/docs/deployment.html +3 -3
  356. data/docs/dev-environment.html +3 -3
  357. data/docs/dir-structure.html +3 -3
  358. data/docs/doc-conventions.html +3 -3
  359. data/docs/end-to-end-tests.html +3 -3
  360. data/docs/features.html +3 -3
  361. data/docs/flash-and-session.html +3 -3
  362. data/docs/form-constraints.html +3 -3
  363. data/docs/forms.html +5 -5
  364. data/docs/getting-started.html +9 -6
  365. data/docs/handlers.html +3 -3
  366. data/docs/hashmap.json +1 -1
  367. data/docs/hooks.html +3 -3
  368. data/docs/i18n.html +3 -3
  369. data/docs/index.html +3 -3
  370. data/docs/instrumentation.html +3 -3
  371. data/docs/javascript.html +3 -3
  372. data/docs/jobs.html +3 -3
  373. data/docs/keyword-injection.html +3 -3
  374. data/docs/layouts.html +3 -3
  375. data/docs/lsp.html +3 -3
  376. data/docs/markdown-examples.html +3 -3
  377. data/docs/middleware.html +3 -3
  378. data/docs/overview.html +5 -5
  379. data/docs/pages.html +3 -3
  380. data/docs/recipes/alternate-layouts.html +3 -3
  381. data/docs/recipes/authentication.html +3 -3
  382. data/docs/recipes/blank-layouts.html +3 -3
  383. data/docs/recipes/custom-flash.html +3 -3
  384. data/docs/recipes/indexed-forms.html +3 -3
  385. data/docs/recipes/migrations.html +3 -3
  386. data/docs/recipes/text-field-component.html +3 -3
  387. data/docs/roadmap.html +3 -3
  388. data/docs/routes.html +3 -3
  389. data/docs/security.html +3 -3
  390. data/docs/seed-data.html +3 -3
  391. data/docs/space-time-continuum.html +3 -3
  392. data/docs/tutorial.html +5 -5
  393. data/docs/unit-tests.html +3 -3
  394. data/docs/why.html +3 -3
  395. data/lib/brut/cli/apps/scaffold.rb +1 -1
  396. data/lib/brut/framework/mcp.rb +1 -1
  397. data/lib/brut/front_end/component.rb +19 -0
  398. data/lib/brut/front_end/components/form_tag.rb +2 -2
  399. data/lib/brut/front_end/page.rb +11 -7
  400. data/lib/brut/sinatra_helpers.rb +1 -0
  401. data/lib/brut/version.rb +1 -1
  402. data/mkbrut/.gitignore +16 -0
  403. data/mkbrut/CODE_OF_CONDUCT.txt +100 -0
  404. data/mkbrut/Gemfile +3 -0
  405. data/mkbrut/Gemfile.lock +19 -0
  406. data/mkbrut/LICENSE.txt +370 -0
  407. data/mkbrut/README.md +145 -0
  408. data/mkbrut/Rakefile +2 -0
  409. data/mkbrut/bin/build +36 -0
  410. data/mkbrut/bin/ci +19 -0
  411. data/mkbrut/bin/docs +19 -0
  412. data/mkbrut/bin/publish +129 -0
  413. data/mkbrut/bin/rake +16 -0
  414. data/mkbrut/bin/setup +30 -0
  415. data/mkbrut/brut-welcome.png +0 -0
  416. data/mkbrut/deploy/.dockerignore +2 -0
  417. data/mkbrut/deploy/Dockerfile +25 -0
  418. data/mkbrut/exe/mkbrut +5 -0
  419. data/mkbrut/lib/mkbrut/app.rb +79 -0
  420. data/mkbrut/lib/mkbrut/app_id.rb +8 -0
  421. data/mkbrut/lib/mkbrut/app_name.rb +29 -0
  422. data/mkbrut/lib/mkbrut/app_options.rb +36 -0
  423. data/mkbrut/lib/mkbrut/base.rb +57 -0
  424. data/mkbrut/lib/mkbrut/cli.rb +107 -0
  425. data/mkbrut/lib/mkbrut/erb_binding_delegate.rb +20 -0
  426. data/mkbrut/lib/mkbrut/internet_identifier.rb +32 -0
  427. data/mkbrut/lib/mkbrut/invalid_identifier.rb +4 -0
  428. data/mkbrut/lib/mkbrut/ops/add_css_import.rb +42 -0
  429. data/mkbrut/lib/mkbrut/ops/add_i18n_message.rb +74 -0
  430. data/mkbrut/lib/mkbrut/ops/add_method.rb +48 -0
  431. data/mkbrut/lib/mkbrut/ops/append_to_file.rb +20 -0
  432. data/mkbrut/lib/mkbrut/ops/base_op.rb +21 -0
  433. data/mkbrut/lib/mkbrut/ops/copy_file.rb +12 -0
  434. data/mkbrut/lib/mkbrut/ops/insert_code_in_method.rb +58 -0
  435. data/mkbrut/lib/mkbrut/ops/insert_route.rb +52 -0
  436. data/mkbrut/lib/mkbrut/ops/mkdir.rb +13 -0
  437. data/mkbrut/lib/mkbrut/ops/prism_parsing_op.rb +70 -0
  438. data/mkbrut/lib/mkbrut/ops/render_template.rb +26 -0
  439. data/mkbrut/lib/mkbrut/ops/skip_file.rb +10 -0
  440. data/mkbrut/lib/mkbrut/ops.rb +16 -0
  441. data/mkbrut/lib/mkbrut/organization.rb +5 -0
  442. data/mkbrut/lib/mkbrut/prefix.rb +26 -0
  443. data/mkbrut/lib/mkbrut/prefixed_io.rb +16 -0
  444. data/mkbrut/lib/mkbrut/segments/bare_bones.rb +185 -0
  445. data/mkbrut/lib/mkbrut/segments/demo.rb +121 -0
  446. data/mkbrut/lib/mkbrut/segments/heroku.rb +30 -0
  447. data/mkbrut/lib/mkbrut/segments/sidekiq.rb +3 -0
  448. data/mkbrut/lib/mkbrut/segments.rb +8 -0
  449. data/mkbrut/lib/mkbrut/version.rb +3 -0
  450. data/mkbrut/lib/mkbrut/versions.rb +13 -0
  451. data/mkbrut/lib/mkbrut.rb +18 -0
  452. data/mkbrut/mkbrut.gemspec +32 -0
  453. data/mkbrut/templates/Base/.dockerignore +25 -0
  454. data/mkbrut/templates/Base/.env.development.erb +60 -0
  455. data/mkbrut/templates/Base/.env.test.erb +8 -0
  456. data/mkbrut/templates/Base/.gitignore +31 -0
  457. data/mkbrut/templates/Base/.projections.json +59 -0
  458. data/mkbrut/templates/Base/Dockerfile.dx +205 -0
  459. data/mkbrut/templates/Base/Gemfile.erb +53 -0
  460. data/mkbrut/templates/Base/Procfile.development +5 -0
  461. data/mkbrut/templates/Base/Procfile.test +1 -0
  462. data/mkbrut/templates/Base/README.md +4 -0
  463. data/mkbrut/templates/Base/README.md.erb +40 -0
  464. data/mkbrut/templates/Base/app/bootstrap.rb +61 -0
  465. data/mkbrut/templates/Base/app/config/i18n/en/1_defaults.rb +128 -0
  466. data/mkbrut/templates/Base/app/config/i18n/en/2_app.rb +24 -0
  467. data/mkbrut/templates/Base/app/public/static/manifest.json.erb +33 -0
  468. data/mkbrut/templates/Base/app/src/app.rb.erb +37 -0
  469. data/mkbrut/templates/Base/app/src/back_end/data_models/app_data_model.rb +5 -0
  470. data/mkbrut/templates/Base/app/src/back_end/data_models/db.rb +19 -0
  471. data/mkbrut/templates/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb +6 -0
  472. data/mkbrut/templates/Base/app/src/back_end/data_models/seed/seed_data.rb +9 -0
  473. data/mkbrut/templates/Base/app/src/front_end/components/app_component.rb +8 -0
  474. data/mkbrut/templates/Base/app/src/front_end/components/custom_element_registration.rb.erb +7 -0
  475. data/mkbrut/templates/Base/app/src/front_end/css/index.css +2 -0
  476. data/mkbrut/templates/Base/app/src/front_end/css/svgs.css +12 -0
  477. data/mkbrut/templates/Base/app/src/front_end/forms/app_form.rb +4 -0
  478. data/mkbrut/templates/Base/app/src/front_end/handlers/app_handler.rb +4 -0
  479. data/mkbrut/templates/Base/app/src/front_end/images/LogoPylon.png +0 -0
  480. data/mkbrut/templates/Base/app/src/front_end/images/LogoTransit.png +0 -0
  481. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-120x120.png +0 -0
  482. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-152x152.png +0 -0
  483. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-167x167.png +0 -0
  484. data/mkbrut/templates/Base/app/src/front_end/images/apple-touch-icon-180x180.png +0 -0
  485. data/mkbrut/templates/Base/app/src/front_end/images/favicon.ico +0 -0
  486. data/mkbrut/templates/Base/app/src/front_end/images/icon.png +0 -0
  487. data/mkbrut/templates/Base/app/src/front_end/images/mkicons.sh +6 -0
  488. data/mkbrut/templates/Base/app/src/front_end/js/index.js +6 -0
  489. data/mkbrut/templates/Base/app/src/front_end/layouts/default_layout.rb.erb +73 -0
  490. data/mkbrut/templates/Base/app/src/front_end/pages/app_page.rb +11 -0
  491. data/mkbrut/templates/Base/app/src/front_end/pages/home_page.rb +62 -0
  492. data/mkbrut/templates/Base/app/src/front_end/support/app_session.rb +6 -0
  493. data/mkbrut/templates/Base/app/src/front_end/svgs/README.md +5 -0
  494. data/mkbrut/templates/Base/app/src/front_end/svgs/comment-button.svg +59 -0
  495. data/mkbrut/templates/Base/bin/README.md.erb +5 -0
  496. data/mkbrut/templates/Base/bin/build-assets +7 -0
  497. data/mkbrut/templates/Base/bin/ci +39 -0
  498. data/mkbrut/templates/Base/bin/console +31 -0
  499. data/mkbrut/templates/Base/bin/db +9 -0
  500. data/mkbrut/templates/Base/bin/dbconsole +51 -0
  501. data/mkbrut/templates/Base/bin/dev +25 -0
  502. data/mkbrut/templates/Base/bin/release +26 -0
  503. data/mkbrut/templates/Base/bin/run +86 -0
  504. data/mkbrut/templates/Base/bin/scaffold +9 -0
  505. data/mkbrut/templates/Base/bin/setup +256 -0
  506. data/mkbrut/templates/Base/bin/startup-message +65 -0
  507. data/mkbrut/templates/Base/bin/test +9 -0
  508. data/mkbrut/templates/Base/bin/test-server +29 -0
  509. data/mkbrut/templates/Base/bin/watch-and-build-assets +37 -0
  510. data/mkbrut/templates/Base/config.ru +16 -0
  511. data/mkbrut/templates/Base/docker-compose.dx.yml +92 -0
  512. data/mkbrut/templates/Base/dx/README.md +28 -0
  513. data/mkbrut/templates/Base/dx/bash_customizations +12 -0
  514. data/mkbrut/templates/Base/dx/bash_customizations.local +8 -0
  515. data/mkbrut/templates/Base/dx/build +107 -0
  516. data/mkbrut/templates/Base/dx/docker-compose.env.erb +25 -0
  517. data/mkbrut/templates/Base/dx/dx.sh.lib +137 -0
  518. data/mkbrut/templates/Base/dx/exec +68 -0
  519. data/mkbrut/templates/Base/dx/prune +19 -0
  520. data/mkbrut/templates/Base/dx/show-help-in-app-container-then-wait.sh +38 -0
  521. data/mkbrut/templates/Base/dx/start +30 -0
  522. data/mkbrut/templates/Base/dx/stop +23 -0
  523. data/mkbrut/templates/Base/package.json.erb +37 -0
  524. data/mkbrut/templates/Base/puma.config.rb +53 -0
  525. data/mkbrut/templates/Base/specs/e2e/home_page.spec.rb.erb +23 -0
  526. data/mkbrut/templates/Base/specs/front_end/js/SpecHelper.js +24 -0
  527. data/mkbrut/templates/Base/specs/front_end/pages/home_page.spec.rb +22 -0
  528. data/mkbrut/templates/Base/specs/lint_factories.spec.rb +7 -0
  529. data/mkbrut/templates/Base/specs/spec_helper.rb +78 -0
  530. data/mkbrut/templates/Base/specs/support.rb +2 -0
  531. data/mkbrut/templates/segments/BareBones/app/src/front_end/handlers/trigger_exception_handler.rb +24 -0
  532. data/mkbrut/templates/segments/BareBones/app/src/front_end/js/Example.js.erb +49 -0
  533. data/mkbrut/templates/segments/BareBones/specs/front_end/handlers/trigger_exception_handler.spec.rb +41 -0
  534. data/mkbrut/templates/segments/BareBones/specs/front_end/js/Example.spec.js.erb +38 -0
  535. data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/db/guestbook_message.rb +3 -0
  536. data/mkbrut/templates/segments/Demo/app/src/back_end/data_models/migrations/20250628194124_guestbook.rb +14 -0
  537. data/mkbrut/templates/segments/Demo/app/src/front_end/components/flash_component.rb +36 -0
  538. data/mkbrut/templates/segments/Demo/app/src/front_end/css/constraint-violations.css +18 -0
  539. data/mkbrut/templates/segments/Demo/app/src/front_end/css/fonts.css +19 -0
  540. data/mkbrut/templates/segments/Demo/app/src/front_end/fonts/monaspace-xenon.ttf +0 -0
  541. data/mkbrut/templates/segments/Demo/app/src/front_end/forms/guestbook_message_form.rb +4 -0
  542. data/mkbrut/templates/segments/Demo/app/src/front_end/handlers/guestbook_message_handler.rb +64 -0
  543. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page/message_component.rb +41 -0
  544. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/guestbook_page.rb +43 -0
  545. data/mkbrut/templates/segments/Demo/app/src/front_end/pages/new_guestbook_message_page.rb +64 -0
  546. data/mkbrut/templates/segments/Demo/specs/back_end/data_models/db/guestbook_message.spec.rb +5 -0
  547. data/mkbrut/templates/segments/Demo/specs/e2e/guest_message.spec.rb +54 -0
  548. data/mkbrut/templates/segments/Demo/specs/factories/db/guestbook_message.factory.rb +7 -0
  549. data/mkbrut/templates/segments/Demo/specs/front_end/components/flash_component.spec.rb +5 -0
  550. data/mkbrut/templates/segments/Demo/specs/front_end/handlers/guestbook_message_handler.spec.rb +122 -0
  551. data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb +5 -0
  552. data/mkbrut/templates/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb +52 -0
  553. data/mkbrut/templates/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb +5 -0
  554. data/mkbrut/templates/segments/Heroku/bin/deploy +11 -0
  555. data/mkbrut/templates/segments/Heroku/deploy/Dockerfile +125 -0
  556. data/mkbrut/templates/segments/Heroku/deploy/docker-entrypoint +15 -0
  557. data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +26 -0
  558. metadata +188 -24
  559. data/brut-js/CHANGELOG.md +0 -5
  560. data/docs/assets/adrs.md.JRxZ5uYE.lean.js +0 -1
  561. data/docs/assets/chunks/@localSearchIndexroot.C9FqcQxD.js +0 -1
  562. data/docs/assets/overview.md.iMnwLO4x.js +0 -1
  563. data/docs/assets/overview.md.iMnwLO4x.lean.js +0 -1
  564. data/docs/assets/tutorial.md.BYXj4cOu.js +0 -1
  565. data/docs/assets/tutorial.md.BYXj4cOu.lean.js +0 -1
  566. /data/docs/assets/{components.md.BfeWD9sX.lean.js → components.md.DHh-NwKs.lean.js} +0 -0
  567. /data/docs/assets/{configuration.md.DoSBNc0H.lean.js → configuration.md.D8Wz3oJU.lean.js} +0 -0
  568. /data/docs/assets/{forms.md.DFveP5g_.lean.js → forms.md.BRE85eju.lean.js} +0 -0
@@ -0,0 +1,205 @@
1
+ # This file is heavily documented to explain what is going on and why.
2
+ # If you are reading this, however, you now own this file and can
3
+ # change it how you like. Just be sure you understand how it works in the
4
+ # context of docker-compose.dx.yml and the files in dx/,
5
+ # which are referred to as the Workspace
6
+ #
7
+ # This file is a set of instructions to build a Docker _image_, which is
8
+ # then use to _start_ a _container_.
9
+
10
+ # This uses a base image where Ruby is already installed. This saves
11
+ # us from having to install Ruby ourselves. Change this whenever you update
12
+ # Ruby. Note that by convention, "3.4" will be whatever the latest point
13
+ # release of Ruby 3.4 is. If you don't want that, specify an exact Ruby version here.
14
+ # Note that this value is intended to be in sync with the tag of the image
15
+ # found in dx/docker-compose.env
16
+ FROM ruby:3.4
17
+
18
+ # This attempts to make RUN directives fail when UNIX pipelines are involved
19
+ SHELL [ "/bin/bash", "-o", "pipefail", "-c" ]
20
+
21
+ # This tells apt-get and friends not to ask for interactive input
22
+ # as this creates massive confusion in the context of building a Docker image.
23
+ ENV DEBIAN_FRONTEND=noninteractive
24
+
25
+ # These packages are needed to set up other repos to install other
26
+ # packages and/or are useful in installing other software
27
+ #
28
+ # - ca-certificates - needed by Postgres client
29
+ # - curl - needed by various installation instructions
30
+ # - gnupg - needed to install Docker
31
+ # - lsb-release - needed by Postgres install instructions
32
+ # - rsync - needed by Brut's build_assets command
33
+ # - vim - needed when we want to edit files inside container
34
+ RUN apt-get -y clean && \
35
+ apt-get -y update && \
36
+ apt-get install --quiet --yes \
37
+ ca-certificates \
38
+ curl \
39
+ gnupg \
40
+ lsb-release \
41
+ rsync \
42
+ vim
43
+
44
+ # These are dependencies needed to install Chromium via Playright.
45
+ # You can check this list via
46
+ #
47
+ # npx playwright install-deps --dry-run chromium
48
+ #
49
+ RUN apt-get install -y --no-install-recommends libasound2 \
50
+ libatk-bridge2.0-0 \
51
+ libatk1.0-0 \
52
+ libatspi2.0-0 \
53
+ libcairo2 \
54
+ libcups2 \
55
+ libdbus-1-3 \
56
+ libdrm2 \
57
+ libgbm1 \
58
+ libglib2.0-0 \
59
+ libnspr4 \
60
+ libnss3 \
61
+ libpango-1.0-0 \
62
+ libx11-6 \
63
+ libxcb1 \
64
+ libxcomposite1 \
65
+ libxdamage1 \
66
+ libxext6 \
67
+ libxfixes3 \
68
+ libxkbcommon0 \
69
+ libxrandr2 \
70
+ xvfb \
71
+ fonts-noto-color-emoji \
72
+ fonts-unifont \
73
+ libfontconfig1 \
74
+ libfreetype6 \
75
+ xfonts-scalable \
76
+ fonts-liberation \
77
+ fonts-ipafont-gothic \
78
+ fonts-wqy-zenhei \
79
+ fonts-tlwg-loma-otf \
80
+ fonts-freefont-ttf
81
+
82
+
83
+ # Install Docker itself. Note that this is installed only what is needed to run
84
+ # the Docker CLI - the docker-compose.dx.yml will connect this docker's socket
85
+ # to the one on the host. This sets up "Docker outside Docker" and
86
+ # is here only to build the production Docker containers and to push
87
+ # them to a repository. This is not intended to run containers from
88
+ # inside this one.
89
+ RUN install -m 0755 -d /etc/apt/keyrings && \
90
+ curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
91
+ chmod a+r /etc/apt/keyrings/docker.gpg && \
92
+ echo \
93
+ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
94
+ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
95
+ tee /etc/apt/sources.list.d/docker.list > /dev/null && \
96
+ apt-get update --quiet --yes && \
97
+ apt-get install --quiet --yes docker-ce \
98
+ docker-ce-cli \
99
+ containerd.io \
100
+ docker-buildx-plugin \
101
+ docker-compose-plugin
102
+
103
+
104
+ # Install Postgres Client, per https://www.postgresql.org/download/linux/debian/
105
+ # Note that ca-certificates and curl are installed above
106
+ #
107
+ # Also note that the version here should match the version set up in
108
+ # docker-compose.dx.yml
109
+ RUN sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
110
+ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
111
+ apt-get update && \
112
+ apt-get -y install postgresql-client-16
113
+
114
+ # Update RubyGems and Bundler, setting RubyGems not to generate
115
+ # documentation as that is slow and you likely won't use it.
116
+ RUN echo "gem: --no-document" >> ~/.gemrc && \
117
+ gem update --system && \
118
+ gem install bundler
119
+
120
+ # Installs the Heroku CLI, per Heroku docs at
121
+ # https://devcenter.heroku.com/articles/heroku-cli#install-with-ubuntu-debian-apt-get
122
+ RUN curl https://cli-assets.heroku.com/install-ubuntu.sh | sh
123
+
124
+ # Up to now, RUN directives ran as the root user. When using this container
125
+ # for development, we do not want to run as the root user. On macOS, this is not
126
+ # a big deal, but in Linux, the root user inside this container can create files
127
+ # as the root user on your computer. You don't want that.
128
+
129
+ # What is tricky is that we ultimately want the non-root user here
130
+ # to have the same UID and same groups as your user on your host/computer.
131
+ # And, we want that user to be able to run Docker commands.
132
+
133
+ # First, set up some build args that `dx/build` will override with the actual values.
134
+ # The reason these all have values is that Docker will not fail if they are omitted,
135
+ # but it will behave strangely.
136
+ #
137
+ # Their user id, which ideally is overridden to match your user id on the host
138
+ ARG user_uid=10001
139
+
140
+ # Their group id, which ideally is overridden to match your group id on the host
141
+ ARG user_gid=10002
142
+
143
+ # The group id that can access /var/run/docker.sock on the host.
144
+ # If this isn't mapped properly, no docker-out-of-docker commands will work
145
+ ARG docker_gid=10003
146
+
147
+ # This can be blank if the OS is such that the user inside the container can access
148
+ # /var/run/docker.sock simply from being in docker_gid. If this is not
149
+ # the case (as on macOS), it is not only sad, but we must add the group
150
+ # 0 (root) to the groups our new user is in.
151
+ ARG sadly_user_must_be_added_to_root=
152
+
153
+ # Create the user's group ID if it does not exist
154
+ RUN getent group ${user_gid} || groupadd --gid ${user_gid} appgroup
155
+
156
+ # Create the docker group id if it does not exist
157
+ RUN getent group ${docker_gid} || groupadd --gid ${docker_gid} hostdocker
158
+
159
+ # Create the user and set up their shell.
160
+ # Note that we put bash_customizations in both .profile and .bashrc
161
+ # to increase the chances they are used when running bash in various configurations
162
+ RUN useradd --uid ${user_uid} --gid ${user_gid} --groups ${sadly_user_must_be_added_to_root}${docker_gid} --create-home --home-dir /home/appuser appuser && \
163
+ echo ". ~/.bash_customizations" >> /home/appuser/.profile && \
164
+ echo ". ~/.bash_customizations.local" >> /home/appuser/.profile && \
165
+ echo ". ~/.bash_customizations" >> /home/appuser/.bashrc && \
166
+ echo ". ~/.bash_customizations.local" >> /home/appuser/.bashrc
167
+
168
+ # Now we must grant ownership to the new user over various files they will need to
169
+ # run or use
170
+ COPY --chown=appuser:${user_gid} dx/show-help-in-app-container-then-wait.sh /home/appuser
171
+ COPY --chown=appuser:${user_gid} dx/bash_customizations /home/appuser/.bash_customizations
172
+ COPY --chown=appuser:${user_gid} dx/bash_customizations.local /home/appuser/.bash_customizations.local
173
+
174
+ # This switches to the new user, meaniung all subsequent RUN directives will
175
+ # be run as this user. The USER directive allows changing both the user
176
+ # and the current group. We are omitting the group part of that because
177
+ # to include would exclude the user from all other groups we just set them up
178
+ # as belonging to.
179
+ USER appuser
180
+
181
+ # Install NodeJS, per https://nodejs.org/en/download
182
+ #
183
+ # Yes, this is seting up nvm just to install one version of node we will ever user in
184
+ # here and yes, this sucks. But it's better to use the vendor's official
185
+ # recommendation.
186
+ RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \
187
+ \. "$HOME/.nvm/nvm.sh" && \
188
+ nvm install 22 && \
189
+ node -v && nvm current && npm -v
190
+
191
+
192
+
193
+ # This arg should have the version of playwright present in the app's Gemfile.lock.
194
+ # This is because the playright NodeJS library and the Ruby gem must have the same
195
+ # version or things won't work right. The value is blank because it really has to be
196
+ # detected during `dx/build`.
197
+ ARG PLAYWRIGHT_VERSION
198
+ # Now install the version of Playwright we detected as well as Chromium. NOTE, we
199
+ # must install Chromium, not chrome, because there is no version of Chrome for an
200
+ # ARM-based Debian linux, which is what this Dockerfile will build on an Apple
201
+ # Silicon Mac.
202
+ RUN \. "$HOME/.nvm/nvm.sh" && \
203
+ nvm use default && \
204
+ npm install -g playwright@$PLAYWRIGHT_VERSION && \
205
+ npx playwright install chromium
@@ -0,0 +1,53 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Gemfile organization:
4
+ #
5
+ # 1. Brut is always at the top
6
+ # 2. The rest of the gems are in alphabetical order
7
+ # 3. Do not specify a gem version unless there is a specific reason.
8
+ # 4. Each gem should have a comment preceding it explaining
9
+ # what the gem is for and why the project needs it.
10
+ # 5. If a version was specified, make sure the comment explains
11
+ # why it had to be specified and the conditions under which it
12
+ # can be removed.
13
+ # 6. Do not create group blocks. Instead, use the group: option for each
14
+ # gem. This creates a single clean list of gems in order.
15
+
16
+ gem "brut", "<%= versions.brut_version_specifier %>"
17
+
18
+ # Audit our dependencies
19
+ gem "bundler-audit", groups: [ :test ]
20
+
21
+ # This allows us to make assertions about test setup that are not themselves tests
22
+ gem "confidence-check", groups: [ :test ]
23
+
24
+ # Dotenv manages the environment variables in the development
25
+ # and test environments. See .env.development, .env.development.local,
26
+ # and .env.test
27
+ gem "dotenv", groups: [ :development, :test ]
28
+
29
+ # FactoryBot manages test and seed data
30
+ gem "factory_bot", groups: [ :development, :test ]
31
+
32
+ # Faker is used to create realistic data for test and seed data.
33
+ gem "faker", groups: [ :development, :test ]
34
+
35
+
36
+ # We use Postgres
37
+ gem "pg"
38
+
39
+ # Allows using Playwright from Ruby.
40
+ # We lock the version because it must be the same as the verison
41
+ # of playwright in package.json. This ensures that we can reliably
42
+ # install the right browsers and that everything will work right.
43
+ gem "playwright-ruby-client", "1.52.0", groups: [ :test ]
44
+
45
+ # Sinatra needs a webserver and puma is the best
46
+ gem "puma"
47
+
48
+ # Uses RSpec for testing
49
+ gem "rspec", groups: [ :test ]
50
+
51
+ # Allows for diagnosing failing tests
52
+ gem "with_clues", groups: [ :test ]
53
+
@@ -0,0 +1,5 @@
1
+ web: PORT=6502 bin/run
2
+ css: bin/watch-and-build-assets css
3
+ js: bin/watch-and-build-assets js
4
+ images: bin/watch-and-build-assets images
5
+ startup_message: PORT=6502 bin/startup-message
@@ -0,0 +1 @@
1
+ web: PORT=6503 bin/run
@@ -0,0 +1,4 @@
1
+ # Workspace
2
+
3
+ The *workspace* is the part of the dev environment that runs directly on the
4
+ developer's machine. It is made up of Bash and Docker.
@@ -0,0 +1,40 @@
1
+ # <%= app_name %>
2
+
3
+ A great new app!
4
+
5
+ ## Setup
6
+
7
+ 1. Clone this repo
8
+ 2. Ensure you have Docker installed
9
+ 3. Build the Foundation of your dev environment:
10
+
11
+ ```
12
+ dx/build
13
+ ```
14
+ 4. Start it up:
15
+
16
+ ```
17
+ dx/start
18
+ ```
19
+ 5. In another terminal, shell into the container you just started:
20
+
21
+ ```
22
+ dx/exec bash
23
+ ```
24
+ 6. Run setup:
25
+
26
+ ```
27
+ dx/setup
28
+ ```
29
+ 7. Start the app:
30
+
31
+ ```
32
+ bin/dev
33
+ ```
34
+
35
+ 8. Visit `http://localhost:6502`
36
+ 9. Now get to work!
37
+
38
+
39
+
40
+
@@ -0,0 +1,61 @@
1
+ # Handles the configuration and startup process for your Brut-powered
2
+ # app and anything that needs its configuration, such as a CLI.
3
+ #
4
+ # This class models three phases:
5
+ #
6
+ # 1. *Initialized* - Ruby is running, but no Brut configuration has happened.
7
+ #
8
+ # ```ruby
9
+ # bootstrap = Bootstrap.new
10
+ # ```
11
+ # 2. *Configured* - Brut's static configuration is set up.
12
+ # See `Brut::Framework::MCP.initialize`.
13
+ #
14
+ # ```ruby
15
+ # configured = bootstrap.configure_only!
16
+ # ```
17
+ #
18
+ # 3. *Bootstrapped* - Everything is set up and configured, services
19
+ # have been connected-to and the app is generally ready to receive
20
+ # requests or have its logic executed.
21
+ #
22
+ # ```ruby
23
+ # booted = configured.bootstrap!
24
+ # ```
25
+ class Bootstrap
26
+
27
+ def configure_only!
28
+ require "bundler"
29
+
30
+ Bundler.require(:default, ENV.fetch("RACK_ENV").to_sym)
31
+
32
+ require "brut"
33
+ require "pathname"
34
+
35
+ Brut.container.store_required_path(
36
+ "project_root",
37
+ "Root of the entire project's source code checkout",
38
+ (Pathname(__dir__) / "..").expand_path)
39
+
40
+
41
+ $: << File.join(Brut.container.project_root,"app","src")
42
+
43
+ require "app"
44
+
45
+ @mcp = Brut::Framework::MCP.new(app_klass: ::App)
46
+ @app = @mcp.app
47
+ self
48
+ end
49
+
50
+ attr_reader :rack_app, :app
51
+
52
+ # @return [Bootstrap::ConfiguredBootstrap] that contains
53
+ # the {Brut::Framework::App} and {Brut::Framework::MCP}.
54
+ def bootstrap!
55
+ self.configure_only!
56
+ @mcp.boot!
57
+ @rack_app = @mcp.sinatra_app.new
58
+ self
59
+ end
60
+
61
+ end
@@ -0,0 +1,128 @@
1
+ # Brut's defaults for various strings required by Brut's internals.
2
+ #
3
+ # You are discouraged from changing this file.
4
+ {
5
+ # en: must be the first entry, thus indicating this is the EN translations
6
+ en: {
7
+ time:{
8
+ formats: { # strftime formats
9
+ iso_8601: "%Y-%m-%d %H:%M:%S.%6N %Z",
10
+ full_with_tz: "%Y-%m-%d %H:%M:%S %Z",
11
+ full: "%Y-%m-%d %H:%M:%S",
12
+ default: "%Y-%m-%d %H:%M:%S",
13
+ date: "%a, %b %e, %Y",
14
+ date_no_dow: "%b %e, %Y",
15
+ date_no_year: "%a, %b %e",
16
+ date_no_year_no_dow: "%b %e",
17
+ month_day_year: "%b %e, %Y",
18
+ month_day_year_no_year: "%b %e",
19
+ day_of_week: "%A",
20
+ time_only: "%l:%M %p",
21
+ },
22
+ am: "AM",
23
+ pm: "PM",
24
+ },
25
+ date: {
26
+ formats: {
27
+ iso_8601: "%Y-%m-%d",
28
+ full: "%Y-%m-%d",
29
+ default: "%a, %b %e, %Y",
30
+ date: "%a, %b %e, %Y",
31
+ date_no_dow: "%b %e, %Y",
32
+ date_no_year: "%a, %b %e",
33
+ date_no_year_no_dow: "%b %e",
34
+ month_day_year: "%b %e, %Y",
35
+ month_day_year_no_year: "%b %e",
36
+ day_of_week: "%A",
37
+ day_of_week_short: "%a",
38
+ time_only: "%l:%M %p",
39
+ },
40
+ abbr_day_names: [
41
+ "Sun",
42
+ "Mon",
43
+ "Tue",
44
+ "Wed",
45
+ "Thu",
46
+ "Fri",
47
+ "Sat",
48
+ ],
49
+ day_names: [
50
+ "Sunday",
51
+ "Monday",
52
+ "Tuesday",
53
+ "Wednesday",
54
+ "Thursday",
55
+ "Friday",
56
+ "Saturday",
57
+ ],
58
+ abbr_month_names: [
59
+ "",
60
+ "Jan",
61
+ "Feb",
62
+ "Mar",
63
+ "Apr",
64
+ "May",
65
+ "Jun",
66
+ "Jul",
67
+ "Aug",
68
+ "Sep",
69
+ "Oct",
70
+ "Nov",
71
+ "Dec",
72
+ ],
73
+ month_names: [
74
+ "",
75
+ "January",
76
+ "February",
77
+ "March",
78
+ "April",
79
+ "May",
80
+ "June",
81
+ "July",
82
+ "August",
83
+ "September",
84
+ "October",
85
+ "November",
86
+ "December",
87
+ ],
88
+ },
89
+ cv: { # short for "constraint violations" to avoid having to type that out
90
+ this_field: "This field",
91
+ cs: { # short for "client-side", again to not have to type it out
92
+ # These keys use camel-case because that is how the browser defines
93
+ # these values, based on ValidityState
94
+ badInput: "%{field} is the wrong type of data",
95
+ patternMismatch: "%{field} isn't in the right format",
96
+ rangeOverflow: "%{field} is too big",
97
+ rangeUnderflow: "%{field} is too small",
98
+ stepMismatch: "%{field} is not a valid value in the range",
99
+ tooLong: "%{field} is too long",
100
+ tooShort: "%{field} is too short",
101
+ typeMismatch: "%{field} is the wrong type",
102
+ valueMissing: "%{field} is required",
103
+ general: "Form is invalid",
104
+ },
105
+ ss: { # short for "server-side", again not to have to type it out
106
+ # These are snake case, which is idiomatic for Ruby. The values
107
+ # here are all based on DataObjectValidator's behavior
108
+ required: "%{field} is required",
109
+ too_short: "%{field} is too short; must be at least %{minlength} characters",
110
+ },
111
+ },
112
+ diagnostics: { # This is to help diagnose issues with the translation system and is not
113
+ # intended to store real strings to be used by your app
114
+ has_interpolations: "Test %{interp} Test",
115
+ has_pluralizations: {
116
+ one: "Once!",
117
+ other: "More than once!"
118
+ },
119
+ has_pluralizations_and_zero: {
120
+ zero: "ZERO",
121
+ one: "ONE",
122
+ other: "MORE",
123
+ },
124
+ simple1: "SIMPLE1",
125
+ simple2: "SIMPLE2",
126
+ }
127
+ },
128
+ }
@@ -0,0 +1,24 @@
1
+ # All app-specific translations, or overrides of Brut's defaults, go here.
2
+ {
3
+ # en: must be the first entry, thus indicating this is the EN translations
4
+ en: {
5
+ cv: {
6
+ cs: {
7
+ },
8
+ ss: {
9
+ email_taken: "This email has been taken",
10
+ },
11
+ },
12
+ pages: { # Page-specific messages - this key is relied-upon by Brut to exist
13
+ HomePage: {
14
+ title: "Welcome!",
15
+ }
16
+ },
17
+ components: { # Component-specific messages - this key is relied-upon by Brut to exist
18
+ },
19
+ clis: { # Messages used in CLIs - this key is relied-upon by Brut to exist
20
+ },
21
+ hello: "Hello, and welcome to Brut!",
22
+ # Other keys can go here and you can organize them however you like.
23
+ },
24
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "<%= app_name %>",
3
+ "short_name": "<%= app_name %>",
4
+ "description": "The <%= app_name %> App",
5
+ "start_url": "/",
6
+ "scope": "/",
7
+ "display": "standalone",
8
+ "theme_color": "#A70C00",
9
+ "icons": [
10
+ {
11
+ "src": "/static/images/icon.png"
12
+ },
13
+ {
14
+ "src": "/static/images/apple-touch-icon-120x120.png",
15
+ "sizes": "120x120"
16
+ },
17
+ {
18
+ "src": "/static/images/apple-touch-icon-152x152.png",
19
+ "sizes": "152x152"
20
+ },
21
+ {
22
+ "src": "/static/images/apple-touch-icon-167x167.png",
23
+ "sizes": "167x167"
24
+ },
25
+ {
26
+ "src": "/static/images/apple-touch-icon-180x180.png",
27
+ "sizes": "180x180"
28
+ }
29
+ ]
30
+ }
31
+
32
+
33
+
@@ -0,0 +1,37 @@
1
+ class App < Brut::Framework::App
2
+ def id = "<%= app_id %>"
3
+ def organization = "<%= organization %>"
4
+
5
+ def initialize
6
+ # Add additional initialization to this initializers.
7
+ # Be sure to use the lazy/block form of store because when this code
8
+ # runs, the app may not have access to networked resources.
9
+ Brut.container.override("session_class",AppSession)
10
+ Brut.container.override("external_id_prefix","<%= prefix %>")
11
+ end
12
+
13
+ def boot!
14
+ # Perform any additional bootstrapping here, such as configuration of
15
+ # job back-ends or other data stores. When this runs, you can be sure
16
+ # the app has access to networked resources
17
+ end
18
+
19
+ # Various class methods may be called here to configure your app. See the API
20
+ # documentation for Brut::Framework::App.
21
+
22
+ # Generic error handler. Is expected to return a Rack response.
23
+ error do |exception:, http_status_code:|
24
+ SemanticLogger["App"].error(exception || "Unknown error", http_status_code:)
25
+ [
26
+ http_status_code || 500,
27
+ {},
28
+ exception&.message || "Internal Server Error '#{http_status_code}'"
29
+ ]
30
+ end
31
+
32
+ # Declare your app's routes.
33
+ routes do
34
+ page "/" # Special route for HomePage
35
+ end
36
+ end
37
+
@@ -0,0 +1,5 @@
1
+ AppDataModel = Class.new(Sequel::Model)
2
+ # Base class for all your data models
3
+ class AppDataModel
4
+ end
5
+
@@ -0,0 +1,19 @@
1
+ # Namespace for all data models. This makes it easy
2
+ # to avoid the conflation of database table models from
3
+ # domain models.
4
+ module DB
5
+ # Execute the code in the block in a database transaction.
6
+ # This calls `Sequel::Model.db.transaction`, which is ultimately
7
+ # `Sequel::Database#transaction`. Please review that documentation as well
8
+ # as the documentation of your databnase so you understand
9
+ # how transactions work.
10
+ #
11
+ # @see https://rubydoc.info/gems/sequel/5.93.0/Sequel/Database#transaction-instance_method
12
+ def self.transaction(opts=:use_default,&block)
13
+ if opts == :use_default
14
+ opts = Sequel::Database::OPTS
15
+ end
16
+ Sequel::Model.db.transaction(opts,&block)
17
+ end
18
+ end
19
+
@@ -0,0 +1,6 @@
1
+ Sequel.migration do
2
+ up do
3
+ run %{CREATE EXTENSION IF NOT EXISTS citext}
4
+ end
5
+ end
6
+
@@ -0,0 +1,9 @@
1
+ require "brut/back_end/seed_data"
2
+ class SeedData < Brut::BackEnd::SeedData
3
+ include FactoryBot::Syntax::Methods
4
+ def seed!
5
+ # Create records here. This method is not expected
6
+ # to be idempotent. You can (and should) use your
7
+ # FactoryBot factories here.
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ # Base class for your app's components.
2
+ class AppComponent < Brut::FrontEnd::Component
3
+ include Brut::Framework::Errors # provides access to methods in this module
4
+ include Brut::FrontEnd::Components # Allows Brut-provided components to be
5
+ # used as a Phlex "kit"
6
+ include CustomElementRegistration
7
+ end
8
+
@@ -0,0 +1,7 @@
1
+ # Registers your app's autnomous custom elements
2
+ # with Phlex, so you can use them like normal HTML elements.
3
+ module CustomElementRegistration
4
+ def self.included(other)
5
+ other.register_element :<%= prefix %>_example
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ @import "brut-css/dist/brut.css";
2
+ @import "svgs.css";