brut 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/brut +34 -0
- data/lib/brut/cli/apps/build_assets.rb +78 -48
- data/lib/brut/cli/apps/db.rb +168 -202
- data/lib/brut/cli/apps/deploy.rb +291 -0
- data/lib/brut/cli/apps/heroku_container_based_deploy.rb +7 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/add_segment.rb +5 -5
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/add_segment_options.rb +1 -1
- data/lib/brut/cli/apps/new/app.rb +240 -0
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/app_id.rb +1 -1
- data/lib/brut/cli/apps/new/app_name.rb +29 -0
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/base.rb +9 -6
- data/lib/brut/cli/apps/new/erb_binding_delegate.rb +23 -0
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/internet_identifier.rb +5 -5
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/invalid_identifier.rb +1 -1
- data/{mkbrut/lib/mkbrut/app.rb → lib/brut/cli/apps/new/old_app.rb} +8 -11
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/add_css_import.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/add_i18n_message.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/add_method.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/append_to_file.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/base_op.rb +3 -3
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/copy_file.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/insert_code_in_method.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/insert_into_file.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/insert_route.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/mkdir.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/prism_parsing_op.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/render_template.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/ops/skip_file.rb +1 -1
- data/lib/brut/cli/apps/new/ops.rb +17 -0
- data/lib/brut/cli/apps/new/organization.rb +5 -0
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/prefix.rb +1 -1
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/segments/bare_bones.rb +12 -11
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/segments/demo.rb +16 -15
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/segments/heroku.rb +9 -5
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/segments/sidekiq.rb +44 -21
- data/lib/brut/cli/apps/new/segments.rb +8 -0
- data/lib/brut/cli/apps/new/version.rb +3 -0
- data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/versions.rb +2 -2
- data/lib/brut/cli/apps/new.rb +26 -0
- data/lib/brut/cli/apps/scaffold.rb +150 -141
- data/lib/brut/cli/apps/test.rb +95 -69
- data/lib/brut/cli/commands/base_command.rb +174 -0
- data/lib/brut/cli/commands/compound_command.rb +29 -0
- data/lib/brut/cli/commands/execution_context.rb +32 -0
- data/lib/brut/cli/commands/help.rb +26 -0
- data/lib/brut/cli/commands/output_error.rb +13 -0
- data/lib/brut/cli/commands/raise_error.rb +11 -0
- data/lib/brut/cli/commands.rb +8 -0
- data/lib/brut/cli/execute_result.rb +39 -0
- data/lib/brut/cli/executor.rb +9 -4
- data/lib/brut/cli/output.rb +13 -0
- data/lib/brut/cli/parsed_command_line.rb +143 -0
- data/lib/brut/cli/runner.rb +124 -0
- data/lib/brut/cli.rb +7 -29
- data/lib/brut/framework/container.rb +1 -1
- data/lib/brut/framework/mcp.rb +59 -13
- data/lib/brut/framework/project_environment.rb +3 -1
- data/lib/brut/junk_drawer.rb +3 -1
- data/lib/brut/spec_support/cli_command_support.rb +45 -0
- data/lib/brut/spec_support/e2e_test_server.rb +3 -0
- data/lib/brut/spec_support/general_support.rb +1 -1
- data/lib/brut/spec_support/matchers/have_executed.rb +35 -0
- data/lib/brut/spec_support/rspec_setup.rb +4 -8
- data/lib/brut/spec_support.rb +1 -0
- data/lib/brut/tui/ansi_escape_code.rb +104 -0
- data/lib/brut/tui/event_loop.rb +168 -0
- data/lib/brut/tui/events/base_event.rb +29 -0
- data/lib/brut/tui/events/event_bus.rb +73 -0
- data/lib/brut/tui/events/event_loop_started.rb +5 -0
- data/lib/brut/tui/events/exception.rb +24 -0
- data/lib/brut/tui/events/tick.rb +12 -0
- data/lib/brut/tui/events.rb +7 -0
- data/lib/brut/tui/markup_string.rb +70 -0
- data/lib/brut/tui/script/block_step.rb +17 -0
- data/lib/brut/tui/script/events/command_execution_failed.rb +4 -0
- data/lib/brut/tui/script/events/command_execution_succeeded.rb +3 -0
- data/lib/brut/tui/script/events/command_std_err.rb +3 -0
- data/lib/brut/tui/script/events/command_std_out.rb +14 -0
- data/lib/brut/tui/script/events/executing_command.rb +12 -0
- data/lib/brut/tui/script/events/message.rb +15 -0
- data/lib/brut/tui/script/events/phase_completed.rb +4 -0
- data/lib/brut/tui/script/events/phase_started.rb +14 -0
- data/lib/brut/tui/script/events/script_completed.rb +5 -0
- data/lib/brut/tui/script/events/script_started.rb +12 -0
- data/lib/brut/tui/script/events/step_completed.rb +3 -0
- data/lib/brut/tui/script/events/step_started.rb +12 -0
- data/lib/brut/tui/script/events.rb +14 -0
- data/lib/brut/tui/script/exec_step.rb +67 -0
- data/lib/brut/tui/script/logging_subscriber.rb +98 -0
- data/lib/brut/tui/script/puts_subscriber.rb +109 -0
- data/lib/brut/tui/script/step.rb +13 -0
- data/lib/brut/tui/script.rb +215 -0
- data/lib/brut/tui/terminal.rb +74 -0
- data/lib/brut/tui/terminal_theme.rb +144 -0
- data/lib/brut/tui/themes/dark.rb +14 -0
- data/lib/brut/tui/themes/light.rb +17 -0
- data/lib/brut/tui/themes/none.rb +9 -0
- data/lib/brut/tui/themes.rb +5 -0
- data/lib/brut/tui.rb +15 -0
- data/lib/brut/version.rb +1 -1
- data/lib/brut.rb +1 -0
- data/templates/Base/.env.development.local +2 -0
- data/templates/Base/bin/ci +42 -0
- data/{mkbrut/templates → templates}/Base/bin/release +2 -2
- data/templates/Base/bin/setup +174 -0
- data/{mkbrut/templates → templates}/Base/bin/watch-and-build-assets +1 -1
- data/{mkbrut/templates → templates}/Base/dx/docker-compose.env.erb +1 -1
- data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/css/fonts.css +1 -1
- data/{mkbrut/templates → templates}/segments/Heroku/deploy/Dockerfile +2 -2
- data/templates/segments/Heroku/deploy/docker_config.rb +30 -0
- metadata +254 -1009
- data/.gitignore +0 -55
- data/.projections.json +0 -10
- data/CHANGELOG.md +0 -167
- data/CODE_OF_CONDUCT.txt +0 -99
- data/Dockerfile.dx +0 -82
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -243
- data/LICENSE.txt +0 -370
- data/README.md +0 -90
- data/Rakefile +0 -25
- data/assets/Logo-Square.pxd +0 -0
- data/assets/LogoPylon.pxd +0 -0
- data/assets/LogoStop.pxd +0 -0
- data/assets/LogoTall.pxd +0 -0
- data/assets/MetroIcon.graffle +0 -0
- data/assets/MetroLogo.graffle +0 -0
- data/assets/SocialImage.png +0 -0
- data/assets/SocialImage.pxd +0 -0
- data/assets/YouTubeThumb.pxd +0 -0
- data/bin/bin_kit.rb +0 -51
- data/bin/build +0 -86
- data/bin/ci +0 -40
- data/bin/dev +0 -20
- data/bin/docs +0 -79
- data/bin/generate-and-run-rubocop +0 -52
- data/bin/new-version +0 -8
- data/bin/publish +0 -61
- data/bin/rake +0 -27
- data/bin/rspec +0 -27
- data/bin/rubocop +0 -27
- data/bin/setup +0 -252
- data/bin/test +0 -18
- data/brut-css/.nvim.lua +0 -1
- data/brut-css/README.md +0 -28
- data/brut-css/bin/build +0 -50
- data/brut-css/bin/ci +0 -19
- data/brut-css/bin/dev +0 -1
- data/brut-css/bin/docs +0 -34
- data/brut-css/bin/publish +0 -21
- data/brut-css/bin/setup +0 -6
- data/brut-css/config/media-queries-all.css +0 -15
- data/brut-css/config/media-queries-minimal.css +0 -5
- data/brut-css/config/postcss.config.cjs +0 -7
- data/brut-css/config/pseudo-classes-all.css +0 -9
- data/brut-css/dx +0 -1
- data/brut-css/package-lock.json +0 -3165
- data/brut-css/package.json +0 -36
- data/brut-css/src/css/appearance.css +0 -145
- data/brut-css/src/css/border.css +0 -522
- data/brut-css/src/css/colors.css +0 -3502
- data/brut-css/src/css/dimensions.css +0 -548
- data/brut-css/src/css/flex.css +0 -179
- data/brut-css/src/css/index.css +0 -13
- data/brut-css/src/css/layout.css +0 -120
- data/brut-css/src/css/list.css +0 -41
- data/brut-css/src/css/positioning.css +0 -354
- data/brut-css/src/css/properties/colors.css +0 -455
- data/brut-css/src/css/properties/index.css +0 -3
- data/brut-css/src/css/properties/spacing.css +0 -140
- data/brut-css/src/css/properties/typography.css +0 -224
- data/brut-css/src/css/reset.css +0 -107
- data/brut-css/src/css/spacing.css +0 -585
- data/brut-css/src/css/typography.css +0 -519
- data/brut-css/src/css/utils.css +0 -104
- data/brut-css/src/docs/1_getting-started/1_overview.md +0 -46
- data/brut-css/src/docs/1_getting-started/2_installation.md +0 -25
- data/brut-css/src/docs/1_getting-started/3_core-concepts.md +0 -75
- data/brut-css/src/docs/1_getting-started/4_simple-example.md +0 -132
- data/brut-css/src/docs/1_getting-started/page.html.ejs +0 -10
- data/brut-css/src/docs/2_properties/page.html.ejs +0 -71
- data/brut-css/src/docs/3_classes/color-demo.html.ejs +0 -31
- data/brut-css/src/docs/3_classes/page.html.ejs +0 -87
- data/brut-css/src/docs/4_customization/1_design-system.md +0 -36
- data/brut-css/src/docs/4_customization/2_breakpoints.md +0 -75
- data/brut-css/src/docs/4_customization/3_pseudo-classes.md +0 -74
- data/brut-css/src/docs/4_customization/4_advanced-configuration.md +0 -40
- data/brut-css/src/docs/4_customization/page.html.ejs +0 -10
- data/brut-css/src/docs/docs.css +0 -98
- data/brut-css/src/docs/includes/body-and-header.html.ejs +0 -30
- data/brut-css/src/docs/includes/footer-and-rest.html.ejs +0 -9
- data/brut-css/src/docs/includes/head.html.ejs +0 -5
- data/brut-css/src/docs/includes/nav.html.ejs +0 -10
- data/brut-css/src/docs/index.html.ejs +0 -32
- data/brut-css/src/docs/prism-twilight.min.css +0 -1
- data/brut-css/src/js/Logger.js +0 -71
- data/brut-css/src/js/build.js +0 -111
- data/brut-css/src/js/cli/CLIArgError.js +0 -7
- data/brut-css/src/js/cli/Debug.js +0 -27
- data/brut-css/src/js/cli/DocsDir.js +0 -16
- data/brut-css/src/js/cli/DocsTemplateSourceDir.js +0 -16
- data/brut-css/src/js/cli/InputFile.js +0 -31
- data/brut-css/src/js/cli/MediaQueryConfigFile.js +0 -10
- data/brut-css/src/js/cli/OutputFile.js +0 -22
- data/brut-css/src/js/cli/ParsedArg.js +0 -17
- data/brut-css/src/js/cli/PathToBrutCSSRoot.js +0 -19
- data/brut-css/src/js/cli/PseudoClassConfigFile.js +0 -11
- data/brut-css/src/js/cli.js +0 -108
- data/brut-css/src/js/docGenerator.js +0 -467
- data/brut-css/src/js/mediaQueryConfigParser.js +0 -98
- data/brut-css/src/js/post-css-plugins/addMediaQueriesPlugin.js +0 -49
- data/brut-css/src/js/post-css-plugins/addPseudoClassesPlugin.js +0 -42
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/Category.js +0 -9
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/DocState.js +0 -185
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/Documentable.js +0 -8
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/Group.js +0 -7
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/ParsedComment.js +0 -73
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/Property.js +0 -9
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/PropertyCategory.js +0 -4
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/PropertyGroup.js +0 -8
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/Rule.js +0 -12
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/RuleCategory.js +0 -4
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/RuleGroup.js +0 -8
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/SeeRef.js +0 -5
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin/SeeURL.js +0 -9
- data/brut-css/src/js/post-css-plugins/generateDocumentationPlugin.js +0 -49
- data/brut-css/src/js/post-css-plugins/generateRootCustomPropertiesPlugin.js +0 -45
- data/brut-css/src/js/pseudoClassConfigParser.js +0 -145
- data/brut-js/.projections.json +0 -10
- data/brut-js/README.md +0 -118
- data/brut-js/bin/build +0 -19
- data/brut-js/bin/ci +0 -5
- data/brut-js/bin/docs +0 -25
- data/brut-js/bin/publish +0 -21
- data/brut-js/bin/setup +0 -6
- data/brut-js/docs/README.md +0 -8
- data/brut-js/docs/jsdoc-plugins/customElementTag.js +0 -8
- data/brut-js/docs/jsdoc-theme/publish.js +0 -692
- data/brut-js/docs/jsdoc-theme/static/scripts/linenumber.js +0 -25
- data/brut-js/docs/jsdoc-theme/static/scripts/prettify/Apache-License-2.0.txt +0 -202
- data/brut-js/docs/jsdoc-theme/static/scripts/prettify/lang-css.js +0 -2
- data/brut-js/docs/jsdoc-theme/static/scripts/prettify/prettify.js +0 -28
- data/brut-js/docs/jsdoc-theme/static/styles/jsdoc-default.css +0 -327
- data/brut-js/docs/jsdoc-theme/static/styles/prettify-jsdoc.css +0 -111
- data/brut-js/docs/jsdoc-theme/static/styles/prettify-tomorrow.css +0 -132
- data/brut-js/docs/jsdoc-theme/tmpl/augments.tmpl +0 -10
- data/brut-js/docs/jsdoc-theme/tmpl/container.tmpl +0 -199
- data/brut-js/docs/jsdoc-theme/tmpl/details.tmpl +0 -143
- data/brut-js/docs/jsdoc-theme/tmpl/example.tmpl +0 -2
- data/brut-js/docs/jsdoc-theme/tmpl/examples.tmpl +0 -13
- data/brut-js/docs/jsdoc-theme/tmpl/exceptions.tmpl +0 -32
- data/brut-js/docs/jsdoc-theme/tmpl/layout.tmpl +0 -38
- data/brut-js/docs/jsdoc-theme/tmpl/mainpage.tmpl +0 -14
- data/brut-js/docs/jsdoc-theme/tmpl/members.tmpl +0 -38
- data/brut-js/docs/jsdoc-theme/tmpl/method.tmpl +0 -131
- data/brut-js/docs/jsdoc-theme/tmpl/modifies.tmpl +0 -14
- data/brut-js/docs/jsdoc-theme/tmpl/params.tmpl +0 -131
- data/brut-js/docs/jsdoc-theme/tmpl/properties.tmpl +0 -108
- data/brut-js/docs/jsdoc-theme/tmpl/returns.tmpl +0 -19
- data/brut-js/docs/jsdoc-theme/tmpl/source.tmpl +0 -8
- data/brut-js/docs/jsdoc-theme/tmpl/tutorial.tmpl +0 -19
- data/brut-js/docs/jsdoc-theme/tmpl/type.tmpl +0 -7
- data/brut-js/docs/jsdoc.config.json +0 -23
- data/brut-js/docs/package-lock.json +0 -343
- data/brut-js/docs/package.json +0 -7
- data/brut-js/dx +0 -1
- data/brut-js/package-lock.json +0 -2210
- data/brut-js/package.json +0 -36
- data/brut-js/specs/AjaxSubmit.spec.js +0 -453
- data/brut-js/specs/Autosubmit.spec.js +0 -127
- data/brut-js/specs/ConfirmSubmit.spec.js +0 -224
- data/brut-js/specs/ConstraintViolationMessage.spec.js +0 -33
- data/brut-js/specs/ConstraintViolationMessages.spec.js +0 -32
- data/brut-js/specs/CopyToClipboard.spec.js +0 -35
- data/brut-js/specs/Form.spec.js +0 -137
- data/brut-js/specs/I18nTranslation.spec.js +0 -19
- data/brut-js/specs/LocaleDetection.spec.js +0 -22
- data/brut-js/specs/Message.spec.js +0 -15
- data/brut-js/specs/SpecHelper.js +0 -23
- data/brut-js/specs/Tabs.spec.js +0 -41
- data/brut-js/specs/Toast.spec.js +0 -34
- data/brut-js/specs/config/asset_metadata.json +0 -7
- data/brut-js/src/AjaxSubmit.js +0 -499
- data/brut-js/src/Autosubmit.js +0 -63
- data/brut-js/src/BaseCustomElement.js +0 -261
- data/brut-js/src/ConfirmSubmit.js +0 -137
- data/brut-js/src/ConfirmationDialog.js +0 -143
- data/brut-js/src/ConstraintViolationMessage.js +0 -140
- data/brut-js/src/ConstraintViolationMessages.js +0 -98
- data/brut-js/src/CopyToClipboard.js +0 -96
- data/brut-js/src/Form.js +0 -147
- data/brut-js/src/I18nTranslation.js +0 -64
- data/brut-js/src/LocaleDetection.js +0 -117
- data/brut-js/src/Logger.js +0 -90
- data/brut-js/src/Message.js +0 -62
- data/brut-js/src/RichString.js +0 -116
- data/brut-js/src/Tabs.js +0 -168
- data/brut-js/src/Toast.js +0 -102
- data/brut-js/src/Tracing.js +0 -247
- data/brut-js/src/appForTestingOnly.js +0 -15
- data/brut-js/src/index.js +0 -133
- data/brut-js/src/testing/AssetMetadata.js +0 -35
- data/brut-js/src/testing/AssetMetadataLoader.js +0 -25
- data/brut-js/src/testing/CustomElementTest.js +0 -235
- data/brut-js/src/testing/DOMCreator.js +0 -45
- data/brut-js/src/testing/index.js +0 -48
- data/brut.gemspec +0 -71
- data/brutrb.com/.vitepress/config.mjs +0 -164
- data/brutrb.com/.vitepress/plugins/jsdocLinker.js +0 -34
- data/brutrb.com/.vitepress/plugins/rdocLinker.js +0 -18
- data/brutrb.com/.vitepress/theme/custom.css +0 -14
- data/brutrb.com/.vitepress/theme/index.js +0 -18
- data/brutrb.com/.vitepress/theme/style.css +0 -139
- data/brutrb.com/adrs.md +0 -16
- data/brutrb.com/ai.md +0 -68
- data/brutrb.com/assets.md +0 -131
- data/brutrb.com/bin/build +0 -5
- data/brutrb.com/bin/deploy +0 -7
- data/brutrb.com/bin/dev +0 -5
- data/brutrb.com/bin/setup +0 -6
- data/brutrb.com/brut-js.md +0 -128
- data/brutrb.com/business-logic.md +0 -55
- data/brutrb.com/cli.md +0 -274
- data/brutrb.com/components.md +0 -265
- data/brutrb.com/configuration.md +0 -256
- data/brutrb.com/css.md +0 -103
- data/brutrb.com/custom-element-tests.md +0 -148
- data/brutrb.com/database-access.md +0 -201
- data/brutrb.com/database-schema.md +0 -320
- data/brutrb.com/deployment.md +0 -158
- data/brutrb.com/dev-environment.md +0 -186
- data/brutrb.com/dir-structure.md +0 -120
- data/brutrb.com/doc-conventions.md +0 -41
- data/brutrb.com/dx +0 -1
- data/brutrb.com/end-to-end-tests.md +0 -176
- data/brutrb.com/features.md +0 -373
- data/brutrb.com/flash-and-session.md +0 -208
- data/brutrb.com/form-constraints.md +0 -266
- data/brutrb.com/forms.md +0 -238
- data/brutrb.com/getting-started.md +0 -142
- data/brutrb.com/handlers.md +0 -177
- data/brutrb.com/hooks.md +0 -176
- data/brutrb.com/i18n.md +0 -190
- data/brutrb.com/images/DevEnvironment.graffle +0 -0
- data/brutrb.com/images/DevEnvironment.png +0 -0
- data/brutrb.com/images/LogoSquare.png +0 -0
- data/brutrb.com/images/LogoStop.png +0 -0
- data/brutrb.com/images/LogoTall.png +0 -0
- data/brutrb.com/images/Makefile +0 -10
- data/brutrb.com/images/OverviewMetro.graffle +0 -0
- data/brutrb.com/images/OverviewMetro.png +0 -0
- data/brutrb.com/images/dev-env-overview.dot +0 -54
- data/brutrb.com/images/dev-env-overview.png +0 -0
- data/brutrb.com/images/dev-env-protocol.dot +0 -37
- data/brutrb.com/images/dev-env-protocol.png +0 -0
- data/brutrb.com/images/overview.graffle +0 -0
- data/brutrb.com/images/overview.png +0 -0
- data/brutrb.com/images/spa.dot +0 -19
- data/brutrb.com/images/spa.png +0 -0
- data/brutrb.com/images/tutorial/02-confirmation-dialog-browser-element-styled.png +0 -0
- data/brutrb.com/images/tutorial/02-confirmation-dialog-browser-element.png +0 -0
- data/brutrb.com/images/tutorial/02-confirmation-dialog-browser.png +0 -0
- data/brutrb.com/images/tutorial/02-confirmation-flow.graffle +0 -0
- data/brutrb.com/images/tutorial/02-confirmation-flow.png +0 -0
- data/brutrb.com/images/tutorial/basic-form-with-violations.png +0 -0
- data/brutrb.com/images/tutorial/basic-form.png +0 -0
- data/brutrb.com/images/tutorial/initial-home-page.png +0 -0
- data/brutrb.com/images/tutorial/new-post-editor.png +0 -0
- data/brutrb.com/images/tutorial/new-post-home-page.png +0 -0
- data/brutrb.com/images/tutorial/styled-form-with-server-side-violations.png +0 -0
- data/brutrb.com/images/tutorial/styled-form-with-violations.png +0 -0
- data/brutrb.com/images/tutorial/styled-home-page-with-posts.png +0 -0
- data/brutrb.com/images/tutorial/styled-home-page.png +0 -0
- data/brutrb.com/images/tutorial/welcome-to-brut.png +0 -0
- data/brutrb.com/images/workspace-protocol.dot +0 -44
- data/brutrb.com/images/workspace-protocol.png +0 -0
- data/brutrb.com/index.md +0 -34
- data/brutrb.com/instrumentation.md +0 -331
- data/brutrb.com/javascript.md +0 -122
- data/brutrb.com/jobs.md +0 -114
- data/brutrb.com/keyword-injection.md +0 -195
- data/brutrb.com/layouts.md +0 -156
- data/brutrb.com/lsp.md +0 -23
- data/brutrb.com/markdown-examples.md +0 -85
- data/brutrb.com/middleware.md +0 -80
- data/brutrb.com/overview.md +0 -68
- data/brutrb.com/package-lock.json +0 -2451
- data/brutrb.com/package.json +0 -11
- data/brutrb.com/pages.md +0 -290
- data/brutrb.com/public/SocialImage.png +0 -0
- data/brutrb.com/public/favicon.ico +0 -0
- data/brutrb.com/recipes/alternate-layouts.md +0 -32
- data/brutrb.com/recipes/authentication.md +0 -336
- data/brutrb.com/recipes/custom-flash.md +0 -51
- data/brutrb.com/recipes/dev-env-secrets.md +0 -87
- data/brutrb.com/recipes/form-errors.md +0 -148
- data/brutrb.com/recipes/indexed-forms.md +0 -149
- data/brutrb.com/recipes/migrations.md +0 -210
- data/brutrb.com/recipes/text-field-component.md +0 -182
- data/brutrb.com/roadmap.md +0 -52
- data/brutrb.com/routes.md +0 -189
- data/brutrb.com/security.md +0 -102
- data/brutrb.com/seed-data.md +0 -63
- data/brutrb.com/space-time-continuum.md +0 -81
- data/brutrb.com/tutorial.md +0 -138
- data/brutrb.com/tutorials/01-intro.md +0 -1654
- data/brutrb.com/tutorials/02-dialog.md +0 -569
- data/brutrb.com/unit-tests.md +0 -148
- data/brutrb.com/why.md +0 -19
- data/docker-compose.dx.yml +0 -25
- data/docs/404.html +0 -26
- data/docs/CNAME +0 -1
- data/docs/SocialImage.png +0 -0
- data/docs/adrs.html +0 -29
- data/docs/ai.html +0 -29
- data/docs/api/Brut/BackEnd/SeedData.html +0 -493
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server/FlushSpans.html +0 -214
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares/Server.html +0 -125
- data/docs/api/Brut/BackEnd/Sidekiq/Middlewares.html +0 -125
- data/docs/api/Brut/BackEnd/Sidekiq.html +0 -125
- data/docs/api/Brut/BackEnd/Validators/FormValidator.html +0 -414
- data/docs/api/Brut/BackEnd/Validators.html +0 -128
- data/docs/api/Brut/BackEnd.html +0 -132
- data/docs/api/Brut/CLI/App.html +0 -1601
- data/docs/api/Brut/CLI/AppRunner.html +0 -491
- data/docs/api/Brut/CLI/Apps/BuildAssets/All.html +0 -264
- data/docs/api/Brut/CLI/Apps/BuildAssets/CSS.html +0 -306
- data/docs/api/Brut/CLI/Apps/BuildAssets/Images.html +0 -262
- data/docs/api/Brut/CLI/Apps/BuildAssets/JS.html +0 -314
- data/docs/api/Brut/CLI/Apps/BuildAssets.html +0 -183
- data/docs/api/Brut/CLI/Apps/DB/Create.html +0 -365
- data/docs/api/Brut/CLI/Apps/DB/Drop.html +0 -357
- data/docs/api/Brut/CLI/Apps/DB/Migrate.html +0 -389
- data/docs/api/Brut/CLI/Apps/DB/NewMigration.html +0 -339
- data/docs/api/Brut/CLI/Apps/DB/Rebuild.html +0 -329
- data/docs/api/Brut/CLI/Apps/DB/Seed.html +0 -347
- data/docs/api/Brut/CLI/Apps/DB/Status.html +0 -383
- data/docs/api/Brut/CLI/Apps/DB.html +0 -183
- data/docs/api/Brut/CLI/Apps/DeployBase/GitChecks.html +0 -270
- data/docs/api/Brut/CLI/Apps/DeployBase.html +0 -257
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy/Deploy.html +0 -587
- data/docs/api/Brut/CLI/Apps/HerokuContainerBasedDeploy.html +0 -196
- data/docs/api/Brut/CLI/Apps/Scaffold/Action/Route.html +0 -303
- data/docs/api/Brut/CLI/Apps/Scaffold/Action.html +0 -508
- data/docs/api/Brut/CLI/Apps/Scaffold/Component.html +0 -398
- data/docs/api/Brut/CLI/Apps/Scaffold/CustomElementTest.html +0 -374
- data/docs/api/Brut/CLI/Apps/Scaffold/DbModel.html +0 -384
- data/docs/api/Brut/CLI/Apps/Scaffold/E2ETest.html +0 -410
- data/docs/api/Brut/CLI/Apps/Scaffold/Form.html +0 -262
- data/docs/api/Brut/CLI/Apps/Scaffold/Page/Route.html +0 -303
- data/docs/api/Brut/CLI/Apps/Scaffold/Page.html +0 -480
- data/docs/api/Brut/CLI/Apps/Scaffold/RoutesEditor.html +0 -450
- data/docs/api/Brut/CLI/Apps/Scaffold/Test.html +0 -380
- data/docs/api/Brut/CLI/Apps/Scaffold.html +0 -253
- data/docs/api/Brut/CLI/Apps/Test/Audit.html +0 -470
- data/docs/api/Brut/CLI/Apps/Test/E2e.html +0 -407
- data/docs/api/Brut/CLI/Apps/Test/JS.html +0 -262
- data/docs/api/Brut/CLI/Apps/Test/Run.html +0 -578
- data/docs/api/Brut/CLI/Apps/Test.html +0 -253
- data/docs/api/Brut/CLI/Apps.html +0 -125
- data/docs/api/Brut/CLI/Command.html +0 -2425
- data/docs/api/Brut/CLI/Error.html +0 -139
- data/docs/api/Brut/CLI/ExecutionResults/Result.html +0 -664
- data/docs/api/Brut/CLI/ExecutionResults.html +0 -675
- data/docs/api/Brut/CLI/Executor.html +0 -561
- data/docs/api/Brut/CLI/InvalidOption.html +0 -245
- data/docs/api/Brut/CLI/Options.html +0 -880
- data/docs/api/Brut/CLI/Output.html +0 -699
- data/docs/api/Brut/CLI/SystemExecError.html +0 -451
- data/docs/api/Brut/CLI.html +0 -263
- data/docs/api/Brut/FactoryBot.html +0 -225
- data/docs/api/Brut/Framework/App.html +0 -1097
- data/docs/api/Brut/Framework/Config.html +0 -1071
- data/docs/api/Brut/Framework/Container.html +0 -1464
- data/docs/api/Brut/Framework/Error.html +0 -140
- data/docs/api/Brut/Framework/Errors/AbstractMethod.html +0 -232
- data/docs/api/Brut/Framework/Errors/Bug.html +0 -234
- data/docs/api/Brut/Framework/Errors/MissingConfiguration.html +0 -257
- data/docs/api/Brut/Framework/Errors/MissingParameter.html +0 -273
- data/docs/api/Brut/Framework/Errors/NoClassForPath.html +0 -471
- data/docs/api/Brut/Framework/Errors/NotFound.html +0 -308
- data/docs/api/Brut/Framework/Errors/NotImplemented.html +0 -234
- data/docs/api/Brut/Framework/Errors.html +0 -351
- data/docs/api/Brut/Framework/FussyTypeEnforcement.html +0 -392
- data/docs/api/Brut/Framework/MCP.html +0 -871
- data/docs/api/Brut/Framework/ProjectEnvironment.html +0 -648
- data/docs/api/Brut/Framework.html +0 -129
- data/docs/api/Brut/FrontEnd/AssetPathResolver.html +0 -317
- data/docs/api/Brut/FrontEnd/Component/Helpers.html +0 -420
- data/docs/api/Brut/FrontEnd/Component.html +0 -434
- data/docs/api/Brut/FrontEnd/Components/ConstraintViolations.html +0 -491
- data/docs/api/Brut/FrontEnd/Components/FormTag.html +0 -526
- data/docs/api/Brut/FrontEnd/Components/I18nTranslations.html +0 -313
- data/docs/api/Brut/FrontEnd/Components/Input.html +0 -195
- data/docs/api/Brut/FrontEnd/Components/Inputs/ButtonTag.html +0 -447
- data/docs/api/Brut/FrontEnd/Components/Inputs/CsrfToken.html +0 -339
- data/docs/api/Brut/FrontEnd/Components/Inputs/InputTag.html +0 -568
- data/docs/api/Brut/FrontEnd/Components/Inputs/RadioButton.html +0 -419
- data/docs/api/Brut/FrontEnd/Components/Inputs/SelectTagWithOptions.html +0 -610
- data/docs/api/Brut/FrontEnd/Components/Inputs/TextareaTag.html +0 -534
- data/docs/api/Brut/FrontEnd/Components/Inputs.html +0 -125
- data/docs/api/Brut/FrontEnd/Components/LocaleDetection.html +0 -367
- data/docs/api/Brut/FrontEnd/Components/PageIdentifier.html +0 -355
- data/docs/api/Brut/FrontEnd/Components/TimeTag.html +0 -655
- data/docs/api/Brut/FrontEnd/Components/Traceparent.html +0 -352
- data/docs/api/Brut/FrontEnd/Components.html +0 -156
- data/docs/api/Brut/FrontEnd/CsrfProtector.html +0 -250
- data/docs/api/Brut/FrontEnd/Download.html +0 -467
- data/docs/api/Brut/FrontEnd/Flash.html +0 -1150
- data/docs/api/Brut/FrontEnd/Form.html +0 -1227
- data/docs/api/Brut/FrontEnd/Forms/Button.html +0 -331
- data/docs/api/Brut/FrontEnd/Forms/ButtonInputDefinition.html +0 -537
- data/docs/api/Brut/FrontEnd/Forms/ConstraintViolation.html +0 -590
- data/docs/api/Brut/FrontEnd/Forms/Input/Color.html +0 -201
- data/docs/api/Brut/FrontEnd/Forms/Input/TimeOfDay.html +0 -535
- data/docs/api/Brut/FrontEnd/Forms/Input.html +0 -1567
- data/docs/api/Brut/FrontEnd/Forms/InputDeclarations.html +0 -635
- data/docs/api/Brut/FrontEnd/Forms/InputDefinition.html +0 -1336
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInput.html +0 -730
- data/docs/api/Brut/FrontEnd/Forms/RadioButtonGroupInputDefinition.html +0 -587
- data/docs/api/Brut/FrontEnd/Forms/SelectInput.html +0 -734
- data/docs/api/Brut/FrontEnd/Forms/SelectInputDefinition.html +0 -582
- data/docs/api/Brut/FrontEnd/Forms/ValidityState.html +0 -659
- data/docs/api/Brut/FrontEnd/Forms.html +0 -127
- data/docs/api/Brut/FrontEnd/GenericResponse.html +0 -377
- data/docs/api/Brut/FrontEnd/Handler.html +0 -442
- data/docs/api/Brut/FrontEnd/Handlers/CspReportingHandler.html +0 -318
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler/TraceParent.html +0 -336
- data/docs/api/Brut/FrontEnd/Handlers/InstrumentationHandler.html +0 -399
- data/docs/api/Brut/FrontEnd/Handlers/LocaleDetectionHandler.html +0 -354
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler/Form.html +0 -151
- data/docs/api/Brut/FrontEnd/Handlers/MissingHandler.html +0 -315
- data/docs/api/Brut/FrontEnd/Handlers.html +0 -125
- data/docs/api/Brut/FrontEnd/HandlingResults.html +0 -339
- data/docs/api/Brut/FrontEnd/HttpMethod.html +0 -661
- data/docs/api/Brut/FrontEnd/HttpStatus.html +0 -496
- data/docs/api/Brut/FrontEnd/InlineSvgLocator.html +0 -284
- data/docs/api/Brut/FrontEnd/Layout.html +0 -486
- data/docs/api/Brut/FrontEnd/Middleware.html +0 -135
- data/docs/api/Brut/FrontEnd/Middlewares/AnnotateBrutOwnedPaths.html +0 -288
- data/docs/api/Brut/FrontEnd/Middlewares/Favicon.html +0 -292
- data/docs/api/Brut/FrontEnd/Middlewares/OpenTelemetrySpan.html +0 -324
- data/docs/api/Brut/FrontEnd/Middlewares/ReloadApp.html +0 -376
- data/docs/api/Brut/FrontEnd/Middlewares.html +0 -125
- data/docs/api/Brut/FrontEnd/Page.html +0 -781
- data/docs/api/Brut/FrontEnd/Pages/MissingPage.html +0 -797
- data/docs/api/Brut/FrontEnd/Pages.html +0 -125
- data/docs/api/Brut/FrontEnd/RequestContext.html +0 -1312
- data/docs/api/Brut/FrontEnd/RouteHook.html +0 -424
- data/docs/api/Brut/FrontEnd/RouteHooks/AgeFlash.html +0 -242
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineScripts.html +0 -249
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts/ReportOnly.html +0 -264
- data/docs/api/Brut/FrontEnd/RouteHooks/CSPNoInlineStylesOrScripts.html +0 -261
- data/docs/api/Brut/FrontEnd/RouteHooks/LocaleDetection.html +0 -284
- data/docs/api/Brut/FrontEnd/RouteHooks/SetupRequestContext.html +0 -252
- data/docs/api/Brut/FrontEnd/RouteHooks.html +0 -115
- data/docs/api/Brut/FrontEnd/Routing/FormHandlerRoute.html +0 -227
- data/docs/api/Brut/FrontEnd/Routing/FormRoute.html +0 -305
- data/docs/api/Brut/FrontEnd/Routing/MissingForm.html +0 -324
- data/docs/api/Brut/FrontEnd/Routing/MissingHandler.html +0 -319
- data/docs/api/Brut/FrontEnd/Routing/MissingPage.html +0 -315
- data/docs/api/Brut/FrontEnd/Routing/MissingPath.html +0 -315
- data/docs/api/Brut/FrontEnd/Routing/PageRoute.html +0 -327
- data/docs/api/Brut/FrontEnd/Routing/Route.html +0 -761
- data/docs/api/Brut/FrontEnd/Routing.html +0 -927
- data/docs/api/Brut/FrontEnd/Session.html +0 -1195
- data/docs/api/Brut/FrontEnd.html +0 -134
- data/docs/api/Brut/I18n/BaseMethods.html +0 -931
- data/docs/api/Brut/I18n/ForBackEnd.html +0 -302
- data/docs/api/Brut/I18n/ForCLI.html +0 -302
- data/docs/api/Brut/I18n/ForHTML.html +0 -296
- data/docs/api/Brut/I18n/HTTPAcceptLanguage/AlwaysEnglish.html +0 -316
- data/docs/api/Brut/I18n/HTTPAcceptLanguage.html +0 -930
- data/docs/api/Brut/I18n.html +0 -127
- data/docs/api/Brut/Instrumentation/LoggerSpanExporter.html +0 -435
- data/docs/api/Brut/Instrumentation/Methods/ClassMethods.html +0 -596
- data/docs/api/Brut/Instrumentation/Methods.html +0 -173
- data/docs/api/Brut/Instrumentation/OpenTelemetry/NormalizedAttributes.html +0 -286
- data/docs/api/Brut/Instrumentation/OpenTelemetry/Span.html +0 -302
- data/docs/api/Brut/Instrumentation/OpenTelemetry.html +0 -866
- data/docs/api/Brut/Instrumentation.html +0 -128
- data/docs/api/Brut/RubocopConfig.html +0 -237
- data/docs/api/Brut/SinatraHelpers/ClassMethods.html +0 -534
- data/docs/api/Brut/SinatraHelpers.html +0 -281
- data/docs/api/Brut/SpecSupport/ClockSupport.html +0 -383
- data/docs/api/Brut/SpecSupport/ComponentSupport.html +0 -496
- data/docs/api/Brut/SpecSupport/E2ETestServer.html +0 -503
- data/docs/api/Brut/SpecSupport/E2eSupport.html +0 -142
- data/docs/api/Brut/SpecSupport/EnhancedNode.html +0 -403
- data/docs/api/Brut/SpecSupport/FlashSupport.html +0 -278
- data/docs/api/Brut/SpecSupport/GeneralSupport/ClassMethods.html +0 -401
- data/docs/api/Brut/SpecSupport/GeneralSupport.html +0 -195
- data/docs/api/Brut/SpecSupport/HandlerSupport.html +0 -160
- data/docs/api/Brut/SpecSupport/Matchers/BeABug.html +0 -142
- data/docs/api/Brut/SpecSupport/Matchers/BePageFor.html +0 -142
- data/docs/api/Brut/SpecSupport/Matchers/BeRoutingFor.html +0 -155
- data/docs/api/Brut/SpecSupport/Matchers/HaveConstraintViolation.html +0 -583
- data/docs/api/Brut/SpecSupport/Matchers/HaveGenerated.html +0 -149
- data/docs/api/Brut/SpecSupport/Matchers/HaveHTMLAttribute.html +0 -466
- data/docs/api/Brut/SpecSupport/Matchers/HaveI18nString.html +0 -149
- data/docs/api/Brut/SpecSupport/Matchers/HaveLinkTo.html +0 -149
- data/docs/api/Brut/SpecSupport/Matchers/HaveRedirectedTo.html +0 -165
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedHttpStatus.html +0 -158
- data/docs/api/Brut/SpecSupport/Matchers/HaveReturnedRackResponse.html +0 -156
- data/docs/api/Brut/SpecSupport/Matchers.html +0 -125
- data/docs/api/Brut/SpecSupport/RSpecSetup/OptionalSidekiqSupport.html +0 -335
- data/docs/api/Brut/SpecSupport/RSpecSetup.html +0 -637
- data/docs/api/Brut/SpecSupport/SessionSupport.html +0 -196
- data/docs/api/Brut/SpecSupport.html +0 -129
- data/docs/api/Brut.html +0 -341
- data/docs/api/Clock.html +0 -603
- data/docs/api/ModuleName.html +0 -595
- data/docs/api/RichString.html +0 -775
- data/docs/api/SemanticLogger/Appender/Async.html +0 -219
- data/docs/api/Sequel/Extensions/BrutInstrumentation.html +0 -119
- data/docs/api/Sequel/Extensions/BrutMigrations.html +0 -541
- data/docs/api/Sequel/Extensions.html +0 -117
- data/docs/api/Sequel/Plugins/CreatedAt/InstanceMethods.html +0 -105
- data/docs/api/Sequel/Plugins/CreatedAt.html +0 -125
- data/docs/api/Sequel/Plugins/ExternalId/ClassMethods.html +0 -207
- data/docs/api/Sequel/Plugins/ExternalId/InstanceMethods.html +0 -186
- data/docs/api/Sequel/Plugins/ExternalId.html +0 -218
- data/docs/api/Sequel/Plugins/FindBang/ClassMethods.html +0 -202
- data/docs/api/Sequel/Plugins/FindBang.html +0 -125
- data/docs/api/Sequel/Plugins.html +0 -117
- data/docs/api/Sequel.html +0 -117
- data/docs/api/_index.html +0 -1719
- data/docs/api/class_list.html +0 -54
- data/docs/api/css/common.css +0 -1
- data/docs/api/css/full_list.css +0 -59
- data/docs/api/css/style.css +0 -504
- data/docs/api/file.README.html +0 -172
- data/docs/api/file_list.html +0 -59
- data/docs/api/frames.html +0 -22
- data/docs/api/index.html +0 -172
- data/docs/api/js/app.js +0 -344
- data/docs/api/js/full_list.js +0 -242
- data/docs/api/js/jquery.js +0 -4
- data/docs/api/method_list.html +0 -4422
- data/docs/api/top-level-namespace.html +0 -112
- data/docs/assets/02-confirmation-dialog-browser-element-styled.3NEGM20-.png +0 -0
- data/docs/assets/02-confirmation-dialog-browser-element.DPsf0xUW.png +0 -0
- data/docs/assets/02-confirmation-dialog-browser.DH8ALFO4.png +0 -0
- data/docs/assets/02-confirmation-flow.D9gZ0S5U.png +0 -0
- data/docs/assets/DevEnvironment.DaFcVfwP.png +0 -0
- data/docs/assets/LogoStop.Gb3tDhL1.png +0 -0
- data/docs/assets/OverviewMetro.DUS-5fUZ.png +0 -0
- data/docs/assets/adrs.md.YglbWtQe.js +0 -1
- data/docs/assets/adrs.md.YglbWtQe.lean.js +0 -1
- data/docs/assets/ai.md.ChLnvDAX.js +0 -1
- data/docs/assets/ai.md.ChLnvDAX.lean.js +0 -1
- data/docs/assets/app.CovevI7X.js +0 -1
- data/docs/assets/assets.md.BEF6Oz6K.js +0 -19
- data/docs/assets/assets.md.BEF6Oz6K.lean.js +0 -1
- data/docs/assets/basic-form-with-violations.Cv6Y9-Q_.png +0 -0
- data/docs/assets/basic-form.DbHnu0oW.png +0 -0
- data/docs/assets/brut-js.md.BMz0X1Rz.js +0 -12
- data/docs/assets/brut-js.md.BMz0X1Rz.lean.js +0 -1
- data/docs/assets/business-logic.md.DbuaOYGU.js +0 -1
- data/docs/assets/business-logic.md.DbuaOYGU.lean.js +0 -1
- data/docs/assets/chunks/@localSearchIndexroot.BiNc3tFI.js +0 -1
- data/docs/assets/chunks/VPLocalSearchBox.CrvLAvKW.js +0 -8
- data/docs/assets/chunks/framework.C4nOkCZI.js +0 -18
- data/docs/assets/chunks/theme.BAi5_yQI.js +0 -2
- data/docs/assets/cli.md.DDMar_51.js +0 -122
- data/docs/assets/cli.md.DDMar_51.lean.js +0 -1
- data/docs/assets/components.md.9sqJ27Oc.js +0 -96
- data/docs/assets/components.md.9sqJ27Oc.lean.js +0 -1
- data/docs/assets/configuration.md.Cb_oAR8Z.js +0 -78
- data/docs/assets/configuration.md.Cb_oAR8Z.lean.js +0 -1
- data/docs/assets/css.md.K5rOCOQY.js +0 -21
- data/docs/assets/css.md.K5rOCOQY.lean.js +0 -1
- data/docs/assets/custom-element-tests.md.DiLe-eFw.js +0 -69
- data/docs/assets/custom-element-tests.md.DiLe-eFw.lean.js +0 -1
- data/docs/assets/database-access.md.Dc8l2Plf.js +0 -63
- data/docs/assets/database-access.md.Dc8l2Plf.lean.js +0 -1
- data/docs/assets/database-schema.md.BJ_JhXmO.js +0 -70
- data/docs/assets/database-schema.md.BJ_JhXmO.lean.js +0 -1
- data/docs/assets/deployment.md.CHTx2eTR.js +0 -55
- data/docs/assets/deployment.md.CHTx2eTR.lean.js +0 -1
- data/docs/assets/dev-env-protocol.DysDAtnz.png +0 -0
- data/docs/assets/dev-environment.md.B1S9p5ZK.js +0 -16
- data/docs/assets/dev-environment.md.B1S9p5ZK.lean.js +0 -1
- data/docs/assets/dir-structure.md.D1T2kGwj.js +0 -46
- data/docs/assets/dir-structure.md.D1T2kGwj.lean.js +0 -1
- data/docs/assets/doc-conventions.md.CDnWaEFg.js +0 -1
- data/docs/assets/doc-conventions.md.CDnWaEFg.lean.js +0 -1
- data/docs/assets/end-to-end-tests.md.BJJdNDYL.js +0 -28
- data/docs/assets/end-to-end-tests.md.BJJdNDYL.lean.js +0 -1
- data/docs/assets/features.md.BDWxnyNO.js +0 -154
- data/docs/assets/features.md.BDWxnyNO.lean.js +0 -1
- data/docs/assets/flash-and-session.md.CUsMxoNl.js +0 -79
- data/docs/assets/flash-and-session.md.CUsMxoNl.lean.js +0 -1
- data/docs/assets/form-constraints.md.KlfXSKm2.js +0 -90
- data/docs/assets/form-constraints.md.KlfXSKm2.lean.js +0 -1
- data/docs/assets/forms.md.BdpYpNIk.js +0 -64
- data/docs/assets/forms.md.BdpYpNIk.lean.js +0 -1
- data/docs/assets/getting-started.md.CKpNGvno.js +0 -31
- data/docs/assets/getting-started.md.CKpNGvno.lean.js +0 -1
- data/docs/assets/handlers.md.C5tUwmmo.js +0 -54
- data/docs/assets/handlers.md.C5tUwmmo.lean.js +0 -1
- data/docs/assets/hooks.md.CoiYCKRc.js +0 -80
- data/docs/assets/hooks.md.CoiYCKRc.lean.js +0 -1
- data/docs/assets/i18n.md.DxkCKhUw.js +0 -23
- data/docs/assets/i18n.md.DxkCKhUw.lean.js +0 -1
- data/docs/assets/index.md.DnphWyQd.js +0 -1
- data/docs/assets/index.md.DnphWyQd.lean.js +0 -1
- data/docs/assets/initial-home-page.DNIaYmgP.png +0 -0
- data/docs/assets/instrumentation.md.BcxjC4jd.js +0 -90
- data/docs/assets/instrumentation.md.BcxjC4jd.lean.js +0 -1
- data/docs/assets/javascript.md.D6fxhaQb.js +0 -31
- data/docs/assets/javascript.md.D6fxhaQb.lean.js +0 -1
- data/docs/assets/jobs.md.Bi3qb3v6.js +0 -25
- data/docs/assets/jobs.md.Bi3qb3v6.lean.js +0 -1
- data/docs/assets/keyword-injection.md.CqLnnzIz.js +0 -21
- data/docs/assets/keyword-injection.md.CqLnnzIz.lean.js +0 -1
- data/docs/assets/layouts.md.HEbeK7Jr.js +0 -68
- data/docs/assets/layouts.md.HEbeK7Jr.lean.js +0 -1
- data/docs/assets/lsp.md.bE9dW8n9.js +0 -1
- data/docs/assets/lsp.md.bE9dW8n9.lean.js +0 -1
- data/docs/assets/markdown-examples.md.BPmtHlc-.js +0 -33
- data/docs/assets/markdown-examples.md.BPmtHlc-.lean.js +0 -1
- data/docs/assets/middleware.md.BhOIsg59.js +0 -20
- data/docs/assets/middleware.md.BhOIsg59.lean.js +0 -1
- data/docs/assets/new-post-editor.DrHr-5oh.png +0 -0
- data/docs/assets/new-post-home-page.Bm34lyMg.png +0 -0
- data/docs/assets/overview.md.BpWAgPFH.js +0 -1
- data/docs/assets/overview.md.BpWAgPFH.lean.js +0 -1
- data/docs/assets/pages.md.B3sQXpEd.js +0 -45
- data/docs/assets/pages.md.B3sQXpEd.lean.js +0 -1
- data/docs/assets/recipes_alternate-layouts.md.C1QzVkA7.js +0 -22
- data/docs/assets/recipes_alternate-layouts.md.C1QzVkA7.lean.js +0 -1
- data/docs/assets/recipes_authentication.md.CyvoIW82.js +0 -157
- data/docs/assets/recipes_authentication.md.CyvoIW82.lean.js +0 -1
- data/docs/assets/recipes_custom-flash.md.6gFqf2uL.js +0 -26
- data/docs/assets/recipes_custom-flash.md.6gFqf2uL.lean.js +0 -1
- data/docs/assets/recipes_dev-env-secrets.md.DC_jVY9U.js +0 -12
- data/docs/assets/recipes_dev-env-secrets.md.DC_jVY9U.lean.js +0 -1
- data/docs/assets/recipes_form-errors.md.B5ptSzMO.js +0 -66
- data/docs/assets/recipes_form-errors.md.B5ptSzMO.lean.js +0 -1
- data/docs/assets/recipes_indexed-forms.md.BYYQGW2C.js +0 -74
- data/docs/assets/recipes_indexed-forms.md.BYYQGW2C.lean.js +0 -1
- data/docs/assets/recipes_migrations.md.Cid7-3cu.js +0 -97
- data/docs/assets/recipes_migrations.md.Cid7-3cu.lean.js +0 -1
- data/docs/assets/recipes_text-field-component.md.VhOsCtKI.js +0 -101
- data/docs/assets/recipes_text-field-component.md.VhOsCtKI.lean.js +0 -1
- data/docs/assets/roadmap.md.DqC1Y7Zt.js +0 -1
- data/docs/assets/roadmap.md.DqC1Y7Zt.lean.js +0 -1
- data/docs/assets/routes.md.C1dgIBtD.js +0 -21
- data/docs/assets/routes.md.C1dgIBtD.lean.js +0 -1
- data/docs/assets/security.md.Jn4SY1uK.js +0 -1
- data/docs/assets/security.md.Jn4SY1uK.lean.js +0 -1
- data/docs/assets/seed-data.md.UZW0WxYN.js +0 -14
- data/docs/assets/seed-data.md.UZW0WxYN.lean.js +0 -1
- data/docs/assets/spa.qejUdp-5.png +0 -0
- data/docs/assets/space-time-continuum.md.D9rYGDFH.js +0 -1
- data/docs/assets/space-time-continuum.md.D9rYGDFH.lean.js +0 -1
- data/docs/assets/style.B1z60PPQ.css +0 -1
- data/docs/assets/styled-form-with-server-side-violations.Bjxd8Dpv.png +0 -0
- data/docs/assets/styled-form-with-violations.Bv_sa9tg.png +0 -0
- data/docs/assets/styled-home-page-with-posts.Dd4kG89D.png +0 -0
- data/docs/assets/styled-home-page.BzdI7dWz.png +0 -0
- data/docs/assets/tutorial.md.BX6f6l00.js +0 -27
- data/docs/assets/tutorial.md.BX6f6l00.lean.js +0 -1
- data/docs/assets/tutorials_01-intro.md.CzZ3kpF_.js +0 -708
- data/docs/assets/tutorials_01-intro.md.CzZ3kpF_.lean.js +0 -1
- data/docs/assets/tutorials_02-dialog.md.Z_DOF2mU.js +0 -274
- data/docs/assets/tutorials_02-dialog.md.Z_DOF2mU.lean.js +0 -1
- data/docs/assets/unit-tests.md.vDsdBbO_.js +0 -13
- data/docs/assets/unit-tests.md.vDsdBbO_.lean.js +0 -1
- data/docs/assets/welcome-to-brut.VSWzl17-.png +0 -0
- data/docs/assets/why.md.4WpxdrQ2.js +0 -1
- data/docs/assets/why.md.4WpxdrQ2.lean.js +0 -1
- data/docs/assets/workspace-protocol.C0gXsoDb.png +0 -0
- data/docs/assets.html +0 -47
- data/docs/brut-css/brut.max.css +0 -22372
- data/docs/brut-css/classes/appearances.html +0 -783
- data/docs/brut-css/classes/background-colors.html +0 -3529
- data/docs/brut-css/classes/border-colors.html +0 -3529
- data/docs/brut-css/classes/borders.html +0 -2293
- data/docs/brut-css/classes/dimensions.html +0 -2581
- data/docs/brut-css/classes/flex.html +0 -917
- data/docs/brut-css/classes/foreground-colors.html +0 -3261
- data/docs/brut-css/classes/junk-drawer.html +0 -431
- data/docs/brut-css/classes/layout.html +0 -668
- data/docs/brut-css/classes/lists.html +0 -331
- data/docs/brut-css/classes/positioning.html +0 -1751
- data/docs/brut-css/classes/spacings.html +0 -2633
- data/docs/brut-css/classes/typography.html +0 -2206
- data/docs/brut-css/customization/advanced-configuration.html +0 -204
- data/docs/brut-css/customization/breakpoints.html +0 -227
- data/docs/brut-css/customization/design-system.html +0 -197
- data/docs/brut-css/customization/pseudo-classes.html +0 -228
- data/docs/brut-css/docs.css +0 -98
- data/docs/brut-css/getting-started/core-concepts.html +0 -234
- data/docs/brut-css/getting-started/installation.html +0 -190
- data/docs/brut-css/getting-started/overview.html +0 -210
- data/docs/brut-css/getting-started/simple-example.html +0 -285
- data/docs/brut-css/index.html +0 -193
- data/docs/brut-css/prism-twilight.min.css +0 -1
- data/docs/brut-css/properties/colors.html +0 -1548
- data/docs/brut-css/properties/spacings.html +0 -614
- data/docs/brut-css/properties/typography.html +0 -777
- data/docs/brut-js/api/AjaxSubmit.html +0 -452
- data/docs/brut-js/api/AjaxSubmit.js.html +0 -550
- data/docs/brut-js/api/Autosubmit.html +0 -192
- data/docs/brut-js/api/Autosubmit.js.html +0 -114
- data/docs/brut-js/api/BaseCustomElement.html +0 -1091
- data/docs/brut-js/api/BaseCustomElement.js.html +0 -312
- data/docs/brut-js/api/BrutCustomElements.html +0 -172
- data/docs/brut-js/api/BufferedLogger.html +0 -173
- data/docs/brut-js/api/ConfirmSubmit.html +0 -286
- data/docs/brut-js/api/ConfirmSubmit.js.html +0 -188
- data/docs/brut-js/api/ConfirmationDialog.html +0 -425
- data/docs/brut-js/api/ConfirmationDialog.js.html +0 -194
- data/docs/brut-js/api/ConstraintViolationMessage.html +0 -498
- data/docs/brut-js/api/ConstraintViolationMessage.js.html +0 -191
- data/docs/brut-js/api/ConstraintViolationMessages.html +0 -590
- data/docs/brut-js/api/ConstraintViolationMessages.js.html +0 -149
- data/docs/brut-js/api/CopyToClipboard.html +0 -345
- data/docs/brut-js/api/CopyToClipboard.js.html +0 -147
- data/docs/brut-js/api/Form.html +0 -291
- data/docs/brut-js/api/Form.js.html +0 -198
- data/docs/brut-js/api/I18nTranslation.html +0 -409
- data/docs/brut-js/api/I18nTranslation.js.html +0 -115
- data/docs/brut-js/api/LocaleDetection.html +0 -312
- data/docs/brut-js/api/LocaleDetection.js.html +0 -168
- data/docs/brut-js/api/Logger.html +0 -702
- data/docs/brut-js/api/Logger.js.html +0 -141
- data/docs/brut-js/api/Message.html +0 -238
- data/docs/brut-js/api/Message.js.html +0 -113
- data/docs/brut-js/api/PrefixedLogger.html +0 -369
- data/docs/brut-js/api/RichString.html +0 -1049
- data/docs/brut-js/api/RichString.js.html +0 -167
- data/docs/brut-js/api/Tabs.html +0 -295
- data/docs/brut-js/api/Tabs.js.html +0 -219
- data/docs/brut-js/api/Toast.html +0 -270
- data/docs/brut-js/api/Toast.js.html +0 -153
- data/docs/brut-js/api/Tracing.html +0 -277
- data/docs/brut-js/api/Tracing.js.html +0 -298
- data/docs/brut-js/api/external-CustomElementRegistry.html +0 -140
- data/docs/brut-js/api/external-Performance.html +0 -138
- data/docs/brut-js/api/external-Promise.html +0 -138
- data/docs/brut-js/api/external-ValidityState.html +0 -138
- data/docs/brut-js/api/external-Window.html +0 -233
- data/docs/brut-js/api/external-fetch.html +0 -138
- data/docs/brut-js/api/global.html +0 -400
- data/docs/brut-js/api/index.html +0 -168
- data/docs/brut-js/api/index.js.html +0 -184
- data/docs/brut-js/api/module-testing.html +0 -383
- data/docs/brut-js/api/scripts/linenumber.js +0 -25
- data/docs/brut-js/api/scripts/prettify/Apache-License-2.0.txt +0 -202
- data/docs/brut-js/api/scripts/prettify/lang-css.js +0 -2
- data/docs/brut-js/api/scripts/prettify/prettify.js +0 -28
- data/docs/brut-js/api/styles/jsdoc-default.css +0 -327
- data/docs/brut-js/api/styles/prettify-jsdoc.css +0 -111
- data/docs/brut-js/api/styles/prettify-tomorrow.css +0 -132
- data/docs/brut-js/api/testing.AssetMetadata.html +0 -172
- data/docs/brut-js/api/testing.AssetMetadataLoader.html +0 -171
- data/docs/brut-js/api/testing.CustomElementTest.html +0 -679
- data/docs/brut-js/api/testing.DOMCreator.html +0 -171
- data/docs/brut-js/api/testing_AssetMetadata.js.html +0 -86
- data/docs/brut-js/api/testing_AssetMetadataLoader.js.html +0 -76
- data/docs/brut-js/api/testing_CustomElementTest.js.html +0 -286
- data/docs/brut-js/api/testing_DOMCreator.js.html +0 -96
- data/docs/brut-js/api/testing_index.js.html +0 -99
- data/docs/brut-js.html +0 -40
- data/docs/business-logic.html +0 -29
- data/docs/cli.html +0 -150
- data/docs/components.html +0 -124
- data/docs/configuration.html +0 -106
- data/docs/css.html +0 -49
- data/docs/custom-element-tests.html +0 -97
- data/docs/database-access.html +0 -91
- data/docs/database-schema.html +0 -98
- data/docs/deployment.html +0 -83
- data/docs/dev-environment.html +0 -44
- data/docs/dir-structure.html +0 -74
- data/docs/doc-conventions.html +0 -29
- data/docs/end-to-end-tests.html +0 -56
- data/docs/favicon.ico +0 -0
- data/docs/features.html +0 -182
- data/docs/flash-and-session.html +0 -107
- data/docs/form-constraints.html +0 -118
- data/docs/forms.html +0 -92
- data/docs/getting-started.html +0 -59
- data/docs/handlers.html +0 -82
- data/docs/hashmap.json +0 -1
- data/docs/hooks.html +0 -108
- data/docs/i18n.html +0 -51
- data/docs/index.html +0 -29
- data/docs/instrumentation.html +0 -118
- data/docs/javascript.html +0 -59
- data/docs/jobs.html +0 -53
- data/docs/keyword-injection.html +0 -49
- data/docs/layouts.html +0 -96
- data/docs/lsp.html +0 -29
- data/docs/markdown-examples.html +0 -61
- data/docs/middleware.html +0 -48
- data/docs/overview.html +0 -29
- data/docs/pages.html +0 -73
- data/docs/recipes/alternate-layouts.html +0 -50
- data/docs/recipes/authentication.html +0 -185
- data/docs/recipes/custom-flash.html +0 -54
- data/docs/recipes/dev-env-secrets.html +0 -40
- data/docs/recipes/form-errors.html +0 -94
- data/docs/recipes/indexed-forms.html +0 -102
- data/docs/recipes/migrations.html +0 -125
- data/docs/recipes/text-field-component.html +0 -129
- data/docs/roadmap.html +0 -29
- data/docs/routes.html +0 -49
- data/docs/security.html +0 -29
- data/docs/seed-data.html +0 -42
- data/docs/space-time-continuum.html +0 -29
- data/docs/tutorial.html +0 -55
- data/docs/tutorials/01-intro.html +0 -736
- data/docs/tutorials/02-dialog.html +0 -302
- data/docs/unit-tests.html +0 -41
- data/docs/vp-icons.css +0 -1
- data/docs/why.html +0 -29
- data/docs-todo.md +0 -32
- data/dx/bash_customizations +0 -6
- data/dx/build +0 -73
- data/dx/build.pre +0 -15
- data/dx/docker-compose.env +0 -22
- data/dx/dx.sh.lib +0 -24
- data/dx/exec +0 -75
- data/dx/setupkit.sh.lib +0 -144
- data/dx/show-help-in-app-container-then-wait.sh +0 -38
- data/lib/brut/cli/app.rb +0 -238
- data/lib/brut/cli/app_runner.rb +0 -252
- data/lib/brut/cli/command.rb +0 -258
- data/lib/brut/cli/execution_results.rb +0 -119
- data/lib/brut/front_end/layouts/_internal.html.erb +0 -68
- data/lib/brut/front_end/pages/_missing_page.html.erb +0 -17
- data/mkbrut/.gitignore +0 -16
- data/mkbrut/CODE_OF_CONDUCT.txt +0 -100
- data/mkbrut/Gemfile +0 -3
- data/mkbrut/Gemfile.lock +0 -20
- data/mkbrut/LICENSE.txt +0 -370
- data/mkbrut/README.md +0 -145
- data/mkbrut/Rakefile +0 -2
- data/mkbrut/bin/build +0 -36
- data/mkbrut/bin/ci +0 -19
- data/mkbrut/bin/docs +0 -19
- data/mkbrut/bin/publish +0 -129
- data/mkbrut/bin/rake +0 -16
- data/mkbrut/bin/setup +0 -30
- data/mkbrut/brut-welcome.png +0 -0
- data/mkbrut/deploy/.dockerignore +0 -2
- data/mkbrut/deploy/Dockerfile +0 -25
- data/mkbrut/dx +0 -1
- data/mkbrut/exe/mkbrut +0 -5
- data/mkbrut/lib/mkbrut/app_name.rb +0 -29
- data/mkbrut/lib/mkbrut/app_options.rb +0 -36
- data/mkbrut/lib/mkbrut/cli.rb +0 -189
- data/mkbrut/lib/mkbrut/erb_binding_delegate.rb +0 -20
- data/mkbrut/lib/mkbrut/ops.rb +0 -17
- data/mkbrut/lib/mkbrut/organization.rb +0 -5
- data/mkbrut/lib/mkbrut/segments.rb +0 -8
- data/mkbrut/lib/mkbrut/version.rb +0 -3
- data/mkbrut/lib/mkbrut.rb +0 -20
- data/mkbrut/mkbrut.gemspec +0 -34
- data/mkbrut/templates/Base/app/src/front_end/images/LogoPylon.png +0 -0
- data/mkbrut/templates/Base/bin/build-assets +0 -7
- data/mkbrut/templates/Base/bin/ci +0 -39
- data/mkbrut/templates/Base/bin/db +0 -9
- data/mkbrut/templates/Base/bin/scaffold +0 -9
- data/mkbrut/templates/Base/bin/setup +0 -287
- data/mkbrut/templates/Base/bin/test +0 -9
- data/mkbrut/templates/Base/bin/test-server +0 -29
- data/mkbrut/templates/Base/dx/prune +0 -19
- data/mkbrut/templates/Base/dx/start +0 -30
- data/mkbrut/templates/Base/dx/stop +0 -23
- data/mkbrut/templates/segments/Heroku/deploy/heroku_config.rb +0 -27
- data/specs/brut/front_end/forms/input.spec.rb +0 -978
- data/specs/brut/front_end/forms/radio_button_group_input.spec.rb +0 -54
- data/specs/brut/front_end/forms/select_input.spec.rb +0 -54
- data/specs/brut/instrumentation/methods.spec.rb +0 -399
- data/specs/brut/junk_drawer.spec.rb +0 -79
- data/specs/spec_helper.rb +0 -27
- data/specs/support/matchers/have_constraint_violation.rb +0 -23
- data/specs/support/matchers.rb +0 -5
- data/specs/support.rb +0 -3
- /data/{mkbrut/lib/mkbrut → lib/brut/cli/apps/new}/prefixed_io.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/.dockerignore +0 -0
- /data/{mkbrut/templates → templates}/Base/.env.development.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/.env.test.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/.gitignore +0 -0
- /data/{mkbrut/templates → templates}/Base/.projections.json +0 -0
- /data/{mkbrut/templates → templates}/Base/Dockerfile.dx +0 -0
- /data/{mkbrut/templates → templates}/Base/Gemfile.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/Procfile.development +0 -0
- /data/{mkbrut/templates → templates}/Base/Procfile.test +0 -0
- /data/{mkbrut/templates → templates}/Base/README.md +0 -0
- /data/{mkbrut/templates → templates}/Base/README.md.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/bootstrap.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/config/i18n/en/1_defaults.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/config/i18n/en/2_app.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/public/static/manifest.json.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/app.rb.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/back_end/data_models/app_data_model.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/back_end/data_models/db.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/back_end/data_models/seed/seed_data.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/components/app_component.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/components/custom_element_registration.rb.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/css/index.css +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/css/svgs.css +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/forms/app_form.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/handlers/app_handler.rb +0 -0
- /data/{brutrb.com → templates/Base/app/src/front_end}/images/LogoPylon.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/LogoTransit.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/apple-touch-icon-120x120.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/apple-touch-icon-152x152.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/apple-touch-icon-167x167.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/apple-touch-icon-180x180.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/favicon.ico +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/icon.png +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/images/mkicons.sh +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/js/index.js +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/layouts/blank_layout.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/layouts/default_layout.rb.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/pages/app_page.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/pages/home_page.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/support/app_session.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/svgs/README.md +0 -0
- /data/{mkbrut/templates → templates}/Base/app/src/front_end/svgs/comment-button.svg +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/README.md.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/console +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/dbconsole +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/dev +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/run +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/run.run +0 -0
- /data/{mkbrut/templates → templates}/Base/bin/startup-message +0 -0
- /data/{mkbrut/templates → templates}/Base/config.ru +0 -0
- /data/{mkbrut/templates → templates}/Base/docker-compose.dx.yml +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/README.md +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/bash_customizations +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/bash_customizations.local +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/build +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/dx.sh.lib +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/exec +0 -0
- /data/{dx → templates/Base/dx}/prune +0 -0
- /data/{mkbrut/templates → templates}/Base/dx/show-help-in-app-container-then-wait.sh +0 -0
- /data/{dx → templates/Base/dx}/start +0 -0
- /data/{dx → templates/Base/dx}/stop +0 -0
- /data/{mkbrut/templates → templates}/Base/package.json.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/puma.config.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/e2e/home_page.spec.rb.erb +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/front_end/js/SpecHelper.js +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/front_end/pages/home_page.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/lint_factories.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/spec_helper.rb +0 -0
- /data/{mkbrut/templates → templates}/Base/specs/support.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/BareBones/app/src/front_end/handlers/trigger_exception_handler.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/BareBones/app/src/front_end/js/Example.js.erb +0 -0
- /data/{mkbrut/templates → templates}/segments/BareBones/specs/front_end/handlers/trigger_exception_handler.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/BareBones/specs/front_end/js/Example.spec.js.erb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/back_end/data_models/db/guestbook_message.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/back_end/data_models/migrations/20250628194124_guestbook.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/components/flash_component.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/css/constraint-violations.css +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/fonts/monaspace-xenon.ttf +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/forms/guestbook_message_form.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/handlers/guestbook_message_handler.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/pages/guestbook_page/message_component.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/pages/guestbook_page.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/app/src/front_end/pages/new_guestbook_message_page.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/back_end/data_models/db/guestbook_message.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/e2e/guest_message.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/factories/db/guestbook_message.factory.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/front_end/components/flash_component.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/front_end/handlers/guestbook_message_handler.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/front_end/pages/guestbook_page/message_component.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/front_end/pages/guestbook_page.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Demo/specs/front_end/pages/new_guestbook_message_page.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Heroku/bin/deploy +0 -0
- /data/{mkbrut/templates → templates}/segments/Heroku/deploy/docker-entrypoint +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/app/boot_sidekiq.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/app/config/sidekiq.yml +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/app/src/back_end/jobs/app_job.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/app/src/back_end/jobs/example_job.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/app/src/back_end/segments/sidekiq_segment.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/bin/run.sidekiq +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/specs/back_end/jobs/example_job.spec.rb +0 -0
- /data/{mkbrut/templates → templates}/segments/Sidekiq/specs/integration/sidekiq_works.spec.rb +0 -0
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
# Instrumentation and Observability
|
|
2
|
-
|
|
3
|
-
Brut has built-in support for OpenTelemetry, which is an open standard used by many observability vendors
|
|
4
|
-
to allow you to understand the behavior of your app in production. Brut also includes a configuration for
|
|
5
|
-
the [otel-desktop-viewer](https://github.com/CtrlSpice/otel-desktop-viewer/), which allows you to see
|
|
6
|
-
instrumentation in development.
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
### Why Instrument?
|
|
11
|
-
|
|
12
|
-
In production, you'll need to know what your app is doing and how well it's working. Historically, logs
|
|
13
|
-
can provide this information in a roundabout way. Over the last many years, Application Performance
|
|
14
|
-
Monitoring (APM) vendors like New Relic and Data Dog allowed developers to see much richer detail about
|
|
15
|
-
how an app is working.
|
|
16
|
-
|
|
17
|
-
You could see, for example, the 95th percentil of your dashboard controller's performance, or the top 10
|
|
18
|
-
slowest SQL statements your app is executing. OpenTelemetry attempts to unify the API used to communicate
|
|
19
|
-
this information from your app to your chosen vendor, and most vendors support it.
|
|
20
|
-
|
|
21
|
-
Instrumentation, then, is a way to record what your app is doing, how long its taking, and perhaps even
|
|
22
|
-
why it's doing what it's doing, down to a very specific level. If properly configured, you could examine
|
|
23
|
-
the performance of the app for a particular user on a particular day.
|
|
24
|
-
|
|
25
|
-
### Setting up Instrumentation
|
|
26
|
-
|
|
27
|
-
Brut automatically sets up OpenTelemetry (OTel) tracing. The primary interface you will use is
|
|
28
|
-
`Brut::Instrumentation::OpenTelemetry`, which is available via `Brut.container.instrumentation`. We'll
|
|
29
|
-
discuss that in a moment.
|
|
30
|
-
|
|
31
|
-
To configure the specifics of where the traces will go, the OTel gem uses environment variables:
|
|
32
|
-
|
|
33
|
-
| Variable | Value | Purpose |
|
|
34
|
-
|--------------------------------------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
35
|
-
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Depends on environment | Where to send the tracers. This is provided by your vendor, but is `http://otel-desktop-viewer:4318` in development |
|
|
36
|
-
| `OTEL_EXPORTER_OTLP_HEADERS` | Depends on vendor | Your vendor may ask you to set this. It often contains identifying information or API keys |
|
|
37
|
-
| `OTEL_EXPORTER_OTLP_PROTOCOL` | http/protobuf | Your vendor may request a different protocol, but protobuf is common and supported by otel-desktop-viewer |
|
|
38
|
-
| `OTEL_LOG_LEVEL` | debug | Useful when setting everything up to understand why things aren't working if they aren't working |
|
|
39
|
-
| `OTEL_RUBY_BSP_START_THREAD_ON_BOOT` | false | Deals with esoteric issues with Puma. See [this GitHub issue](https://github.com/open-telemetry/opentelemetry-ruby/issues/462) for the details.
|
|
40
|
-
| `OTEL_SERVICE_NAME` | Your app's `id` from `App` | Identifiers your app's name to the vendor |
|
|
41
|
-
| `OTEL_TRACES_EXPORTER` | otlp | Configures the class inside the OTel gem that will export the instrumentation to the vendor. If you omit this, Brut will log the instrumentation to the console |
|
|
42
|
-
|
|
43
|
-
When you created your Brut app, your `.env.development` and `.env.test` should have values for all these
|
|
44
|
-
environment variables that will send instrumentation to the otel-desktop-viewer that was also configured.
|
|
45
|
-
|
|
46
|
-
If you run your app using `bin/dev` and use the app for a bit, then go to `http://localhost:8000`, you
|
|
47
|
-
will see the otel-desktop-viewer UI and can browse the spans and traces sent by Brut.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### What is Instrumented By Default
|
|
51
|
-
|
|
52
|
-
Brut attempts to automatically instrument useful things so you don't have to do anything to start getting
|
|
53
|
-
data. Brut will attempt to conform to standard semantics for HTTP requests and SQL statements.
|
|
54
|
-
|
|
55
|
-
Here is a non-exhaustive list of what Brut automatically instruments:
|
|
56
|
-
|
|
57
|
-
* How long each page or handler request takes, broken down by components.
|
|
58
|
-
* CLI execution time
|
|
59
|
-
* Time to rebuild the schema for tests
|
|
60
|
-
* Time to run tests
|
|
61
|
-
* Time to apply migrations
|
|
62
|
-
* Time spent inside a route hook
|
|
63
|
-
* The locale detected from the browser
|
|
64
|
-
* The layout class used when rendering a page
|
|
65
|
-
* If a requested path is owned by Brut or not
|
|
66
|
-
* Ignored parameters on all form submissions
|
|
67
|
-
* How long reloading takes in development
|
|
68
|
-
* CSP reporting results
|
|
69
|
-
* SQL Statements
|
|
70
|
-
|
|
71
|
-
> [!WARNING]
|
|
72
|
-
> `Sequel::Extensions::BrutInstrumentation` sets up telemetry for
|
|
73
|
-
> Sequel, and it does it in a relatively simplistic way. The result
|
|
74
|
-
> is that *all* SQL statements are part of the telemetry, including
|
|
75
|
-
> the actual values inserted or used in `WHERE` clauses.
|
|
76
|
-
> While you should not be putting sensitive data into your database,
|
|
77
|
-
> be warned that this is happening. There are plans to improve this
|
|
78
|
-
> to be more flexible and reduce the chance of sensitive data
|
|
79
|
-
> being sent in traces.
|
|
80
|
-
|
|
81
|
-
### Adding Your Own Instrumentation
|
|
82
|
-
|
|
83
|
-
You can add instrumentation in two main ways, both of which can be used together.
|
|
84
|
-
|
|
85
|
-
#### Instrumenting Existing Methods
|
|
86
|
-
|
|
87
|
-
Although Brut instruments the entrypoints to pages, handlers, and components, you will likely have your own set of back-end business logic that needs to be instrumented. If you aren't trying to diagnose a specific problem and just want to see your back-end class' methods show up in your instrumentation vendor's dashboard, `Brut::Instrumentation::Methods` will be the easiest way to do that.
|
|
88
|
-
|
|
89
|
-
`Brut::Instrumentation::Methods` can be included in any class, and provides three class methods, which are *mutually exclusive*:
|
|
90
|
-
|
|
91
|
-
* `instrument_all` instruments all methods, public and private.
|
|
92
|
-
* `instrument_public` instruments only public methods.
|
|
93
|
-
* `instrument` instruments one or more named methods.
|
|
94
|
-
|
|
95
|
-
`initialize` is never instrumented.
|
|
96
|
-
|
|
97
|
-
Consider this class:
|
|
98
|
-
|
|
99
|
-
```ruby
|
|
100
|
-
class Widget
|
|
101
|
-
def initialize
|
|
102
|
-
# ...
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def search
|
|
106
|
-
# ...
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def save
|
|
110
|
-
# ...
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
private
|
|
114
|
-
|
|
115
|
-
def delete_orphans
|
|
116
|
-
# ...
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If we use `instrument_all`…
|
|
122
|
-
|
|
123
|
-
```ruby
|
|
124
|
-
class Widget
|
|
125
|
-
include Brut::Instrumentation::Methods
|
|
126
|
-
instrument_all
|
|
127
|
-
|
|
128
|
-
# ...
|
|
129
|
-
end
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
…`search`, `save`, and `delete_orphans` will be instrumented. If we use `instrument_public`…
|
|
133
|
-
|
|
134
|
-
```ruby
|
|
135
|
-
class Widget
|
|
136
|
-
include Brut::Instrumentation::Methods
|
|
137
|
-
instrument_public
|
|
138
|
-
|
|
139
|
-
# ...
|
|
140
|
-
end
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
…then only `search` and `save` are instrumented.
|
|
144
|
-
|
|
145
|
-
We can pick and choose by using `instrument`.
|
|
146
|
-
|
|
147
|
-
```ruby{2,7,20}
|
|
148
|
-
class Widget
|
|
149
|
-
include Brut::Instrumentation::Methods
|
|
150
|
-
def initialize
|
|
151
|
-
# ...
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
instrument def search
|
|
155
|
-
# ...
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def save
|
|
159
|
-
# ...
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
private
|
|
163
|
-
|
|
164
|
-
def delete_orphans
|
|
165
|
-
# ...
|
|
166
|
-
end
|
|
167
|
-
instrument :delete_orphans
|
|
168
|
-
end
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Above, `search` and `delete_orphans` are instrumented. Since `def` in Ruby returns a symbol, `instrument def search` is the same as `instrument :search`.
|
|
172
|
-
|
|
173
|
-
#### Explicit Instrumentation with Spans, Attributes, and Events
|
|
174
|
-
|
|
175
|
-
To add explicit instrumentation, you'll create one or more of the following:
|
|
176
|
-
|
|
177
|
-
* *Spans* record a block of code. They are shown as a sub-span if one is already in effect. When you
|
|
178
|
-
create a span, that means it will be shown in the context of the HTTP request.
|
|
179
|
-
* *Attributes* can be added to the current span to provide more context about what is happening. For
|
|
180
|
-
example, the HTTP request method is an attribute of the span used for the HTTP request. These attributes
|
|
181
|
-
allow for sophisticated querying in the vendor's UI.
|
|
182
|
-
* *Events* record things that happen and metadata about that thing. These are like log statements. They
|
|
183
|
-
are associated with the span you are in when you add the event.
|
|
184
|
-
|
|
185
|
-
These can all be added via `Brut.container.instrumentation`, which is a
|
|
186
|
-
`Brut::Instrumentation::OpenTelemetry` instance.
|
|
187
|
-
|
|
188
|
-
These methods are available:
|
|
189
|
-
|
|
190
|
-
* `span(name,**attributes,&block)` - Create a new span around the block yielded.
|
|
191
|
-
* `add_attributes(attributes)` - Add attributes to the current span. These will be prefixed with your
|
|
192
|
-
app's prefix so it's clear in the observability UI that they are for your app and not standard.
|
|
193
|
-
* `add_event(name,**attributes)` - Add an event with optional attributes for the current span.
|
|
194
|
-
* `record_exception(ex,attributes=nil)` - Record an exception that was caught.
|
|
195
|
-
* `record_and_reraise_exception!(ex,attributes=nil)` - Record an exception and raise it.
|
|
196
|
-
|
|
197
|
-
Suppose you want to instrument `RequireAuthBeforeHook` from the [hooks](/hooks) documentation. Although
|
|
198
|
-
the hook's `before` method is instrumented by Brut already, let's add some metadata to that span, and also
|
|
199
|
-
add a span around the login check.
|
|
200
|
-
|
|
201
|
-
```ruby {11-16,18,20,23-26}
|
|
202
|
-
# app/src/front_end/route_hooks/require_auth_before_hook.rb
|
|
203
|
-
class RequireAuthBeforeHook < Brut::FrontEnd::RouteHook
|
|
204
|
-
def before(request_context:,session:,request:,env:)
|
|
205
|
-
is_home_page = request.path_info.match(/^\/?$/)
|
|
206
|
-
is_auth_route = request.path_info.match?(/^\/auth\//)
|
|
207
|
-
is_brut_owned_path = env["brut.owned_path"]
|
|
208
|
-
|
|
209
|
-
requires_login = !is_home_page &&
|
|
210
|
-
!is_auth_route &&
|
|
211
|
-
!is_brut_owned_path
|
|
212
|
-
Brut.container.instrumentation.add_attributes(
|
|
213
|
-
requires_login:,
|
|
214
|
-
is_home_page:,
|
|
215
|
-
is_auth_route:,
|
|
216
|
-
is_brut_owned_path:
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
Brut.container.instrumentation.span("login-check") do |span|
|
|
220
|
-
if session.logged_in?
|
|
221
|
-
span.add_attributes(logged_in: true)
|
|
222
|
-
request_context[:authenticated_account] = session.authenticated_account
|
|
223
|
-
requires_login = false
|
|
224
|
-
else
|
|
225
|
-
span.add_attributes(logged_in: false)
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
if requires_login
|
|
230
|
-
redirect_to(Auth::LoginPage)
|
|
231
|
-
else
|
|
232
|
-
continue
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Now, for every request someone makes to our app, we will see a span for the `RequireAuthBeforeHook`, and
|
|
240
|
-
inside that span, we'll see the attributes we added as well as a sub-span representing the login check
|
|
241
|
-
(which itself will have an attribute about the user's logged-in status).
|
|
242
|
-
|
|
243
|
-
### Client-Side Observability
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
The class `Brut::FrontEnd::Handlers::InstrumentationHandler` is set up to receive information from the
|
|
247
|
-
client-side to provide insights about client-side behavior as part of a server-side request. Brut
|
|
248
|
-
attempts to join up any client-side instrumentation to the request that served it.
|
|
249
|
-
|
|
250
|
-
It does this via the `Brut::FrontEnd::Components::Traceparent` component, which is included in your default layout when you created your Brut app. This creates a `<meta>` tag containing standardized information used to
|
|
251
|
-
connect the client-side behavior to the server-side request.
|
|
252
|
-
|
|
253
|
-
The Brut custom element `<brut-tracing>` uses this information, along with statistics from the browser, to
|
|
254
|
-
send a custom payload back to Brut at the route `/__brut/instrumentation`, which is handled by the
|
|
255
|
-
aforementioned `InstrumentationHandler`.
|
|
256
|
-
|
|
257
|
-
You should then see client-side tracing information as a sub-span of your HTTP request. The information available depends on the browser, and some browsers don't send much. Also keep in mind that clock drift is real and while client-side timings are accurate, the timestamps will not be.
|
|
258
|
-
|
|
259
|
-
### Logging
|
|
260
|
-
|
|
261
|
-
Brut configures [SemanticLogger](https://logger.rocketjob.io/), but uses it sparingly. Currently, Brut performs very little logging, and no request logging. You may have noticed that your app doesn't produce a lot of output in development. Brut's assumption is that you will use an OpenTelemetry vendor to understand your app in production or the otel-desktop-viewer in developoment.
|
|
262
|
-
|
|
263
|
-
That said, since SemanticLogger is configured, you can use it at will:
|
|
264
|
-
|
|
265
|
-
```ruby
|
|
266
|
-
class HomePage
|
|
267
|
-
def page_template
|
|
268
|
-
SemanticLogger[self.class].debug "page being rendered"
|
|
269
|
-
|
|
270
|
-
# ...
|
|
271
|
-
|
|
272
|
-
end
|
|
273
|
-
end
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
The logging system is currently not very configurable, and works as follows:
|
|
277
|
-
|
|
278
|
-
* In development, log messages are written to the standard output and to `logs/development.log`
|
|
279
|
-
* In test, log messages are written to `logs/test.log`
|
|
280
|
-
* In production, log messages are written to the standard output
|
|
281
|
-
|
|
282
|
-
The default log level is "debug" for the web app at "fatal" for CLI apps. You can set `LOG_LEVEL` in the environment to change this:
|
|
283
|
-
|
|
284
|
-
* `"debug"` - Show all messages
|
|
285
|
-
* `"info"` - Show info and above (not debug messages)
|
|
286
|
-
* `"warn"` - Show warnings and above (not info, not debug)
|
|
287
|
-
* `"error"` - Show errors and fatals only
|
|
288
|
-
* `"fatal"` - Show fatals only
|
|
289
|
-
|
|
290
|
-
Most CLIs also allow `--log-level` to accept one of these strings as wel ass `--verbose` to set the log level to debug.
|
|
291
|
-
|
|
292
|
-
## Testing
|
|
293
|
-
|
|
294
|
-
Generally you don't want to test instrumentation unless it's highly complex and critical to the app's
|
|
295
|
-
ability to be maintained. Ideally, your end-to-end tests will cover all the instrumentation code you
|
|
296
|
-
write so you can be sure that none of that causes a problem.
|
|
297
|
-
|
|
298
|
-
## Recommended Practices
|
|
299
|
-
|
|
300
|
-
Entire books and conferences exist on how to properly instrument your app. Our suggestion is to take what
|
|
301
|
-
you have by default and add additional instrumentation only to solve specific problems or identify
|
|
302
|
-
specific issues.
|
|
303
|
-
|
|
304
|
-
## Technical Notes
|
|
305
|
-
|
|
306
|
-
> [!IMPORTANT]
|
|
307
|
-
> Technical Notes are for deeper understanding and debugging. While we will try to keep them up-to-date with changes to Brut's
|
|
308
|
-
> internals, the source code is always more correct.
|
|
309
|
-
|
|
310
|
-
_Last Updated Aug 27, 2025_
|
|
311
|
-
|
|
312
|
-
OpenTelemetry is notoriously opaque and, ironically, unobservable in its own behavior. Thus, the implementation is subject to change as I figure out what actually does what.
|
|
313
|
-
|
|
314
|
-
### Web Requests
|
|
315
|
-
|
|
316
|
-
`Brut::FrontEnd::Middlewares::OpenTelemetrySpan` is configured in `Brut::Framework::MCP` as the first middleware. It sets up the outer span for all web requests. Inside each request block (the code internal to Brut that calls handlers or pages), this span's name is modified with the HTTP method and path via the `brut.otel.root_span` in the Rack environment.
|
|
317
|
-
|
|
318
|
-
### Client-Side
|
|
319
|
-
|
|
320
|
-
The client-side portion of this is highly customized. The Otel open source code for the client side is
|
|
321
|
-
massive and hugely complex, so Brut decided to try to produce something simple and straightforward as a
|
|
322
|
-
start. This can and will evolve over time.
|
|
323
|
-
|
|
324
|
-
### CLI Commands
|
|
325
|
-
|
|
326
|
-
Brut CLI commands are instrumented as well,
|
|
327
|
-
in `Brut::CLI::App` in `execute!`, however the trace only begins if the underlying command is going to be executed. This may change.
|
|
328
|
-
|
|
329
|
-
### Sidekiq Jobs
|
|
330
|
-
|
|
331
|
-
Although Brut currently does not provide a default Sidekiq configuration, if you set up Sidekiq and include the `opentelemetry-instrumentation-sidekiq` gem in your app's `Gemfile`, you should see instrumentation of your Sidekiq jobs. In practice, this default set up doesn't seem to work very well, so expect this to change for the better.
|
data/brutrb.com/javascript.md
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# JavaScript
|
|
2
|
-
|
|
3
|
-
Brut provides basic bundling using [esbuild](https://esbuild.github.io/). You can
|
|
4
|
-
use any front-end framework with Brut, but you don't have to use one.
|
|
5
|
-
|
|
6
|
-
Brut provides [BrutJS](/brut-js), which is a lightweight library of HTML custom elements and utility code. These elements can provide a fair bit of front-end functionality using progressive enhancement without the need for a framework.
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
All your app's JavaScript lives in `app/src/front_end/js`, or in modules you bring in via `package.json`. Brut
|
|
11
|
-
will *bundle* all of that up into a single `.js` file that is served up with your app. Brut does this by using
|
|
12
|
-
esbuild, a stable and standardized tool for bundling JavaScript.
|
|
13
|
-
|
|
14
|
-
The way esbuild works is to be given an *entry point* that requires, or transitively requires, all of your
|
|
15
|
-
JavaScript by using ES6 modules. `app/src/front_end/js/index.js` is the entry point for your app.
|
|
16
|
-
|
|
17
|
-
For example, if you have a `Widget` class that uses a `Status` class, and you also use the third party library
|
|
18
|
-
"foobar", here is how all the files would look.
|
|
19
|
-
|
|
20
|
-
First, `package.json` (in your app's root) would include `"foobar"` (and it must set `"type"` to `"module"`):
|
|
21
|
-
|
|
22
|
-
```json {3,6}
|
|
23
|
-
{
|
|
24
|
-
"name": "your-app",
|
|
25
|
-
"type": "module",
|
|
26
|
-
"license": "UNLICENSED",
|
|
27
|
-
"dependencies": {
|
|
28
|
-
"foobar": "^0.0.11"
|
|
29
|
-
},
|
|
30
|
-
"devDependencies": {
|
|
31
|
-
"chokidar-cli": "^3.0.0",
|
|
32
|
-
"esbuild": "^0.20.2",
|
|
33
|
-
"jsdom": "^25.0.1",
|
|
34
|
-
"mocha": "^10.7.3",
|
|
35
|
-
"playwright": "^1.50.1"
|
|
36
|
-
},
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Next, `app/src/front_end/js/index.js` would import both `"foobar"` and `"Widget"`:
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
import { foobar } from "foobar"
|
|
44
|
-
import Widget from "./Widget"
|
|
45
|
-
|
|
46
|
-
// ...
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Notice that "foobar", since it's brought in as a third party dependency, is imported without a `./`. Be careful
|
|
50
|
-
here! Every third party library has a different syntax for how to import whatever it is or does. Consult the
|
|
51
|
-
documentation of each third party library you wish to import.
|
|
52
|
-
|
|
53
|
-
The second `import` uses a `./` because it's importing a file in `app/src/front_end/js`, namely `Widget.js`. Be
|
|
54
|
-
careful here, too, as you must be sure to `export` the right thing. Here's what `app/src/front_end/js/Widget.js`
|
|
55
|
-
might look like:
|
|
56
|
-
|
|
57
|
-
```javascript
|
|
58
|
-
import Status from "./extra/Status"
|
|
59
|
-
|
|
60
|
-
class Widget {
|
|
61
|
-
status = new Status()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export default Widget
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Note that we import `Status` here. Unlike Ruby, ES6 modules requires each class that references a class to
|
|
68
|
-
import it explicitly. Also notice that we do `export default Widget`, which allows `import Widget` to work.
|
|
69
|
-
|
|
70
|
-
Finally, `app/src/front_end/extra/Status.js` looks like so:
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
class Status {
|
|
74
|
-
}
|
|
75
|
-
export default Status
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
When `bin/build-assets` runs, esbuild will use `app/src/front_end/js/index.js` as its *entry point*, and will
|
|
79
|
-
bundle both `Widget.js` and the "foobar" library. When it bundles `Widget.js`, it will see that it imports
|
|
80
|
-
`extra/Status.js` and bundle that, too.
|
|
81
|
-
|
|
82
|
-
This bundle can be included in your app by ensuring this is in your layout:
|
|
83
|
-
|
|
84
|
-
```ruby {5}
|
|
85
|
-
def view_template
|
|
86
|
-
doctype
|
|
87
|
-
html(lang: "en") do
|
|
88
|
-
head do
|
|
89
|
-
script(defer: true, src: asset_path("/js/app.js"))
|
|
90
|
-
# ...
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
The `asset_path` helper takes a logical path—`/js/app.js`—and returns the actual path the browser can use. More
|
|
94
|
-
details on this can be found in [assets](/assets).
|
|
95
|
-
|
|
96
|
-
## Testing
|
|
97
|
-
|
|
98
|
-
Client-side behavior is best tested with end-to-end tests, however you can simplify your end-to-end tests by
|
|
99
|
-
creating unit tests of your custom elements. [BrutJS provides limited support for this](/brut-js/api/module-testing.html)
|
|
100
|
-
|
|
101
|
-
## Recommended Practices
|
|
102
|
-
|
|
103
|
-
Brut encourages you to use HTML custom elements as progressive enhancements over server-generated views. This sort of client-side code will age well. The toolchain and dependencies are minimal, so you will not have to worry too much about code written this way.
|
|
104
|
-
|
|
105
|
-
It *will* be lower level and more verbose than existing frameworks. We would argue that it is not significantly more difficult and the sustainability is worth it.
|
|
106
|
-
|
|
107
|
-
## Technical Notes
|
|
108
|
-
|
|
109
|
-
> [!IMPORTANT]
|
|
110
|
-
> Technical Notes are for deeper understanding and debugging. While we will try to keep them up-to-date with changes to Brut's
|
|
111
|
-
> internals, the source code is always more correct.
|
|
112
|
-
|
|
113
|
-
_Last Updated May 7, 2025_
|
|
114
|
-
|
|
115
|
-
Currently, Brut only supports a single entry point and bundle. This could be easily made more flexible if there
|
|
116
|
-
is a desire to finely tweak the JavaScript loaded on specific pages.
|
|
117
|
-
|
|
118
|
-
Brut also does not expose any esbuild configuration. This could be provided in the future, but for now, it is hard-coded.
|
|
119
|
-
|
|
120
|
-
Brut may provide more direct support for import maps, but as of now, import maps are
|
|
121
|
-
not widely used outside of Rails, and tend to cause a lot of problems, especially if
|
|
122
|
-
you aren't able to field an HTTP/2 web server (or even know what that is).
|
data/brutrb.com/jobs.md
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# Background Jobs
|
|
2
|
-
|
|
3
|
-
Brut ships without any background job system, however it should work with any system you'd like to use. Brut
|
|
4
|
-
can install/configure Sidekiq for you, however you are expected to understand Sidekiq in order to use it.
|
|
5
|
-
|
|
6
|
-
## Setting up Sidekiq
|
|
7
|
-
|
|
8
|
-
Brut's code-generation system used for installing capabilities are called *segments*, and Brut provides a
|
|
9
|
-
Sidekiq segment you can use to get an initial working setup of Sidekiq in your Brut app.
|
|
10
|
-
|
|
11
|
-
### Adding the Segment
|
|
12
|
-
|
|
13
|
-
1. Ensure your project files are all committed. This is so you can easily see (and, if needed, undo) the
|
|
14
|
-
changes `mkbrut` will make.
|
|
15
|
-
2. Use `mkbrut` to add the segment:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
docker run \
|
|
19
|
-
--pull always \
|
|
20
|
-
-v "$PWD":"$PWD" \
|
|
21
|
-
-w "$PWD" \
|
|
22
|
-
-u $(id -u):$(id -g) \
|
|
23
|
-
-it \
|
|
24
|
-
thirdtank/mkbrut \
|
|
25
|
-
mkbrut add-segment -r /path/to/your/project sidekiq
|
|
26
|
-
```
|
|
27
|
-
3. This will modify and create various files in your project. Check them out if you like:
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
> git status
|
|
31
|
-
```
|
|
32
|
-
4. Exit your dev environment (i.e. hit `Ctrl-C` wherever you ran `dx/start`).
|
|
33
|
-
5. Rebuild and restart your dev environment. This may take a moment, since Valkey will be downloaded.
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
your-computer> dx/build
|
|
37
|
-
your-computer> dx/start
|
|
38
|
-
```
|
|
39
|
-
6. In another Terminal, connect to your dev container and run `bin/setup`
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
your-computer> dx/exec bash
|
|
43
|
-
devcontainer> bin/setup
|
|
44
|
-
```
|
|
45
|
-
7. The segment provides an integration test that will use the actual Sidekiq server and client, running
|
|
46
|
-
against the actual Valkey database that was installed:
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
devcontainer> bin/test e2e specs/integration/sidekiq_works.spec.rb
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
If this test passes, you are ready to go.
|
|
53
|
-
|
|
54
|
-
### Using Sidekiq in Brut
|
|
55
|
-
|
|
56
|
-
Jobs live in `app/src/back_end/jobs`, however this is just a convention and is not enforced - you can place a
|
|
57
|
-
job anywhere that Zeitwerk will find the class. Brut also provides basic configuration and a base job.
|
|
58
|
-
|
|
59
|
-
| File | Purpose|
|
|
60
|
-
|------|--------|
|
|
61
|
-
| `app/config/sidekiq.yml` | Standard configuration for Sidekiq |
|
|
62
|
-
| `app/src/back-end/jobs/app_job.r` | Base class for your jobs that includes `Sidekiq::Job` |
|
|
63
|
-
| `app/src/back-end/segments/sidekiq_segment.rb` | Initial client and server configuration for Sidekiq (that you can't do with `sidekiq.yml`. This sets up basic observability for your jobs |
|
|
64
|
-
|
|
65
|
-
### Accessing the Web UI
|
|
66
|
-
|
|
67
|
-
The Sidekiq segment mounts the Sidekiq Web UI to your app inside `config.ru`:
|
|
68
|
-
|
|
69
|
-
```ruby
|
|
70
|
-
# ...
|
|
71
|
-
map "/sidekiq" do
|
|
72
|
-
use Rack::Auth::Basic, "Sidekiq" do |username, password|
|
|
73
|
-
[username, password] == [ENV.fetch("SIDEKIQ_BASIC_AUTH_USER"), ENV.fetch("SIDEKIQ_BASIC_AUTH_PASSWORD")]
|
|
74
|
-
end
|
|
75
|
-
run Sidekiq::Web.new
|
|
76
|
-
end
|
|
77
|
-
# ...
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Values for `SIDEKIQ_BASIC_AUTH_USER` and `SIDEKIQ_BASIC_AUTH_PASSWORD` for dev and test are placed into
|
|
81
|
-
`.env.development` and `.env.test`, respectively. You must provide these values for production, based on
|
|
82
|
-
however you are managing environment variables.
|
|
83
|
-
|
|
84
|
-
Once you start the app, navigat to `http://localhost:6502/sidekiq` and enter the username/password from
|
|
85
|
-
`.env.development`. You should see the web UI.
|
|
86
|
-
|
|
87
|
-
### Deploying with The Heroku Segment
|
|
88
|
-
|
|
89
|
-
If you have set up [Heroku Container-based Deployment](/deployment.md#heroku-container-based-deployment), you
|
|
90
|
-
may need to modify `deploy/heroku_config.rb`. The Sidekiq segement should have edited this, however if you
|
|
91
|
-
installed the Heroku segment after setting up Sidekiq, you'll need to add to the file:
|
|
92
|
-
|
|
93
|
-
```ruby [2-6]
|
|
94
|
-
class HerokuConfig
|
|
95
|
-
def self.additional_images
|
|
96
|
-
{
|
|
97
|
-
"sidekiq" => {
|
|
98
|
-
cmd: "bin/run sidekiq",
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Setting Up Other Job Systems
|
|
106
|
-
|
|
107
|
-
To use another job system, you'll likely want to start with `app/src/app.rb`. You can place all your
|
|
108
|
-
initialize code in `#boot!` to get things working, then factor it out from there. `App`, the class in that
|
|
109
|
-
file, is a normal class, so you can extract your setup to other normal classes and bring them in as you would
|
|
110
|
-
in any other Ruby app.
|
|
111
|
-
|
|
112
|
-
Just note that `App`'s `initialize` method should avoid making network connections, so while you are safe to
|
|
113
|
-
create objects and configuration here, do not connect to databases or anything like that. You *can* do that
|
|
114
|
-
inside `boot!`.
|