brut 0.0.28 → 0.1.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 (532) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.projections.json +10 -0
  4. data/.rspec +3 -0
  5. data/Dockerfile.dx +32 -14
  6. data/Gemfile.lock +1 -1
  7. data/README.md +23 -2
  8. data/assets/Logo-Square.pxd +0 -0
  9. data/assets/LogoPylon.pxd +0 -0
  10. data/assets/LogoStop.pxd +0 -0
  11. data/assets/LogoTall.pxd +0 -0
  12. data/assets/MetroLogo.graffle +0 -0
  13. data/assets/SocialImage.png +0 -0
  14. data/assets/SocialImage.pxd +0 -0
  15. data/bin/docs +24 -2
  16. data/bin/rspec +27 -0
  17. data/bin/setup +3 -3
  18. data/brutrb.com/.vitepress/config.mjs +45 -8
  19. data/brutrb.com/.vitepress/theme/custom.css +7 -0
  20. data/brutrb.com/.vitepress/theme/style.css +29 -17
  21. data/brutrb.com/ai.md +10 -15
  22. data/brutrb.com/assets.md +2 -9
  23. data/brutrb.com/brut-js.md +12 -2
  24. data/brutrb.com/cli.md +9 -13
  25. data/brutrb.com/components.md +118 -96
  26. data/brutrb.com/configuration.md +3 -4
  27. data/brutrb.com/css.md +2 -2
  28. data/brutrb.com/custom-element-tests.md +3 -4
  29. data/brutrb.com/database-access.md +1 -1
  30. data/brutrb.com/database-schema.md +29 -41
  31. data/brutrb.com/deployment.md +123 -45
  32. data/brutrb.com/dev-environment.md +7 -7
  33. data/brutrb.com/dir-structure.md +120 -0
  34. data/brutrb.com/doc-conventions.md +18 -15
  35. data/brutrb.com/dx +1 -0
  36. data/brutrb.com/end-to-end-tests.md +12 -10
  37. data/brutrb.com/features.md +373 -0
  38. data/brutrb.com/flash-and-session.md +115 -131
  39. data/brutrb.com/form-constraints.md +266 -0
  40. data/brutrb.com/forms.md +140 -765
  41. data/brutrb.com/getting-started.md +10 -11
  42. data/brutrb.com/handlers.md +119 -95
  43. data/brutrb.com/hooks.md +18 -20
  44. data/brutrb.com/i18n.md +6 -4
  45. data/brutrb.com/images/LogoPylon.png +0 -0
  46. data/brutrb.com/images/LogoSquare.png +0 -0
  47. data/brutrb.com/images/LogoStop.png +0 -0
  48. data/brutrb.com/images/LogoTall.png +0 -0
  49. data/brutrb.com/images/OverviewMetro.graffle +0 -0
  50. data/brutrb.com/images/OverviewMetro.png +0 -0
  51. data/brutrb.com/index.md +4 -3
  52. data/brutrb.com/instrumentation.md +7 -10
  53. data/brutrb.com/javascript.md +14 -14
  54. data/brutrb.com/keyword-injection.md +72 -114
  55. data/brutrb.com/layouts.md +20 -52
  56. data/brutrb.com/lsp.md +1 -1
  57. data/brutrb.com/overview.md +35 -377
  58. data/brutrb.com/pages.md +119 -207
  59. data/brutrb.com/public/SocialImage.png +0 -0
  60. data/brutrb.com/public/favicon.ico +0 -0
  61. data/brutrb.com/recipes/alternate-layouts.md +32 -0
  62. data/brutrb.com/recipes/authentication.md +315 -6
  63. data/brutrb.com/recipes/blank-layouts.md +22 -0
  64. data/brutrb.com/recipes/custom-flash.md +51 -0
  65. data/brutrb.com/recipes/indexed-forms.md +149 -0
  66. data/brutrb.com/recipes/text-field-component.md +182 -0
  67. data/brutrb.com/routes.md +56 -82
  68. data/brutrb.com/security.md +0 -3
  69. data/brutrb.com/space-time-continuum.md +8 -12
  70. data/brutrb.com/tutorial.md +1 -1
  71. data/brutrb.com/why.md +19 -0
  72. data/docker-compose.dx.yml +5 -2
  73. data/docs/404.html +8 -3
  74. data/docs/SocialImage.png +0 -0
  75. data/docs/ai.html +11 -6
  76. data/docs/api/Brut/BackEnd/SeedData.html +1 -1
  77. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +1 -1
  78. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +1 -1
  79. data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +1 -1
  80. data/docs/api/Brut/BackEnd/Sidekiq.html +1 -1
  81. data/docs/api/Brut/BackEnd/Validators/FormValidator.html +1 -1
  82. data/docs/api/Brut/BackEnd/Validators.html +1 -1
  83. data/docs/api/Brut/BackEnd.html +1 -1
  84. data/docs/api/Brut/CLI/App.html +1 -1
  85. data/docs/api/Brut/CLI/AppRunner.html +1 -1
  86. data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +1 -1
  87. data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +1 -1
  88. data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +1 -1
  89. data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +1 -1
  90. data/docs/api/Brut/CLI/Apps/BuildAssets.html +1 -1
  91. data/docs/api/Brut/CLI/Apps/DB/Create.html +1 -1
  92. data/docs/api/Brut/CLI/Apps/DB/Drop.html +1 -1
  93. data/docs/api/Brut/CLI/Apps/DB/Migrate.html +1 -1
  94. data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +1 -1
  95. data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +1 -1
  96. data/docs/api/Brut/CLI/Apps/DB/Seed.html +1 -1
  97. data/docs/api/Brut/CLI/Apps/DB/Status.html +1 -1
  98. data/docs/api/Brut/CLI/Apps/DB.html +1 -1
  99. data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +1 -1
  100. data/docs/api/Brut/CLI/Apps/DeployBase.html +1 -1
  101. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +1 -1
  102. data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +1 -1
  103. data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +1 -1
  104. data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +1 -1
  105. data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +1 -1
  106. data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +1 -1
  107. data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +1 -1
  108. data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +1 -1
  109. data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +1 -1
  110. data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +1 -1
  111. data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +1 -1
  112. data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +1 -1
  113. data/docs/api/Brut/CLI/Apps/Scaffold.html +1 -1
  114. data/docs/api/Brut/CLI/Apps/Test/Audit.html +1 -1
  115. data/docs/api/Brut/CLI/Apps/Test/E2e.html +1 -1
  116. data/docs/api/Brut/CLI/Apps/Test/JS.html +1 -1
  117. data/docs/api/Brut/CLI/Apps/Test/Run.html +1 -1
  118. data/docs/api/Brut/CLI/Apps/Test.html +1 -1
  119. data/docs/api/Brut/CLI/Apps.html +1 -1
  120. data/docs/api/Brut/CLI/Command.html +1 -1
  121. data/docs/api/Brut/CLI/Error.html +1 -1
  122. data/docs/api/Brut/CLI/ExecutionResults/Result.html +1 -1
  123. data/docs/api/Brut/CLI/ExecutionResults.html +1 -1
  124. data/docs/api/Brut/CLI/Executor.html +1 -1
  125. data/docs/api/Brut/CLI/InvalidOption.html +1 -1
  126. data/docs/api/Brut/CLI/Options.html +1 -1
  127. data/docs/api/Brut/CLI/Output.html +1 -1
  128. data/docs/api/Brut/CLI/SystemExecError.html +1 -1
  129. data/docs/api/Brut/CLI.html +1 -1
  130. data/docs/api/Brut/FactoryBot.html +1 -1
  131. data/docs/api/Brut/Framework/App.html +1 -1
  132. data/docs/api/Brut/Framework/Config.html +1 -1
  133. data/docs/api/Brut/Framework/Container.html +1 -1
  134. data/docs/api/Brut/Framework/Error.html +1 -1
  135. data/docs/api/Brut/Framework/Errors/AbstractMethod.html +1 -1
  136. data/docs/api/Brut/Framework/Errors/Bug.html +1 -1
  137. data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +1 -1
  138. data/docs/api/Brut/Framework/Errors/MissingParameter.html +1 -1
  139. data/docs/api/Brut/Framework/Errors/NoClassForPath.html +1 -1
  140. data/docs/api/Brut/Framework/Errors/NotFound.html +1 -1
  141. data/docs/api/Brut/Framework/Errors/NotImplemented.html +1 -1
  142. data/docs/api/Brut/Framework/Errors.html +1 -1
  143. data/docs/api/Brut/Framework/FussyTypeEnforcement.html +1 -1
  144. data/docs/api/Brut/Framework/MCP.html +1 -1
  145. data/docs/api/Brut/Framework/ProjectEnvironment.html +1 -1
  146. data/docs/api/Brut/Framework.html +1 -1
  147. data/docs/api/Brut/FrontEnd/AssetPathResolver.html +1 -1
  148. data/docs/api/Brut/FrontEnd/Component/Helpers.html +1 -1
  149. data/docs/api/Brut/FrontEnd/Component.html +1 -1
  150. data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +1 -1
  151. data/docs/api/Brut/FrontEnd/Components/FormTag.html +1 -1
  152. data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +1 -1
  153. data/docs/api/Brut/FrontEnd/Components/Input.html +1 -1
  154. data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +1 -1
  155. data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +1 -1
  156. data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +1 -1
  157. data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +1 -1
  158. data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +1 -1
  159. data/docs/api/Brut/FrontEnd/Components/Inputs.html +1 -1
  160. data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +1 -1
  161. data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +1 -1
  162. data/docs/api/Brut/FrontEnd/Components/TimeTag.html +1 -1
  163. data/docs/api/Brut/FrontEnd/Components/Traceparent.html +1 -1
  164. data/docs/api/Brut/FrontEnd/Components.html +1 -1
  165. data/docs/api/Brut/FrontEnd/Download.html +1 -1
  166. data/docs/api/Brut/FrontEnd/Flash.html +1 -1
  167. data/docs/api/Brut/FrontEnd/Form.html +9 -11
  168. data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +1 -1
  169. data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +201 -0
  170. data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +535 -0
  171. data/docs/api/Brut/FrontEnd/Forms/Input.html +983 -35
  172. data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +1 -1
  173. data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +29 -19
  174. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +141 -20
  175. data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +1 -1
  176. data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +141 -20
  177. data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +1 -1
  178. data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +1 -1
  179. data/docs/api/Brut/FrontEnd/Forms.html +1 -1
  180. data/docs/api/Brut/FrontEnd/GenericResponse.html +1 -1
  181. data/docs/api/Brut/FrontEnd/Handler.html +1 -1
  182. data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +1 -1
  183. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +1 -1
  184. data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +1 -1
  185. data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +1 -1
  186. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +1 -1
  187. data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +1 -1
  188. data/docs/api/Brut/FrontEnd/Handlers.html +1 -1
  189. data/docs/api/Brut/FrontEnd/HandlingResults.html +1 -1
  190. data/docs/api/Brut/FrontEnd/HttpMethod.html +1 -1
  191. data/docs/api/Brut/FrontEnd/HttpStatus.html +1 -1
  192. data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +1 -1
  193. data/docs/api/Brut/FrontEnd/Layout.html +1 -1
  194. data/docs/api/Brut/FrontEnd/Middleware.html +1 -1
  195. data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +1 -1
  196. data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +1 -1
  197. data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +1 -1
  198. data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +1 -1
  199. data/docs/api/Brut/FrontEnd/Middlewares.html +1 -1
  200. data/docs/api/Brut/FrontEnd/Page.html +1 -1
  201. data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +1 -1
  202. data/docs/api/Brut/FrontEnd/Pages.html +1 -1
  203. data/docs/api/Brut/FrontEnd/RequestContext.html +1 -1
  204. data/docs/api/Brut/FrontEnd/RouteHook.html +1 -1
  205. data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +1 -1
  206. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +1 -1
  207. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +1 -1
  208. data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +1 -1
  209. data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +1 -1
  210. data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +1 -1
  211. data/docs/api/Brut/FrontEnd/RouteHooks.html +1 -1
  212. data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +1 -1
  213. data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +1 -1
  214. data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +1 -1
  215. data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +1 -1
  216. data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +1 -1
  217. data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +1 -1
  218. data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +1 -1
  219. data/docs/api/Brut/FrontEnd/Routing/Route.html +1 -1
  220. data/docs/api/Brut/FrontEnd/Routing.html +1 -1
  221. data/docs/api/Brut/FrontEnd/Session.html +1 -1
  222. data/docs/api/Brut/FrontEnd.html +1 -1
  223. data/docs/api/Brut/I18n/BaseMethods.html +1 -1
  224. data/docs/api/Brut/I18n/ForBackEnd.html +1 -1
  225. data/docs/api/Brut/I18n/ForCLI.html +1 -1
  226. data/docs/api/Brut/I18n/ForHTML.html +1 -1
  227. data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +1 -1
  228. data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +1 -1
  229. data/docs/api/Brut/I18n.html +1 -1
  230. data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +1 -1
  231. data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +1 -1
  232. data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +1 -1
  233. data/docs/api/Brut/Instrumentation/OpenTelemetry.html +1 -1
  234. data/docs/api/Brut/Instrumentation.html +1 -1
  235. data/docs/api/Brut/SinatraHelpers/ClassMethods.html +1 -1
  236. data/docs/api/Brut/SinatraHelpers.html +1 -1
  237. data/docs/api/Brut/SpecSupport/ClockSupport.html +1 -1
  238. data/docs/api/Brut/SpecSupport/ComponentSupport.html +1 -1
  239. data/docs/api/Brut/SpecSupport/E2ETestServer.html +1 -1
  240. data/docs/api/Brut/SpecSupport/E2eSupport.html +1 -1
  241. data/docs/api/Brut/SpecSupport/EnhancedNode.html +1 -1
  242. data/docs/api/Brut/SpecSupport/FlashSupport.html +1 -1
  243. data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +1 -1
  244. data/docs/api/Brut/SpecSupport/GeneralSupport.html +1 -1
  245. data/docs/api/Brut/SpecSupport/HandlerSupport.html +1 -1
  246. data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +1 -1
  247. data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +1 -1
  248. data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +1 -1
  249. data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +1 -1
  250. data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +1 -1
  251. data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +1 -1
  252. data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +1 -1
  253. data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +1 -1
  254. data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +1 -1
  255. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +1 -1
  256. data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +1 -1
  257. data/docs/api/Brut/SpecSupport/Matchers.html +1 -1
  258. data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +1 -1
  259. data/docs/api/Brut/SpecSupport/RSpecSetup.html +1 -1
  260. data/docs/api/Brut/SpecSupport/SessionSupport.html +1 -1
  261. data/docs/api/Brut/SpecSupport.html +1 -1
  262. data/docs/api/Brut.html +1 -1
  263. data/docs/api/Clock.html +1 -1
  264. data/docs/api/RichString.html +1 -1
  265. data/docs/api/SemanticLogger/Appender/Async.html +1 -1
  266. data/docs/api/Sequel/Extensions/BrutInstrumentation.html +1 -1
  267. data/docs/api/Sequel/Extensions/BrutMigrations.html +1 -1
  268. data/docs/api/Sequel/Extensions.html +1 -1
  269. data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +1 -1
  270. data/docs/api/Sequel/Plugins/CreatedAt.html +1 -1
  271. data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +1 -1
  272. data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +1 -1
  273. data/docs/api/Sequel/Plugins/ExternalId.html +1 -1
  274. data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +1 -1
  275. data/docs/api/Sequel/Plugins/FindBang.html +1 -1
  276. data/docs/api/Sequel/Plugins.html +1 -1
  277. data/docs/api/Sequel.html +1 -1
  278. data/docs/api/_index.html +15 -1
  279. data/docs/api/class_list.html +1 -1
  280. data/docs/api/css/full_list.css +2 -1
  281. data/docs/api/css/style.css +14 -13
  282. data/docs/api/file.README.html +22 -3
  283. data/docs/api/index.html +22 -3
  284. data/docs/api/method_list.html +435 -275
  285. data/docs/api/top-level-namespace.html +1 -1
  286. data/docs/assets/LogoStop.Gb3tDhL1.png +0 -0
  287. data/docs/assets/OverviewMetro.DUS-5fUZ.png +0 -0
  288. data/docs/assets/{ai.md._6HCDL6d.js → ai.md.Cy9GWnER.js} +1 -1
  289. data/docs/assets/ai.md.Cy9GWnER.lean.js +1 -0
  290. data/docs/assets/{app.BX81XO4N.js → app.ClaS47Ru.js} +1 -1
  291. data/docs/assets/{assets.md.D3wunzLx.js → assets.md.7C3HWkga.js} +3 -3
  292. data/docs/assets/{assets.md.D3wunzLx.lean.js → assets.md.7C3HWkga.lean.js} +1 -1
  293. data/docs/assets/{brut-js.md.o2DAO2s2.js → brut-js.md.B4GYxQVw.js} +1 -1
  294. data/docs/assets/{brut-js.md.o2DAO2s2.lean.js → brut-js.md.B4GYxQVw.lean.js} +1 -1
  295. data/docs/assets/chunks/@localSearchIndexroot.Biqy1A4t.js +1 -0
  296. data/docs/assets/chunks/{VPLocalSearchBox.gABXcTWp.js → VPLocalSearchBox.DtgDfde2.js} +1 -1
  297. data/docs/assets/chunks/{theme.DwUXXAL3.js → theme.B45bvibT.js} +2 -2
  298. data/docs/assets/{cli.md.RmeA2b0i.js → cli.md.CjsktgFz.js} +15 -20
  299. data/docs/assets/components.md.DatoNgFo.js +96 -0
  300. data/docs/assets/{components.md.CRUMdRoN.lean.js → components.md.DatoNgFo.lean.js} +1 -1
  301. data/docs/assets/{configuration.md.BGHl8oRC.js → configuration.md.DeyhpqEx.js} +3 -3
  302. data/docs/assets/{css.md.DJgj2clw.js → css.md.CltvJqAa.js} +3 -3
  303. data/docs/assets/{custom-element-tests.md.BrYJQEl3.js → custom-element-tests.md.B_rbta32.js} +3 -3
  304. data/docs/assets/{database-access.md.C7l-Vuvb.js → database-access.md.gnluu54N.js} +1 -1
  305. data/docs/assets/{database-schema.md.BUjR0VS1.js → database-schema.md.CSYk6E6v.js} +6 -6
  306. data/docs/assets/{database-schema.md.BUjR0VS1.lean.js → database-schema.md.CSYk6E6v.lean.js} +1 -1
  307. data/docs/assets/deployment.md.BLseERGV.js +48 -0
  308. data/docs/assets/deployment.md.BLseERGV.lean.js +1 -0
  309. data/docs/assets/dev-environment.md.BroAOLhF.js +11 -0
  310. data/docs/assets/dir-structure.md.CWir1pic.js +46 -0
  311. data/docs/assets/dir-structure.md.CWir1pic.lean.js +1 -0
  312. data/docs/assets/doc-conventions.md.BzmSrTEW.js +1 -0
  313. data/docs/assets/doc-conventions.md.BzmSrTEW.lean.js +1 -0
  314. data/docs/assets/{end-to-end-tests.md.yfQHC0b5.js → end-to-end-tests.md.DzqRpZ43.js} +5 -3
  315. data/docs/assets/end-to-end-tests.md.DzqRpZ43.lean.js +1 -0
  316. data/docs/assets/features.md.DPFXsy0z.js +154 -0
  317. data/docs/assets/features.md.DPFXsy0z.lean.js +1 -0
  318. data/docs/assets/flash-and-session.md.nPvUpnUx.js +79 -0
  319. data/docs/assets/{flash-and-session.md.BXY8RvT0.lean.js → flash-and-session.md.nPvUpnUx.lean.js} +1 -1
  320. data/docs/assets/form-constraints.md.x5tNpTTI.js +90 -0
  321. data/docs/assets/form-constraints.md.x5tNpTTI.lean.js +1 -0
  322. data/docs/assets/forms.md.C2Dizvzq.js +64 -0
  323. data/docs/assets/forms.md.C2Dizvzq.lean.js +1 -0
  324. data/docs/assets/{getting-started.md.Ciz82L0m.js → getting-started.md.C93e0odB.js} +5 -5
  325. data/docs/assets/{getting-started.md.Ciz82L0m.lean.js → getting-started.md.C93e0odB.lean.js} +1 -1
  326. data/docs/assets/handlers.md.Chyri6KA.js +54 -0
  327. data/docs/assets/handlers.md.Chyri6KA.lean.js +1 -0
  328. data/docs/assets/{hooks.md.C4-moMny.js → hooks.md.Jmb5VOLA.js} +4 -4
  329. data/docs/assets/{hooks.md.C4-moMny.lean.js → hooks.md.Jmb5VOLA.lean.js} +1 -1
  330. data/docs/assets/{i18n.md.Do9i1qWl.js → i18n.md.xQhiGo1G.js} +2 -2
  331. data/docs/assets/{i18n.md.Do9i1qWl.lean.js → i18n.md.xQhiGo1G.lean.js} +1 -1
  332. data/docs/assets/index.md.CAMqGBJE.js +1 -0
  333. data/docs/assets/index.md.CAMqGBJE.lean.js +1 -0
  334. data/docs/assets/{instrumentation.md.a9Pjps4P.js → instrumentation.md.BgcaGVYH.js} +2 -2
  335. data/docs/assets/{instrumentation.md.a9Pjps4P.lean.js → instrumentation.md.BgcaGVYH.lean.js} +1 -1
  336. data/docs/assets/{javascript.md.GWbhRS51.js → javascript.md.DzrMxUmI.js} +7 -7
  337. data/docs/assets/{javascript.md.GWbhRS51.lean.js → javascript.md.DzrMxUmI.lean.js} +1 -1
  338. data/docs/assets/keyword-injection.md.95Zgh2eN.js +21 -0
  339. data/docs/assets/{keyword-injection.md.Dt2tKREs.lean.js → keyword-injection.md.95Zgh2eN.lean.js} +1 -1
  340. data/docs/assets/{layouts.md.cPnh3NId.js → layouts.md.CJGDFY-m.js} +2 -15
  341. data/docs/assets/layouts.md.CJGDFY-m.lean.js +1 -0
  342. data/docs/assets/{lsp.md.Bsu-f6VU.js → lsp.md.Dn1rIiW0.js} +1 -1
  343. data/docs/assets/{lsp.md.Bsu-f6VU.lean.js → lsp.md.Dn1rIiW0.lean.js} +1 -1
  344. data/docs/assets/overview.md.Bdq4qt3L.js +1 -0
  345. data/docs/assets/overview.md.Bdq4qt3L.lean.js +1 -0
  346. data/docs/assets/pages.md.B7Hc-i6H.js +45 -0
  347. data/docs/assets/pages.md.B7Hc-i6H.lean.js +1 -0
  348. data/docs/assets/recipes_alternate-layouts.md.BwEytl59.js +22 -0
  349. data/docs/assets/recipes_alternate-layouts.md.BwEytl59.lean.js +1 -0
  350. data/docs/assets/recipes_authentication.md.Dzvi_g69.js +156 -0
  351. data/docs/assets/recipes_authentication.md.Dzvi_g69.lean.js +1 -0
  352. data/docs/assets/recipes_blank-layouts.md.fyAUJyJR.js +15 -0
  353. data/docs/assets/recipes_blank-layouts.md.fyAUJyJR.lean.js +1 -0
  354. data/docs/assets/recipes_custom-flash.md.CrQbI5eH.js +26 -0
  355. data/docs/assets/recipes_custom-flash.md.CrQbI5eH.lean.js +1 -0
  356. data/docs/assets/recipes_indexed-forms.md.CstYyOSo.js +74 -0
  357. data/docs/assets/recipes_indexed-forms.md.CstYyOSo.lean.js +1 -0
  358. data/docs/assets/recipes_text-field-component.md.H4wLAK0Z.js +101 -0
  359. data/docs/assets/recipes_text-field-component.md.H4wLAK0Z.lean.js +1 -0
  360. data/docs/assets/routes.md.B8kfUPHU.js +21 -0
  361. data/docs/assets/{routes.md.BMM7peut.lean.js → routes.md.B8kfUPHU.lean.js} +1 -1
  362. data/docs/assets/{security.md.C668yXCi.js → security.md.C0G_AZR-.js} +1 -1
  363. data/docs/assets/{security.md.C668yXCi.lean.js → security.md.C0G_AZR-.lean.js} +1 -1
  364. data/docs/assets/space-time-continuum.md.xl44xDos.js +1 -0
  365. data/docs/assets/{space-time-continuum.md.KPUIKysQ.lean.js → space-time-continuum.md.xl44xDos.lean.js} +1 -1
  366. data/docs/assets/{style.D73IYGCX.css → style.prAgp4yQ.css} +1 -1
  367. data/docs/assets/tutorial.md.a4a0eVOy.js +1 -0
  368. data/docs/assets/tutorial.md.a4a0eVOy.lean.js +1 -0
  369. data/docs/assets/why.md.C-hk5xgJ.js +1 -0
  370. data/docs/assets/why.md.C-hk5xgJ.lean.js +1 -0
  371. data/docs/assets.html +12 -7
  372. data/docs/brut-js/api/AjaxSubmit.html +1 -1
  373. data/docs/brut-js/api/AjaxSubmit.js.html +1 -1
  374. data/docs/brut-js/api/Autosubmit.html +1 -1
  375. data/docs/brut-js/api/Autosubmit.js.html +1 -1
  376. data/docs/brut-js/api/BaseCustomElement.html +1 -1
  377. data/docs/brut-js/api/BaseCustomElement.js.html +1 -1
  378. data/docs/brut-js/api/BrutCustomElements.html +1 -1
  379. data/docs/brut-js/api/BufferedLogger.html +1 -1
  380. data/docs/brut-js/api/ConfirmSubmit.html +1 -1
  381. data/docs/brut-js/api/ConfirmSubmit.js.html +1 -1
  382. data/docs/brut-js/api/ConfirmationDialog.html +1 -1
  383. data/docs/brut-js/api/ConfirmationDialog.js.html +1 -1
  384. data/docs/brut-js/api/ConstraintViolationMessage.html +1 -1
  385. data/docs/brut-js/api/ConstraintViolationMessage.js.html +1 -1
  386. data/docs/brut-js/api/ConstraintViolationMessages.html +1 -1
  387. data/docs/brut-js/api/ConstraintViolationMessages.js.html +1 -1
  388. data/docs/brut-js/api/CopyToClipboard.html +1 -1
  389. data/docs/brut-js/api/CopyToClipboard.js.html +1 -1
  390. data/docs/brut-js/api/Form.html +1 -1
  391. data/docs/brut-js/api/Form.js.html +1 -1
  392. data/docs/brut-js/api/I18nTranslation.html +1 -1
  393. data/docs/brut-js/api/I18nTranslation.js.html +1 -1
  394. data/docs/brut-js/api/LocaleDetection.html +1 -1
  395. data/docs/brut-js/api/LocaleDetection.js.html +1 -1
  396. data/docs/brut-js/api/Logger.html +1 -1
  397. data/docs/brut-js/api/Logger.js.html +1 -1
  398. data/docs/brut-js/api/Message.html +1 -1
  399. data/docs/brut-js/api/Message.js.html +1 -1
  400. data/docs/brut-js/api/PrefixedLogger.html +1 -1
  401. data/docs/brut-js/api/RichString.html +1 -1
  402. data/docs/brut-js/api/RichString.js.html +1 -1
  403. data/docs/brut-js/api/Tabs.html +1 -1
  404. data/docs/brut-js/api/Tabs.js.html +1 -1
  405. data/docs/brut-js/api/Tracing.html +1 -1
  406. data/docs/brut-js/api/Tracing.js.html +1 -1
  407. data/docs/brut-js/api/external-CustomElementRegistry.html +1 -1
  408. data/docs/brut-js/api/external-Performance.html +1 -1
  409. data/docs/brut-js/api/external-Promise.html +1 -1
  410. data/docs/brut-js/api/external-ValidityState.html +1 -1
  411. data/docs/brut-js/api/external-Window.html +1 -1
  412. data/docs/brut-js/api/external-fetch.html +1 -1
  413. data/docs/brut-js/api/global.html +1 -1
  414. data/docs/brut-js/api/index.html +1 -1
  415. data/docs/brut-js/api/index.js.html +1 -1
  416. data/docs/brut-js/api/module-testing.html +1 -1
  417. data/docs/brut-js/api/testing.AssetMetadata.html +1 -1
  418. data/docs/brut-js/api/testing.AssetMetadataLoader.html +1 -1
  419. data/docs/brut-js/api/testing.CustomElementTest.html +1 -1
  420. data/docs/brut-js/api/testing.DOMCreator.html +1 -1
  421. data/docs/brut-js/api/testing_AssetMetadata.js.html +1 -1
  422. data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +1 -1
  423. data/docs/brut-js/api/testing_CustomElementTest.js.html +1 -1
  424. data/docs/brut-js/api/testing_DOMCreator.js.html +1 -1
  425. data/docs/brut-js/api/testing_index.js.html +1 -1
  426. data/docs/brut-js.html +12 -7
  427. data/docs/business-logic.html +10 -5
  428. data/docs/cli.html +26 -26
  429. data/docs/components.html +61 -64
  430. data/docs/configuration.html +13 -8
  431. data/docs/css.html +14 -9
  432. data/docs/custom-element-tests.html +14 -9
  433. data/docs/database-access.html +12 -7
  434. data/docs/database-schema.html +15 -10
  435. data/docs/deployment.html +58 -6
  436. data/docs/dev-environment.html +12 -7
  437. data/docs/dir-structure.html +74 -0
  438. data/docs/doc-conventions.html +11 -6
  439. data/docs/end-to-end-tests.html +15 -8
  440. data/docs/favicon.ico +0 -0
  441. data/docs/features.html +182 -0
  442. data/docs/flash-and-session.html +73 -82
  443. data/docs/form-constraints.html +118 -0
  444. data/docs/forms.html +57 -367
  445. data/docs/getting-started.html +15 -10
  446. data/docs/handlers.html +51 -61
  447. data/docs/hashmap.json +1 -1
  448. data/docs/hooks.html +14 -9
  449. data/docs/i18n.html +12 -7
  450. data/docs/index.html +11 -6
  451. data/docs/instrumentation.html +12 -7
  452. data/docs/javascript.html +17 -12
  453. data/docs/jobs.html +10 -5
  454. data/docs/keyword-injection.html +22 -21
  455. data/docs/layouts.html +12 -20
  456. data/docs/lsp.html +11 -6
  457. data/docs/markdown-examples.html +10 -5
  458. data/docs/middleware.html +10 -5
  459. data/docs/not-released.html +10 -5
  460. data/docs/overview.html +11 -138
  461. data/docs/pages.html +49 -121
  462. data/docs/recipes/alternate-layouts.html +50 -0
  463. data/docs/recipes/authentication.html +166 -6
  464. data/docs/recipes/blank-layouts.html +43 -0
  465. data/docs/recipes/custom-flash.html +54 -0
  466. data/docs/recipes/indexed-forms.html +102 -0
  467. data/docs/recipes/text-field-component.html +129 -0
  468. data/docs/routes.html +16 -19
  469. data/docs/security.html +11 -6
  470. data/docs/seed-data.html +10 -5
  471. data/docs/space-time-continuum.html +11 -6
  472. data/docs/tutorial.html +11 -6
  473. data/docs/unit-tests.html +10 -5
  474. data/docs/why.html +29 -0
  475. data/dx/bash_customizations +7 -0
  476. data/dx/build +13 -2
  477. data/dx/docker-compose.env +1 -1
  478. data/dx/exec +25 -8
  479. data/lib/brut/front_end/form.rb +8 -8
  480. data/lib/brut/front_end/forms/input.rb +253 -20
  481. data/lib/brut/front_end/forms/input_definition.rb +15 -12
  482. data/lib/brut/front_end/forms/radio_button_group_input.rb +8 -1
  483. data/lib/brut/front_end/forms/select_input.rb +8 -1
  484. data/lib/brut/front_end.rb +1 -0
  485. data/lib/brut/version.rb +1 -1
  486. data/specs/brut/front_end/forms/input.spec.rb +978 -0
  487. data/specs/brut/front_end/forms/radio_button_group_input.spec.rb +54 -0
  488. data/specs/brut/front_end/forms/select_input.spec.rb +54 -0
  489. data/specs/spec_helper.rb +27 -0
  490. data/specs/support/matchers/have_constraint_violation.rb +23 -0
  491. data/specs/support/matchers.rb +5 -0
  492. data/specs/support.rb +3 -0
  493. metadata +141 -77
  494. data/brutrb.com/public/images/logo-300.png +0 -0
  495. data/brutrb.com/public/images/logo.png +0 -0
  496. data/docs/assets/ai.md._6HCDL6d.lean.js +0 -1
  497. data/docs/assets/chunks/@localSearchIndexroot.CoYzciVi.js +0 -1
  498. data/docs/assets/components.md.CRUMdRoN.js +0 -104
  499. data/docs/assets/deployment.md.Dbka4OTr.js +0 -1
  500. data/docs/assets/deployment.md.Dbka4OTr.lean.js +0 -1
  501. data/docs/assets/dev-environment.md.GZv6xvi9.js +0 -11
  502. data/docs/assets/doc-conventions.md.-kN3Xo5C.js +0 -1
  503. data/docs/assets/doc-conventions.md.-kN3Xo5C.lean.js +0 -1
  504. data/docs/assets/end-to-end-tests.md.yfQHC0b5.lean.js +0 -1
  505. data/docs/assets/flash-and-session.md.BXY8RvT0.js +0 -93
  506. data/docs/assets/forms.md.B-koVgyw.js +0 -379
  507. data/docs/assets/forms.md.B-koVgyw.lean.js +0 -1
  508. data/docs/assets/handlers.md.089DVD3v.js +0 -69
  509. data/docs/assets/handlers.md.089DVD3v.lean.js +0 -1
  510. data/docs/assets/index.md.B28EwVpq.js +0 -1
  511. data/docs/assets/index.md.B28EwVpq.lean.js +0 -1
  512. data/docs/assets/keyword-injection.md.Dt2tKREs.js +0 -25
  513. data/docs/assets/layouts.md.cPnh3NId.lean.js +0 -1
  514. data/docs/assets/overview.Da81cB9R.png +0 -0
  515. data/docs/assets/overview.md.C5wlBcR5.js +0 -133
  516. data/docs/assets/overview.md.C5wlBcR5.lean.js +0 -1
  517. data/docs/assets/pages.md.BE3kfOc5.js +0 -122
  518. data/docs/assets/pages.md.BE3kfOc5.lean.js +0 -1
  519. data/docs/assets/recipes_authentication.md.CAsXf7hk.js +0 -1
  520. data/docs/assets/recipes_authentication.md.CAsXf7hk.lean.js +0 -1
  521. data/docs/assets/routes.md.BMM7peut.js +0 -29
  522. data/docs/assets/space-time-continuum.md.KPUIKysQ.js +0 -1
  523. data/docs/assets/tutorial.md.BnoGjrdK.js +0 -1
  524. data/docs/assets/tutorial.md.BnoGjrdK.lean.js +0 -1
  525. data/docs/images/logo-300.png +0 -0
  526. data/docs/images/logo.png +0 -0
  527. /data/docs/assets/{cli.md.RmeA2b0i.lean.js → cli.md.CjsktgFz.lean.js} +0 -0
  528. /data/docs/assets/{configuration.md.BGHl8oRC.lean.js → configuration.md.DeyhpqEx.lean.js} +0 -0
  529. /data/docs/assets/{css.md.DJgj2clw.lean.js → css.md.CltvJqAa.lean.js} +0 -0
  530. /data/docs/assets/{custom-element-tests.md.BrYJQEl3.lean.js → custom-element-tests.md.B_rbta32.lean.js} +0 -0
  531. /data/docs/assets/{database-access.md.C7l-Vuvb.lean.js → database-access.md.gnluu54N.lean.js} +0 -0
  532. /data/docs/assets/{dev-environment.md.GZv6xvi9.lean.js → dev-environment.md.BroAOLhF.lean.js} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0212844b1dd1d69682b3b4ec4ab2a9917087b3d931916e39d9ccf0239d6a2f9c'
