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,185 @@
1
+ # The bare bones configuration on top of a blank Brut app.
2
+ class MKBrut::Segments::BareBones < MKBrut::Base
3
+
4
+ def self.friendly_name = "Bare bones framing"
5
+
6
+ def initialize(app_options:, current_dir:, templates_dir:)
7
+ @project_root = current_dir / app_options.app_name
8
+ @templates_dir = templates_dir / "segments" / "BareBones"
9
+ @erb_binding = ErbBindingDelegate.new(app_options)
10
+ end
11
+
12
+ def add!
13
+
14
+ operations = copy_files(@templates_dir, @project_root) +
15
+ other_operations(@project_root)
16
+
17
+ operations.each do |operation|
18
+ operation.call
19
+ end
20
+
21
+ end
22
+
23
+ def other_operations(project_root)
24
+ [
25
+ MKBrut::Ops::InsertRoute.new(
26
+ project_root: @project_root,
27
+ code: %{path "/trigger_exception", method: :get}
28
+ ),
29
+ MKBrut::Ops::InsertCodeInMethod.new(
30
+ file: @project_root / "app" / "src" / "app.rb",
31
+ class_name: "App",
32
+ method_name: "initialize",
33
+ code: %{
34
+ Brut.container.store(
35
+ "trigger_exception_key",
36
+ String,
37
+ "String used to prevent anyone from triggering exceptions in TriggerExceptionHandler"
38
+ ) do
39
+ ENV.fetch("TRIGGER_EXCEPTION_KEY")
40
+ end},
41
+ ),
42
+ InsertCustomElement.new(
43
+ project_root: @project_root,
44
+ element_class_name: "Example",
45
+ ),
46
+ MKBrut::Ops::InsertCodeInMethod.new(
47
+ file: @project_root / "app" / "src" / "front_end" / "pages" / "home_page.rb",
48
+ class_name: "HomePage",
49
+ method_name: "page_template",
50
+ code: %{
51
+ #{ @erb_binding.prefix }_example(
52
+ transform: "upper",
53
+ class: [ "pos-fixed",
54
+ "bottom-0",
55
+ "left-0",
56
+ "w-100",
57
+ "ff-sans",
58
+ "lh-title",
59
+ "tracked",
60
+ "f-5",
61
+ "f-6-ns",
62
+ "tc",
63
+ "pa-3",
64
+ "mt-3",
65
+ "db", ]
66
+ ) do
67
+ "We Like the Web"
68
+ end
69
+ }
70
+ ),
71
+ InsertEndToEndTestCode.new(
72
+ file: @project_root / "specs" / "e2e" / "home_page.spec.rb",
73
+ code: %{
74
+ example = page.locator("#{ @erb_binding.prefix }-example")
75
+ # The #{ @erb_binding.prefix }-example custom element will transform
76
+ # the text it contains. Since this is an end-to-end test
77
+ # the element should've done its thing and given us
78
+ # upper-case text.
79
+ expect(example).to have_text("WE LIKE THE WEB") }
80
+ ),
81
+ MKBrut::Ops::AppendToFile.new(
82
+ file: @project_root / ".env.development",
83
+ content: %{
84
+ # Key used to allow triggering an exception. This is required to prevent
85
+ # just anyone from triggering one.
86
+ TRIGGER_EXCEPTION_KEY=dev-trigger-exception
87
+ }
88
+ ),
89
+ MKBrut::Ops::AppendToFile.new(
90
+ file: @project_root / ".env.test",
91
+ content: "TRIGGER_EXCEPTION_KEY=test-trigger-exception"
92
+ ),
93
+
94
+ ]
95
+ end
96
+ class InsertCustomElement < MKBrut::Ops::BaseOp
97
+ def initialize(project_root:, element_class_name:)
98
+ @file = project_root / "app" / "src" / "front_end" / "js" / "index.js"
99
+ @element_class_name = element_class_name
100
+ end
101
+ def call
102
+ if dry_run?
103
+ puts "Would insert custom element '#{@element_class_name}' into #{@file}"
104
+ return
105
+ end
106
+ inserted = false
107
+ new_source = []
108
+ File.read(@file).split("\n").each do |line|
109
+ regexp = /^document\.addEventListener\(\"DOMContentLoaded\"/
110
+ if line.match?(regexp)
111
+ new_source << %{import #{@element_class_name} from "./#{@element_class_name}"}
112
+ new_source << line
113
+ new_source << %{ #{@element_class_name}.define()}
114
+ inserted = true
115
+ else
116
+ new_source << line
117
+ end
118
+ end
119
+ if !inserted
120
+ raise "Could not find a place to insert code in '#{@file}'. Trying to find a line that matches this regular expression:\n\n#{regexp.inspect}"
121
+ end
122
+ File.open(@file, "w") do |file|
123
+ file.puts new_source.join("\n")
124
+ end
125
+ end
126
+ end
127
+
128
+ class InsertEndToEndTestCode < MKBrut::Ops::PrismParsingOp
129
+ def initialize(file:, code:)
130
+ @file = file
131
+ @code = code
132
+ end
133
+ def call
134
+ if dry_run?
135
+ puts "Would insert end-to-end test code into #{@file}:\n\n#{@code}\n"
136
+ return
137
+ end
138
+ parse_file!
139
+
140
+ found_describe = false
141
+ first_it_block = nil
142
+
143
+ @tree.value.statements.body.each do |top|
144
+ if top.is_a?(Prism::CallNode) &&
145
+ top.name == :describe &&
146
+ top.block
147
+ found_describe = true
148
+
149
+ statements = top.block.body
150
+ if statements.respond_to?(:body)
151
+ statements.body.each do |statement|
152
+ if statement.is_a?(Prism::CallNode) &&
153
+ statement.name == :it &&
154
+ statement.block
155
+
156
+ first_it_block = statement
157
+ break
158
+
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ if !first_it_block
165
+ if found_describe
166
+ raise "Could not find an 'it' block inside the first 'describe' in '#{@file}'"
167
+ else
168
+ raise "Could not find a 'describe' block in '#{@file}'"
169
+ end
170
+ end
171
+
172
+ insertion_point = first_it_block.block.location.end_offset - 3
173
+
174
+ block_line = @source.lines[first_it_block.location.start_line - 1]
175
+ describe_indent = block_line[/^\s*/]
176
+ it_indent = describe_indent + " "
177
+
178
+ new_source = @source.dup.insert(insertion_point, "\n#{it_indent}#{@code}\n#{describe_indent}")
179
+ File.open(@file, "w") do |file|
180
+ file.puts new_source
181
+ end
182
+ end
183
+ end
184
+
185
+ end
@@ -0,0 +1,121 @@
1
+ # Additional classes and configuration for a new Brut
2
+ # app that provides a more demonstration of the features.
3
+ class MKBrut::Segments::Demo < MKBrut::Base
4
+
5
+ def self.friendly_name = "Demo features and files"
6
+
7
+ def initialize(app_options:, current_dir:, templates_dir:)
8
+ @project_root = current_dir / app_options.app_name
9
+ @templates_dir = templates_dir / "segments" / "Demo"
10
+ @erb_binding = ErbBindingDelegate.new(app_options)
11
+ end
12
+
13
+ def add!
14
+ operations = copy_files(@templates_dir, @project_root) +
15
+ other_operations(@project_root)
16
+
17
+ operations.each do |operation|
18
+ operation.call
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def other_operations(project_root)
25
+ [
26
+ MKBrut::Ops::AddI18nMessage.new(
27
+ project_root: project_root,
28
+ hash: {
29
+ en: {
30
+ cv: {
31
+ ss: {
32
+ not_enough_words: "%{field} does not have enough words",
33
+ already_posted: "You've already posted a message. Thanks for that!",
34
+ },
35
+ },
36
+ pages: {
37
+ "NewGuestbookMessagePage": {
38
+ title: "New guestbook message page",
39
+ },
40
+ "GuestbookPage": {
41
+ title: "Guestbook page",
42
+ },
43
+ },
44
+ guestbook_not_saved: "Your guestbook message was not saved",
45
+ guestbook_saved: "Thanks for writing!",
46
+ },
47
+ }
48
+ ),
49
+ MKBrut::Ops::InsertRoute.new(
50
+ project_root: project_root,
51
+ code: %{page "/guestbook"},
52
+ ),
53
+ MKBrut::Ops::InsertRoute.new(
54
+ project_root: project_root,
55
+ code: %{form "/guestbook_message"},
56
+ ),
57
+ MKBrut::Ops::InsertRoute.new(
58
+ project_root: project_root,
59
+ code: %{page "/new_guestbook_message"},
60
+ ),
61
+ MKBrut::Ops::InsertCodeInMethod.new(
62
+ file: project_root / "app" / "src" / "back_end" / "data_models" / "seed" / "seed_data.rb",
63
+ class_name: "SeedData",
64
+ method_name: "seed!",
65
+ code: %{
66
+ 10.times do
67
+ create(:guestbook_message, created_at: Date.today - rand(1..100))
68
+ end
69
+ }
70
+ ),
71
+ MKBrut::Ops::AddCSSImport.new(
72
+ project_root: project_root,
73
+ import: "constraint-violations.css"
74
+ ),
75
+ MKBrut::Ops::AddCSSImport.new(
76
+ project_root: project_root,
77
+ import: "fonts.css"
78
+ ),
79
+ MKBrut::Ops::InsertCodeInMethod.new(
80
+ file: project_root / "app" / "src" / "front_end" / "pages"/ "home_page.rb",
81
+ class_name: "HomePage",
82
+ method_name: "page_template",
83
+ where: :start,
84
+ code: %{
85
+ div(class: "w-50 mh-auto mt-4") do
86
+ a(href: NewGuestbookMessagePage.routing,
87
+ class: "db f-3 ff-sans blue-400 fw-bold tc"
88
+ ) do
89
+ "Sign The Guestbook!"
90
+ end
91
+ end
92
+ }
93
+ ),
94
+ MKBrut::Ops::AddMethod.new(
95
+ file: project_root / "app" / "src" / "front_end" / "support" / "app_session.rb",
96
+ class_name: "AppSession",
97
+ code: %{def signed_guestbook? = !!self.guestbook_message},
98
+ ),
99
+ MKBrut::Ops::AddMethod.new(
100
+ file: project_root / "app" / "src" / "front_end" / "support" / "app_session.rb",
101
+ class_name: "AppSession",
102
+ code: %{
103
+ def guestbook_message
104
+ DB::GuestbookMessage.find(
105
+ external_id: self[:guestbook_message_external_id]
106
+ )
107
+ end
108
+ }
109
+ ),
110
+ MKBrut::Ops::AddMethod.new(
111
+ file: project_root / "app" / "src" / "front_end" / "support" / "app_session.rb",
112
+ class_name: "AppSession",
113
+ code: %{
114
+ def signed_guestbook(guestbook_message)
115
+ self[:guestbook_message_external_id] = guestbook_message.external_id
116
+ end
117
+ }
118
+ ),
119
+ ]
120
+ end
121
+ end
@@ -0,0 +1,30 @@
1
+ class MKBrut::Segments::Heroku < MKBrut::Base
2
+ def self.friendly_name = "Heroku-based Deployment"
3
+
4
+ def initialize(app_options:, current_dir:, templates_dir:)
5
+ @project_root = current_dir / app_options.app_name
6
+ @templates_dir = templates_dir / "segments" / "Heroku"
7
+ @erb_binding = MKBrut::ErbBindingDelegate.new(app_options)
8
+ end
9
+
10
+ def add!
11
+ operations = copy_files(@templates_dir, @project_root) +
12
+ other_operations
13
+
14
+ operations.each do |operation|
15
+ operation.call
16
+ end
17
+ end
18
+
19
+ def other_operations
20
+ [
21
+ MKBrut::Ops::AppendToFile.new(
22
+ file: @project_root / ".gitignore",
23
+ content: %{
24
+ # These are generated by bin/deploy
25
+ deploy/Dockerfile.*
26
+ }
27
+ )
28
+ ]
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ # Adds Sidekiq to a Brut app
2
+ class MKBrut::Segments::Sidekiq
3
+ end
@@ -0,0 +1,8 @@
1
+ module MKBrut
2
+ module Segments
3
+ autoload :BareBones, "mkbrut/segments/bare_bones"
4
+ autoload :Demo, "mkbrut/segments/demo"
5
+ autoload :Sidekiq, "mkbrut/segments/demo"
6
+ autoload :Heroku, "mkbrut/segments/heroku"
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module MKBrut
2
+ VERSION = "0.8.0"
3
+ end
@@ -0,0 +1,13 @@
1
+ require "pathname"
2
+ require "json"
3
+ require_relative "version"
4
+
5
+ class MKBrut::Versions
6
+ def initialize
7
+ @brut_version = MKBrut::VERSION
8
+ end
9
+
10
+ def brut_version_specifier = "~> #{@brut_version}"
11
+ def brut_css_version_specifier = "~#{@brut_version}"
12
+ def brut_js_version_specifier = "~#{@brut_version}"
13
+ end
@@ -0,0 +1,18 @@
1
+ module MKBrut
2
+ autoload :App, "mkbrut/app"
3
+ autoload :AppId, "mkbrut/app_id"
4
+ autoload :AppName, "mkbrut/app_name"
5
+ autoload :AppOptions, "mkbrut/app_options"
6
+ autoload :Base, "mkbrut/base"
7
+ autoload :CLI, "mkbrut/cli"
8
+ autoload :ErbBindingDelegate, "mkbrut/erb_binding_delegate"
9
+ autoload :InternetIdentifier, "mkbrut/internet_identifier"
10
+ autoload :InvalidIdentifier, "mkbrut/invalid_identifier"
11
+ autoload :Ops, "mkbrut/ops"
12
+ autoload :Organization, "mkbrut/organization"
13
+ autoload :Prefix, "mkbrut/prefix"
14
+ autoload :Segments, "mkbrut/segments"
15
+ autoload :Versions, "mkbrut/versions"
16
+ autoload :PrefixedIO, "mkbrut/prefixed_io"
17
+ autoload :VERSION, "mkbrut/version"
18
+ end
@@ -0,0 +1,32 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "mkbrut/version"
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "mkbrut"
6
+ spec.version = MKBrut::VERSION
7
+ spec.authors = ["Dave Copeland"]
8
+ spec.email = ["davec@naildrivin5.com"]
9
+
10
+ spec.summary = "Create a new Brut App"
11
+ spec.description = "mkbrut is how you go from zero to having a Brut app where you can start working."
12
+ spec.homepage = "https://brutrb.com"
13
+ spec.bindir = "exe"
14
+
15
+ spec.files = Dir.glob("lib/**/*.rb") + # Gem source code
16
+ Dir.glob( # Templates used to create a new Brut app
17
+ "templates/**/*",
18
+ flags: File::FNM_DOTMATCH
19
+ ).reject {
20
+ it =~ /\/\.{1,2}$/ # Pesky dotfile
21
+ }.reject {
22
+ it =~ /\.DS_Store$/ # FML
23
+ } +
24
+ [
25
+ "exe/mkbrut", # executable
26
+ ]
27
+
28
+ spec.executables = ["mkbrut"]
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "rake"
32
+ end
@@ -0,0 +1,25 @@
1
+ # Ignore git directory.
2
+ /.git/
3
+ /.gitignore
4
+
5
+ # Ignore bundler config.
6
+ /.bundle
7
+
8
+ # Ignore all environment files
9
+ /.env*
10
+
11
+ # Ignore all logfiles and tempfiles.
12
+ /logs/*
13
+ /tmp/*
14
+
15
+ # The most important thing to ignore of all time
16
+ /node_modules/
17
+
18
+ # Ignore generated assets
19
+ /app/public/*
20
+
21
+ # Ignore Docker-related files
22
+ /.dockerignore
23
+ /Dockerfile*
24
+ /docker-compose.*
25
+ /deploy/docker-compose.*
@@ -0,0 +1,60 @@
1
+ # Environment variables needed for running in development. This file
2
+ # also serves as the canonical list of ALL environment variables the app
3
+ # must have in production.
4
+ #
5
+ # Each env var should be preceded by a comment explaining its purpose.
6
+ # The env var itself can be written in one of two ways:
7
+ #
8
+ # * Conventionally set a value:
9
+ #
10
+ # ```
11
+ # # the API key to interact with the OCP Widgets Service.
12
+ # WIDGETS_API_KEY=some-value
13
+ # ```
14
+ # Ideally, all values are set this way so that everyone is using the same
15
+ # value and the app just works without having to go to an external service
16
+ # to get a real secret for local development.
17
+ #
18
+ # * Indicates a local override is required:
19
+ #
20
+ # ```
21
+ # # the API key to interact with the OCP Widgets Service.
22
+ # LOCAL:WIDGETS_API_KEY
23
+ # ```
24
+ #
25
+ # In this form, bin/setup will ask the developer for the value and place
26
+ # it in .env.development.local. As your app evolves and adds more
27
+ # environment variables, you can add them like this and `bin/setup` will
28
+ # see which ones are present vs missing.
29
+
30
+ # Session secret used to encrypt the session
31
+ SESSION_SECRET=<%= session_secret %>
32
+ # URL to the database
33
+ DATABASE_URL=postgres://postgres:postgres@postgres:5432/<%= app_id %>_development
34
+
35
+ # Configures the endpoint where OTel traces are sent.
36
+ # In dev and test, it's the otel-desktop-viewer set up in
37
+ # docker-compose.dx.yml. For production, consult your
38
+ # OTel vendor's documentation.
39
+ OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-desktop-viewer:4318"
40
+
41
+ # OTel exporter to use for sending traces to the endpoint. You usually
42
+ # want otlp, however, in production, consult your vendor's documentation to be sure.
43
+ OTEL_TRACES_EXPORTER="otlp"
44
+
45
+ # OTel exporter protocol. You usually want http/protobuf, however,
46
+ # in production, consult your vendor's documentation to be sure.
47
+ OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
48
+
49
+ # This controls the background thread used by the span processor.
50
+ # I swear I had to set this to false to make stuff work, however
51
+ # various corporate AI chatbots said it should be true for use with
52
+ # Puma. I'm going with my hazy memory for now.
53
+ OTEL_RUBY_BSP_START_THREAD_ON_BOOT=false
54
+
55
+ # OTel log level. Set this to "debug" to try to figure out why OTel isn't working.
56
+ OTEL_LOG_LEVEL=warn
57
+
58
+ # If set to true, Puma will log its configuration, which is handy to understand
59
+ # if what you think you configured actually got configured.
60
+ PUMA_LOG_CONFIG=true
@@ -0,0 +1,8 @@
1
+ SESSION_SECRET=<%= session_secret %>
2
+ DATABASE_URL=postgres://postgres:postgres@postgres:5432/<%= app_id %>_test
3
+ OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-desktop-viewer:4318"
4
+ OTEL_TRACES_EXPORTER="otlp"
5
+ OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
6
+ OTEL_RUBY_BSP_START_THREAD_ON_BOOT=false
7
+ OTEL_LOG_LEVEL=warn
8
+ PUMA_LOG_CONFIG=true
@@ -0,0 +1,31 @@
1
+ # Never checkin tmp
2
+ /tmp
3
+ # This should never be checked in
4
+ /node_modules
5
+ # This contains generated code, so should not be checked in
6
+ /app/public/css
7
+ # This contains generated code, so should not be checked in
8
+ /app/public/js
9
+ # This contains generated code, so should not be checked in
10
+ /app/public/static/images/
11
+ # Don't want to check in the generated JSDocs dir
12
+ /jsdocs
13
+ # This is generated per environment
14
+ /app/config/asset_metadata.json
15
+ # Don't check in logs
16
+ /logs
17
+
18
+ # This could contain actual secrets and should not be checked in
19
+ /.env.development.local
20
+
21
+ # These are generated artifacts
22
+ /deploy/Dockerfile.*
23
+ /deploy/docker-compose.yml
24
+
25
+ # RSpec configuration should be in one place.
26
+ # Devs can override as needed, but this is not how
27
+ # configuration is to be shared
28
+ /.rspec
29
+
30
+ # Gems installed locally should not be checked in
31
+ /local-gems
@@ -0,0 +1,59 @@
1
+ {
2
+ "app/src/*.rb": {
3
+ "alternate": "specs/{}.spec.rb",
4
+ "type": "source"
5
+ },
6
+ "app/src/front_end/js/*.js": {
7
+ "alternate": "specs/front_end/js/{}.spec.js",
8
+ "type": "js"
9
+ },
10
+ "specs/*.spec.rb": {
11
+ "alternate": "app/src/{}.rb",
12
+ "type": "spec"
13
+ },
14
+ "specs/front_end/js/*.spec.js": {
15
+ "alternate": "app/src/front_end/js/{}.js",
16
+ "type": "jsspec"
17
+ },
18
+ "app/src/front_end/components/*.rb": {
19
+ "type": "component"
20
+ },
21
+ "app/src/front_end/forms/*.rb": {
22
+ "type": "form"
23
+ },
24
+ "app/src/front_end/handlers/*.rb": {
25
+ "type": "handler"
26
+ },
27
+ "app/src/front_end/pages/*.rb": {
28
+ "type": "page"
29
+ },
30
+ "app/src/front_end/pages/*.html.rb": {
31
+ "type": "erb"
32
+ },
33
+ "app/src/back_end/data_models/db/*.rb": {
34
+ "type": "db"
35
+ },
36
+ "app/src/back_end/data_models/migrations/*.rb": {
37
+ "type": "migration"
38
+ },
39
+ "app/src/back_end/data_models/migrations/*.sql": {
40
+ "type": "migration"
41
+ },
42
+ "app/src/back_end/data_models/seed/*.rb": {
43
+ "type": "seed"
44
+ },
45
+ "app/src/back_end/domain/*.rb": {
46
+ "type": "domain"
47
+ },
48
+ "app/src/back_end/jobs/*.rb": {
49
+ "type": "job"
50
+ },
51
+ "app/src/back_end/service_wrappers/*.rb": {
52
+ "type": "service_wrapper"
53
+ },
54
+ "specs/factories/*.factory.rb": {
55
+ "type": "factory",
56
+ "alternate": "app/src/back_end/data_models/{}.rb"
57
+ }
58
+
59
+ }