From 8cd3cca08c1fe6394e14d738c08aa9e2af6de878 Mon Sep 17 00:00:00 2001 From: Dave Benvenuti Date: Tue, 14 Jan 2025 10:38:44 -0800 Subject: [PATCH] WIP --- lib/protoboeuf/codegen.rb | 135 +- lib/protoboeuf/decorated_field.rb | 11 +- lib/protoboeuf/google/protobuf/any.rb | 22 +- lib/protoboeuf/google/protobuf/boolvalue.rb | 19 +- lib/protoboeuf/google/protobuf/bytesvalue.rb | 19 +- lib/protoboeuf/google/protobuf/descriptor.rb | 1498 ++++++++++++++--- lib/protoboeuf/google/protobuf/doublevalue.rb | 19 +- lib/protoboeuf/google/protobuf/duration.rb | 22 +- lib/protoboeuf/google/protobuf/field_mask.rb | 19 +- lib/protoboeuf/google/protobuf/floatvalue.rb | 19 +- lib/protoboeuf/google/protobuf/int32value.rb | 19 +- lib/protoboeuf/google/protobuf/int64value.rb | 19 +- lib/protoboeuf/google/protobuf/stringvalue.rb | 19 +- lib/protoboeuf/google/protobuf/struct.rb | 83 +- lib/protoboeuf/google/protobuf/timestamp.rb | 22 +- lib/protoboeuf/google/protobuf/uint32value.rb | 19 +- lib/protoboeuf/google/protobuf/uint64value.rb | 19 +- test/fixtures/person.proto | 15 + test/fixtures/typed_test.correct.rb | 47 +- test/hash_serialization_test.rb | 83 + test/message_test.rb | 2 + 21 files changed, 1851 insertions(+), 279 deletions(-) create mode 100644 test/fixtures/person.proto create mode 100644 test/hash_serialization_test.rb diff --git a/lib/protoboeuf/codegen.rb b/lib/protoboeuf/codegen.rb index 68416a7..15c9d29 100644 --- a/lib/protoboeuf/codegen.rb +++ b/lib/protoboeuf/codegen.rb @@ -77,6 +77,105 @@ def resolve end end + # Generates #to_h, #as_json, and #to_json methods + class HashSerializationCompiler + include TypeHelper + + attr_reader :message, :fields, :oneof_selection_fields, :generate_types + + class << self + def result(message:, fields:, oneof_selection_fields:, generate_types:) + new(message:, fields:, oneof_selection_fields:, generate_types:).result + end + end + + def initialize(message:, fields:, oneof_selection_fields:, generate_types:) + @message = message + @fields = fields.sort_by(&:number) # Serialize fields in their proto order + @oneof_selection_fields = oneof_selection_fields + @generate_types = generate_types + end + + def result + <<~RUBY + #{type_signature(returns: "T::Hash[Symbol, T.untyped]")} + #{hash_serializer_rb(method_name: "to_h")} + + #{type_signature(params: { options: "T::Hash[T.untyped, T.untyped]" }, returns: "T::Hash[Symbol, T.untyped]")} + #{hash_serializer_rb(method_name: "as_json", json: true)} + + def to_json(options = {}) + require 'json' + JSON.dump(as_json(options)) + end + RUBY + end + + private + + def hash_serializer_rb(method_name:, json: false) + <<~HASH_SERIALIZER + def #{method_name}(options = {}) + result = {} + + #{fields.map { |f| assign_result_hash_rb(f, json:) }.join("\n")} + + result + end + HASH_SERIALIZER + end + + def assign_result_hash_rb(field, json: false) + key = hash_key_rb(field, json:) + value = hash_value_rb(field, json:) + + if field.has_oneof_index? && !field.optional? + oneof_selection_field_name = oneof_selection_fields[field.oneof_index].name.dump + field_name = field.name.dump + + "result[#{key}] = #{value} if send(:#{oneof_selection_field_name}) == :#{field_name}" + elsif field.repeated? + "#{value}.tap { |v| result[#{key}] = v if !options[:compact] || v.any? }" + elsif field.optional? + "result[#{key}] = #{value} if !options[:compact] || has_#{field.name}?" + else + "result[#{key}] = #{value}" + end + end + + def hash_key_rb(field, json:) + json ? field.json_name.dump : ":#{field.name.dump}" + end + + def hash_value_rb(field, json:) + return hash_value_for_map_rb(field, json:) if field.map_field? + + # For primitives or arrays of primitives we can just use the instance variable value + return field.iv_name unless field.type == :TYPE_MESSAGE + + recurse_with = json ? "as_json(options)" : "to_h(options)" + + if field.repeated? + # repeated maps aren't possible so we don't have to worry about to_h arity or as_json not being defined + "#{field.iv_name}.map { |v| v.#{recurse_with} }" + else + "#{field.iv_name}.#{recurse_with}" + end + end + + def hash_value_for_map_rb(field, json:) + if field.map_type.value.type == :TYPE_MESSAGE + recurse_with = json ? "as_json(options)" : "to_h(options)" + + <<~RUBY + #{field.iv_name}.transform_values { |value| value.#{recurse_with} } + RUBY + else + field.iv_name + end + end + end + class MessageCompiler attr_reader :generate_types, :requires @@ -88,8 +187,13 @@ def result(message, toplevel_enums, generate_types:, requires:, syntax:, options end end - attr_reader :message, :fields, :oneof_fields, :syntax - attr_reader :optional_fields, :enum_field_types + attr_reader :message, + :fields, + :oneof_fields, + :syntax, + :optional_fields, + :enum_field_types, + :oneof_selection_fields def initialize(message, toplevel_enums, generate_types:, requires:, syntax:, options:) @message = message @@ -160,32 +264,7 @@ def class_body end def conversion - fields = self.fields.reject do |field| - field.has_oneof_index? && !field.optional? - end - - oneofs = @oneof_selection_fields.map do |field| - "send(#{field.name.dump}).tap { |f| result[f.to_sym] = send(f) if f }" - end - - <<~RUBY - #{type_signature(returns: "T::Hash[Symbol, T.untyped]")} - def to_h - result = {} - #{(oneofs + fields.map { |field| convert_field(field) }).join("\n")} - result - end - RUBY - end - - def convert_field(field) - if field.repeated? - "result['#{field.name}'.to_sym] = #{field.iv_name}" - elsif field.type == :TYPE_MESSAGE - "result['#{field.name}'.to_sym] = #{field.iv_name}.to_h" - else - "result['#{field.name}'.to_sym] = #{field.iv_name}" - end + HashSerializationCompiler.result(message:, fields:, oneof_selection_fields:, generate_types:) end def encode diff --git a/lib/protoboeuf/decorated_field.rb b/lib/protoboeuf/decorated_field.rb index ac916dc..7f28298 100644 --- a/lib/protoboeuf/decorated_field.rb +++ b/lib/protoboeuf/decorated_field.rb @@ -8,7 +8,16 @@ class DecoratedField extend Forwardable - def_delegators :@original_field, :name, :label, :type_name, :type, :number, :options, :oneof_index, :has_oneof_index? + def_delegators :@original_field, + :name, + :label, + :type_name, + :type, + :number, + :options, + :oneof_index, + :has_oneof_index?, + :json_name def initialize(field:, message:, syntax:) @original_field = field diff --git a/lib/protoboeuf/google/protobuf/any.rb b/lib/protoboeuf/google/protobuf/any.rb index 5977153..bd43e26 100644 --- a/lib/protoboeuf/google/protobuf/any.rb +++ b/lib/protoboeuf/google/protobuf/any.rb @@ -551,12 +551,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["type_url".to_sym] = @type_url - result["value".to_sym] = @value + + result[:"type_url"] = @type_url + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["typeUrl"] = @type_url + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/boolvalue.rb b/lib/protoboeuf/google/protobuf/boolvalue.rb index ed3424c..7c0fb62 100644 --- a/lib/protoboeuf/google/protobuf/boolvalue.rb +++ b/lib/protoboeuf/google/protobuf/boolvalue.rb @@ -347,11 +347,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/bytesvalue.rb b/lib/protoboeuf/google/protobuf/bytesvalue.rb index 05905a2..e8d48be 100644 --- a/lib/protoboeuf/google/protobuf/bytesvalue.rb +++ b/lib/protoboeuf/google/protobuf/bytesvalue.rb @@ -406,11 +406,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/descriptor.rb b/lib/protoboeuf/google/protobuf/descriptor.rb index af152fe..93596ea 100644 --- a/lib/protoboeuf/google/protobuf/descriptor.rb +++ b/lib/protoboeuf/google/protobuf/descriptor.rb @@ -510,11 +510,30 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["file".to_sym] = @file + + result[:"file"] = @file.map { |v| v.to_h(options) } if !options[ + :compact + ] || @file.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["file"] = @file.map { |v| v.as_json(options) } if !options[ + :compact + ] || @file.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FileDescriptorProto def self.decode(buff) @@ -3355,23 +3374,87 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"package"] = @package if !options[:compact] || has_package? + result[:"dependency"] = @dependency if !options[:compact] || + @dependency.any? + result[:"message_type"] = @message_type.map do |v| + v.to_h(options) + end if !options[:compact] || + @message_type.map { |v| v.to_h(options) }.any? + result[:"enum_type"] = @enum_type.map do |v| + v.to_h(options) + end if !options[:compact] || + @enum_type.map { |v| v.to_h(options) }.any? + result[:"service"] = @service.map { |v| v.to_h(options) } if !options[ + :compact + ] || @service.map { |v| v.to_h(options) }.any? + result[:"extension"] = @extension.map do |v| + v.to_h(options) + end if !options[:compact] || + @extension.map { |v| v.to_h(options) }.any? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result[:"source_code_info"] = @source_code_info.to_h( + options + ) if !options[:compact] || has_source_code_info? + result[:"public_dependency"] = @public_dependency if !options[ + :compact + ] || @public_dependency.any? + result[:"weak_dependency"] = @weak_dependency if !options[:compact] || + @weak_dependency.any? + result[:"syntax"] = @syntax if !options[:compact] || has_syntax? + result[:"edition"] = @edition if !options[:compact] || has_edition? + + result + end + + def as_json(options = {}) result = {} - result["name".to_sym] = @name - result["package".to_sym] = @package - result["dependency".to_sym] = @dependency - result["public_dependency".to_sym] = @public_dependency - result["weak_dependency".to_sym] = @weak_dependency - result["message_type".to_sym] = @message_type - result["enum_type".to_sym] = @enum_type - result["service".to_sym] = @service - result["extension".to_sym] = @extension - result["options".to_sym] = @options.to_h - result["source_code_info".to_sym] = @source_code_info.to_h - result["syntax".to_sym] = @syntax - result["edition".to_sym] = @edition + + result["name"] = @name if !options[:compact] || has_name? + result["package"] = @package if !options[:compact] || has_package? + result["dependency"] = @dependency if !options[:compact] || + @dependency.any? + result["messageType"] = @message_type.map do |v| + v.as_json(options) + end if !options[:compact] || + @message_type.map { |v| v.as_json(options) }.any? + result["enumType"] = @enum_type.map do |v| + v.as_json(options) + end if !options[:compact] || + @enum_type.map { |v| v.as_json(options) }.any? + result["service"] = @service.map do |v| + v.as_json(options) + end if !options[:compact] || + @service.map { |v| v.as_json(options) }.any? + result["extension"] = @extension.map do |v| + v.as_json(options) + end if !options[:compact] || + @extension.map { |v| v.as_json(options) }.any? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result["sourceCodeInfo"] = @source_code_info.as_json( + options + ) if !options[:compact] || has_source_code_info? + result["publicDependency"] = @public_dependency if !options[ + :compact + ] || @public_dependency.any? + result["weakDependency"] = @weak_dependency if !options[:compact] || + @weak_dependency.any? + result["syntax"] = @syntax if !options[:compact] || has_syntax? + result["edition"] = @edition if !options[:compact] || has_edition? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class DescriptorProto def self.decode(buff) @@ -4203,13 +4286,33 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["start".to_sym] = @start - result["end".to_sym] = @end - result["options".to_sym] = @options.to_h + + result[:"start"] = @start if !options[:compact] || has_start? + result[:"end"] = @end if !options[:compact] || has_end? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result end + + def as_json(options = {}) + result = {} + + result["start"] = @start if !options[:compact] || has_start? + result["end"] = @end if !options[:compact] || has_end? + result["options"] = @options.as_json(options) if !options[ + :compact + ] || has_options? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class ReservedRange @@ -4838,12 +4941,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["start".to_sym] = @start - result["end".to_sym] = @end + + result[:"start"] = @start if !options[:compact] || has_start? + result[:"end"] = @end if !options[:compact] || has_end? + result end + + def as_json(options = {}) + result = {} + + result["start"] = @start if !options[:compact] || has_start? + result["end"] = @end if !options[:compact] || has_end? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -7053,20 +7172,88 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["field".to_sym] = @field - result["extension".to_sym] = @extension - result["nested_type".to_sym] = @nested_type - result["enum_type".to_sym] = @enum_type - result["extension_range".to_sym] = @extension_range - result["oneof_decl".to_sym] = @oneof_decl - result["options".to_sym] = @options.to_h - result["reserved_range".to_sym] = @reserved_range - result["reserved_name".to_sym] = @reserved_name + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"field"] = @field.map { |v| v.to_h(options) } if !options[ + :compact + ] || @field.map { |v| v.to_h(options) }.any? + result[:"nested_type"] = @nested_type.map do |v| + v.to_h(options) + end if !options[:compact] || + @nested_type.map { |v| v.to_h(options) }.any? + result[:"enum_type"] = @enum_type.map do |v| + v.to_h(options) + end if !options[:compact] || + @enum_type.map { |v| v.to_h(options) }.any? + result[:"extension_range"] = @extension_range.map do |v| + v.to_h(options) + end if !options[:compact] || + @extension_range.map { |v| v.to_h(options) }.any? + result[:"extension"] = @extension.map do |v| + v.to_h(options) + end if !options[:compact] || + @extension.map { |v| v.to_h(options) }.any? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result[:"oneof_decl"] = @oneof_decl.map do |v| + v.to_h(options) + end if !options[:compact] || + @oneof_decl.map { |v| v.to_h(options) }.any? + result[:"reserved_range"] = @reserved_range.map do |v| + v.to_h(options) + end if !options[:compact] || + @reserved_range.map { |v| v.to_h(options) }.any? + result[:"reserved_name"] = @reserved_name if !options[:compact] || + @reserved_name.any? + result end + + def as_json(options = {}) + result = {} + + result["name"] = @name if !options[:compact] || has_name? + result["field"] = @field.map { |v| v.as_json(options) } if !options[ + :compact + ] || @field.map { |v| v.as_json(options) }.any? + result["nestedType"] = @nested_type.map do |v| + v.as_json(options) + end if !options[:compact] || + @nested_type.map { |v| v.as_json(options) }.any? + result["enumType"] = @enum_type.map do |v| + v.as_json(options) + end if !options[:compact] || + @enum_type.map { |v| v.as_json(options) }.any? + result["extensionRange"] = @extension_range.map do |v| + v.as_json(options) + end if !options[:compact] || + @extension_range.map { |v| v.as_json(options) }.any? + result["extension"] = @extension.map do |v| + v.as_json(options) + end if !options[:compact] || + @extension.map { |v| v.as_json(options) }.any? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result["oneofDecl"] = @oneof_decl.map do |v| + v.as_json(options) + end if !options[:compact] || + @oneof_decl.map { |v| v.as_json(options) }.any? + result["reservedRange"] = @reserved_range.map do |v| + v.as_json(options) + end if !options[:compact] || + @reserved_range.map { |v| v.as_json(options) }.any? + result["reservedName"] = @reserved_name if !options[:compact] || + @reserved_name.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class ExtensionRangeOptions def self.decode(buff) @@ -8036,15 +8223,40 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["number".to_sym] = @number - result["full_name".to_sym] = @full_name - result["type".to_sym] = @type - result["reserved".to_sym] = @reserved - result["repeated".to_sym] = @repeated + + result[:"number"] = @number if !options[:compact] || has_number? + result[:"full_name"] = @full_name if !options[:compact] || + has_full_name? + result[:"type"] = @type if !options[:compact] || has_type? + result[:"reserved"] = @reserved if !options[:compact] || + has_reserved? + result[:"repeated"] = @repeated if !options[:compact] || + has_repeated? + result end + + def as_json(options = {}) + result = {} + + result["number"] = @number if !options[:compact] || has_number? + result["fullName"] = @full_name if !options[:compact] || + has_full_name? + result["type"] = @type if !options[:compact] || has_type? + result["reserved"] = @reserved if !options[:compact] || + has_reserved? + result["repeated"] = @repeated if !options[:compact] || + has_repeated? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end module VerificationState DECLARATION = 0 @@ -9102,14 +9314,49 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"declaration"] = @declaration.map do |v| + v.to_h(options) + end if !options[:compact] || + @declaration.map { |v| v.to_h(options) }.any? + result[:"verification"] = @verification if !options[:compact] || + has_verification? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) result = {} - result["uninterpreted_option".to_sym] = @uninterpreted_option - result["declaration".to_sym] = @declaration - result["features".to_sym] = @features.to_h - result["verification".to_sym] = @verification + + result["declaration"] = @declaration.map do |v| + v.as_json(options) + end if !options[:compact] || + @declaration.map { |v| v.as_json(options) }.any? + result["verification"] = @verification if !options[:compact] || + has_verification? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FieldDescriptorProto def self.decode(buff) @@ -11241,21 +11488,58 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["number".to_sym] = @number - result["label".to_sym] = @label - result["type".to_sym] = @type - result["type_name".to_sym] = @type_name - result["extendee".to_sym] = @extendee - result["default_value".to_sym] = @default_value - result["oneof_index".to_sym] = @oneof_index - result["json_name".to_sym] = @json_name - result["options".to_sym] = @options.to_h - result["proto3_optional".to_sym] = @proto3_optional + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"extendee"] = @extendee if !options[:compact] || has_extendee? + result[:"number"] = @number if !options[:compact] || has_number? + result[:"label"] = @label if !options[:compact] || has_label? + result[:"type"] = @type if !options[:compact] || has_type? + result[:"type_name"] = @type_name if !options[:compact] || + has_type_name? + result[:"default_value"] = @default_value if !options[:compact] || + has_default_value? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result[:"oneof_index"] = @oneof_index if !options[:compact] || + has_oneof_index? + result[:"json_name"] = @json_name if !options[:compact] || + has_json_name? + result[:"proto3_optional"] = @proto3_optional if !options[:compact] || + has_proto3_optional? + result end + + def as_json(options = {}) + result = {} + + result["name"] = @name if !options[:compact] || has_name? + result["extendee"] = @extendee if !options[:compact] || has_extendee? + result["number"] = @number if !options[:compact] || has_number? + result["label"] = @label if !options[:compact] || has_label? + result["type"] = @type if !options[:compact] || has_type? + result["typeName"] = @type_name if !options[:compact] || + has_type_name? + result["defaultValue"] = @default_value if !options[:compact] || + has_default_value? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result["oneofIndex"] = @oneof_index if !options[:compact] || + has_oneof_index? + result["jsonName"] = @json_name if !options[:compact] || + has_json_name? + result["proto3Optional"] = @proto3_optional if !options[:compact] || + has_proto3_optional? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class OneofDescriptorProto def self.decode(buff) @@ -11874,12 +12158,30 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + + result + end + + def as_json(options = {}) result = {} - result["name".to_sym] = @name - result["options".to_sym] = @options.to_h + + result["name"] = @name if !options[:compact] || has_name? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class EnumDescriptorProto def self.decode(buff) @@ -12515,12 +12817,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"start"] = @start if !options[:compact] || has_start? + result[:"end"] = @end if !options[:compact] || has_end? + + result + end + + def as_json(options = {}) result = {} - result["start".to_sym] = @start - result["end".to_sym] = @end + + result["start"] = @start if !options[:compact] || has_start? + result["end"] = @end if !options[:compact] || has_end? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -13705,15 +14023,48 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["value".to_sym] = @value - result["options".to_sym] = @options.to_h - result["reserved_range".to_sym] = @reserved_range - result["reserved_name".to_sym] = @reserved_name + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"value"] = @value.map { |v| v.to_h(options) } if !options[ + :compact + ] || @value.map { |v| v.to_h(options) }.any? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result[:"reserved_range"] = @reserved_range.map do |v| + v.to_h(options) + end if !options[:compact] || + @reserved_range.map { |v| v.to_h(options) }.any? + result[:"reserved_name"] = @reserved_name if !options[:compact] || + @reserved_name.any? + result end + + def as_json(options = {}) + result = {} + + result["name"] = @name if !options[:compact] || has_name? + result["value"] = @value.map { |v| v.as_json(options) } if !options[ + :compact + ] || @value.map { |v| v.as_json(options) }.any? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result["reservedRange"] = @reserved_range.map do |v| + v.as_json(options) + end if !options[:compact] || + @reserved_range.map { |v| v.as_json(options) }.any? + result["reservedName"] = @reserved_name if !options[:compact] || + @reserved_name.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class EnumValueDescriptorProto def self.decode(buff) @@ -14509,13 +14860,32 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["number".to_sym] = @number - result["options".to_sym] = @options.to_h + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"number"] = @number if !options[:compact] || has_number? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + + result + end + + def as_json(options = {}) + result = {} + + result["name"] = @name if !options[:compact] || has_name? + result["number"] = @number if !options[:compact] || has_number? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class ServiceDescriptorProto def self.decode(buff) @@ -15338,13 +15708,36 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"method"] = @method.map { |v| v.to_h(options) } if !options[ + :compact + ] || @method.map { |v| v.to_h(options) }.any? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + + result + end + + def as_json(options = {}) result = {} - result["name".to_sym] = @name - result["method".to_sym] = @method - result["options".to_sym] = @options.to_h + + result["name"] = @name if !options[:compact] || has_name? + result["method"] = @method.map { |v| v.as_json(options) } if !options[ + :compact + ] || @method.map { |v| v.as_json(options) }.any? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class MethodDescriptorProto def self.decode(buff) @@ -16476,16 +16869,48 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["input_type".to_sym] = @input_type - result["output_type".to_sym] = @output_type - result["options".to_sym] = @options.to_h - result["client_streaming".to_sym] = @client_streaming - result["server_streaming".to_sym] = @server_streaming + + result[:"name"] = @name if !options[:compact] || has_name? + result[:"input_type"] = @input_type if !options[:compact] || + has_input_type? + result[:"output_type"] = @output_type if !options[:compact] || + has_output_type? + result[:"options"] = @options.to_h(options) if !options[:compact] || + has_options? + result[:"client_streaming"] = @client_streaming if !options[ + :compact + ] || has_client_streaming? + result[:"server_streaming"] = @server_streaming if !options[ + :compact + ] || has_server_streaming? + result end + + def as_json(options = {}) + result = {} + + result["name"] = @name if !options[:compact] || has_name? + result["inputType"] = @input_type if !options[:compact] || + has_input_type? + result["outputType"] = @output_type if !options[:compact] || + has_output_type? + result["options"] = @options.as_json(options) if !options[:compact] || + has_options? + result["clientStreaming"] = @client_streaming if !options[:compact] || + has_client_streaming? + result["serverStreaming"] = @server_streaming if !options[:compact] || + has_server_streaming? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FileOptions def self.decode(buff) @@ -19717,33 +20142,138 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"java_package"] = @java_package if !options[:compact] || + has_java_package? + result[:"java_outer_classname"] = @java_outer_classname if !options[ + :compact + ] || has_java_outer_classname? + result[:"optimize_for"] = @optimize_for if !options[:compact] || + has_optimize_for? + result[:"java_multiple_files"] = @java_multiple_files if !options[ + :compact + ] || has_java_multiple_files? + result[:"go_package"] = @go_package if !options[:compact] || + has_go_package? + result[:"cc_generic_services"] = @cc_generic_services if !options[ + :compact + ] || has_cc_generic_services? + result[:"java_generic_services"] = @java_generic_services if !options[ + :compact + ] || has_java_generic_services? + result[:"py_generic_services"] = @py_generic_services if !options[ + :compact + ] || has_py_generic_services? + result[ + :"java_generate_equals_and_hash" + ] = @java_generate_equals_and_hash if !options[:compact] || + has_java_generate_equals_and_hash? + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[ + :"java_string_check_utf8" + ] = @java_string_check_utf8 if !options[:compact] || + has_java_string_check_utf8? + result[:"cc_enable_arenas"] = @cc_enable_arenas if !options[ + :compact + ] || has_cc_enable_arenas? + result[:"objc_class_prefix"] = @objc_class_prefix if !options[ + :compact + ] || has_objc_class_prefix? + result[:"csharp_namespace"] = @csharp_namespace if !options[ + :compact + ] || has_csharp_namespace? + result[:"swift_prefix"] = @swift_prefix if !options[:compact] || + has_swift_prefix? + result[:"php_class_prefix"] = @php_class_prefix if !options[ + :compact + ] || has_php_class_prefix? + result[:"php_namespace"] = @php_namespace if !options[:compact] || + has_php_namespace? + result[ + :"php_metadata_namespace" + ] = @php_metadata_namespace if !options[:compact] || + has_php_metadata_namespace? + result[:"ruby_package"] = @ruby_package if !options[:compact] || + has_ruby_package? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) result = {} - result["java_package".to_sym] = @java_package - result["java_outer_classname".to_sym] = @java_outer_classname - result["java_multiple_files".to_sym] = @java_multiple_files + + result["javaPackage"] = @java_package if !options[:compact] || + has_java_package? + result["javaOuterClassname"] = @java_outer_classname if !options[ + :compact + ] || has_java_outer_classname? + result["optimizeFor"] = @optimize_for if !options[:compact] || + has_optimize_for? + result["javaMultipleFiles"] = @java_multiple_files if !options[ + :compact + ] || has_java_multiple_files? + result["goPackage"] = @go_package if !options[:compact] || + has_go_package? + result["ccGenericServices"] = @cc_generic_services if !options[ + :compact + ] || has_cc_generic_services? + result["javaGenericServices"] = @java_generic_services if !options[ + :compact + ] || has_java_generic_services? + result["pyGenericServices"] = @py_generic_services if !options[ + :compact + ] || has_py_generic_services? result[ - "java_generate_equals_and_hash".to_sym - ] = @java_generate_equals_and_hash - result["java_string_check_utf8".to_sym] = @java_string_check_utf8 - result["optimize_for".to_sym] = @optimize_for - result["go_package".to_sym] = @go_package - result["cc_generic_services".to_sym] = @cc_generic_services - result["java_generic_services".to_sym] = @java_generic_services - result["py_generic_services".to_sym] = @py_generic_services - result["deprecated".to_sym] = @deprecated - result["cc_enable_arenas".to_sym] = @cc_enable_arenas - result["objc_class_prefix".to_sym] = @objc_class_prefix - result["csharp_namespace".to_sym] = @csharp_namespace - result["swift_prefix".to_sym] = @swift_prefix - result["php_class_prefix".to_sym] = @php_class_prefix - result["php_namespace".to_sym] = @php_namespace - result["php_metadata_namespace".to_sym] = @php_metadata_namespace - result["ruby_package".to_sym] = @ruby_package - result["features".to_sym] = @features.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + "javaGenerateEqualsAndHash" + ] = @java_generate_equals_and_hash if !options[:compact] || + has_java_generate_equals_and_hash? + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["javaStringCheckUtf8"] = @java_string_check_utf8 if !options[ + :compact + ] || has_java_string_check_utf8? + result["ccEnableArenas"] = @cc_enable_arenas if !options[:compact] || + has_cc_enable_arenas? + result["objcClassPrefix"] = @objc_class_prefix if !options[ + :compact + ] || has_objc_class_prefix? + result["csharpNamespace"] = @csharp_namespace if !options[:compact] || + has_csharp_namespace? + result["swiftPrefix"] = @swift_prefix if !options[:compact] || + has_swift_prefix? + result["phpClassPrefix"] = @php_class_prefix if !options[:compact] || + has_php_class_prefix? + result["phpNamespace"] = @php_namespace if !options[:compact] || + has_php_namespace? + result["phpMetadataNamespace"] = @php_metadata_namespace if !options[ + :compact + ] || has_php_metadata_namespace? + result["rubyPackage"] = @ruby_package if !options[:compact] || + has_ruby_package? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class MessageOptions def self.decode(buff) @@ -20906,21 +21436,68 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["message_set_wire_format".to_sym] = @message_set_wire_format + + result[ + :"message_set_wire_format" + ] = @message_set_wire_format if !options[:compact] || + has_message_set_wire_format? result[ - "no_standard_descriptor_accessor".to_sym - ] = @no_standard_descriptor_accessor - result["deprecated".to_sym] = @deprecated - result["map_entry".to_sym] = @map_entry + :"no_standard_descriptor_accessor" + ] = @no_standard_descriptor_accessor if !options[:compact] || + has_no_standard_descriptor_accessor? + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[:"map_entry"] = @map_entry if !options[:compact] || + has_map_entry? result[ - "deprecated_legacy_json_field_conflicts".to_sym - ] = @deprecated_legacy_json_field_conflicts - result["features".to_sym] = @features.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + :"deprecated_legacy_json_field_conflicts" + ] = @deprecated_legacy_json_field_conflicts if !options[:compact] || + has_deprecated_legacy_json_field_conflicts? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["messageSetWireFormat"] = @message_set_wire_format if !options[ + :compact + ] || has_message_set_wire_format? + result[ + "noStandardDescriptorAccessor" + ] = @no_standard_descriptor_accessor if !options[:compact] || + has_no_standard_descriptor_accessor? + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["mapEntry"] = @map_entry if !options[:compact] || + has_map_entry? + result[ + "deprecatedLegacyJsonFieldConflicts" + ] = @deprecated_legacy_json_field_conflicts if !options[:compact] || + has_deprecated_legacy_json_field_conflicts? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FieldOptions def self.decode(buff) @@ -21525,12 +22102,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"value"] = @value if !options[:compact] || has_value? + result[:"edition"] = @edition if !options[:compact] || has_edition? + + result + end + + def as_json(options = {}) result = {} - result["edition".to_sym] = @edition - result["value".to_sym] = @value + + result["value"] = @value if !options[:compact] || has_value? + result["edition"] = @edition if !options[:compact] || has_edition? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FeatureSupport @@ -22474,14 +23067,47 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"edition_introduced"] = @edition_introduced if !options[ + :compact + ] || has_edition_introduced? + result[:"edition_deprecated"] = @edition_deprecated if !options[ + :compact + ] || has_edition_deprecated? + result[:"deprecation_warning"] = @deprecation_warning if !options[ + :compact + ] || has_deprecation_warning? + result[:"edition_removed"] = @edition_removed if !options[ + :compact + ] || has_edition_removed? + + result + end + + def as_json(options = {}) result = {} - result["edition_introduced".to_sym] = @edition_introduced - result["edition_deprecated".to_sym] = @edition_deprecated - result["deprecation_warning".to_sym] = @deprecation_warning - result["edition_removed".to_sym] = @edition_removed + + result["editionIntroduced"] = @edition_introduced if !options[ + :compact + ] || has_edition_introduced? + result["editionDeprecated"] = @edition_deprecated if !options[ + :compact + ] || has_edition_deprecated? + result["deprecationWarning"] = @deprecation_warning if !options[ + :compact + ] || has_deprecation_warning? + result["editionRemoved"] = @edition_removed if !options[:compact] || + has_edition_removed? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end module CType STRING = 0 @@ -24925,24 +25551,79 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["ctype".to_sym] = @ctype - result["packed".to_sym] = @packed - result["jstype".to_sym] = @jstype - result["lazy".to_sym] = @lazy - result["unverified_lazy".to_sym] = @unverified_lazy - result["deprecated".to_sym] = @deprecated - result["weak".to_sym] = @weak - result["debug_redact".to_sym] = @debug_redact - result["retention".to_sym] = @retention - result["targets".to_sym] = @targets - result["edition_defaults".to_sym] = @edition_defaults - result["features".to_sym] = @features.to_h - result["feature_support".to_sym] = @feature_support.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + + result[:"ctype"] = @ctype if !options[:compact] || has_ctype? + result[:"packed"] = @packed if !options[:compact] || has_packed? + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[:"lazy"] = @lazy if !options[:compact] || has_lazy? + result[:"jstype"] = @jstype if !options[:compact] || has_jstype? + result[:"weak"] = @weak if !options[:compact] || has_weak? + result[:"unverified_lazy"] = @unverified_lazy if !options[:compact] || + has_unverified_lazy? + result[:"debug_redact"] = @debug_redact if !options[:compact] || + has_debug_redact? + result[:"retention"] = @retention if !options[:compact] || + has_retention? + result[:"targets"] = @targets if !options[:compact] || @targets.any? + result[:"edition_defaults"] = @edition_defaults.map do |v| + v.to_h(options) + end if !options[:compact] || + @edition_defaults.map { |v| v.to_h(options) }.any? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"feature_support"] = @feature_support.to_h( + options + ) if !options[:compact] || has_feature_support? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["ctype"] = @ctype if !options[:compact] || has_ctype? + result["packed"] = @packed if !options[:compact] || has_packed? + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["lazy"] = @lazy if !options[:compact] || has_lazy? + result["jstype"] = @jstype if !options[:compact] || has_jstype? + result["weak"] = @weak if !options[:compact] || has_weak? + result["unverifiedLazy"] = @unverified_lazy if !options[:compact] || + has_unverified_lazy? + result["debugRedact"] = @debug_redact if !options[:compact] || + has_debug_redact? + result["retention"] = @retention if !options[:compact] || + has_retention? + result["targets"] = @targets if !options[:compact] || @targets.any? + result["editionDefaults"] = @edition_defaults.map do |v| + v.as_json(options) + end if !options[:compact] || + @edition_defaults.map { |v| v.as_json(options) }.any? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["featureSupport"] = @feature_support.as_json( + options + ) if !options[:compact] || has_feature_support? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class OneofOptions def self.decode(buff) @@ -25610,12 +26291,37 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["features".to_sym] = @features.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class EnumOptions def self.decode(buff) @@ -26582,17 +27288,53 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["allow_alias".to_sym] = @allow_alias - result["deprecated".to_sym] = @deprecated + + result[:"allow_alias"] = @allow_alias if !options[:compact] || + has_allow_alias? + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? result[ - "deprecated_legacy_json_field_conflicts".to_sym - ] = @deprecated_legacy_json_field_conflicts - result["features".to_sym] = @features.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + :"deprecated_legacy_json_field_conflicts" + ] = @deprecated_legacy_json_field_conflicts if !options[:compact] || + has_deprecated_legacy_json_field_conflicts? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["allowAlias"] = @allow_alias if !options[:compact] || + has_allow_alias? + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[ + "deprecatedLegacyJsonFieldConflicts" + ] = @deprecated_legacy_json_field_conflicts if !options[:compact] || + has_deprecated_legacy_json_field_conflicts? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class EnumValueOptions def self.decode(buff) @@ -27656,15 +28398,51 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["deprecated".to_sym] = @deprecated - result["features".to_sym] = @features.to_h - result["debug_redact".to_sym] = @debug_redact - result["feature_support".to_sym] = @feature_support.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"debug_redact"] = @debug_redact if !options[:compact] || + has_debug_redact? + result[:"feature_support"] = @feature_support.to_h( + options + ) if !options[:compact] || has_feature_support? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["debugRedact"] = @debug_redact if !options[:compact] || + has_debug_redact? + result["featureSupport"] = @feature_support.as_json( + options + ) if !options[:compact] || has_feature_support? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class ServiceOptions def self.decode(buff) @@ -28431,13 +29209,41 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) result = {} - result["features".to_sym] = @features.to_h - result["deprecated".to_sym] = @deprecated - result["uninterpreted_option".to_sym] = @uninterpreted_option + + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class MethodOptions def self.decode(buff) @@ -29401,14 +30207,47 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["deprecated".to_sym] = @deprecated - result["idempotency_level".to_sym] = @idempotency_level - result["features".to_sym] = @features.to_h - result["uninterpreted_option".to_sym] = @uninterpreted_option + + result[:"deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result[:"idempotency_level"] = @idempotency_level if !options[ + :compact + ] || has_idempotency_level? + result[:"features"] = @features.to_h(options) if !options[:compact] || + has_features? + result[:"uninterpreted_option"] = @uninterpreted_option.map do |v| + v.to_h(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) + result = {} + + result["deprecated"] = @deprecated if !options[:compact] || + has_deprecated? + result["idempotencyLevel"] = @idempotency_level if !options[ + :compact + ] || has_idempotency_level? + result["features"] = @features.as_json(options) if !options[ + :compact + ] || has_features? + result["uninterpretedOption"] = @uninterpreted_option.map do |v| + v.as_json(options) + end if !options[:compact] || + @uninterpreted_option.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class UninterpretedOption def self.decode(buff) @@ -29911,12 +30750,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"name_part"] = @name_part + result[:"is_extension"] = @is_extension + + result + end + + def as_json(options = {}) result = {} - result["name_part".to_sym] = @name_part - result["is_extension".to_sym] = @is_extension + + result["namePart"] = @name_part + result["isExtension"] = @is_extension + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -31285,17 +32140,59 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["name".to_sym] = @name - result["identifier_value".to_sym] = @identifier_value - result["positive_int_value".to_sym] = @positive_int_value - result["negative_int_value".to_sym] = @negative_int_value - result["double_value".to_sym] = @double_value - result["string_value".to_sym] = @string_value - result["aggregate_value".to_sym] = @aggregate_value + + result[:"name"] = @name.map { |v| v.to_h(options) } if !options[ + :compact + ] || @name.map { |v| v.to_h(options) }.any? + result[:"identifier_value"] = @identifier_value if !options[ + :compact + ] || has_identifier_value? + result[:"positive_int_value"] = @positive_int_value if !options[ + :compact + ] || has_positive_int_value? + result[:"negative_int_value"] = @negative_int_value if !options[ + :compact + ] || has_negative_int_value? + result[:"double_value"] = @double_value if !options[:compact] || + has_double_value? + result[:"string_value"] = @string_value if !options[:compact] || + has_string_value? + result[:"aggregate_value"] = @aggregate_value if !options[:compact] || + has_aggregate_value? + result end + + def as_json(options = {}) + result = {} + + result["name"] = @name.map { |v| v.as_json(options) } if !options[ + :compact + ] || @name.map { |v| v.as_json(options) }.any? + result["identifierValue"] = @identifier_value if !options[:compact] || + has_identifier_value? + result["positiveIntValue"] = @positive_int_value if !options[ + :compact + ] || has_positive_int_value? + result["negativeIntValue"] = @negative_int_value if !options[ + :compact + ] || has_negative_int_value? + result["doubleValue"] = @double_value if !options[:compact] || + has_double_value? + result["stringValue"] = @string_value if !options[:compact] || + has_string_value? + result["aggregateValue"] = @aggregate_value if !options[:compact] || + has_aggregate_value? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FeatureSet def self.decode(buff) @@ -32696,16 +33593,53 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["field_presence".to_sym] = @field_presence - result["enum_type".to_sym] = @enum_type - result["repeated_field_encoding".to_sym] = @repeated_field_encoding - result["utf8_validation".to_sym] = @utf8_validation - result["message_encoding".to_sym] = @message_encoding - result["json_format".to_sym] = @json_format + + result[:"field_presence"] = @field_presence if !options[:compact] || + has_field_presence? + result[:"enum_type"] = @enum_type if !options[:compact] || + has_enum_type? + result[ + :"repeated_field_encoding" + ] = @repeated_field_encoding if !options[:compact] || + has_repeated_field_encoding? + result[:"utf8_validation"] = @utf8_validation if !options[:compact] || + has_utf8_validation? + result[:"message_encoding"] = @message_encoding if !options[ + :compact + ] || has_message_encoding? + result[:"json_format"] = @json_format if !options[:compact] || + has_json_format? + + result + end + + def as_json(options = {}) + result = {} + + result["fieldPresence"] = @field_presence if !options[:compact] || + has_field_presence? + result["enumType"] = @enum_type if !options[:compact] || + has_enum_type? + result[ + "repeatedFieldEncoding" + ] = @repeated_field_encoding if !options[:compact] || + has_repeated_field_encoding? + result["utf8Validation"] = @utf8_validation if !options[:compact] || + has_utf8_validation? + result["messageEncoding"] = @message_encoding if !options[:compact] || + has_message_encoding? + result["jsonFormat"] = @json_format if !options[:compact] || + has_json_format? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class FeatureSetDefaults def self.decode(buff) @@ -33550,13 +34484,38 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["edition".to_sym] = @edition - result["overridable_features".to_sym] = @overridable_features.to_h - result["fixed_features".to_sym] = @fixed_features.to_h + + result[:"edition"] = @edition if !options[:compact] || has_edition? + result[:"overridable_features"] = @overridable_features.to_h( + options + ) if !options[:compact] || has_overridable_features? + result[:"fixed_features"] = @fixed_features.to_h( + options + ) if !options[:compact] || has_fixed_features? + result end + + def as_json(options = {}) + result = {} + + result["edition"] = @edition if !options[:compact] || has_edition? + result["overridableFeatures"] = @overridable_features.as_json( + options + ) if !options[:compact] || has_overridable_features? + result["fixedFeatures"] = @fixed_features.as_json( + options + ) if !options[:compact] || has_fixed_features? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -34350,13 +35309,40 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"defaults"] = @defaults.map do |v| + v.to_h(options) + end if !options[:compact] || + @defaults.map { |v| v.to_h(options) }.any? + result[:"minimum_edition"] = @minimum_edition if !options[:compact] || + has_minimum_edition? + result[:"maximum_edition"] = @maximum_edition if !options[:compact] || + has_maximum_edition? + + result + end + + def as_json(options = {}) result = {} - result["defaults".to_sym] = @defaults - result["minimum_edition".to_sym] = @minimum_edition - result["maximum_edition".to_sym] = @maximum_edition + + result["defaults"] = @defaults.map do |v| + v.as_json(options) + end if !options[:compact] || + @defaults.map { |v| v.as_json(options) }.any? + result["minimumEdition"] = @minimum_edition if !options[:compact] || + has_minimum_edition? + result["maximumEdition"] = @maximum_edition if !options[:compact] || + has_maximum_edition? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class SourceCodeInfo def self.decode(buff) @@ -35671,17 +36657,48 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["path".to_sym] = @path - result["span".to_sym] = @span - result["leading_comments".to_sym] = @leading_comments - result["trailing_comments".to_sym] = @trailing_comments + + result[:"path"] = @path if !options[:compact] || @path.any? + result[:"span"] = @span if !options[:compact] || @span.any? + result[:"leading_comments"] = @leading_comments if !options[ + :compact + ] || has_leading_comments? + result[:"trailing_comments"] = @trailing_comments if !options[ + :compact + ] || has_trailing_comments? result[ - "leading_detached_comments".to_sym - ] = @leading_detached_comments + :"leading_detached_comments" + ] = @leading_detached_comments if !options[:compact] || + @leading_detached_comments.any? + result end + + def as_json(options = {}) + result = {} + + result["path"] = @path if !options[:compact] || @path.any? + result["span"] = @span if !options[:compact] || @span.any? + result["leadingComments"] = @leading_comments if !options[ + :compact + ] || has_leading_comments? + result["trailingComments"] = @trailing_comments if !options[ + :compact + ] || has_trailing_comments? + result[ + "leadingDetachedComments" + ] = @leading_detached_comments if !options[:compact] || + @leading_detached_comments.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -36135,11 +37152,32 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"location"] = @location.map do |v| + v.to_h(options) + end if !options[:compact] || + @location.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) result = {} - result["location".to_sym] = @location + + result["location"] = @location.map do |v| + v.as_json(options) + end if !options[:compact] || + @location.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class GeneratedCodeInfo def self.decode(buff) @@ -37407,15 +38445,38 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["path".to_sym] = @path - result["source_file".to_sym] = @source_file - result["begin".to_sym] = @begin - result["end".to_sym] = @end - result["semantic".to_sym] = @semantic + + result[:"path"] = @path if !options[:compact] || @path.any? + result[:"source_file"] = @source_file if !options[:compact] || + has_source_file? + result[:"begin"] = @begin if !options[:compact] || has_begin? + result[:"end"] = @end if !options[:compact] || has_end? + result[:"semantic"] = @semantic if !options[:compact] || + has_semantic? + result end + + def as_json(options = {}) + result = {} + + result["path"] = @path if !options[:compact] || @path.any? + result["sourceFile"] = @source_file if !options[:compact] || + has_source_file? + result["begin"] = @begin if !options[:compact] || has_begin? + result["end"] = @end if !options[:compact] || has_end? + result["semantic"] = @semantic if !options[:compact] || + has_semantic? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end # required field readers @@ -37869,11 +38930,32 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["annotation".to_sym] = @annotation + + result[:"annotation"] = @annotation.map do |v| + v.to_h(options) + end if !options[:compact] || + @annotation.map { |v| v.to_h(options) }.any? + + result + end + + def as_json(options = {}) + result = {} + + result["annotation"] = @annotation.map do |v| + v.as_json(options) + end if !options[:compact] || + @annotation.map { |v| v.as_json(options) }.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/doublevalue.rb b/lib/protoboeuf/google/protobuf/doublevalue.rb index 7bd516a..57cb485 100644 --- a/lib/protoboeuf/google/protobuf/doublevalue.rb +++ b/lib/protoboeuf/google/protobuf/doublevalue.rb @@ -341,11 +341,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/duration.rb b/lib/protoboeuf/google/protobuf/duration.rb index c8848e9..1e472af 100644 --- a/lib/protoboeuf/google/protobuf/duration.rb +++ b/lib/protoboeuf/google/protobuf/duration.rb @@ -595,12 +595,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["seconds".to_sym] = @seconds - result["nanos".to_sym] = @nanos + + result[:"seconds"] = @seconds + result[:"nanos"] = @nanos + + result + end + + def as_json(options = {}) + result = {} + + result["seconds"] = @seconds + result["nanos"] = @nanos + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/field_mask.rb b/lib/protoboeuf/google/protobuf/field_mask.rb index a63d3af..36bfe6c 100644 --- a/lib/protoboeuf/google/protobuf/field_mask.rb +++ b/lib/protoboeuf/google/protobuf/field_mask.rb @@ -421,11 +421,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["paths".to_sym] = @paths + + result[:"paths"] = @paths if !options[:compact] || @paths.any? + + result + end + + def as_json(options = {}) + result = {} + + result["paths"] = @paths if !options[:compact] || @paths.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/floatvalue.rb b/lib/protoboeuf/google/protobuf/floatvalue.rb index 395f0f3..6421508 100644 --- a/lib/protoboeuf/google/protobuf/floatvalue.rb +++ b/lib/protoboeuf/google/protobuf/floatvalue.rb @@ -341,11 +341,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/int32value.rb b/lib/protoboeuf/google/protobuf/int32value.rb index 99e1f76..50ba8aa 100644 --- a/lib/protoboeuf/google/protobuf/int32value.rb +++ b/lib/protoboeuf/google/protobuf/int32value.rb @@ -427,11 +427,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/int64value.rb b/lib/protoboeuf/google/protobuf/int64value.rb index b0c8f8c..a345a1d 100644 --- a/lib/protoboeuf/google/protobuf/int64value.rb +++ b/lib/protoboeuf/google/protobuf/int64value.rb @@ -429,11 +429,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/stringvalue.rb b/lib/protoboeuf/google/protobuf/stringvalue.rb index 4ac9462..24dda8d 100644 --- a/lib/protoboeuf/google/protobuf/stringvalue.rb +++ b/lib/protoboeuf/google/protobuf/stringvalue.rb @@ -406,11 +406,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/struct.rb b/lib/protoboeuf/google/protobuf/struct.rb index 0228456..810cfac 100644 --- a/lib/protoboeuf/google/protobuf/struct.rb +++ b/lib/protoboeuf/google/protobuf/struct.rb @@ -626,11 +626,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["fields".to_sym] = @fields + + result[:"fields"] = @fields.to_h if !options[:compact] || + @fields.to_h.any? + + result + end + + def as_json(options = {}) + result = {} + + result["fields"] = @fields.to_h if !options[:compact] || + @fields.to_h.any? + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class Value def self.decode(buff) @@ -1782,11 +1799,46 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) + result = {} + + result[:"null_value"] = @null_value if send(:"kind") == :"null_value" + result[:"number_value"] = @number_value if send(:"kind") == + :"number_value" + result[:"string_value"] = @string_value if send(:"kind") == + :"string_value" + result[:"bool_value"] = @bool_value if send(:"kind") == :"bool_value" + result[:"struct_value"] = @struct_value.to_h(options) if send( + :"kind" + ) == :"struct_value" + result[:"list_value"] = @list_value.to_h(options) if send(:"kind") == + :"list_value" + + result + end + + def as_json(options = {}) result = {} - send("kind").tap { |f| result[f.to_sym] = send(f) if f } + + result["nullValue"] = @null_value if send(:"kind") == :"null_value" + result["numberValue"] = @number_value if send(:"kind") == + :"number_value" + result["stringValue"] = @string_value if send(:"kind") == + :"string_value" + result["boolValue"] = @bool_value if send(:"kind") == :"bool_value" + result["structValue"] = @struct_value.as_json(options) if send( + :"kind" + ) == :"struct_value" + result["listValue"] = @list_value.as_json(options) if send(:"kind") == + :"list_value" + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end class ListValue def self.decode(buff) @@ -2248,11 +2300,30 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["values".to_sym] = @values + + result[:"values"] = @values.map { |v| v.to_h(options) } if !options[ + :compact + ] || @values.map { |v| v.to_h(options) }.any? + result end + + def as_json(options = {}) + result = {} + + result["values"] = @values.map { |v| v.as_json(options) } if !options[ + :compact + ] || @values.map { |v| v.as_json(options) }.any? + + result + end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/timestamp.rb b/lib/protoboeuf/google/protobuf/timestamp.rb index ff5cf7c..4d1ba34 100644 --- a/lib/protoboeuf/google/protobuf/timestamp.rb +++ b/lib/protoboeuf/google/protobuf/timestamp.rb @@ -595,12 +595,28 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["seconds".to_sym] = @seconds - result["nanos".to_sym] = @nanos + + result[:"seconds"] = @seconds + result[:"nanos"] = @nanos + + result + end + + def as_json(options = {}) + result = {} + + result["seconds"] = @seconds + result["nanos"] = @nanos + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/uint32value.rb b/lib/protoboeuf/google/protobuf/uint32value.rb index bd54058..aa3b588 100644 --- a/lib/protoboeuf/google/protobuf/uint32value.rb +++ b/lib/protoboeuf/google/protobuf/uint32value.rb @@ -410,11 +410,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/lib/protoboeuf/google/protobuf/uint64value.rb b/lib/protoboeuf/google/protobuf/uint64value.rb index e1764d8..cc91447 100644 --- a/lib/protoboeuf/google/protobuf/uint64value.rb +++ b/lib/protoboeuf/google/protobuf/uint64value.rb @@ -410,11 +410,26 @@ def _encode(buff) buff end - def to_h + def to_h(options = {}) result = {} - result["value".to_sym] = @value + + result[:"value"] = @value + + result + end + + def as_json(options = {}) + result = {} + + result["value"] = @value + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end end end diff --git a/test/fixtures/person.proto b/test/fixtures/person.proto new file mode 100644 index 0000000..1ac2886 --- /dev/null +++ b/test/fixtures/person.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +message Employer { + optional string name = 1; +} + +message Person { + optional string first_name = 1; + optional string last_name = 2; + optional int32 year_of_birth = 3; + optional Employer current_employer = 4; + repeated Employer previous_employers = 5; + map employers_by_name = 6; + map tags = 7; +} diff --git a/test/fixtures/typed_test.correct.rb b/test/fixtures/typed_test.correct.rb index 9f73016..7bb96a9 100644 --- a/test/fixtures/typed_test.correct.rb +++ b/test/fixtures/typed_test.correct.rb @@ -1633,14 +1633,47 @@ def _encode(buff) end sig { returns(T::Hash[Symbol, T.untyped]) } - def to_h + def to_h(options = {}) result = {} - send("oneof_field").tap { |f| result[f.to_sym] = send(f) if f } - result["int_field".to_sym] = @int_field - result["string_field".to_sym] = @string_field - result["repeated_ints".to_sym] = @repeated_ints - result["map_field".to_sym] = @map_field - result["bytes_field".to_sym] = @bytes_field + + result[:"int_field"] = @int_field + result[:"string_field"] = @string_field if !options[:compact] || + has_string_field? + result[:"enum_1"] = @enum_1 if send(:"oneof_field") == :"enum_1" + result[:"enum_2"] = @enum_2 if send(:"oneof_field") == :"enum_2" + result[:"repeated_ints"] = @repeated_ints if !options[:compact] || + @repeated_ints.any? + result[:"map_field"] = @map_field.to_h if !options[:compact] || + @map_field.to_h.any? + result[:"bytes_field"] = @bytes_field + + result + end + + sig do + params(options: T::Hash[T.untyped, T.untyped]).returns( + T::Hash[Symbol, T.untyped] + ) + end + def as_json(options = {}) + result = {} + + result["intField"] = @int_field + result["stringField"] = @string_field if !options[:compact] || + has_string_field? + result["enum1"] = @enum_1 if send(:"oneof_field") == :"enum_1" + result["enum2"] = @enum_2 if send(:"oneof_field") == :"enum_2" + result["repeatedInts"] = @repeated_ints if !options[:compact] || + @repeated_ints.any? + result["mapField"] = @map_field.to_h if !options[:compact] || + @map_field.to_h.any? + result["bytesField"] = @bytes_field + result end + + def to_json(options = {}) + require "json" + JSON.dump(as_json(options)) + end end diff --git a/test/hash_serialization_test.rb b/test/hash_serialization_test.rb new file mode 100644 index 0000000..cddf905 --- /dev/null +++ b/test/hash_serialization_test.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require "helper" + +class HashSerializationTest < ProtoBoeuf::Test + unit = parse_proto_string(<<~PROTO) + syntax = "proto3"; + + message Employer { + string name = 1; + } + + message Person { + string first_name = 1; + optional string nick_name = 2; + optional int32 birth_year = 3; + optional Employer current_employer = 4; + repeated Employer previous_employers = 5; + map favorite_employers_by_name = 6; + map metadata = 7; + } + + message EmployerWithCustomJsonNames { + optional string name = 1 [json_name = "NAME"]; + } + + message PersonWithCustomJsonNames { + string first_name = 1 [json_name = "FIRST_NAME"]; + optional string nick_name = 2 [json_name = "NICK_NAME"]; + optional int32 birth_year = 3 [json_name = "BIRTH_YEAR"]; + optional Employer current_employer = 4 [json_name = "CURRENT_EMPLOYER"]; + repeated Employer previous_employers = 5 [json_name = "PREVIOUS_EMPLOYERS"]; + map employers_by_name = 6 [json_name = "EMPLOYERS_BY_NAME"]; + map tags = 7 [json_name = "TAGS"]; + } + PROTO + + puts ProtoBoeuf::CodeGen.new(unit).to_ruby + + class_eval ProtoBoeuf::CodeGen.new(unit).to_ruby + + def test_to_h + jane = Person.new( + first_name: "Jane", + nick_name: "J-dog", + birth_year: 1984, + current_employer: Employer.new(name: "Business Inc."), + previous_employers: [Employer.new(name: "Funny Business LLC")], + favorite_employers_by_name: { + "Business Inc." => Employer.new(name: "Business Inc."), + }, + metadata: { "favorite_color" => "blue" }, + ) + + assert_equal( + { + first_name: "Jane", + nick_name: "J-dog", + birth_year: 1984, + current_employer: { name: "Business Inc." }, + previous_employers: [{ name: "Funny Business LLC" }], + favorite_employers_by_name: { "Business Inc." => { name: "Business Inc." } }, + metadata: { "favorite_color" => "blue" }, + }, + jane.to_h, + ) + + nobody = Person.new + + assert_equal( + { + first_name: "", + nick_name: "", + birth_year: 0, + current_employer: {}, + previous_employers: [], + favorite_employers_by_name: {}, + metadata: {}, + }, + nobody.to_h, + ) + end +end diff --git a/test/message_test.rb b/test/message_test.rb index e56cdba..499c086 100644 --- a/test/message_test.rb +++ b/test/message_test.rb @@ -7,6 +7,8 @@ class MessageTest < ProtoBoeuf::Test unit = parse_proto_file(FIXTURE_FILE) gen = ProtoBoeuf::CodeGen.new(unit) + File.open("fahk.rb", "w") { |f| f.puts(gen.to_ruby) } + class_eval gen.to_ruby def test_sint64