suspenders 20250317.0 → 20251219.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/CODEOWNERS +9 -0
  4. data/CONTRIBUTING.md +71 -0
  5. data/FEATURES.md +177 -0
  6. data/GOALS.md +65 -0
  7. data/LICENSE +21 -0
  8. data/NEWS.md +808 -0
  9. data/README.md +59 -67
  10. data/RELEASING.md +18 -0
  11. data/Rakefile +6 -13
  12. data/SECURITY.md +19 -0
  13. data/exe/suspenders +38 -0
  14. data/lib/suspenders/cli.rb +64 -0
  15. data/lib/suspenders/version.rb +4 -4
  16. data/lib/suspenders.rb +5 -6
  17. data/lib/templates/Procfile +3 -0
  18. data/lib/templates/Procfile.dev +2 -0
  19. data/lib/{generators/templates/views/flashes.html.erb → templates/app/views/application/_flashes.html.erb} +4 -2
  20. data/lib/templates/app/views/application/_form_errors.html.erb +11 -0
  21. data/lib/templates/config/initializers/sidekiq.rb +14 -0
  22. data/lib/templates/lib/development/seeder.rb +21 -0
  23. data/lib/templates/lib/tasks/development.rake +15 -0
  24. data/lib/templates/spec/support/action_mailer.rb +11 -0
  25. data/lib/{generators/templates/factories/factory_bot_rspec.rb → templates/spec/support/factory_bot.rb} +0 -2
  26. data/lib/templates/web.rb +544 -0
  27. data/sig/suspenders.rbs +4 -0
  28. metadata +34 -119
  29. data/lib/generators/suspenders/accessibility_generator.rb +0 -24
  30. data/lib/generators/suspenders/advisories_generator.rb +0 -32
  31. data/lib/generators/suspenders/ci_generator.rb +0 -54
  32. data/lib/generators/suspenders/email_generator.rb +0 -56
  33. data/lib/generators/suspenders/environments/development_generator.rb +0 -50
  34. data/lib/generators/suspenders/environments/production_generator.rb +0 -27
  35. data/lib/generators/suspenders/environments/test_generator.rb +0 -39
  36. data/lib/generators/suspenders/factories_generator.rb +0 -64
  37. data/lib/generators/suspenders/inline_svg_generator.rb +0 -24
  38. data/lib/generators/suspenders/install/web_generator.rb +0 -85
  39. data/lib/generators/suspenders/jobs_generator.rb +0 -34
  40. data/lib/generators/suspenders/lint_generator.rb +0 -94
  41. data/lib/generators/suspenders/prerequisites_generator.rb +0 -19
  42. data/lib/generators/suspenders/rake_generator.rb +0 -25
  43. data/lib/generators/suspenders/setup_generator.rb +0 -14
  44. data/lib/generators/suspenders/styles_generator.rb +0 -84
  45. data/lib/generators/suspenders/tasks_generator.rb +0 -20
  46. data/lib/generators/suspenders/testing_generator.rb +0 -113
  47. data/lib/generators/suspenders/views_generator.rb +0 -38
  48. data/lib/generators/templates/ci/ci.yml.tt +0 -148
  49. data/lib/generators/templates/email/email_interceptor.rb +0 -11
  50. data/lib/generators/templates/factories/factories.rb +0 -2
  51. data/lib/generators/templates/factories/factories_test.rb +0 -9
  52. data/lib/generators/templates/inline_svg/inline_svg.rb +0 -3
  53. data/lib/generators/templates/install/web/CONTRIBUTING.md +0 -94
  54. data/lib/generators/templates/lint/config_better_html.yml +0 -2
  55. data/lib/generators/templates/lint/config_initializers_better_html.rb +0 -9
  56. data/lib/generators/templates/lint/erb-lint.yml +0 -63
  57. data/lib/generators/templates/lint/erblint.rake +0 -47
  58. data/lib/generators/templates/lint/eslintrc.json +0 -7
  59. data/lib/generators/templates/lint/package.json +0 -4
  60. data/lib/generators/templates/lint/prettierignore +0 -1
  61. data/lib/generators/templates/lint/prettierrc +0 -11
  62. data/lib/generators/templates/lint/rubocop.yml.tt +0 -7
  63. data/lib/generators/templates/lint/stylelintrc.json +0 -3
  64. data/lib/generators/templates/prerequisites/node-version.tt +0 -1
  65. data/lib/generators/templates/setup/bin_setup.rb +0 -39
  66. data/lib/generators/templates/styles/postcss.config.js +0 -11
  67. data/lib/generators/templates/tasks/dev.rake +0 -12
  68. data/lib/generators/templates/testing/action_mailer.rb +0 -5
  69. data/lib/install/web.rb +0 -70
  70. data/lib/suspenders/cleanup/generate_readme.rb +0 -165
  71. data/lib/suspenders/cleanup/organize_gemfile.rb +0 -134
  72. data/lib/suspenders/engine.rb +0 -5
  73. data/lib/suspenders/generators.rb +0 -126
  74. data/lib/suspenders/railtie.rb +0 -4
  75. data/lib/tasks/suspenders.rake +0 -37
  76. /data/lib/{generators/templates/factories → templates/spec}/factories_spec.rb +0 -0
  77. /data/lib/{generators/templates/testing → templates/spec/support}/driver.rb +0 -0
  78. /data/lib/{generators/templates/testing → templates/spec/support}/i18n.rb +0 -0
  79. /data/lib/{generators/templates/testing → templates/spec/support}/shoulda_matchers.rb +0 -0
