Skip to content

Commit dc567e6

Browse files
author
zhandao
committed
Impl style option
1 parent 4275a01 commit dc567e6

File tree

14 files changed

+66
-57
lines changed

14 files changed

+66
-57
lines changed

README.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ gem exec nextgen create myapp
4545

4646
This will download the latest version of the `nextgen` gem and use it to create an app in the `myapp` directory. You'll be asked to configure the tech stack through several interactive prompts. If you have a `~/.railsrc` file, it will be ignored.
4747

48+
Options:
49+
- `style`: control the **optional enhancements** you can choose in the generator.
50+
- defaults to `default`, [enhancements list](config)
51+
- presets:
52+
- `full` (`--style=full`), [enhancements list](config/styles/full)
53+
- your local configs: `--style=path/to/your/style_dir`
54+
4855
> [!TIP]
4956
> If you get an "Unknown command exec" error, fix it by upgrading rubygems: `gem update --system`.
5057
@@ -59,7 +66,7 @@ Check out the [examples directory](./examples) to see some Rails apps that were
5966
On top of that foundation, Nextgen offers dozens of useful enhancements to the vanilla Rails experience. You are free to pick and choose which (if any) of these to apply to your new project. Behind the scenes, **each enhancement is applied in a separate git commit,** so that you can later see what was applied and why, and revert the suggestions if necessary.
6067

