Skip to content

Commit

Permalink
Support hashes for struct initializers (#5716)
Browse files Browse the repository at this point in the history
* support hashes for struct initalizers

* convert hash keys to string

* update tests

* add extra asserts
  • Loading branch information
jbolinger authored and TeBoring committed Jul 25, 2019
1 parent dcc8ffd commit 41e1234
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
8 changes: 8 additions & 0 deletions ruby/ext/google/protobuf_c/map.c
Expand Up @@ -71,6 +71,9 @@ static VALUE table_key(Map* self, VALUE key,
case UPB_TYPE_BYTES:
case UPB_TYPE_STRING:
// Strings: use string content directly.
if (TYPE(key) == T_SYMBOL) {
key = rb_id2str(SYM2ID(key));
}
Check_Type(key, T_STRING);
key = native_slot_encode_and_freeze_string(self->key_type, key);
*out_key = RSTRING_PTR(key);
Expand Down Expand Up @@ -397,6 +400,11 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) {
void* mem;
key = table_key(self, key, keybuf, &keyval, &length);

if (TYPE(value) == T_HASH) {
VALUE args[1] = { value };
value = rb_class_new_instance(1, args, self->value_type_class);
}

mem = value_memory(&v);
native_slot_set("", self->value_type, self->value_type_class, mem, value);

Expand Down
14 changes: 14 additions & 0 deletions ruby/tests/basic.rb
Expand Up @@ -204,6 +204,20 @@ def test_map_field
end
end

def test_map_field_with_symbol
m = MapMessage.new
assert m.map_string_int32 == {}
assert m.map_string_msg == {}

m = MapMessage.new(
:map_string_int32 => {a: 1, "b" => 2},
:map_string_msg => {a: TestMessage2.new(:foo => 1),
b: TestMessage2.new(:foo => 10)})
assert_equal 1, m.map_string_int32[:a]
assert_equal 2, m.map_string_int32[:b]
assert_equal 10, m.map_string_msg[:b].foo
end

def test_map_inspect
m = MapMessage.new(
:map_string_int32 => {"a" => 1, "b" => 2},
Expand Down
54 changes: 54 additions & 0 deletions ruby/tests/well_known_types_test.rb
Expand Up @@ -139,4 +139,58 @@ def test_any
assert any.is(Google::Protobuf::Timestamp)
assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
end

def test_struct_init
s = Google::Protobuf::Struct.new(fields: {'a' => Google::Protobuf::Value.new({number_value: 4.4})})
assert_equal 4.4, s['a']

s = Google::Protobuf::Struct.new(fields: {'a' => {number_value: 2.2}})
assert_equal 2.2, s['a']

s = Google::Protobuf::Struct.new(fields: {a: {number_value: 1.1}})
assert_equal 1.1, s[:a]
end

def test_struct_nested_init
s = Google::Protobuf::Struct.new(
fields: {
'a' => {string_value: 'A'},
'b' => {struct_value: {
fields: {
'x' => {list_value: {values: [{number_value: 1.0}, {string_value: "ok"}]}},
'y' => {bool_value: true}}}
},
'c' => {struct_value: {}}
}
)
assert_equal 'A', s['a']
assert_equal 'A', s[:a]
expected_b_x = [Google::Protobuf::Value.new(number_value: 1.0), Google::Protobuf::Value.new(string_value: "ok")]
assert_equal expected_b_x, s['b']['x'].values
assert_equal expected_b_x, s[:b][:x].values
assert_equal expected_b_x, s['b'][:x].values
assert_equal expected_b_x, s[:b]['x'].values
assert_equal true, s['b']['y']
assert_equal true, s[:b][:y]
assert_equal true, s[:b]['y']
assert_equal true, s['b'][:y]
assert_equal Google::Protobuf::Struct.new, s['c']
assert_equal Google::Protobuf::Struct.new, s[:c]

s = Google::Protobuf::Struct.new(
fields: {
a: {string_value: 'Eh'},
b: {struct_value: {
fields: {
y: {bool_value: false}}}
}
}
)
assert_equal 'Eh', s['a']
assert_equal 'Eh', s[:a]
assert_equal false, s['b']['y']
assert_equal false, s[:b][:y]
assert_equal false, s['b'][:y]
assert_equal false, s[:b]['y']
end
end

0 comments on commit 41e1234

Please sign in to comment.