From 07dcfe4da3818c8a84d127f7fa2a8af7e530b4f2 Mon Sep 17 00:00:00 2001 From: Ufuk Kayserilioglu Date: Tue, 1 Nov 2022 19:06:02 +0000 Subject: [PATCH 1/2] Drop Pry runtime dependency --- Gemfile | 1 + Gemfile.lock | 2 +- tapioca.gemspec | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 25fd32bb1..c50137ff5 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ gem("minitest") gem("minitest-hooks") gem("minitest-reporters") gem("debug", require: false) +gem("pry") gem("pry-byebug") gem("rubocop-shopify", require: false) gem("rubocop-sorbet", ">= 0.4.1") diff --git a/Gemfile.lock b/Gemfile.lock index 7e1a7c9c7..272d28fc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,7 +21,6 @@ PATH bundler (>= 1.17.3) netrc (>= 0.11.0) parallel (>= 1.21.0) - pry (>= 0.12.2) rbi (~> 0.0.0, >= 0.0.16) sorbet-static-and-runtime (>= 0.5.9204) spoom (~> 1.1.0, >= 1.1.11) @@ -380,6 +379,7 @@ DEPENDENCIES minitest-reporters net-smtp (= 0.3.3) nokogiri + pry pry-byebug rails rake diff --git a/tapioca.gemspec b/tapioca.gemspec index c4d6cee1b..1accd7963 100644 --- a/tapioca.gemspec +++ b/tapioca.gemspec @@ -26,7 +26,6 @@ Gem::Specification.new do |spec| spec.add_dependency("bundler", ">= 1.17.3") spec.add_dependency("netrc", ">= 0.11.0") spec.add_dependency("parallel", ">= 1.21.0") - spec.add_dependency("pry", ">= 0.12.2") spec.add_dependency("rbi", "~> 0.0.0", ">= 0.0.16") spec.add_dependency("sorbet-static-and-runtime", ">= 0.5.9204") spec.add_dependency("spoom", "~> 1.1.0", ">= 1.1.11") From 22e983dd8bc9dae124dbd59cc1a881b49decccd2 Mon Sep 17 00:00:00 2001 From: Ufuk Kayserilioglu Date: Tue, 1 Nov 2022 19:15:00 +0000 Subject: [PATCH 2/2] Replace `Pry::WrappedMethod` functionality Add relevant machinery inside the `Reflection` class to discover file candidates for a given constant based on the source location of the given constant's (or its singleton class') methods. --- lib/tapioca/gem/pipeline.rb | 10 +++--- lib/tapioca/runtime/reflection.rb | 55 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/tapioca/gem/pipeline.rb b/lib/tapioca/gem/pipeline.rb index 8044a3164..e95dfbd71 100644 --- a/lib/tapioca/gem/pipeline.rb +++ b/lib/tapioca/gem/pipeline.rb @@ -342,7 +342,7 @@ def compile_superclass(constant) sig { params(constant: Module, strict: T::Boolean).returns(T::Boolean) } def defined_in_gem?(constant, strict: true) - files = Set.new(get_file_candidates(constant)) + files = get_file_candidates(constant) .merge(Runtime::Trackers::ConstantDefinition.files_for(constant)) return !strict if files.empty? @@ -352,13 +352,11 @@ def defined_in_gem?(constant, strict: true) end end - sig { params(constant: Module).returns(T::Array[String]) } + sig { params(constant: Module).returns(T::Set[String]) } def get_file_candidates(constant) - wrapped_module = Pry::WrappedModule.new(constant) - - wrapped_module.send(:method_candidates).flatten.filter_map(&:source_file).uniq + file_candidates_for(constant) rescue ArgumentError, NameError - [] + Set.new end sig { params(name: String).void } diff --git a/lib/tapioca/runtime/reflection.rb b/lib/tapioca/runtime/reflection.rb index 1e2d3908b..cd5f0cfc4 100644 --- a/lib/tapioca/runtime/reflection.rb +++ b/lib/tapioca/runtime/reflection.rb @@ -183,6 +183,61 @@ def attached_class_of(singleton_class) T.cast(result, Module) end + + sig { params(constant: Module).returns(T::Set[String]) } + def file_candidates_for(constant) + relevant_methods_for(constant).filter_map do |method| + method.source_location&.first + end.to_set + end + + private + + sig { params(constant: Module).returns(T::Array[UnboundMethod]) } + def relevant_methods_for(constant) + methods = methods_for(constant).select(&:source_location) + .reject { |x| method_defined_by_forwardable_module?(x) } + + return methods unless methods.empty? + + constants_of(constant).flat_map do |const_name| + if (mod = child_module_for_parent_with_name(constant, const_name.to_s)) + relevant_methods_for(mod) + else + [] + end + end + end + + sig { params(constant: Module).returns(T::Array[UnboundMethod]) } + def methods_for(constant) + modules = [constant, singleton_class_of(constant)] + method_list_methods = [ + PUBLIC_INSTANCE_METHODS_METHOD, + PROTECTED_INSTANCE_METHODS_METHOD, + PRIVATE_INSTANCE_METHODS_METHOD, + ] + + modules.product(method_list_methods).flat_map do |mod, method_list_method| + method_list_method.bind_call(mod, false).map { |name| mod.instance_method(name) } + end + end + + sig { params(parent: Module, name: String).returns(T.nilable(Module)) } + def child_module_for_parent_with_name(parent, name) + return if parent.autoload?(name) + + child = constantize(name, inherit: true, namespace: parent) + return unless Module === child + return unless name_of(child) == "#{name_of(parent)}::#{name}" + + child + end + + sig { params(method: UnboundMethod).returns(T::Boolean) } + def method_defined_by_forwardable_module?(method) + method.source_location&.first == Object.const_source_location(:Forwardable)&.first + end end end end