diff --git a/lib/tapioca/commands/gem.rb b/lib/tapioca/commands/gem.rb index e5cb4af4a..56905eb6c 100644 --- a/lib/tapioca/commands/gem.rb +++ b/lib/tapioca/commands/gem.rb @@ -122,7 +122,7 @@ def loader sig { returns(Gemfile) } def bundle - @bundle ||= Gemfile.new + @bundle ||= Gemfile.new(@exclude) end sig { void } diff --git a/lib/tapioca/gemfile.rb b/lib/tapioca/gemfile.rb index cbbecaed3..61747c8f2 100644 --- a/lib/tapioca/gemfile.rb +++ b/lib/tapioca/gemfile.rb @@ -21,16 +21,40 @@ class Gemfile # `Bundler.require`. module AutoRequireHook extend T::Sig + extend T::Helpers - sig { void.checked(:never) } + requires_ancestor { ::Bundler::Dependency } + + @exclude = T.let([], T::Array[String]) + + class << self + extend T::Sig + + sig { params(exclude: T::Array[String]).returns(T::Array[String]) } + attr_writer :exclude + + sig { params(name: T.untyped).returns(T::Boolean) } + def excluded?(name) + @exclude.include?(name) + end + end + + sig { returns(T.untyped).checked(:never) } def autorequire + value = super + + # If the gem is excluded, we don't want to force require it, in case + # it has side-effects users don't want. For example, `fakefs` gem, if + # loaded, takes over filesystem operations. + return value if AutoRequireHook.excluded?(name) + # If a gem is marked as `require: false`, then its `autorequire` # value will be `[]`. But, we want those gems to be loaded for our # purposes as well, so we return `nil` in those cases, instead, which # means `require: true`. - super.tap do |value| - return nil if value == [] - end + return nil if value == [] + + value end ::Bundler::Dependency.prepend(self) @@ -45,8 +69,9 @@ def autorequire sig { returns(T::Array[String]) } attr_reader(:missing_specs) - sig { void } - def initialize + sig { params(exclude: T::Array[String]).void } + def initialize(exclude) + AutoRequireHook.exclude = exclude @gemfile = T.let(File.new(Bundler.default_gemfile), File) @lockfile = T.let(File.new(Bundler.default_lockfile), File) @definition = T.let(Bundler::Dsl.evaluate(gemfile, lockfile, {}), Bundler::Definition) diff --git a/spec/tapioca/cli/gem_spec.rb b/spec/tapioca/cli/gem_spec.rb index 6201518ed..b9e2ca2ba 100644 --- a/spec/tapioca/cli/gem_spec.rb +++ b/spec/tapioca/cli/gem_spec.rb @@ -484,19 +484,33 @@ class Foo::Secret; end write("lib/foo/secret.rb", "class Foo::Secret; end") end + bar = mock_gem("bar", "1.0.0") do + write("lib/bar.rb", <<~RUBY) + module Foo + MY_CONSTANT = 42 + end + RUBY + end + @project.require_mock_gem(foo, require: false) + @project.require_mock_gem(bar, require: false) @project.bundle_install @project.write("sorbet/tapioca/require.rb", <<~RB) require "foo/secret" RB - result = @project.tapioca("gem foo") + result = @project.tapioca("gem --exclude bar") + + refute_includes(result.out, <<~OUT) + Compiled bar + OUT assert_includes(result.out, <<~OUT) Compiled foo OUT + refute_project_file_exist("sorbet/rbi/gems/bar@1.0.0.rbi") assert_project_file_equal("sorbet/rbi/gems/foo@0.0.1.rbi", template(<<~RBI)) #{FOO_RBI.rstrip} class Foo::Secret; end