Skip to content

Commit 48c48d4

Browse files
committed
Add option to configure Zeitwerk in new gems
Add a question to configure Zeitwerk when creating new gems (false by default). It also supports a --zeitwerk flag to do it: bundle gem mygem --zeitwerk
1 parent d57d302 commit 48c48d4

File tree

7 files changed

+99
-3
lines changed

7 files changed

+99
-3
lines changed

bundler/lib/bundler/cli.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ def viz
549549
desc: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
550550
method_option :ext, type: :string, desc: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
551551
method_option :git, type: :boolean, default: true, desc: "Initialize a git repo inside your library."
552+
method_option :zeitwerk, type: :boolean, desc: "Configure Zeitwerk as the class loader. Set a default with `bundle config set --global gem.zeitwerk true`."
552553
method_option :mit, type: :boolean, desc: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
553554
method_option :rubocop, type: :boolean, desc: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
554555
method_option :changelog, type: :boolean, desc: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."

bundler/lib/bundler/cli/gem.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ def run
145145
config[:ci_config_path] = ".circleci "
146146
end
147147

148+
if ask_and_set(:zeitwerk, "Do you want to use Zeitwerk to load classes?",
149+
"With Zeitwerk (https://github.com/fxn/zeitwerk), Ruby can load classes automatically " \
150+
"based on name conventions so that you don't have to require files manually.")
151+
config[:zeitwerk] = true
152+
end
153+
148154
if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?",
149155
"This means that any other developer or company will be legally allowed to use your code " \
150156
"for free as long as they admit you created it. You can read more about the MIT license " \

bundler/lib/bundler/templates/newgem/lib/newgem.rb.tt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
# frozen_string_literal: true
22

3+
<%- unless config[:zeitwerk] -%>
34
require_relative "<%= File.basename(config[:namespaced_path]) %>/version"
5+
<%- end -%>
46
<%- if config[:ext] -%>
57
require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>"
68
<%- end -%>
9+
<%- if config[:zeitwerk] -%>
10+
require "zeitwerk"
11+
<%- if config[:name].include?("-") -%>
12+
loader = Zeitwerk::Loader.for_gem_extension(<%= config[:constant_array][0..-2].join("::") %>)
13+
<%- else -%>
14+
loader = Zeitwerk::Loader.for_gem
15+
<%- end -%>
16+
loader.setup
17+
<%- end -%>
718

819
<%- config[:constant_array].each_with_index do |c, i| -%>
920
<%= " " * i %>module <%= c %>

bundler/lib/bundler/templates/newgem/newgem.gemspec.tt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ Gem::Specification.new do |spec|
4343

4444
# Uncomment to register a new dependency of your gem
4545
# spec.add_dependency "example-gem", "~> 1.0"
46+
<%- if config[:zeitwerk] -%>
47+
spec.add_dependency "zeitwerk"
48+
<%- end -%>
4649
<%- if config[:ext] == 'rust' -%>
4750
spec.add_dependency "rb_sys", "~> 0.9.91"
4851
<%- end -%>

bundler/spec/bundler/gem_helper_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
before(:each) do
1212
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
13-
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
13+
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__ZEITWERK" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
1414
git("config --global init.defaultBranch main")
1515
bundle "gem #{app_name}"
1616
prepare_gemspec(app_gemspec_path)

bundler/spec/commands/newgem_spec.rb

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def bundle_exec_standardrb
3838
git("config --global github.user bundleuser")
3939

4040
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
41-
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
41+
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__ZEITWERK" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
4242
end
4343

4444
describe "git repo initialization" do
@@ -74,6 +74,34 @@ def bundle_exec_standardrb
7474
end
7575
end
7676

77+
shared_examples_for "--zeitwerk flag" do
78+
let(:gem_name) { "my_gem" }
79+
80+
before do
81+
bundle "gem #{gem_name} --zeitwerk"
82+
end
83+
it "configures zeitwerk" do
84+
gem_skeleton_assertions
85+
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "zeitwerk"')
86+
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to include <<~RUBY
87+
require "zeitwerk"
88+
loader = Zeitwerk::Loader.for_gem
89+
loader.setup
90+
RUBY
91+
end
92+
end
93+
94+
shared_examples_for "--no-zeitwerk flag" do
95+
before do
96+
bundle "gem #{gem_name} --no-zeitwerk"
97+
end
98+
it "does not configure zeitwerk" do
99+
gem_skeleton_assertions
100+
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to_not include('spec.add_dependency "zeitwerk"')
101+
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to_not include('require "zeitwerk"')
102+
end
103+
end
104+
77105
shared_examples_for "--mit flag" do
78106
before do
79107
bundle "gem #{gem_name} --mit"
@@ -1408,6 +1436,28 @@ def create_temporary_dir(dir)
14081436
end
14091437
end
14101438

1439+
context "testing --zeitwerk option against bundle config settings" do
1440+
let(:gem_name) { "my_gem" }
1441+
1442+
let(:require_path) { "my_gem" }
1443+
1444+
context "with zeitwerk option in bundle config settings set to true" do
1445+
before do
1446+
global_config "BUNDLE_GEM__ZEITWERK" => "true"
1447+
end
1448+
it_behaves_like "--zeitwerk flag"
1449+
it_behaves_like "--no-zeitwerk flag"
1450+
end
1451+
1452+
context "with zeitwerk option in bundle config settings set to false" do
1453+
before do
1454+
global_config "BUNDLE_GEM__ZEITWERK" => "false"
1455+
end
1456+
it_behaves_like "--zeitwerk flag"
1457+
it_behaves_like "--no-zeitwerk flag"
1458+
end
1459+
end
1460+
14111461
context "testing --github-username option against git and bundle config settings" do
14121462
context "without git config set" do
14131463
before do
@@ -1716,6 +1766,31 @@ def create_temporary_dir(dir)
17161766
expect(bundled_app("foobar/.github/workflows/main.yml")).to exist
17171767
end
17181768

1769+
it "asks about Zeitwerk" do
1770+
global_config "BUNDLE_GEM__ZEITWERK" => nil
1771+
1772+
bundle "gem foobar" do |input, _, _|
1773+
input.puts "yes"
1774+
end
1775+
1776+
expect(bundled_app("foobar/foobar.gemspec").read).to include('spec.add_dependency "zeitwerk"')
1777+
end
1778+
1779+
context("gem extensions") do
1780+
let(:gem_name) { "my-gem" }
1781+
1782+
it "configures zeitwerk detecting the gem extension" do
1783+
bundle "gem my-gem --zeitwerk"
1784+
1785+
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.add_dependency "zeitwerk"')
1786+
expect(bundled_app("#{gem_name}/lib/my/gem.rb").read).to include <<~RUBY
1787+
require "zeitwerk"
1788+
loader = Zeitwerk::Loader.for_gem_extension(My)
1789+
loader.setup
1790+
RUBY
1791+
end
1792+
end
1793+
17191794
it "asks about MIT license" do
17201795
global_config "BUNDLE_GEM__MIT" => nil
17211796

bundler/spec/other/major_deprecation_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@
621621
describe "deprecating rubocop" do
622622
before do
623623
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false",
624-
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
624+
"BUNDLE_GEM__ZEITWERK" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
625625
end
626626

627627
context "bundle gem --rubocop" do

0 commit comments

Comments
 (0)