4
- data.tar.gz: 871a018ce32f9d1f556eef7950570c8a4dd072736be733e6a7a925e14a8c968c
3
+ metadata.gz: ac39a29b335413475986e02cf9baa658bc44fa2e67e6dbd60dfafa7e4b9c8a2f
4
+ data.tar.gz: 155a9b104168bd18fe08fd8286576d63305d243d6025a4a1fcbcf1611611a8ed
5
5
  SHA512:
6
- metadata.gz: eb49d9e87e53893962c86e2a26ca54f8c82cc9a8fbbeac5e12e1d7aaa4b47cbb13de6ab9429779422a6bc075dd3f4499bf6b18accb7c7ff87943eb32afda0342
7
- data.tar.gz: c8f56cb073d99b1b3f304afe2daf3839b6b2b39ebe492bde05f00037ebf448459049560d3b32707450b65e32916366ea766d57598752026d0c025d1db63d7fe7
6
+ metadata.gz: 6126e575575511de23bd9ffe1429f05fa017664c66f7de07fa93b000edfb4f4dfd7c619d76d02d28e69cb70bfe163c4023d7a79cc53e1e41e3a44b5882cd0fd8
7
+ data.tar.gz: d38e331cd221d1a3bbd666b83a0d3e2df5a17fd4cbdccc47da7ca0df484d8ff46fb91c2f159c9da4fefcb8c829b98a8de4a040f013676170befecc0bcc45c3d1
data/.gitignore CHANGED
@@ -32,3 +32,9 @@
32
32
  /brut-css/dist