6168
> [!TIP]
62-
> For the full list of what Nextgen provides, check out [config/generators.yml](https://github.com/mattbrictson/nextgen/tree/main/config/generators.yml). The source code of each generator can be found in [lib/nextgen/generators](https://github.com/mattbrictson/nextgen/tree/main/lib/nextgen/generators).
69+
> For the full list of what Nextgen provides, check out [config/*.yml](https://github.com/mattbrictson/nextgen/tree/main/config). The source code of each generator can be found in [lib/nextgen/generators](https://github.com/mattbrictson/nextgen/tree/main/lib/nextgen/generators).
6370
6471
Here are some highlights of what Nextgen brings to the table:
6572

@@ -71,16 +78,14 @@ Nextgen can optionally set up a GitHub Actions CI workflow for your app that aut
7178

7279
Prefer RSpec? Nextgen can set you up with RSpec, plus the gems and configuration you need for system specs (browser testing). Or stick with the Rails Minitest defaults. In either case, Nextgen will set up a good default Rake task and appropriate CI job.
7380

74-
### Gems
75-
76-
Nextgen can install and configure your choice of these recommended gems:
81+
### Job Backends
7782

78-
#### Job Backends
79-
80-
- [sidekiq](https://github.com/sidekiq/sidekiq)
83+
- [sidekiq](https://github.com/sidekiq/sidekiq) (`--style=full`)
8184
- [solid_queue](https://github.com/basecamp/solid_queue)
8285

83-
#### Other
86+
### Gems
87+
88+
Nextgen can install and configure your choice of these recommended gems:
8489

8590
- [annotate](https://github.com/ctran/annotate_models)
8691
- [brakeman](https://github.com/presidentbeef/brakeman)

config/job_backend.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
sidekiq:
3+
prompt: "Sidekiq (Redis-backed)"
4+
description: "Install sidekiq gem to use in production"
5+
requires: active_job

config/styles/full/checkers.yml

Whitespace-only changes.

config/styles/full/code_snippets.yml

Whitespace-only changes.

config/styles/full/gems.yml

Whitespace-only changes.

config/job.yml renamed to config/styles/full/job_backend.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11

2-
sidekiq:
3-
prompt: "Sidekiq (Redis-backed)"
4-
description: "Install sidekiq gem to use in production"
5-
requires: active_job
6-
72
solid_queue:
83
prompt: "SolidQueue (Database-backed)"
94
description: "Install solid_queue as ActiveJob's backend"

config/styles/full/workflows.yml

Whitespace-only changes.

lib/nextgen.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,28 @@ def self.generators_path(scope = "")
1414
def self.template_path
1515
Pathname.new(__dir__).join("../template")
1616
end
17+
18+
def self.config_path(style: nil)
19+
if style
20+
if style.match?("/")
21+
Pathname.new(style)
22+
else
23+
Pathname.new(__dir__).join("../config/styles", style)
24+
end
25+
else
26+
Pathname.new(__dir__).join("../config")
27+
end
28+
end
29+
30+
def self.config_for(scope:, style: nil)
31+
base = YAML.load_file("#{Nextgen.config_path}/#{scope}.yml")
32+
if style
33+
base.merge!(YAML.load_file("#{Nextgen.config_path(style: style)}/#{scope}.yml") || {})
34+
end
35+
base
36+
end
37+
38+
def self.scopes_for(style: nil)
39+
Dir[Nextgen.config_path(style: style) + "*.yml"].map { _1.match(/([_a-z]*)\.yml/)[1] }
40+
end
1741
end

lib/nextgen/cli.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class CLI < Thor
66

77
map %w[-v --version] => "version"
88

9+
option :style, type: :string, default: nil
910
desc "create APP_PATH", "Generate a Rails app interactively in APP_PATH"
1011
def create(app_path)
1112
Commands::Create.run(app_path, options)

lib/nextgen/commands/create.rb

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ def self.run(app_path, options)
1818
new(app_path, options).run
1919
end
2020

21-
def initialize(app_path, _options)
21+
def initialize(app_path, options)
2222
@app_path = File.expand_path(app_path)
2323
@app_name = File.basename(@app_path).gsub(/\W/, "_").squeeze("_").camelize
2424
@rails_opts = RailsOptions.new
25+
@style = options[:style]
2526
end
2627

27-
def run # rubocop:disable Metrics/MethodLength Metrics/PerceivedComplexity
28+
def run # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
2829
say_banner
2930
continue_if "Ready to start?"
3031

@@ -39,12 +40,8 @@ def run # rubocop:disable Metrics/MethodLength Metrics/PerceivedComplexity
3940
ask_system_testing if rails_opts.frontend? && rails_opts.test_framework?
4041
say
4142

42-
if prompt.yes?("More detailed configuration? [ job, code snippets, gems ... ] ↵")
43-
ask_job_backend if rails_opts.active_job?
44-
ask_workflows
45-
ask_checkers
46-
ask_code_snippets
47-
ask_optional_enhancements
43+
if prompt.yes?("More enhancements? [ job, code snippets, gems ... ] ↵")
44+
ask_styled_enhancements
4845
end
4946

5047
say_summary
@@ -98,7 +95,7 @@ def ask_full_stack_or_api
9895
"API only" => true
9996
)
10097
rails_opts.api! if api
101-
@generators = {basic: Generators.compatible_with(rails_opts: rails_opts, scope: "basic")}
98+
@generators = {basic: Generators.compatible_with(rails_opts: rails_opts, style: nil, scope: "basic")}
10299
end
103100

104101
def ask_frontend_management
@@ -189,33 +186,17 @@ def ask_system_testing
189186
rails_opts.skip_system_test! unless system_testing
190187
end
191188

192-
def ask_job_backend
193-
generators[:job] = Generators.compatible_with(rails_opts: rails_opts, scope: "job").tap do |it|
194-
it.ask_select("Which #{underline("job backend")} would you like to use?", prompt: prompt)
195-
end
196-
end
197-
198-
def ask_workflows
199-
generators[:workflows] = Generators.compatible_with(rails_opts: rails_opts, scope: "workflows").tap do |it|
200-
it.ask_select("Which #{underline("workflows")} would you like to add?", multi: true, prompt: prompt)
201-
end
202-
end
203-
204-
def ask_checkers
205-
generators[:checkers] = Generators.compatible_with(rails_opts: rails_opts, scope: "checkers").tap do |it|
206-
it.ask_select("Which #{underline("checkers")} would you like to add?", multi: true, prompt: prompt)
207-
end
208-
end
209-
210-
def ask_code_snippets
211-
generators[:code_snippets] = Generators.compatible_with(rails_opts: rails_opts, scope: "code_snippets").tap do |it|
212-
it.ask_select("Which #{underline("code snippets")} would you like to add?", multi: true, prompt: prompt)
213-
end
214-
end
189+
def ask_styled_enhancements
190+
say " ↪ style: #{cyan(@style || "default")}"
191+
Nextgen.scopes_for(style: @style).each do |scope|
192+
gen = Generators.compatible_with(rails_opts: rails_opts, style: @style, scope: scope)
193+
next if gen.empty? || scope == "basic"
215194

216-
def ask_optional_enhancements
217-
generators[:gems] = Generators.compatible_with(rails_opts: rails_opts, scope: "gems").tap do |it|
218-
it.ask_select("Which optional enhancements would you like to add?", multi: true, sort: true, prompt: prompt)
195+
key_word = underline(scope.tr("_", " "))
196+
multi = scope == scope.pluralize
197+
sort = gen.optional.size > 10
198+
gen.ask_select("Which #{key_word} would you like to add?", prompt: prompt, multi: multi, sort: sort)
199+
generators[scope.to_sym] = gen
219200
end
220201
end
221202
end

lib/nextgen/commands/helpers.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ def capture_version(command)
110110
end
111111

112112
def activated_generators
113-
activated = generators[:gems].all_active_names
114-
activated.prepend(generators[:job].all_active_names.first) unless generators[:job].nil?
115-
113+
activated = generators.values.flat_map(&:all_active_names)
116114
activated.any? ? activated.sort_by(&:downcase) : ["<None>"]
117115
end
118116

lib/nextgen/generators.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
module Nextgen
44
class Generators
5-
def self.compatible_with(rails_opts:, scope:)
6-
yaml_path = File.expand_path("../../config/#{scope}.yml", __dir__)
5+
def self.compatible_with(rails_opts:, style:, scope:)
76
new(scope, api: rails_opts.api?).tap do |generators|
8-
YAML.load_file(yaml_path).each do |name, options|
7+
Nextgen.config_for(style: style, scope: scope).each do |name, options|
98
options ||= {}
109
requirements = Array(options["requires"])
1110
next unless requirements.all? { |req| rails_opts.public_send(:"#{req}?") }
@@ -18,7 +17,6 @@ def self.compatible_with(rails_opts:, scope:)
1817
questions: options["questions"]
1918
)
2019
end
21-
2220
generators.deactivate_node unless rails_opts.requires_node?
2321
end
2422
end
@@ -29,9 +27,11 @@ def initialize(scope, **vars)
2927
@scope = scope
3028
end
3129

30+
def empty? = @generators.empty?
31+
3232
def ask_select(question, multi: false, sort: false, prompt: TTY::Prompt.new)
33-
opt = sort ? optional.sort_by { |label, _| label.downcase }.to_h : optional
34-
args = [question, opt, {cycle: true, filter: true}]
33+
opts = sort ? optional.sort_by { |label, _| label.downcase }.to_h : optional
34+
args = [question, opts, {cycle: true, filter: true}]
3535
answers = multi ? prompt.multi_select(*args) : [prompt.select(*args)]
3636

3737
answers.each do |answer|

0 commit comments

Comments
 (0)