aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <jhaberman@gmail.com>2016-11-15 10:31:15 -0800
committerGitHub <noreply@github.com>2016-11-15 10:31:15 -0800
commitbf379715c93b581eeb078cec1f0dd8a7d79df431 (patch)
tree5094c2c5f8ad7252508cca751756f4ae63429929
parentc6f3d700b90cd51328c8b5f6c144789ca237e771 (diff)
parent74a636a7a29132ff89b4d8a487618d9a411fdaa4 (diff)
downloadprotobuf-bf379715c93b581eeb078cec1f0dd8a7d79df431.tar.gz
protobuf-bf379715c93b581eeb078cec1f0dd8a7d79df431.tar.bz2
protobuf-bf379715c93b581eeb078cec1f0dd8a7d79df431.zip
Merge pull request #2323 from marcinwyszynski/master
More Ruby-eqsue interface
-rw-r--r--ruby/ext/google/protobuf_c/message.c44
-rw-r--r--ruby/tests/basic.rb10
2 files changed, 54 insertions, 0 deletions
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index e16250f3..837a974b 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -178,6 +178,45 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
}
}
+VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
+ MessageHeader* self;
+ VALUE method_name, method_str;
+ char* name;
+ size_t name_len;
+ bool setter;
+ const upb_oneofdef* o;
+ const upb_fielddef* f;
+
+ TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "Expected method name as first argument.");
+ }
+ method_name = argv[0];
+ if (!SYMBOL_P(method_name)) {
+ rb_raise(rb_eArgError, "Expected symbol as method name.");
+ }
+ method_str = rb_id2str(SYM2ID(method_name));
+ name = RSTRING_PTR(method_str);
+ name_len = RSTRING_LEN(method_str);
+ setter = false;
+
+ // Setters have names that end in '='.
+ if (name[name_len - 1] == '=') {
+ setter = true;
+ name_len--;
+ }
+
+ // See if this name corresponds to either a oneof or field in this message.
+ if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
+ &o)) {
+ return rb_call_super(argc, argv);
+ }
+ if (o != NULL) {
+ return setter ? Qfalse : Qtrue;
+ }
+ return Qtrue;
+}
+
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
MessageHeader* self;
VALUE method_str;
@@ -305,6 +344,9 @@ VALUE Message_deep_copy(VALUE _self) {
VALUE Message_eq(VALUE _self, VALUE _other) {
MessageHeader* self;
MessageHeader* other;
+ if (TYPE(_self) != TYPE(_other)) {
+ return Qfalse;
+ }
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
@@ -459,6 +501,8 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
rb_define_method(klass, "method_missing",
Message_method_missing, -1);
+ rb_define_method(klass, "respond_to_missing?",
+ Message_respond_to_missing, -1);
rb_define_method(klass, "initialize", Message_initialize, -1);
rb_define_method(klass, "dup", Message_dup, 0);
// Also define #clone so that we don't inherit Object#clone.
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index 989a047e..967ff81f 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -1181,5 +1181,15 @@ module BasicTest
m2 = MapMessage.decode_json(MapMessage.encode_json(m))
assert m == m2
end
+
+ def test_comparison_with_arbitrary_object
+ assert_false MapMessage.new == nil
+ end
+
+ def test_respond_to
+ msg = MapMessage.new
+ assert msg.respond_to?(:map_string_int32)
+ assert_false msg.respond_to?(:bacon)
+ end
end
end