33
33
  # This is where the CSS lives temporarily while docs are being built
34
34
  /brut-css/src/docs/brut.css
35
+
36
+ # Per-developer Bash customizations that could contain secrets
37
+ /dx/bash_customizations.local
38
+
39
+ # Gems are installed here for LSP convienience
40
+ /local-gems
data/.projections.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "lib/*.rb": {
3
+ "alternate": "specs/{}.spec.rb",
4
+ "type": "source"
5
+ },
6
+ "specs/*.spec.rb": {
7
+ "alternate": "lib/{}.rb",
8
+ "type": "spec"
9
+ }
10
+ }
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ -I specs
2
+ --require spec_helper
3
+ -P "specs/**/*.spec.rb"
data/Dockerfile.dx CHANGED
@@ -10,28 +10,46 @@ RUN apt-get -y clean && \
10
10
  apt-get -y update && \
11
11
  apt-get install --quiet --yes ca-certificates curl gnupg rsync
12
12
 
13
- # Install NODE per https://github.com/nodesource/distributions?tab=readme-ov-file#using-debian-as-root-nodejs-22
14
- RUN curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh && \
15
- bash /tmp/nodesource_setup.sh && \
16
- apt-get install -y nodejs
17
-
18
- # Install Postgres client per https://www.postgresql.org/download/linux/debian/ - note that the
19
- # automated configuration doesn't work, I think because it assumes non-root.
20
- RUN apt-get -y install lsb-release && \
21
- sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
22
- wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
23
- apt-get update && \
24
- apt-get -y install postgresql-client-16
25
-
26
13
  RUN echo "gem: --no-document" >> ~/.gemrc && \
