Skip to content

Commit 08be1dd

Browse files
Dynamically generate README (#1187)
Create README based off the `desc` of the generators. We chose to create a custom class instead of a traditional generator because this script is intended to be run in the [application template][] as a Rake task. It is not intended to be run as a standalone generator, since it only makes sense to be run on concert with `suspenders:install:web`. Updates all generator descriptions to use Herdoc syntax to ensure consistent line breaks. A follow-up commit will update the descriptions to work better in a README. [application template]: https://guides.rubyonrails.org/rails_application_templates.html
1 parent 473e483 commit 08be1dd

23 files changed

+277
-26
lines changed

lib/generators/suspenders/accessibility_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Generators
33
class AccessibilityGenerator < Rails::Generators::Base
44
include Suspenders::Generators::APIAppUnsupported
55

6-
desc "Installs capybara_accessibility_audit and capybara_accessible_selectors"
6+
desc <<~MARKDOWN
7+
Installs capybara_accessibility_audit and capybara_accessible_selectors"
8+
MARKDOWN
79

810
def add_capybara_gems
911
gem_group :test do

lib/generators/suspenders/advisories_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ module Suspenders
22
module Generators
33
class AdvisoriesGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/advisories", __FILE__)
5-
desc(<<~TEXT)
5+
desc <<~MARKDOWN
66
Show security advisories during development.
77
88
Uses the `bundler-audit` gem to update the local security database and
99
show any relevant issues with the app's dependencies via a Rake task.
10-
TEXT
10+
MARKDOWN
1111

1212
def add_bundler_audit
1313
gem_group :development, :test do

lib/generators/suspenders/ci_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ class CiGenerator < Rails::Generators::Base
55
include Suspenders::Generators::Helpers
66

77
source_root File.expand_path("../../templates/ci", __FILE__)
8-
desc "Creates CI files for GitHub Actions"
8+
desc <<~MARKDOWN
9+
Creates CI files for GitHub Actions
10+
MARKDOWN
911

1012
def ci_files
1113
empty_directory ".github/workflows"

lib/generators/suspenders/email_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ module Suspenders
22
module Generators
33
class EmailGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/email", __FILE__)
5-
desc <<~TEXT
5+
desc <<~MARKDOWN
66
Intercepts emails in non-production environments by setting `INTERCEPTOR_ADDRESSES`.
77
88
```sh
99
INTERCEPTOR_ADDRESSES="[email protected],[email protected]" bin/rails s
1010
```
1111
1212
Configures `default_url_options` in `test` and `development`.
13-
TEXT
13+
MARKDOWN
1414

1515
def create_email_interceptor
1616
copy_file "email_interceptor.rb", "app/mailers/email_interceptor.rb"

lib/generators/suspenders/factories_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class FactoriesGenerator < Rails::Generators::Base
44
include Suspenders::Generators::Helpers
55

66
source_root File.expand_path("../../templates/factories", __FILE__)
7-
desc <<~TEXT
7+
desc <<~MARKDOWN
88
Build test data with clarity and ease.
99
1010
This uses FactoryBot to help you define dummy and test data for your test
@@ -17,7 +17,7 @@ class FactoriesGenerator < Rails::Generators::Base
1717
definitions.
1818
1919
Supports the default test suite and RSpec.
20-
TEXT
20+
MARKDOWN
2121

2222
def add_factory_bot
2323
gem_group :development, :test do

lib/generators/suspenders/inline_svg_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Generators
33
class InlineSvgGenerator < Rails::Generators::Base
44
include Suspenders::Generators::APIAppUnsupported
55
source_root File.expand_path("../../templates/inline_svg", __FILE__)
6-
desc "Render SVG images inline, as a potential performance improvement for the viewer."
6+
desc <<~MARKDOWN
7+
Render SVG images inline, as a potential performance improvement for the viewer.
8+
MARKDOWN
79

810
def add_inline_svg_gem
911
gem "inline_svg"

lib/generators/suspenders/jobs_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ module Suspenders
22
module Generators
33
class JobsGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/active_job", __FILE__)
5-
desc "Installs Sidekiq for background job processing."
5+
desc <<~MARKDOWN
6+
Installs Sidekiq for background job processing.
7+
MARKDOWN
68

79
def add_sidekiq_gem
810
gem "sidekiq"

lib/generators/suspenders/lint_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ class LintGenerator < Rails::Generators::Base
44
include Suspenders::Generators::Helpers
55

66
source_root File.expand_path("../../templates/lint", __FILE__)
7-
desc "Creates a holistic linting solution that covers JavaScript, CSS, Ruby and ERB."
7+
desc <<~MARKDOWN
8+
Creates a holistic linting solution that covers JavaScript, CSS, Ruby and ERB.
9+
MARKDOWN
810

911
def check_package_json
1012
unless File.exist? Rails.root.join("package.json")

lib/generators/suspenders/prerequisites_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Generators
33
class PrerequisitesGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/prerequisites", __FILE__)
55

6-
desc "Configures prerequisites. Currently Node."
6+
desc <<~MARKDOWN
7+
Configures prerequisites. Currently Node.
8+
MARKDOWN
79

810
def node_version
911
template "node-version", ".node-version"

lib/generators/suspenders/rake_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ module Suspenders
22
module Generators
33
class RakeGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/rake", __FILE__)
5-
desc(<<~TEXT)
5+
desc <<~MARKDOWN
66
Configures the default Rake task to audit and lint the codebase with
77
`bundler-audit` and `standard`, in addition to running the test suite.
8-
TEXT
8+
MARKDOWN
99

1010
def configure_default_rake_task
1111
append_to_file "Rakefile", <<~RUBY

lib/generators/suspenders/setup_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ module Suspenders
22
module Generators
33
class SetupGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/setup", __FILE__)
5-
desc <<~TEXT
5+
desc <<~MARKDOWN
66
A holistic setup script.
77
88
```sh
99
bin/setup
1010
```
11-
TEXT
11+
MARKDOWN
1212

1313
def replace_bin_setup
1414
copy_file "bin_setup.rb", "bin/setup", force: true

lib/generators/suspenders/styles_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ module Generators
33
class StylesGenerator < Rails::Generators::Base
44
include Suspenders::Generators::APIAppUnsupported
55

6-
desc <<~TEXT
6+
desc <<~MARKDOWN
77
Configures application to use PostCSS via cssbundling-rails.
88
99
Adds modern-normalize, and style sheet structure.
10-
TEXT
10+
MARKDOWN
1111

1212
def add_cssbundling_rails_gem
1313
gem "cssbundling-rails"

lib/generators/suspenders/tasks_generator.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ module Suspenders
22
module Generators
33
class TasksGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/tasks", __FILE__)
5-
desc <<~TEXT
5+
desc <<~MARKDOWN
66
Creates local Rake tasks for development
77
88
bin/rails dev:prime # Sample data for local development environment
9-
TEXT
9+
MARKDOWN
1010

1111
def create_dev_rake
1212
if Bundler.rubygems.find_name("factory_bot").any?

lib/generators/suspenders/testing_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ module Suspenders
22
module Generators
33
class TestingGenerator < Rails::Generators::Base
44
source_root File.expand_path("../../templates/testing", __FILE__)
5-
desc "Set up the project for an in-depth test-driven development workflow."
5+
desc <<~MARKDOWN
6+
Set up the project for an in-depth test-driven development workflow.
7+
MARKDOWN
68

79
def add_gems
810
gem_group :development, :test do

lib/generators/suspenders/views_generator.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Generators
33
class ViewsGenerator < Rails::Generators::Base
44
include Suspenders::Generators::APIAppUnsupported
55

6-
desc "Configures flash messages, page titles and the document lang. Disables Turbo's InstantClick."
6+
desc <<~MARKDOWN
7+
Configures flash messages, page titles and the document lang. Disables Turbo's InstantClick.
8+
MARKDOWN
79
source_root File.expand_path("../../templates/views", __FILE__)
810

911
def install_gems

lib/suspenders.rb

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "suspenders/railtie"
44
require "suspenders/generators"
55
require "suspenders/cleanup/organize_gemfile"
6+
require "suspenders/cleanup/generate_readme"
67

78
module Suspenders
89
# Your code goes here...
+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
require "rails/generators"
2+
require_relative "../../generators/suspenders/environments/development_generator"
3+
require_relative "../../generators/suspenders/environments/test_generator"
4+
require_relative "../../generators/suspenders/environments/production_generator"
5+
require_relative "../../generators/suspenders/accessibility_generator"
6+
require_relative "../../generators/suspenders/advisories_generator"
7+
require_relative "../../generators/suspenders/email_generator"
8+
require_relative "../../generators/suspenders/factories_generator"
9+
require_relative "../../generators/suspenders/inline_svg_generator"
10+
require_relative "../../generators/suspenders/jobs_generator"
11+
require_relative "../../generators/suspenders/lint_generator"
12+
require_relative "../../generators/suspenders/styles_generator"
13+
require_relative "../../generators/suspenders/testing_generator"
14+
require_relative "../../generators/suspenders/views_generator"
15+
16+
module Suspenders
17+
module Cleanup
18+
class GenerateReadme
19+
def self.perform(readme, app_name)
20+
new(readme, app_name).perform
21+
end
22+
23+
attr_reader :readme, :app_name
24+
25+
def initialize(readme, app_name)
26+
@readme = readme
27+
@app_name = app_name
28+
end
29+
30+
def perform
31+
File.open(readme, "w+") do |file|
32+
@file = file
33+
34+
heading app_name, level: 1
35+
36+
prerequisites
37+
38+
local_development
39+
40+
heading "Configuration", level: 2
41+
42+
heading "Test", level: 3
43+
description_for Suspenders::Generators::Environments::TestGenerator
44+
45+
heading "Development", level: 3
46+
description_for Suspenders::Generators::Environments::DevelopmentGenerator
47+
48+
heading "Production", level: 3
49+
description_for Suspenders::Generators::Environments::ProductionGenerator
50+
51+
heading "Linting", level: 3
52+
description_for Suspenders::Generators::LintGenerator
53+
54+
heading "Testing", level: 2
55+
description_for Suspenders::Generators::TestingGenerator
56+
57+
heading "Factories", level: 3
58+
description_for Suspenders::Generators::FactoriesGenerator
59+
60+
heading "Accessibility", level: 2
61+
description_for Suspenders::Generators::AccessibilityGenerator
62+
63+
heading "Advisories", level: 2
64+
description_for Suspenders::Generators::AdvisoriesGenerator
65+
66+
heading "Mailers", level: 2
67+
description_for Suspenders::Generators::EmailGenerator
68+
69+
heading "Jobs", level: 2
70+
description_for Suspenders::Generators::JobsGenerator
71+
72+
heading "Layout and Assets", level: 2
73+
74+
heading "Stylesheets", level: 3
75+
description_for Suspenders::Generators::StylesGenerator
76+
77+
heading "Inline SVG", level: 3
78+
description_for Suspenders::Generators::InlineSvgGenerator
79+
80+
heading "Layout", level: 3
81+
description_for Suspenders::Generators::ViewsGenerator
82+
end
83+
end
84+
85+
private
86+
87+
def new_line
88+
@file.write "\n"
89+
end
90+
91+
def heading(text, level:)
92+
@file.write "#{"#" * level} #{text}\n"
93+
new_line
94+
end
95+
96+
def description_for(generator)
97+
@file.write generator.desc
98+
new_line
99+
end
100+
101+
def local_development
102+
@file.write <<~MARKDOWN
103+
## Local Development
104+
105+
### Initial Setup
106+
107+
```
108+
bin/setup
109+
```
110+
111+
### Running the Development Server
112+
113+
```
114+
bin/rails dev
115+
```
116+
117+
### Seed Data
118+
119+
- Use `db/seeds.rb` to create records that need to exist in all environments.
120+
- Use `lib/tasks/dev.rake` to create records that only need to exist in development.
121+
122+
Running `bin/setup` will run `dev:prime`.
123+
124+
### Tasks
125+
126+
- Use `bin/rails suspenders:db:migrate` to run [database migrations][]. This script ensures they are [reversible][].
127+
- Use `bin/rails suspenders:cleanup:organize_gemfile` to automatically organize the project's Gemfile.
128+
- Use `bin/rails default` to run the default Rake task. This will do the following:
129+
- Run the test suite.
130+
- Run a Ruby and ERB linter.
131+
- Scan the Ruby codebase for any dependecy vulnerabilities.
132+
133+
[database migrations]: https://edgeguides.rubyonrails.org/active_record_migrations.html#running-migrations
134+
[reversible]: https://edgeguides.rubyonrails.org/active_record_migrations.html#making-the-irreversible-possible
135+
136+
MARKDOWN
137+
end
138+
139+
def prerequisites
140+
heading "Prerequisites", level: 2
141+
142+
@file.write <<~MARKDOWN
143+
Ruby: `#{Suspenders::MINIMUM_RUBY_VERSION}`
144+
Node: `#{Suspenders::NODE_LTS_VERSION}`
145+
MARKDOWN
146+
147+
new_line
148+
end
149+
end
150+
end
151+
end

lib/tasks/suspenders.rake

+5
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,10 @@ namespace :suspenders do
2828
task :organize_gemfile do
2929
Suspenders::Cleanup::OrganizeGemfile.perform(Rails.root.join("Gemfile"))
3030
end
31+
32+
desc "Generate README"
33+
task :generate_readme do
34+
Suspenders::Cleanup::GenerateReadme.perform(Rails.root.join("README.md"), Rails.application.class.module_parent_name)
35+
end
3136
end
3237
end

test/generators/suspenders/accessibility_generator_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class AccessibilityGeneratorTest < Rails::Generators::TestCase
6262
test "generator has a description" do
6363
description = "Installs capybara_accessibility_audit and capybara_accessible_selectors"
6464

65-
assert_equal description, Suspenders::Generators::AccessibilityGenerator.desc
65+
assert_match description, Suspenders::Generators::AccessibilityGenerator.desc
6666
end
6767

6868
private

test/generators/suspenders/inline_svg_generator_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class InlinveSvgGeneratorTest < Rails::Generators::TestCase
5757
test "generator has a description" do
5858
description = "Render SVG images inline, as a potential performance improvement for the viewer."
5959

60-
assert_equal description, Suspenders::Generators::InlineSvgGenerator.desc
60+
assert_match description, Suspenders::Generators::InlineSvgGenerator.desc
6161
end
6262

6363
test "configures raising an error when an SVG file is not found" do

test/generators/suspenders/jobs_generator_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class JobsGeneratorTest < Rails::Generators::TestCase
3232
test "generator has a description" do
3333
description = "Installs Sidekiq for background job processing."
3434

35-
assert_equal description, Suspenders::Generators::JobsGenerator.desc
35+
assert_match description, Suspenders::Generators::JobsGenerator.desc
3636
end
3737

3838
test "configures ActiveJob logging" do

0 commit comments

Comments
 (0)