Skip to content

Commit

Permalink
Only generate mixin RBIs for foreign constants
Browse files Browse the repository at this point in the history
  • Loading branch information
egiurleo committed Jun 9, 2022
1 parent 3a25760 commit 434b98b
Show file tree
Hide file tree
Showing 17 changed files with 135 additions and 9 deletions.
2 changes: 2 additions & 0 deletions lib/tapioca/gem/events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def initialize(symbol, constant, node)
end
end

class ForeignScopeNodeAdded < ScopeNodeAdded; end

class MethodNodeAdded < NodeAdded
extend T::Sig

Expand Down
11 changes: 11 additions & 0 deletions lib/tapioca/gem/listeners/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def initialize(pipeline)

sig { params(event: NodeAdded).void }
def dispatch(event)
return unless allow?(event)

case event
when ConstNodeAdded
on_const(event)
Expand All @@ -42,6 +44,15 @@ def on_scope(event)
sig { params(event: MethodNodeAdded).void }
def on_method(event)
end

sig { params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
# Some listeners do not have to take any action on certain events. For example,
# almost every listener should skip ForeignScopeNodeAdded events in order not to generate
# unnecessary RBIs for foreign constants. This method should be overridden by listener
# subclasses to only allow events that are relevant to them.
true
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/dynamic_mixins.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ def on_scope(event)
@pipeline.push_symbol(name) if name
end
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/foreign_constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ def in_bundle_path?(path)
def constant_name_from_singleton_class(constant)
constant.to_s.match("#<Class:(.+)>")&.captures&.first
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ def initialize_method_for(constant)
rescue
nil
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ class RemoveEmptyPayloadScopes < Base
def on_scope(event)
event.node.detach if @pipeline.symbol_in_payload?(event.symbol) && event.node.empty?
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_enums.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ def on_scope(event)

event.node << RBI::TEnumBlock.new(enums)
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ def on_scope(event)
node << RBI::Helper.new("final") if T::Private::Final.final_module?(constant)
node << RBI::Helper.new("sealed") if T::Private::Sealed.sealed_module?(constant)
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_props.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def on_scope(event)
end
end
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_required_ancestors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ def on_scope(event)
event.node << RBI::RequiresAncestor.new(ancestor.to_s)
end
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_signatures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def signature_final?(signature)

final_methods.include?(signature.method_name)
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/sorbet_type_variables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def compile_type_variable_declarations(tree, constant)

tree << RBI::Extend.new("T::Generic")
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/subconstants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ def on_scope(event)
@pipeline.push_constant(name, subconstant)
end
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/tapioca/gem/listeners/yard_doc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ def documentation_comments(name, sigs: [])

comments
end

sig { override.params(event: NodeAdded).returns(T::Boolean) }
def allow?(event)
!event.is_a?(Tapioca::Gem::ForeignScopeNodeAdded)
end
end
end
end
Expand Down
18 changes: 16 additions & 2 deletions lib/tapioca/gem/pipeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,20 @@ def push_const(symbol, constant, node)
@events << Gem::ConstNodeAdded.new(symbol, constant, node)
end

sig { params(symbol: String, constant: Module, node: RBI::Scope).void.checked(:never) }
sig do
params(symbol: String, constant: Module, node: RBI::Scope).void.checked(:never)
end
def push_scope(symbol, constant, node)
@events << Gem::ScopeNodeAdded.new(symbol, constant, node)
end

sig do
params(symbol: String, constant: Module, node: RBI::Scope).void.checked(:never)
end
def push_foreign_scope(symbol, constant, node)
@events << Gem::ForeignScopeNodeAdded.new(symbol, constant, node)
end

sig do
params(
symbol: String,
Expand Down Expand Up @@ -256,7 +265,12 @@ def compile_module(name, constant, foreign_constant: false)
RBI::Module.new(name)
end

push_scope(name, constant, scope)
if foreign_constant
push_foreign_scope(name, constant, scope)
else
push_scope(name, constant, scope)
end

@root << scope
end

Expand Down
47 changes: 46 additions & 1 deletion spec/tapioca/cli/gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1074,10 +1074,55 @@ def foo(a, b, c, d, e, f, g, h); end
assert_success_status(result)
end

it "must do mixin attribution properly" do
# This is pattern is taken from the private `typed_parameters` gem.
typed_parameters = mock_gem("typed_parameters", "0.3.0") do
write("lib/typed_parameters.rb", <<~RUBY)
require "action_controller"
module TypedParameters
end
# This dynamic mixin should be generated in the gem RBI
ActionController::Parameters.include(TypedParameters)
RUBY
end

@project.require_real_gem("actionpack", "6.1.4.4")
@project.require_mock_gem(typed_parameters)

@project.bundle_install

response = @project.tapioca("gem actionpack typed_parameters")

assert_includes(response.out, "Compiled actionpack")
assert_includes(response.out, "Compiled typed_parameters")

# TODO: Uncomment when addressing part 2 of tapioca#890
# actionpack_rbi = @project.read("sorbet/rbi/gems/actionpack@6.1.4.4.rbi")
# actionpack RBI should have nothing in it about `TypedParameters`
# refute_includes(actionpack_rbi, "TypedParameters")

assert_project_file_equal("sorbet/rbi/gems/typed_parameters@0.3.0.rbi", <<~RBI)
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `typed_parameters` gem.
# Please instead update this file by running `bin/tapioca gem typed_parameters`.
class ActionController::Parameters
include ::TypedParameters
end
module TypedParameters; end
RBI
end

it "must generate RBIs for constants defined in a different gem but with mixins in this gem" do
foo = mock_gem("foo", "0.0.1") do
write("lib/foo.rb", <<~RBI)
class Foo; end
class Foo
def baz; end
def buzz; end
end
RBI
end

Expand Down
6 changes: 0 additions & 6 deletions spec/tapioca/gem/pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,6 @@ class String
include ::Foo::Bar
extend ::JSON::Ext::Generator::GeneratorMethods::String::Extend
end
String::BLANK_RE = T.let(T.unsafe(nil), Regexp)
String::ENCODED_BLANKS = T.let(T.unsafe(nil), Concurrent::Map)
RBI

assert_equal(output, compile)
Expand Down Expand Up @@ -597,9 +594,6 @@ class String
include ::Foo::Bar
extend ::JSON::Ext::Generator::GeneratorMethods::String::Extend
end
String::BLANK_RE = T.let(T.unsafe(nil), Regexp)
String::ENCODED_BLANKS = T.let(T.unsafe(nil), Concurrent::Map)
RBI

assert_equal(output, compile)
Expand Down

0 comments on commit 434b98b

Please sign in to comment.