27
14
  gem update --system && \
28
15
  gem install bundler
29
-
30
16
  # Need vim at all times
31
17
  ENV EDITOR=vim
32
18
  RUN apt-get install -y vim && \
33
19
  echo "set -o vi" >> /root/.bashrc
34
20
 
21
+
22
+ # Setup a non-root user
23
+
24
+ # Their user id, which ideally matches their user id on the host
25
+ ARG user_uid=10001
26
+ # Their group id, which ideally matches their group id on the host
27
+ ARG user_gid=10002
28
+
29
+ # Create the user's group ID if it does not exist
30
+ RUN getent group ${user_gid} || groupadd --gid ${user_gid} appgroup
31
+ # Create the user. Note that we put bash_customizations in both .profile and .bashrc
32
+ # to increase the chances they are used when running bash in various configurations
33
+ RUN useradd --uid ${user_uid} --gid ${user_gid} --create-home --home-dir /home/appuser appuser && \
34
+ echo ". ~/.bash_customizations" >> /home/appuser/.profile && \
35
+ echo ". ~/.bash_customizations.local" >> /home/appuser/.profile && \
36
+ echo ". ~/.bash_customizations" >> /home/appuser/.bashrc && \
37
+ echo ". ~/.bash_customizations.local" >> /home/appuser/.bashrc
38
+
39
+ COPY --chown=appuser:${user_gid} dx/show-help-in-app-container-then-wait.sh /home/appuser
40
+ COPY --chown=appuser:${user_gid} dx/bash_customizations /home/appuser/.bash_customizations
41
+ COPY --chown=appuser:${user_gid} dx/bash_customizations.local /home/appuser/.bash_customizations.local
42
+
43
+ # NOT including the group here as that will place the user's environment
44
+ # ONLY in that group and not in all the groups in which they are a part.
45
+ USER appuser
46
+
47
+ # Install NodeJS, per https://nodejs.org/en/download
48
+ RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \
49
+ \. "$HOME/.nvm/nvm.sh" && \
50
+ nvm install 22 && \
51
+ node -v && nvm current && npm -v
52
+
35
53
  # Node's colors are hand-crafted to always look bad and render at least some text unreadable
