diff options
-rw-r--r-- | js/binary/proto_test.js | 6 | ||||
-rw-r--r-- | js/message.js | 4 | ||||
-rw-r--r-- | js/message_test.js | 3 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/map.c | 31 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/message.c | 14 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/protobuf.h | 2 | ||||
-rw-r--r-- | ruby/tests/basic.rb | 10 |
7 files changed, 61 insertions, 9 deletions
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js index f86dc645..f5e1b6bb 100644 --- a/js/binary/proto_test.js +++ b/js/binary/proto_test.js @@ -283,8 +283,7 @@ function checkAllFields(original, copy) { * @param {!proto.jspb.test.TestExtendable} msg */ function checkExtensions(msg) { - assertEquals(-42, - msg.getExtension(proto.jspb.test.extendOptionalInt32)); + assertEquals(0, msg.getExtension(proto.jspb.test.extendOptionalInt32)); assertEquals(-0x7fffffff00000000, msg.getExtension(proto.jspb.test.extendOptionalInt64)); assertEquals(0x80000000, @@ -512,8 +511,7 @@ describe('protoBinaryTest', function() { * @param {proto.jspb.test.TestExtendable} msg */ function fillExtensions(msg) { - msg.setExtension( - proto.jspb.test.extendOptionalInt32, -42); + msg.setExtension(proto.jspb.test.extendOptionalInt32, 0); msg.setExtension( proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000); msg.setExtension( diff --git a/js/message.js b/js/message.js index 05d34e9d..4e2517d3 100644 --- a/js/message.js +++ b/js/message.js @@ -497,7 +497,7 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions, for (var fieldNumber in extensions) { var fieldInfo = extensions[fieldNumber]; var value = getExtensionFn.call(proto, fieldInfo); - if (value) { + if (goog.isDefAndNotNull(value)) { for (var name in fieldInfo.fieldName) { if (fieldInfo.fieldName.hasOwnProperty(name)) { break; // the compiled field name @@ -541,7 +541,7 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions, 'without binary serialization support'); } var value = getExtensionFn.call(proto, fieldInfo); - if (value) { + if (goog.isDefAndNotNull(value)) { if (fieldInfo.isMessageType()) { // If the message type of the extension was generated without binary // support, there may not be a binary message serializer function, and diff --git a/js/message_test.js b/js/message_test.js index a2c5763d..2298742d 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -693,10 +693,11 @@ describe('Message test suite', function() { }); it('testToObject_hasExtensionField', function() { - var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]); + var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1'], 102: ''}]); var obj = data.toObject(); assertEquals('str1', obj.str1); assertEquals('ext1', obj.extField.ext1); + assertEquals('', obj.str); }); it('testGetExtension', function() { diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c index 12f1f9dd..4be54c39 100644 --- a/ruby/ext/google/protobuf_c/map.c +++ b/ruby/ext/google/protobuf_c/map.c @@ -654,6 +654,35 @@ VALUE Map_hash(VALUE _self) { /* * call-seq: + * Map.to_h => {} + * + * Returns a Ruby Hash object containing all the values within the map + */ +VALUE Map_to_h(VALUE _self) { + Map* self = ruby_to_Map(_self); + VALUE hash = rb_hash_new(); + upb_strtable_iter it; + for (upb_strtable_begin(&it, &self->table); + !upb_strtable_done(&it); + upb_strtable_next(&it)) { + VALUE key = table_key_to_ruby( + self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); + upb_value v = upb_strtable_iter_value(&it); + void* mem = value_memory(&v); + VALUE value = native_slot_get(self->value_type, + self->value_type_class, + mem); + + if (self->value_type == UPB_TYPE_MESSAGE) { + value = Message_to_h(value); + } + rb_hash_aset(hash, key, value); + } + return hash; +} + +/* + * call-seq: * Map.inspect => string * * Returns a string representing this map's elements. It will be formatted as @@ -804,6 +833,8 @@ void Map_register(VALUE module) { rb_define_method(klass, "dup", Map_dup, 0); rb_define_method(klass, "==", Map_eq, 1); rb_define_method(klass, "hash", Map_hash, 0); + rb_define_method(klass, "to_hash", Map_to_h, 0); + rb_define_method(klass, "to_h", Map_to_h, 0); rb_define_method(klass, "inspect", Map_inspect, 0); rb_define_method(klass, "merge", Map_merge, 1); rb_include_module(klass, rb_mEnumerable); diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 837a974b..29911140 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -394,7 +394,12 @@ VALUE Message_inspect(VALUE _self) { return str; } - +/* + * call-seq: + * Message.to_h => {} + * + * Returns the message as a Ruby Hash object, with keys as symbols. + */ VALUE Message_to_h(VALUE _self) { MessageHeader* self; VALUE hash; @@ -410,8 +415,13 @@ VALUE Message_to_h(VALUE _self) { VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field); VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { + if (upb_fielddef_ismap(field)) { + msg_value = Map_to_h(msg_value); + } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { msg_value = RepeatedField_to_ary(msg_value); + } else if (msg_value != Qnil && + upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { + msg_value = Message_to_h(msg_value); } rb_hash_aset(hash, msg_key, msg_value); } diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h index d5ced567..520e9d9b 100644 --- a/ruby/ext/google/protobuf_c/protobuf.h +++ b/ruby/ext/google/protobuf_c/protobuf.h @@ -424,6 +424,7 @@ VALUE Map_dup(VALUE _self); VALUE Map_deep_copy(VALUE _self); VALUE Map_eq(VALUE _self, VALUE _other); VALUE Map_hash(VALUE _self); +VALUE Map_to_h(VALUE _self); VALUE Map_inspect(VALUE _self); VALUE Map_merge(VALUE _self, VALUE hashmap); VALUE Map_merge_into_self(VALUE _self, VALUE hashmap); @@ -496,6 +497,7 @@ VALUE Message_deep_copy(VALUE _self); VALUE Message_eq(VALUE _self, VALUE _other); VALUE Message_hash(VALUE _self); VALUE Message_inspect(VALUE _self); +VALUE Message_to_h(VALUE _self); VALUE Message_index(VALUE _self, VALUE field_name); VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value); VALUE Message_descriptor(VALUE klass); diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb index ca81e3a5..34251234 100644 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -927,6 +927,16 @@ module BasicTest :repeated_uint64=>[] } assert_equal expected_result, m.to_h + + m = MapMessage.new( + :map_string_int32 => {"a" => 1, "b" => 2}, + :map_string_msg => {"a" => TestMessage2.new(:foo => 1), + "b" => TestMessage2.new(:foo => 2)}) + expected_result = { + :map_string_int32 => {"a" => 1, "b" => 2}, + :map_string_msg => {"a" => {:foo => 1}, "b" => {:foo => 2}} + } + assert_equal expected_result, m.to_h end |