-
Notifications
You must be signed in to change notification settings - Fork 15.9k
Description
If a oneof field shares the name of a Ruby method defined on Object or Kernel, there is no way to get the oneof field.
Normally, you do something like my_message.my_oneof to get the value. But for a proto definition like oneof method { ... }, that would mean doing my_message.method, which then attempts to call Kernel#method in the Ruby VM (e.g., to look up a method with the given name). That then fails, because method takes a required arg, but that's irrelevant: what it's not doing is looking up the oneof field named method on the message.
Normal, non-oneof fields work around this via the [] method on AbstractMessage, so that you can do my_message["method"]. That access pattern does not work when method is a oneof field instead of a normal field on the message.
Since protobuf allows oneof fields defined with arbitrary names (including names that collide with Ruby method names), there needs to be a way to access the field even in the presence of these collisions.
To my knowledge, there is no workaround for this in the mean time.
Update: #21736 (comment)
What version of protobuf and what language are you using?
Language: Ruby
❯ bundle info google-protobuf
* google-protobuf (4.30.2)
Summary: Protocol Buffers
Homepage: https://developers.google.com/protocol-buffers
Source Code: https://github.com/protocolbuffers/protobuf/tree/v4.30.2/ruby
Path: /pay/home/jez/sandbox/vendor/bundle/ruby/3.3.0/gems/google-protobuf-4.30.2-x86_64-linux
❯ bin/protoc --version
libprotoc 31.0-rc2
What operating system (Linux, Windows, ...) and version?
Linux (platform agnostic)
What runtime / compiler are you using (e.g., python version or gcc version)
Ruby 3.3, but should be version agnostic
What did you do?
Gemfile
source 'https://rubygems.org'
gem 'google-protobuf'Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
bigdecimal (3.1.9)
google-protobuf (4.30.2)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-aarch64-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-arm64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86_64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86_64-linux)
bigdecimal
rake (>= 13)
rake (13.2.1)
PLATFORMS
aarch64-linux
arm64-darwin
ruby
x86-linux
x86_64-darwin
x86_64-linux
DEPENDENCIES
google-protobuf
BUNDLED WITH
2.5.22
test_message.proto
message TestMessageEither {
oneof either {
string left = 1;
int32 right = 2;
}
}
message TestMessageMethod {
oneof method {
string left = 1;
int32 right = 2;
}
}test_message_pb.rb
# frozen_string_literal: true
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: test_message.proto
require 'google/protobuf'
descriptor_data = "\n\x12test_message.proto\">\n\x11TestMessageEither\x12\x0e\n\x04left\x18\x01 \x01(\tH\x00\x12\x0f\n\x05right\x18\x02 \x01(\x05H\x00\x42\x08\n\x06\x65ither\">\n\x11TestMessageMethod\x12\x0e\n\x04left\x18\x01 \x01(\tH\x00\x12\x0f\n\x05right\x18\x02 \x01(\x05H\x00\x42\x08\n\x06method"
pool = ::Google::Protobuf::DescriptorPool.generated_pool
pool.add_serialized_file(descriptor_data)
TestMessageEither = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("TestMessageEither").msgclass
TestMessageMethod = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("TestMessageMethod").msgclassfoo.rb
require 'google/protobuf'
require_relative './test_message_pb.rb'
def try(testcase)
print(testcase)
print(": ")
begin
yield
rescue => e
STDERR.puts("#{e.class}: #{e.message}")
STDERR.puts(e.backtrace)
end
puts
end
puts "----- Expected behavior ------------------------------------------------"
msg = TestMessageEither.new(left: "hello")
try("msg") { p(msg) }
try("msg.left") { p(msg.left) }
try('msg["left"]') { p(msg["left"]) }
try("msg.either") { p(msg.either) }
try('msg["either"]') { p(msg["either"]) }
puts "----- Unexpected behavior ----------------------------------------------"
msg = TestMessageMethod.new(left: "hello")
try("msg") { p(msg) }
try("msg.left") { p(msg.left) }
try('msg["left"]') { p(msg["left"]) }
try("msg.method") { p(msg.method) }
try('msg["method"]') { p(msg["method"]) }.ruby-version
3.3.5
bundle exec ruby foo.rb
What did you expect to see
No exception for the msg.method line, or at least something useful for the msg["method"] line.
What did you see instead?
❯ bundle exec ruby foo.rb
----- Expected behavior ------------------------------------------------
msg: <TestMessageEither: left: "hello">
msg.left: "hello"
msg["left"]: "hello"
msg.either: :left
msg["either"]: nil
----- Unexpected behavior ----------------------------------------------
msg: <TestMessageMethod: left: "hello">
msg.left: "hello"
msg["left"]: "hello"
msg.method: ArgumentError: wrong number of arguments (given 0, expected 1)
foo.rb:29:in `method'
foo.rb:29:in `block in <main>'
foo.rb:8:in `try'
foo.rb:29:in `<main>'
msg["method"]: nil
Anything else we should know about your project / environment
I have included a zipfile if you'd like to avoid copy/pasting a bunch of files:
unzip test.zip
cd sandbox
bundle install
bundle exec ruby foo.rb