36
54
  # no matter what your setup. Cool.
37
55
  ENV NODE_DISABLE_COLORS=1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brut (0.0.28)
4
+ brut (0.1.0)
5
5
  concurrent-ruby
6
6
  i18n
7
7
  irb
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  Brut is a way to make web apps with Ruby, captializing on the knowledge you have—HTTP, HTML, CSS, JavaScript, SQL—without requiring
4
4
  *too* much extra stuff to learn.
5
5
 
6
+ ![Brut Logo in the style of the Washington DC Metro. It has the metro brown background with all text in white Helvetica. Centered at the top is "BrutRB". Below that, in the style of metro stops is "Ruby", next to a red dot with "RB" in it, "HTML/CSS/JS" next to an orange dot with "WP" in it, "Phlex" next to a blue dot with "PL" in it, and "RSpec" next to a green dot with "RS" in it.](brutrb.com/images/LogoStop.png)
7
+
6
8
  ## Installation
7
9
 
8
10
  Add this line to your application's Gemfile:
@@ -19,6 +21,26 @@ Or install it yourself as:
19
21
 
20
22
  $ gem install brut
21
23
 
24
+ ## Getting Started
25
+
26
+ [Please note there is extensive documentation](https://brutrb.com), however to get started, you can use [mkbrut](https://github.com/thirdtank/mkrbut):
27
+
28
+ ```
29
+ docker run --pull always \
30
+ -v "$PWD":"$PWD" \
31
+ -w "$PWD"
32
+ -it \
33
+ thirdtank/mkbrut \
34
+ mkbrut your-new-app
35
+ ```
36
+
37
+ If you have Ruby 3.4 installed somewhere, you can use this via RubyGems as well:
38
+
39
+ ```
40
+ > gem install mkbrut
41
+ > mkbrut your-new-app
42
+ ```
43
+
22
44
  ## Developing
23
45
 
24
46
  The dev environment is managed by Docker and you are encouraged to use this. It's set up so you can edit your code on your computer
@@ -45,6 +67,5 @@ with your editor, but all commands are run inside Docker, which should be more c
45
67
 
46
68
  dx/exec bin/setup --no-credentials
47
69
 
48
- The `--no-credentials` means that you will not be able to push to GitHub or RubyGems from within the Docker container. This
49
- ability is only needed by maintainers to push new versions of the gem. You can push to GitHub from your computer.
70
+ The `--no-credentials` means that you will not be able to push to GitHub or RubyGems from within the Docker container. This ability is only needed by maintainers to push new versions of the gem. You can push to GitHub from your computer.
50
71
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/bin/docs CHANGED
@@ -14,14 +14,36 @@ OptionParser.new do |opts|
14
14
  end
15
15
  end.parse!
16
16
 
17
- public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path.to_s
18
- docs_dir = public_dir + "/api"
17
+ public_dir = (Pathname(__FILE__).dirname / ".." / "brutrb.com" / "public" ).expand_path
18
+ docs_dir = public_dir / "api"
19
19
  brutjs_dir = (Pathname(__FILE__).dirname / ".." / "brut-js" ).expand_path.to_s
20
20
 
21
21
  system(
22
22
  "bundle exec yard doc -o '#{docs_dir}' -m markdown -M rdiscount --backtrace"
23
23
  )
24
24
 
25
+ puts "Hacking CSS"
26
+ [
27
+ docs_dir / "css" / "style.css",
28
+ docs_dir / "css" / "full_list.css"
29
+ ].each do |css_file_to_hack|
30
+ lines = File.read(css_file_to_hack).split(/\n/)
31
+ File.open(css_file_to_hack, "w") do |f|
32
+ lines.each do |line|
33
+ if line =~ /\"Lucida Sans"/
34
+ f.puts line.gsub(/\"Lucida Sans\"/, '"Helvetica Neue", "Lucida Sans"')
35
+ elsif line =~ / Monaco,/
36
+ f.puts line.gsub(/ Monaco,/, '"Courier New", Monaco,')
37
+ elsif line =~ /font-family: monospace;/
38
+ f.puts line.gsub(/font-family: monospace;/, 'font-family: "Courier New", monospace;')
39
+ else
40
+ f.puts line
41
+ end
42
+ end
43
+ f.puts "code { font-family: 'Courier New', monospace; font-weight: 600; }"
44
+ end
45
+ end
46
+
25
47
  FileUtils.chdir brutjs_dir do
26
48
  system("bin/build")
27
49
  end
data/bin/rspec ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("rspec-core", "rspec")
data/bin/setup CHANGED
@@ -83,7 +83,7 @@ def setup(update_gems:,setup_credentials:)
83
83
  system! "ssh-add #{key_file}"
84
84
  end
85
85
 
86
- known_hosts_dest = Pathname("/") / "root" / ".ssh" / "known_hosts"
86
+ known_hosts_dest = Pathname("/") / "home" / "appuser" / ".ssh" / "known_hosts"
87
87
  if known_hosts_dest.exist?
88
88
  log "#{known_hosts_dest} exists, your ssh key should work with GitHub"
89
89
  else
@@ -117,7 +117,7 @@ def setup(update_gems:,setup_credentials:)
117
117
  end
118
118
  log "Your ssh key looks good"
119
119
 
120
- gem_credentials_dest = Pathname("/") / "root" / ".gem" / "credentials"
120
+ gem_credentials_dest = Pathname("/") / "home" / "appuser" / ".gem" / "credentials"
121
121
  if gem_credentials_dest.exist?
122
122
  log "Gem credentials look good"
123
123
  else
@@ -139,7 +139,7 @@ def setup(update_gems:,setup_credentials:)
139
139
  end
140
140
  end
141
141
 
142
- npm_credentials_dest = Pathname("/") / "root" / ".npmrc"
142
+ npm_credentials_dest = Pathname("/") / "home" / "appuser" / ".npmrc"
143
143
  if npm_credentials_dest.exist?
144
144
  log "NPM credentials look good"
145
145
  else
@@ -6,6 +6,33 @@ import jsdocLinker from './plugins/jsdocLinker'
6
6
  export default defineConfig({
7
7
  title: "Brut RB",
8
8
  description: "Documentation for the Brut.RB web framework.",
9
+ head: [
10
+ ["link", { rel: "icon", href: "/favicon.ico" }],
11
+ [
12
+ "meta", {
13
+ property: "og:title",
14
+ content: "BrutRB Documentation"
15
+ }
16
+ ],
17
+ [
18
+ "meta", {
19
+ property: "og:type",
20
+ content: "website"
21
+ }
22
+ ],
23
+ [
24
+ "meta", {
25
+ property: "og:image",
26
+ content: "https://github.com/thirdtank/brut/blob/main/assets/SocialImage.png?raw=true"
27
+ }
28
+ ],
29
+ ["script", {
30
+ defer: "",
31
+ "data-domain": "brutrb.com",
32
+ src: "https://plausible.io/js/script.js"
33
+ }
34
+ ],
35
+ ],
9
36
  themeConfig: {
10
37
  // https://vitepress.dev/reference/default-theme-config
11
38
  search: {
@@ -27,10 +54,11 @@ export default defineConfig({
27
54
  items: [
28
55
  { text: "Getting Started", link: "/getting-started" },
29
56
  { text: "Concepts", link: "/overview" },
30
- { text: "Documentation Conventions", link: "/doc-conventions" },
31
- { text: "Tutorial", link: "/tutorial" },
57
+ { text: "Features", link: "/features" },
58
+ { text: "Directory Structure", link: "/dir-structure" },
32
59
  { text: "Dev Environment", link: "/dev-environment" },
33
- { text: "AI Declaration", link: "/ai" },
60
+ { text: "Tutorial", link: "/tutorial" },
61
+ { text: "Documentation Conventions", link: "/doc-conventions" },
34
62
  ]
35
63
  },
36
64
  {
@@ -41,6 +69,7 @@ export default defineConfig({
41
69
  { text: "Pages", link: "/pages" },
42
70
  { text: "Layouts", link: "/layouts" },
43
71
  { text: "Forms", link: "/forms" },
72
+ { text: "Form Constraints", link: "/form-constraints" },
44
73
  { text: "Handlers and Actions", link: "/handlers" },
45
74
  { text: "Components", link: "/components" },
46
75
  { text: "Flash and Session", link: "/flash-and-session" },
@@ -98,12 +127,20 @@ export default defineConfig({
98
127
  collapsed: true,
99
128
  items: [
100
129
  { text: "Authentication", link: "/recipes/authentication" },
101
- { text: "Form Validations", link: "/recipes/form-validations" },
102
- { text: "Database Migrations", link: "/recipes/database-migrations" },
103
- { text: "Ajax Form Submission", link: "/recipes/ajax-form" },
104
- { text: "Custom Telemetry", link: "/recipes/telemetry" },
105
- { text: "CLI App/Task", link: "/recipes/cli-app" },
130
+ { text: "Alternate Layouts", link: "/recipes/alternate-layouts" },
131
+ { text: "Blank Layouts", link: "/recipes/blank-layouts" },
132
+ { text: "Custom Flash Class", link: "/recipes/custom-flash" },
133
+ { text: "Indexed Form Elements", link: "/recipes/indexed-forms" },
134
+ { text: "Text Field Component", link: "/recipes/text-field-component" },
106
135
  ],
136
+ },
137
+ {
138
+ text: "Meta",
139
+ collapsed: false,
140
+ items: [
141
+ { text: "Why?!", link: "/why" },
142
+ { text: "AI Declaration", link: "/ai" },
143
+ ]
107
144
  }
108
145
  ],
109
146
 
@@ -5,3 +5,10 @@
5
5
  .image-bg {
6
6
  display: none;
7
7
  }
8
+ td > code {
9
+ white-space: nowrap;
10
+ }
11
+
12
+ .VPHero img, .VPHome img {
13
+ border-radius: 0.5rem;
14
+ }
@@ -44,6 +44,7 @@
44
44
  * -------------------------------------------------------------------------- */
45
45
 
46
46
  :root {
47
+ --vp-c-text-1: #362400;
47
48
  --vp-c-default-1: var(--vp-c-gray-1);
48
49
  --vp-c-default-2: var(--vp-c-gray-2);
49
50
  --vp-c-default-3: var(--vp-c-gray-3);
@@ -51,13 +52,14 @@
51
52
 
52
53
  --blue-vp-c-brand-1: #0C00A7;
53
54
  --blue-vp-c-brand-2: #6357FF;
54
- --blue-vp-c-brand-3: #1000E2;
55
- --blue-vp-c-brand-soft: #FAF9FF;
55
+ --blue-vp-c-brand-3: #4C0606;
56
+ --blue-vp-c-brand-soft: #FFF9F9;
57
+
58
+ --vp-c-brand-1: #001842;
59
+ --vp-c-brand-2: #6B84B1;
60
+ --vp-c-brand-3: #0443B1;
61
+ --vp-c-brand-soft: #FFF1D6;
56
62
 
57
- --vp-c-brand-1: #A70C00;
58
- --vp-c-brand-2: #FF6357;
59
- --vp-c-brand-3: #e21000;
60
- --vp-c-brand-soft: #FFE7E5;
61
63
 
62
64
  --xvp-c-brand-1: var(--vp-c-indigo-1);
63
65
  --xvp-c-brand-2: var(--vp-c-indigo-2);
@@ -69,15 +71,25 @@
69
71
  --vp-c-tip-3: var(--vp-c-brand-3);
70
72
  --vp-c-tip-soft: var(--vp-c-brand-soft);
71
73
 
72
- --vp-c-warning-1: var(--vp-c-yellow-1);
73
- --vp-c-warning-2: var(--vp-c-yellow-2);
74
- --vp-c-warning-3: var(--vp-c-yellow-3);
75
- --vp-c-warning-soft: var(--vp-c-yellow-soft);
76
-
77
- --vp-c-danger-1: var(--vp-c-red-1);
78
- --vp-c-danger-2: var(--vp-c-red-2);
79
- --vp-c-danger-3: var(--vp-c-red-3);
80
- --vp-c-danger-soft: var(--vp-c-red-soft);
74
+ --xvp-c-warning-1: var(--vp-c-yellow-1);
75
+ --xvp-c-warning-2: var(--vp-c-yellow-2);
76
+ --xvp-c-warning-3: var(--vp-c-yellow-3);
77
+ --xvp-c-warning-soft: var(--vp-c-yellow-soft);
78
+
79
+ --vp-c-warning-1: #9E5601;
80
+ --vp-c-warning-2: #FDAF53;
81
+ --vp-c-warning-3: #5E3301;
82
+ --vp-c-warning-soft: #FFF3E5;
83
+
84
+ --vp-c-danger-1: #AC0E0E;
85
+ --vp-c-danger-2: #F14E4E;
86
+ --vp-c-danger-3: #4C0606;
87
+ --vp-c-danger-soft: #FFF9F9;
88
+
89
+ --xvp-c-danger-1: var(--vp-c-red-1);
90
+ --xvp-c-danger-2: var(--vp-c-red-2);
91
+ --xvp-c-danger-3: var(--vp-c-red-3);
92
+ --xvp-c-danger-soft: var(--vp-c-red-soft);
81
93
  }
82
94
 
83
95
  /**
@@ -104,8 +116,8 @@
104
116
  --vp-home-hero-name-color: transparent;
105
117
  --vp-home-hero-name-background: -webkit-linear-gradient(
106
118
  120deg,
107
- #333333 30%,
108
- #d14141
119
+ #D67402 20%,
120
+ #11AC0E
109
121
  );
110
122
 
111
123
  --vp-home-hero-image-background-image: linear-gradient(
data/brutrb.com/ai.md CHANGED
@@ -52,22 +52,17 @@ documentation, is produced by a machine, although spelling and grammar correctio
52
52
 
53
53
  We expect an LLM to be able to digest this documentation and source code and provide alternate analysis of how Brut works and how to use it. We hope such analysis is correct and useful, however that cannot be guaranteed, so this documentation is the second best source of truth, the source code being the best.
54
54
 
55
- ## Logo
55
+ ## Logos
56
56
 
57
- The logo is level 4 - ChatGPT created it. I'd love to have a real person make a better one. I just needed
58
- something to get this launched. Please reach out if you want to make a better one + other assets. I'm
59
- willing to pay a real person.
57
+ While the various logos look like someone typed "make me a logo in the style of the Washington, DC Metro", if you look closely, you will see the telltale sings that they were made by a person…a person who is not a professional designer.
60
58
 
61
- ## AI Completions Should Be Viewed with Skepticism
59
+ As such, these are all Level 1.
62
60
 
63
- Due to how LLMs work, there is naturally nothing in any model about Brut. Anything an
64
- existing model tells you about Brut is **100% untrustworthy**. We hope to allow LLMs to consume Brut's
65
- code, documentation, and examples, so it can be an additional source of help, but currently that is not
66
- the case.
61
+ ## AI Information about Brut Should Be Viewed with Skepticism
67
62
 
68
- **Do not ask an LLM about Brut** until this part of the documentation changes.
69
-
70
- For completion-based AI suggestions, **view them with skepticism**. In my
71
- experience, completions from e.g. GitHub CoPilot work OK when replicating a pattern
72
- in the file you are editing, but suggestions in a freshly-opened file tend to be
73
- entirely imaginary or Rails-based. Beware.
63
+ * **Answers from an LLM about Brut are likely incorrect.** LLMs will certainly not
64
+ have been trained on information about Brut, since it is new.
65
+ * **Code Completions of Brut Code are suspect.** I have observed that e.g. GitHub
66
+ CoPilot is capable for properly completing Brut code if there is enough context, but
67
+ it is not capable of, say, creating a component from scratch. **Review all Code
68
+ Completions Carefully**.
data/brutrb.com/assets.md CHANGED
@@ -46,14 +46,7 @@ JavaScript is on line 1 of `app.js`. This is not helpful for diagnosing issues.
46
46
  *SourceMaps* are separate files that translate the minified files back to normal ones, so you can see a normal
47
47
  stack trace with the actual line numbers of your source files.
48
48
 
49
- There are many ways to create source maps and if you've used a tool like WebPack, you'll recall that many of them
50
- don't produce usable source maps. Brut uses esbuild's facility for this, with a focus on correctness. When
51
- you see a line number and a source file in your browser, you can be sure it's accurate.
52
-
53
- The tradeoff is that it can take longer to produce than producing an inaccurate one. I'm not sure who wants
54
- inaccurate source maps, but Brut does not support this. In practice, esbuild is quite fast, so it should not make
55
- a practical difference in your day to day work.
56
-
49
+ Brut's configuration of esbuild is to produce sourcemaps.
57
50
 
58
51
  ## Fonts
59
52
 
@@ -93,7 +86,7 @@ end
93
86
  ## SVGs
94
87
 
95
88
  You can place `.svg` files in `app/src/front_end/images` if you wish to use them in `<img>` tags. However, if
96
- you place svgs in `app/src/front_end/svgs`, they can be inlined into your HTML via `inline_svg`. In this case,
89
+ you place svgs in `app/src/front_end/svgs`, they can be inlined into your HTML via `inline_svg`, provided by `Brut::FrontEnd::Component::Helpers` and included in all components and pages. In this case,
97
90
  there is no need for a build step, since the SVG source is included directly in your HTML. This works well
98
91
  for icons.
99
92
 
@@ -73,7 +73,7 @@ improvements):
73
73
  * Default implementations of `connectedCallback` and `attributeChangedCallback` that call the template method `update`, thus allowing your element to centralize its logic in one place, regardless of how a state change was triggered.
74
74
  * Static `define()` method that defines your element based on its static `tagName` field. This allows richer interaction of elements, as you can do e.g. `document.querySelector(SomeOtherElement.tagName)` and better navigate changes to your code over time.
75
75
 
76
- If you are familiary with the API for autonomous custom elements, `BaseCustomElement` doesn't require
76
+ If you are familiar with the API for autonomous custom elements, `BaseCustomElement` doesn't require
77
77
  learning much more. What you know already will be leveraged.
78
78
 
79
79
  ### Removing BrutJS
@@ -81,10 +81,20 @@ learning much more. What you know already will be leveraged.
81
81
  To remove BrutJS from your app, modify `app/src/front_end/js/index.js` to remove the `import` and call to
82
82
  `define()`. You can then remove it from your `package.json`.
83
83
 
84
- **Note** If you remove it like this, several features will not work, including locale detection, client-side observability, and client-side form validation UX.
84
+ > [!NOTE]
85
+ > If you remove it like this, several features will not work, including locale detection, client-side observability, and client-side form validation UX.
85
86
 
86
87
  ## Recommnded Practices
87
88
 
89
+ ### Leaving BrutJS In Your App
90
+
91
+ BrutJS provides useful tools unrelated to single-page apps, or reactivity, or
92
+ whatever else you might be concerned with in your client-side code. These features
93
+ can work alongside whatever framework you want to use. Leave them in unless they are
94
+ causing a specific problem.
95
+
96
+ ### You Probably Don't Need a Single-Page App
97
+
88
98
  Consider this decision tree from Alex Russell's [If Not React, Then
89
99
  What?](https://infrequently.org/2024/11/if-not-react-then-what/):
90
100
 
data/brutrb.com/cli.md CHANGED
@@ -117,7 +117,7 @@ All of this means that the bulk of CLI-specific code you will write is specifyin
117
117
 
118
118
  Every CLI app is a class that extends `Brut::CLI::App`. This class should contain one inner class for each subcommand. Those classes should extend `Brut::CLI::App`.
119
119
 
120
- Inside your `Brut::CLI::App` class, you can call a few class methods to declare aspects of the UI. In particular, `opts` returns the `OptionParser` in play that you can use to declare global options. Unlike `OptionParser`'s `on` method, Brut's does not require providing a block. Brut will store the runtime options in a hash (see below).
120
+ Inside your `Brut::CLI::App` class, you can call a few class methods to declare aspects of the UI. In particular, `opts` returns the `OptionParser` in play that you can use to declare global options. Unlike `OptionParser`'s `on` method, Brut's does not require providing a block. Brut will store the runtime options in an object (see below).
121
121
 
122
122
  ```ruby
123
123
  class MyAppCLI < Brut::CLI::App
@@ -132,7 +132,7 @@ This code means your app's global options are `--dry-run`, which will not accept
132
132
 
133
133
  Declaring subcommands provides a similar API. Let's say our app has a "status" subcommand, and a "run" subcommand.
134
134
 
135
- ```ruby
135
+ ```ruby {7-11,13-16}
136
136
  class MyAppCLI < Brut::CLI::App
137
137
  description "My awesome command line app"
138
138
 
@@ -189,7 +189,7 @@ end
189
189
 
190
190
  ### Implementing `execute`
191
191
 
192
- Once `execute` is called, your app's internals will have been setup and bootstrapped. That means all you data models can access the database, and any other setup will have ocurred. Generally, `execute` can then have whatever code makes sense.
192
+ Once `execute` is called, your app's internals will have been setup and bootstrapped. That means all your data models can access the database, and any other setup will have ocurred. Generally, `execute` can then have whatever code makes sense.
193
193
 
194
194
  That said, `execute` has access to a few values to understand the command line invocation and to support testing.
195
195
 
@@ -220,23 +220,19 @@ use that affect its behavior.
220
220
 
221
221
  Currently, Brut doesn't provide a way to create this file, but it's relatively straightforward. It's almost entirely boilerplate except for your class:
222
222
 
223
- ```ruby {14}
223
+ ```ruby {9}
224
224
  #!/usr/bin/env ruby
225
225
 
226
226
  require "bundler"
227
227
  Bundler.require
228
228
  require "pathname"
229
-
230
- require "brut/cli"
231
-
232
- APP_PATH = File.join(File.dirname($0),"..","app","src")
233
- $: << APP_PATH
234
- require "cli/my_app"
229
+ require "brut/cli/apps/db"
235
230
 
236
231
  exit Brut::CLI.app(
237
- MyAppCLI,
238
- project_root: Pathname($0).dirname / ".."
239
- )
232
+ Brut::CLI::Apps::DB,
233
+ project_root: Pathname($0).dirname / ".."
234
+ )
235
+
240
236
  ```
241
237
 
242
238
  ## Testing