From 84572e05e20b208703b651c9374762c73835cfd0 Mon Sep 17 00:00:00 2001 From: Olivier Bellone Date: Mon, 24 Jun 2024 11:58:52 -0700 Subject: [PATCH] Ignore anonymous helpers modules --- lib/tapioca/dsl/compilers/grape_endpoints.rb | 8 +- rbi/grape.rbi | 5 ++ .../dsl/compilers/grape_endpoints_spec.rb | 73 ++++++++++++++++--- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/lib/tapioca/dsl/compilers/grape_endpoints.rb b/lib/tapioca/dsl/compilers/grape_endpoints.rb index 87591b2..3db37ae 100644 --- a/lib/tapioca/dsl/compilers/grape_endpoints.rb +++ b/lib/tapioca/dsl/compilers/grape_endpoints.rb @@ -137,14 +137,10 @@ def create_api_class def create_endpoint_class superclass = "::Grape::Endpoint" - helper_mods = constant.namespace_stackable(:helpers) - - if helper_mods.any? { |mod| mod.name.nil? } - raise "Cannot compile Grape API with anonymous helpers" - end + named_helper_mods = constant.namespace_stackable(:helpers).reject { |mod| mod.name.nil? } api.create_class(EndpointClassName, superclass_name: superclass) do |klass| - helper_mods.each do |mod| + named_helper_mods.each do |mod| klass.create_include(mod.name) end end diff --git a/rbi/grape.rbi b/rbi/grape.rbi index 99d2801..a31e384 100644 --- a/rbi/grape.rbi +++ b/rbi/grape.rbi @@ -22,6 +22,11 @@ module Grape sig { params(name: Symbol, block: T.proc.bind(Grape::Validations::ParamsScope).void).void } def params(name, &block); end end + + module ClassMethods + sig { params(new_modules: T.untyped, block: T.nilable(T.proc.bind(Grape::DSL::Helpers::BaseHelper).void)).void } + def helpers(*new_modules, &block); end + end end module RequestResponse diff --git a/spec/tapioca/dsl/compilers/grape_endpoints_spec.rb b/spec/tapioca/dsl/compilers/grape_endpoints_spec.rb index 6c5f6cb..07ef6fe 100644 --- a/spec/tapioca/dsl/compilers/grape_endpoints_spec.rb +++ b/spec/tapioca/dsl/compilers/grape_endpoints_spec.rb @@ -122,7 +122,7 @@ class PrivateEndpoint < ::Grape::Endpoint assert_equal(expected, rbi_for(:TwitterAPI)) end - it "does not process anonymous helpers" do + it "ignores anonymous helpers" do add_ruby_file("twitter_api.rb", <<~RUBY) class TwitterAPI < Grape::API::Instance version 'v1', using: :header, vendor: 'twitter' @@ -130,12 +130,9 @@ class TwitterAPI < Grape::API::Instance prefix :api helpers do - def current_user - @current_user ||= User.authorize!(env) - end - - def authenticate! - error!('401 Unauthorized', 401) unless current_user + params :pagination do + optional :page, type: Integer + optional :per_page, type: Integer end end @@ -148,9 +145,65 @@ def authenticate! end RUBY - assert_raises(RuntimeError, /Cannot compile Grape API with anonymous helpers/) do - rbi_for(:TwitterAPI) - end + expected = template(<<~RUBY) + # typed: strong + + class TwitterAPI + extend GeneratedCallbacksMethods + extend GeneratedRoutingMethods + + module GeneratedCallbacksMethods + sig { params(block: T.proc.bind(PrivateEndpoint).void).void } + def after(&block); end + + sig { params(block: T.proc.bind(PrivateEndpoint).void).void } + def after_validation(&block); end + + sig { params(block: T.proc.bind(PrivateEndpoint).void).void } + def before(&block); end + + sig { params(block: T.proc.bind(PrivateEndpoint).void).void } + def before_validation(&block); end + + sig { params(block: T.proc.bind(PrivateEndpoint).void).void } + def finally(&block); end + end + + module GeneratedRoutingMethods + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def delete(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def get(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def head(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def options(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def patch(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def post(*args, &block); end + + sig { params(args: T.untyped, block: T.nilable(T.proc.bind(PrivateEndpoint).void)).void } + def put(*args, &block); end + + sig { params(param: Symbol, options: T::Hash[Symbol, T.untyped], block: T.nilable(T.proc.bind(T.class_of(PrivateAPIInstance)).void)).void } + def route_param(param, options = {}, &block); end + end + + class PrivateAPIInstance < ::Grape::API::Instance + extend GeneratedRoutingMethods + end + + class PrivateEndpoint < ::Grape::Endpoint; end + end + RUBY + + assert_equal(expected, rbi_for(:TwitterAPI)) end end end