@@ -0,0 +1,544 @@
1
+ # Methods like `copy_file` will accept relative paths to the template's location.
2
+ def source_paths
3
+ Array(super) + [__dir__]
4
+ end
5
+
6
+ def install_gems
7
+ gem "inline_svg"
8
+ gem "sidekiq"
9
+ gem "strong_migrations"
10
+
11
+ gem_group :test do
12
+ # TODO: How can we ensure we're notified of new releases?
13
+ gem "action_dispatch-testing-integration-capybara",
14
+ github: "thoughtbot/action_dispatch-testing-integration-capybara", tag: "v0.2.0",
15
+ require: "action_dispatch/testing/integration/capybara/rspec"
16
+ gem "capybara"
17
+ gem "capybara_accessibility_audit"
18
+ # TODO: How can we ensure we're notified of new releases?
19
+ gem "capybara_accessible_selectors",
20
+ git: "https://github.com/citizensadvice/capybara_accessible_selectors", tag: "v0.12.0"
21
+ gem "selenium-webdriver"
22
+ gem "shoulda-matchers", "~> 6.0"
23
+ gem "webmock"
24
+ end
25
+
26
+ gem_group :development, :test do
27
+ gem "factory_bot_rails"
28
+ gem "rspec-rails", "~> 8.0.0"
29
+ end
30
+ end
31
+
32
+ install_gems
33
+
34
+ after_bundle do
35
+ commit_initial_application_state
36
+
37
+ # Initializers & Configuration
38
+ configure_database
39
+ configure_test_suite
40
+ configure_ci
41
+ configure_sidekiq
42
+ configure_strong_migrations
43
+ configure_mailer_intercepter
44
+ configure_inline_svg
45
+ configure_development_seeder
46
+
47
+ # Environments
48
+ setup_test_environment
49
+ setup_development_environment
50
+ setup_production_environment
51
+ setup_application
52
+
53
+ # Deployment and server
54
+ update_bin_dev
55
+ add_procfiles
56
+
57
+ # Views
58
+ update_layout
59
+
60
+ # Finalization
61
+ run_migrations
62
+ update_readme
63
+ lint_codebase
64
+
65
+ print_message
66
+ end
67
+
68
+ def commit_initial_application_state
69
+ git add: ".", commit: %(-m 'Initial commit') if ENV["SUSPENDERS_ENV"] == "development"
70
+ end
71
+
72
+ def configure_database
73
+ gsub_file "config/database.yml", /^production:.*?password:.*?\n/m, <<~YAML
74
+ production:
75
+ <<: *default
76
+ url: <%= ENV["DATABASE_URL"] %>
77
+ YAML
78
+ end
79
+
80
+ def configure_test_suite
81
+ rails_command "generate rspec:install"
82
+
83
+ # Update default configuration
84
+ uncomment_lines "spec/rails_helper.rb", /config\.infer_spec_type_from_file_location!/
85
+ uncomment_lines "spec/rails_helper.rb", /Rails\.root\.glob/
86
+ gsub_file "spec/spec_helper.rb", /^=begin\n/, ""
87
+ gsub_file "spec/spec_helper.rb", /^=end\n/, ""
88
+
89
+ # Configure Webmock
90
+ inject_into_file "spec/spec_helper.rb", "require \"webmock/rspec\"\n", before: /^RSpec\.configure/
91
+ append_to_file "spec/spec_helper.rb", <<~RUBY
92
+
93
+ WebMock.disable_net_connect!(
94
+ allow_localhost: true,
95
+ allow: [
96
+ /(chromedriver|storage).googleapis.com/,
97
+ "googlechromelabs.github.io"
98
+ ]
99
+ )
100
+ RUBY
101
+
102
+ # Custom configuration
103
+ copy_file "spec/support/action_mailer.rb"
104
+ copy_file "spec/support/driver.rb"
105
+ copy_file "spec/support/i18n.rb"
106
+ copy_file "spec/support/factory_bot.rb"
107
+ copy_file "spec/support/shoulda_matchers.rb"
108
+
109
+ # Custom specs
110
+ copy_file "spec/factories_spec.rb"
111
+ empty_directory "spec/system"
112
+ create_file "spec/system/.gitkeep"
113
+
114
+ # Ignore spec/examples.txt
115
+ append_to_file ".gitignore", "/spec/examples.txt"
116
+ end
117
+
118
+ def configure_ci
119
+ # https://thoughtbot.com/blog/rspec-rails-github-actions-configuration
120
+ append_to_file ".github/workflows/ci.yml", "\n" + <<~YAML.gsub(/^/, " ")
121
+ test:
122
+ runs-on: ubuntu-latest
123
+
124
+ services:
125
+ postgres:
126
+ image: postgres
127
+ env:
128
+ POSTGRES_USER: postgres
129
+ POSTGRES_PASSWORD: postgres
130
+ ports:
131
+ - 5432:5432
132
+ options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
133
+
134
+ # redis:
135
+ # image: valkey/valkey:8
136
+ # ports:
137
+ # - 6379:6379
138
+ # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
139
+
140
+ steps:
141
+ - name: Install packages
142
+ run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libpq-dev
143
+
144
+ - name: Checkout code
145
+ uses: actions/checkout@v5
146
+
147
+ - name: Set up Ruby
148
+ uses: ruby/setup-ruby@v1
149
+ with:
150
+ bundler-cache: true
151
+
152
+ - name: Run Tests
153
+ env:
154
+ RAILS_ENV: test
155
+ DATABASE_URL: postgres://postgres:postgres@localhost:5432
156
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
157
+ # REDIS_URL: redis://localhost:6379/0
158
+ run: bin/rails db:setup spec
159
+
160
+ - name: Keep screenshots from failed system tests
161
+ uses: actions/upload-artifact@v4
162
+ if: failure()
163
+ with:
164
+ name: screenshots
165
+ path: ${{ github.workspace }}/tmp/capybara
166
+ if-no-files-found: ignore
167
+ YAML
168
+ end
169
+
170
+ def configure_sidekiq
171
+ # TODO: Use #initializer instead
172
+ copy_file "config/initializers/sidekiq.rb"
173
+
174
+ prepend_to_file "config/routes.rb", "require \"sidekiq/web\"\n\n"
175
+ sidekiq_route = <<-RUBY
176
+ if Rails.env.local?
177
+ mount Sidekiq::Web => "/sidekiq"
178
+ end
179
+
180
+ RUBY
181
+ insert_into_file "config/routes.rb", sidekiq_route, after: "Rails.application.routes.draw do\n # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html\n"
182
+
183
+ # https://github.com/sidekiq/sidekiq/wiki/Active+Job
184
+ environment "config.active_job.queue_adapter = :sidekiq"
185
+ environment "config.active_job.queue_adapter = :inline", env: "test"
186
+ end
187
+
188
+ def configure_strong_migrations
189
+ rails_command "generate strong_migrations:install"
190
+ end
191
+
192
+ def configure_mailer_intercepter
193
+ lib "email_interceptor.rb", <<~RUBY
194
+ class EmailInterceptor
195
+ def self.delivering_email(message)
196
+ message.to = ENV.fetch("INTERCEPTOR_ADDRESSES", "").split(",")
197
+ end
198
+ end
199
+ RUBY
200
+
201
+ initializer "email_interceptor.rb", <<~RUBY
202
+ Rails.application.configure do
203
+ if ENV.fetch("INTERCEPTOR_ADDRESSES", "").split(",").any?
204
+ config.action_mailer.interceptors = %w[EmailInterceptor]
205
+ end
206
+ end
207
+ RUBY
208
+ end
209
+
210
+ def configure_inline_svg
211
+ initializer "inline_svg.rb", <<~RUBY
212
+ InlineSvg.configure do |config|
213
+ config.raise_on_file_not_found = true
214
+ end
215
+ RUBY
216
+ end
217
+
218
+ def configure_development_seeder
219
+ copy_file "lib/development/seeder.rb"
220
+ copy_file "lib/tasks/development.rake"
221
+ gsub_file "config/application.rb", /config\.autoload_lib\(ignore: %w\[assets tasks\]\)/, "config.autoload_lib(ignore: %w[assets tasks development])"
222
+ end
223
+
224
+ def setup_test_environment
225
+ gsub_file "config/environments/test.rb", /config\.action_dispatch\.show_exceptions = :rescuable/, "config.action_dispatch.show_exceptions = :none"
226
+ uncomment_lines "config/environments/test.rb", /config\.i18n\.raise_on_missing_translations/
227
+ end
228
+
229
+ def setup_development_environment
230
+ environment "config.active_model.i18n_customize_full_message = true", env: "development"
231
+ uncomment_lines "config/environments/development.rb", /config\.i18n\.raise_on_missing_translations/
232
+ uncomment_lines "config/environments/development.rb", /config\.generators\.apply_rubocop_autocorrect_after_generate!/
233
+ end
234
+
235
+ def setup_production_environment
236
+ environment "config.sandbox_by_default = true", env: "production"
237
+ environment "config.active_record.action_on_strict_loading_violation = :log", env: "production"
238
+ gsub_file "config/environments/production.rb", /# config\.asset_host =.*$/, 'config.asset_host = ENV["ASSET_HOST"]'
239
+ gsub_file "config/environments/production.rb", /config\.action_mailer\.default_url_options = \{ host: .*? \}/, 'config.action_mailer.default_url_options = { host: ENV.fetch("APPLICATION_HOST") }'
240
+ end
241
+
242
+ def setup_application
243
+ environment "config.active_record.strict_loading_by_default = true"
244
+ environment "config.active_record.strict_loading_mode = :n_plus_one_only"
245
+ environment "config.require_master_key = true"
246
+ end
247
+
248
+ def update_bin_dev
249
+ # https://github.com/rails/jsbundling-rails/blob/main/lib/install/dev
250
+ # rubocop:disable Style/RedundantStringEscape
251
+ create_file "bin/dev", force: true do
252
+ <<~BASH
253
+ #!/usr/bin/env sh
254
+
255
+ if gem list --no-installed --exact --silent foreman; then
256
+ echo "Installing foreman..."
257
+ gem install foreman
258
+ fi
259
+
260
+ # Default to port 3000 if not specified
261
+ export PORT="\${PORT:-3000}"
262
+
263
+ exec foreman start -f Procfile.dev --env /dev/null "$@"
264
+ BASH
265
+ end
266
+ # rubocop:enable Style/RedundantStringEscape
267
+
268
+ # rubocop:disable Style/NumericLiteralPrefix
269
+ chmod "bin/dev", 0755
270
+ # rubocop:enable Style/NumericLiteralPrefix
271
+ end
272
+
273
+ def add_procfiles
274
+ copy_file "Procfile"
275
+ copy_file "Procfile.dev"
276
+ end
277
+
278
+ def update_layout
279
+ # General partials
280
+ copy_file "app/views/application/_form_errors.html.erb"
281
+ copy_file "app/views/application/_flashes.html.erb"
282
+
283
+ # Application Layout
284
+ gsub_file "app/views/layouts/application.html.erb", /<html>/, "<html lang=\"<%= I18n.locale %>\">"
285
+ application_html_erb = <<-ERB
286
+ <main>
287
+ <%= render "flashes" %>
288
+ <%= yield %>
289
+ </main>
290
+ ERB
291
+ gsub_file "app/views/layouts/application.html.erb", /^ <%= yield %>\n/, application_html_erb
292
+ insert_into_file "app/views/layouts/application.html.erb", " <meta name=\"turbo-prefetch\" content=\"false\">\n", after: "</title>\n"
293
+ end
294
+
295
+ def run_migrations
296
+ rails_command "db:create"
297
+ rails_command "db:migrate"
298
+ end
299
+
300
+ def update_readme
301
+ create_file "README.md", force: true do
302
+ <<~MARKDOWN
303
+ # README
304
+
305
+ This application was initially generated with [Suspenders][].
306
+
307
+ [Suspenders]: https://github.com/thoughtbot/suspenders
308
+
309
+ ## Local Development
310
+
311
+ Run `bin/dev` to start the web server and Sidekiq worker. Then, navigate to [http://localhost:3000][local]
312
+
313
+ [local]: http://localhost:3000
314
+
315
+ ### Strong Migrations
316
+
317
+ Uses [Strong Migrations][] to catch unsafe migrations in development.
318
+
319
+ [Strong Migrations]: https://github.com/ankane/strong_migrations
320
+
321
+ ### Seed Data
322
+
323
+ Follows [our guidance][seed-data-guide] for managing seed data.
324
+
325
+ Use `db/seeds.rb` for data required in **all** environments, and `development:db:seed` for data specific to development environments.
326
+
327
+ Place idempotent seed data in `Development::Seeder`.
328
+
329
+ To load development seed data:
330
+
331
+ ```bash
332
+ bin/rails development:db:seed
333
+ ```
334
+
335
+ To reset your database and reload seed data:
336
+
337
+ ```bash
338
+ bin/rails development:db:seed:replant
339
+ ```
340
+
341
+ The `replant` command truncates all tables and reloads the seed data, providing
342
+ a clean slate for development.
343
+
344
+ [seed-data-guide]: https://github.com/thoughtbot/guides/blob/main/rails/how-to/seed-data.md
345
+
346
+ ## Environment Variables
347
+
348
+ The following environment variables are available in `production`:
349
+
350
+ - `APPLICATION_HOST` - The domain where your application is hosted (required)
351
+ - `ASSET_HOST` - CDN or asset host URL (optional)
352
+ - `RAILS_MASTER_KEY` - Used for decrypting credentials (required)
353
+
354
+ ## Rails Console
355
+
356
+ In deployed environments, the Rails console starts in sandbox mode by default. This means any changes made in the console will be rolled back when you exit.
357
+
358
+ To modify data in deployed environments, you must explicitly disable sandbox mode:
359
+
360
+ ```
361
+ bin/rails console --no-sandbox
362
+ ```
363
+
364
+ This configuration helps prevent accidental data modifications in production.
365
+
366
+ ## Configuration
367
+
368
+ ### All Environments
369
+
370
+ - Enables [strict_loading_by_default][].
371
+ - Sets [strict_loading_mode][] to `:n_plus_one`.
372
+ - Enables [require_master_key][].
373
+
374
+ [strict_loading_by_default]: https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-by-default
375
+ [strict_loading_mode]: https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-mode
376
+ [require_master_key]: https://guides.rubyonrails.org/configuring.html#config-require-master-key
377
+
378
+ ### Test
379
+
380
+ - Enables [raise_on_missing_translations][].
381
+ - Sets [action_dispatch.show_exceptions][] to `:none`.
382
+
383
+ [raise_on_missing_translations]: https://guides.rubyonrails.org/configuring.html#config-i18n-raise-on-missing-translations
384
+ [action_dispatch.show_exceptions]: https://edgeguides.rubyonrails.org/configuring.html#config-action-dispatch-show-exceptions
385
+
386
+ ### Development
387
+
388
+ - Enables [raise_on_missing_translations][].
389
+ - Enables [i18n_customize_full_message][].
390
+ - Enables [apply_rubocop_autocorrect_after_generate!][].
391
+
392
+ [raise_on_missing_translations]: https://guides.rubyonrails.org/configuring.html#config-i18n-raise-on-missing-translations
393
+ [i18n_customize_full_message]: https://guides.rubyonrails.org/configuring.html#config-active-model-i18n-customize-full-message
394
+ [apply_rubocop_autocorrect_after_generate!]: https://guides.rubyonrails.org/configuring.html#configuring-generators
395
+
396
+ ### Production
397
+
398
+ - Enables [sandbox_by_default][].
399
+ - Sets [action_on_strict_loading_violation][] to `:log`.
400
+
401
+ [sandbox_by_default]: https://guides.rubyonrails.org/configuring.html#config-sandbox-by-default
402
+ [action_on_strict_loading_violation]: https://guides.rubyonrails.org/configuring.html#config-active-record-action-on-strict-loading-violation
403
+
404
+ ## Testing
405
+
406
+ Uses [RSpec][] and [RSpec Rails][] in favor of the [default test suite][].
407
+
408
+ The test suite can be run with `bin/rails spec`.
409
+
410
+ Configuration can be found in the following files:
411
+
412
+ ```
413
+ spec/rails_helper.rb
414
+ spec/spec_helper.rb
415
+ spec/support/action_mailer.rb
416
+ spec/support/driver.rb
417
+ spec/support/i18n.rb
418
+ spec/support/shoulda_matchers.rb
419
+ ```
420
+
421
+ - Uses [action_dispatch-testing-integration-capybara][] to introduce Capybara assertions into Request specs.
422
+ - Uses [shoulda-matchers][] for simple one-liner tests for common Rails functionality.
423
+ - Uses [webmock][] for stubbing and setting expectations on HTTP requests in Ruby.
424
+
425
+ [RSpec]: http://rspec.info
426
+ [RSpec Rails]: https://github.com/rspec/rspec-rails
427
+ [default test suite]: https://guides.rubyonrails.org/testing.html
428
+ [action_dispatch-testing-integration-capybara]: https://github.com/thoughtbot/action_dispatch-testing-integration-capybara
429
+ [shoulda-matchers]: https://github.com/thoughtbot/shoulda-matchers
430
+ [webmock]: https://github.com/bblimke/webmock
431
+
432
+ ### Factories
433
+
434
+ Uses [FactoryBot][] as an alternative to [Fixtures][] to help you define
435
+ dummy and test data for your test suite. The `create`, `build`, and
436
+ `build_stubbed` class methods are directly available to all tests.
437
+
438
+ Place FactoryBot definitions in `spec/factories.rb`, at least until it
439
+ grows unwieldy. This helps reduce confusion around circular dependencies and
440
+ makes it easy to jump between definitions.
441
+
442
+ [FactoryBot]: https://github.com/thoughtbot/factory_bot
443
+ [Fixtures]: https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures
444
+
445
+ ## Accessibility
446
+
447
+ Uses [capybara_accessibility_audit][] and
448
+ [capybara_accessible_selectors][] to encourage and enforce accessibility best
449
+ practices.
450
+
451
+ [capybara_accessibility_audit]: https://github.com/thoughtbot/capybara_accessibility_audit
452
+ [capybara_accessible_selectors]: https://github.com/citizensadvice/capybara_accessible_selectors
453
+
454
+ ## Mailers
455
+
456
+ [Intercept][] emails in non-production environments by setting `INTERCEPTOR_ADDRESSES`.
457
+
458
+ ```sh
459
+ INTERCEPTOR_ADDRESSES="user_1@example.com,user_2@example.com" bin/rails s
460
+ ```
461
+
462
+ Configuration can be found at `config/initializers/email_interceptor.rb`.
463
+
464
+ Interceptor can be found at `lib/email_interceptor.rb`.
465
+
466
+ [Intercept]: https://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
467
+
468
+ ## Jobs
469
+
470
+ Uses [Sidekiq][] for [background job][] processing.
471
+
472
+ Configures the `test` environment to use the [inline][] adapter.
473
+
474
+ [Sidekiq]: https://github.com/sidekiq/sidekiq
475
+ [background job]: https://guides.rubyonrails.org/active_job_basics.html
476
+ [inline]: https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html
477
+
478
+ ## Layout and Assets
479
+
480
+ ### Inline SVG
481
+
482
+ Uses [inline_svg][] for embedding SVG documents into views.
483
+
484
+ Configuration can be found at `config/initializers/inline_svg.rb`
485
+
486
+ [inline_svg]: https://github.com/jamesmartin/inline_svg
487
+
488
+ ### Layout
489
+
490
+ - A [partial][] for [flash messages][] is located in `app/views/application/_flashes.html.erb`.
491
+ - A [partial][] for form errors is located in `app/views/application/_form_errors.html.erb`.
492
+ - Sets [lang][] attribute on `<html>` element to `en` via `I18n.local`.
493
+ - Disables Turbo's [Prefetch][] in an effort to reduce unnecessary network requests.
494
+
495
+ [partial]: https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
496
+ [flash messages]: https://guides.rubyonrails.org/action_controller_overview.html#the-flash
497
+ [lang]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang
498
+ [title]: https://github.com/calebhearth/title
499
+ [Prefetch]: https://turbo.hotwired.dev/handbook/drive#prefetching-links-on-hover
500
+ MARKDOWN
501
+ end
502
+ end
503
+
504
+ def lint_codebase
505
+ run "bin/rubocop -a"
506
+ end
507
+
508
+ def print_message
509
+ say ""
510
+ say "Congratulations! You just pulled our suspenders."
511
+ say ""
512
+ say ralph
513
+ end
514
+
515
+ def ralph
516
+ <<~ASCII
517
+ ##################################################
518
+ ################+ ################
519
+ ############ -###########
520
+ ######### =################*. :########
521
+ #######- =####= =#### #######
522
+ ########+ ###+ +##+ ########
523
+ ###########. .###############- ##########
524
+ ###########= +####= :+####* ###########
525
+ ###############= *##############
526
+ ############## +###########- ##############
527
+ ###############=*#################+###############
528
+ ##################################################
529
+ #########: #########
530
+ ######### ########
531
+ ######### ########
532
+ ######### ##. +#= ########
533
+ ######### #= # #* #. ########
534
+ ######### #. # #= #: ########
535
+ ######### :##+ ### ########
536
+ ######### ########
537
+ ######### ########
538
+ ######### ########
539
+ ######### ########
540
+ #########+ #########
541
+ ##################################################
542
+ ##################################################
543
+ ASCII
544
+ end
@@ -0,0 +1,4 @@
1
+ module Suspenders
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end