Skip to content

Commit

Permalink
Cherry-pick #8356 into 3.16.x (#8518)
Browse files Browse the repository at this point in the history
* Ruby: Add support for proto3 json_name in compiler and field definitions

* Address review feedback

* Add test for json_name functionality

Co-authored-by: Lukas Fittl <[email protected]>
  • Loading branch information
acozzette and lfittl authored Apr 20, 2021
1 parent e8b78f8 commit 4aa425c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 8 deletions.
43 changes: 35 additions & 8 deletions ruby/ext/google/protobuf_c/defs.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,20 @@ static VALUE FieldDescriptor_default(VALUE _self) {
return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
}


/*
* call-seq:
* FieldDescriptor.json_name => json_name
*
* Returns this field's json_name, as a Ruby string, or nil if not yet set.
*/
static VALUE FieldDescriptor_json_name(VALUE _self) {
FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
const upb_fielddef *f = self->fielddef;
const char *json_name = upb_fielddef_jsonname(f);
return rb_str_new2(json_name);
}

/*
* call-seq:
* FieldDescriptor.label => label
Expand Down Expand Up @@ -1043,6 +1057,7 @@ static void FieldDescriptor_register(VALUE module) {
rb_define_method(klass, "name", FieldDescriptor_name, 0);
rb_define_method(klass, "type", FieldDescriptor__type, 0);
rb_define_method(klass, "default", FieldDescriptor_default, 0);
rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0);
rb_define_method(klass, "label", FieldDescriptor_label, 0);
rb_define_method(klass, "number", FieldDescriptor_number, 0);
rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
Expand Down Expand Up @@ -1750,6 +1765,16 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
field_proto,
FileBuilderContext_strdup(self->file_builder, default_value));
}

if (rb_funcall(options, rb_intern("key?"), 1,
ID2SYM(rb_intern("json_name"))) == Qtrue) {
VALUE json_name =
rb_hash_lookup(options, ID2SYM(rb_intern("json_name")));

google_protobuf_FieldDescriptorProto_set_json_name(
field_proto,
FileBuilderContext_strdup(self->file_builder, json_name));
}
}

if (oneof_index >= 0) {
Expand Down Expand Up @@ -1899,18 +1924,20 @@ static VALUE MessageBuilderContext_required(int argc, VALUE* argv,
*/
static VALUE MessageBuilderContext_repeated(int argc, VALUE* argv,
VALUE _self) {
VALUE name, type, number, type_class;
VALUE name, type, number;
VALUE type_class, options = Qnil;

if (argc < 3) {
rb_raise(rb_eArgError, "Expected at least 3 arguments.");
rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);

// Allow passing (name, type, number, options) or
// (name, type, number, type_class, options)
if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
options = type_class;
type_class = Qnil;
}
name = argv[0];
type = argv[1];
number = argv[2];
type_class = (argc > 3) ? argv[3] : Qnil;

msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
Qnil, -1, false);
options, -1, false);

return Qnil;
}
Expand Down
6 changes: 6 additions & 0 deletions ruby/tests/encode_decode_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,10 @@ def test_encode_wrong_msg
end
end

def test_json_name
msg = A::B::C::TestJsonName.new(:value => 42)
json = msg.to_json
assert_match json, "{\"CustomJsonName\":42}"
end

end
4 changes: 4 additions & 0 deletions ruby/tests/generated_code.proto
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,7 @@ message TestUnknown {
map<string, TestUnknown> map_unknown = 67;
int32 unknown_field = 89;
}

message TestJsonName {
int32 value = 1 [json_name = "CustomJsonName"];
}
5 changes: 5 additions & 0 deletions src/google/protobuf/compiler/ruby/ruby_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ void GenerateField(const FieldDescriptor* field, io::Printer* printer) {
DefaultValueForField(field));
}

if (field->has_json_name()) {
printer->Print(", json_name: \"$json_name$\"", "json_name",
field->json_name());
}

printer->Print("\n");
}
}
Expand Down

0 comments on commit 4aa425c

Please sign in to comment.