Skip to content

Commit

Permalink
Merge pull request #1840 from Shopify/emily/fix-protobuf-compiler
Browse files Browse the repository at this point in the history
Do not call `has_presence?` on `Protobuf::FieldDescriptor` unless method exists
  • Loading branch information
egiurleo authored Mar 26, 2024
2 parents 05359bf + 62d4eca commit cc008be
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
14 changes: 13 additions & 1 deletion lib/tapioca/dsl/compilers/protobuf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ def gather_constants

private

sig { params(desc: Google::Protobuf::FieldDescriptor).returns(T::Boolean) }
def has_presence?(desc)
if desc.respond_to?(:has_presence?)
# This method is only defined in google-protobuf 3.26.0 and later
desc.has_presence?
else
# In older versions of the gem, the only way we can get this information is
# by checking if an instance of the class responds to the expected method
T.unsafe(constant.allocate).respond_to?("has_#{desc.name}?")
end
end

sig { params(klass: RBI::Scope, names: String).void }
def create_type_members(klass, *names)
klass.create_extend("T::Generic")
Expand Down Expand Up @@ -302,7 +314,7 @@ def create_descriptor_method(klass, desc)
return_type: "void",
)

if desc.has_presence?
if has_presence?(desc)
klass.create_method(
"has_#{field.name}?",
return_type: "Object",
Expand Down
38 changes: 38 additions & 0 deletions spec/tapioca/cli/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2715,6 +2715,44 @@ class Application < Rails::Application
assert_success_status(res)
end
end

# These tests are in this file rather than in google_protobuf_spec.rb because they require
# a different version of the google-protobuf gem than the one that is used in the rest of the tests.
describe "google-protobuf" do
describe "version <= 3.25" do
before(:all) do
@project.require_real_gem("google-protobuf", "~>3.25")
@project.bundle_install!
end

it "generates has_{field.name}? methods in RBI files for classes with Protobuf" do
@project.exec("mkdir lib")
@project.write!("proto/cart.proto", <<~PROTO)
syntax = "proto3";
message Cart {
enum VALUE_TYPE {
NULL = 0;
FIXED_AMOUNT = 1;
PERCENTAGE = 2;
}
optional VALUE_TYPE value_type = 1;
}
PROTO

result = @project.exec("protoc --proto_path=proto --ruby_out=lib proto/cart.proto")
raise "Error executing protoc: #{result.err}" unless result.status

result = @project.tapioca("dsl Cart")
assert_empty_stderr(result)
assert_success_status(result)

cart_rbi = @project.read("sorbet/rbi/dsl/cart.rbi")
assert_includes(cart_rbi, "def has_value_type?; end")
end
end
end
end
end
end

0 comments on commit cc008be

Please sign in to comment.