require'set'require'protobuf/generators/base'require'protobuf/generators/group_generator'moduleProtobufmoduleGeneratorsclassFileGenerator<Baseattr_reader:output_filedefinitialize(*args)super@output_file=::Google::Protobuf::Compiler::CodeGeneratorResponse::File.new(:name=>file_name)@extension_fields=Hash.new{|h,k|h[k]=[]}@known_messages={}@known_enums={}@dangling_messages={}enddeffile_nameconvert_filename(descriptor.name,false)enddefcompilerun_once(:compile)domap_extensions(descriptor,[descriptor.package])print_file_commentprint_generic_requiresprint_import_requiresprint_packagedoinject_optionablegroup=GroupGenerator.new(current_indent)group.add_options(descriptor.options)ifdescriptor.optionsgroup.add_enums(descriptor.enum_type,:namespace=>[descriptor.package])group.add_message_declarations(descriptor.message_type)group.add_messages(descriptor.message_type,:extension_fields=>@extension_fields,:namespace=>[descriptor.package])group.add_extended_messages(unknown_extensions)group.add_services(descriptor.service)group.add_header(:enum,'Enum Classes')group.add_header(:message_declaration,'Message Classes')group.add_header(:options,'File Options')group.add_header(:message,'Message Fields')group.add_header(:extended_message,'Extended Message Fields')group.add_header(:service,'Service Classes')printgroup.to_sendendenddefunknown_extensions@unknown_extensions||=@extension_fields.mapdo|message_name,fields|message_klass=modulize(message_name).safe_constantizeifmessage_klassunknown_fields=fields.rejectdo|field|@known_messages[message_name]&&message_klass.get_field(field.name,true)end[message_name,unknown_fields]else[message_name,fields]endendenddefgenerate_output_filecompileoutput_file.content=to_soutput_fileend# Recursively map out all extensions known in this file.# The key is the type_name of the message being extended, and# the value is an array of field descriptors.#defmap_extensions(descriptor,namespaces)iffully_qualified_token?(descriptor.name)fully_qualified_namespace=descriptor.nameelsif!(namespace=namespaces.reject(&:empty?).join(".")).empty?fully_qualified_namespace=".#{namespace}"end# Record all the message descriptor name's we encounter (should be the whole tree).ifdescriptor.is_a?(::Google::Protobuf::DescriptorProto)@known_messages[fully_qualified_namespace||descriptor.name]=descriptorelsifdescriptor.is_a?(::Google::Protobuf::EnumDescriptorProto)@known_enums[fully_qualified_namespace||descriptor.name]=descriptorreturnenddescriptor.extension.eachdo|field_descriptor|unlessfully_qualified_token?(field_descriptor.name)&&fully_qualified_namespacefield_descriptor.name="#{fully_qualified_namespace}.#{field_descriptor.name}"end@extension_fields[field_descriptor.extendee]<<field_descriptorend[:message_type,:nested_type,:enum_type].eachdo|type|nextunlessdescriptor.respond_to_has_and_present?(type)descriptor.public_send(type).eachdo|type_descriptor|map_extensions(type_descriptor,(namespaces+[type_descriptor.name]))endendenddefprint_file_commentputs"# encoding: utf-8"putsputs"##"puts"# This file is auto-generated. DO NOT EDIT!"puts"#"enddefprint_generic_requiresprint_require("protobuf")print_require("protobuf/rpc/service")ifdescriptor.service.count>0putsenddefprint_import_requiresreturnifdescriptor.dependency.empty?header"Imports"descriptor.dependency.eachdo|dependency|print_require(convert_filename(dependency),ENV.key?('PB_REQUIRE_RELATIVE'))endputsenddefprint_package(&block)namespaces=descriptor.package.split('.')ifnamespaces.empty?&&ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')namespaces=[File.basename(descriptor.name).sub('.proto','')]endnamespaces.reverse.reduce(block)do|previous,namespace|->{print_module(namespace,&previous)}end.callenddefeval_unknown_extensions!@@evaled_dependencies||=Set.new# rubocop:disable Style/ClassVars@@all_messages||={}# rubocop:disable Style/ClassVars@@all_enums||={}# rubocop:disable Style/ClassVarsmap_extensions(descriptor,[descriptor.package])@known_messages.eachdo|name,descriptor|@@all_messages[name]=descriptorend@known_enums.eachdo|name,descriptor|@@all_enums[name]=descriptorend# create package namespaceprint_package{}eval_codeunknown_extensions.eachdo|extendee,fields|eval_dependencies(extendee)fields.eachdo|field|eval_dependencies(field.type_name)endendgroup=GroupGenerator.new(0)group.add_extended_messages(unknown_extensions,false)printgroup.to_seval_coderescue=>ewarn"Error loading unknown extensions #{descriptor.name.inspect} error=#{e}"raiseeendprivatedefconvert_filename(filename,for_require=true)filename.sub(/\.proto/,(for_require?'.pb':'.pb.rb'))enddeffully_qualified_token?(token)token[0]=='.'enddefeval_dependencies(name,namespace=nil)name="#{namespace}.#{name}"ifnamespace&&!fully_qualified_token?(name)returnifname.empty?||@@evaled_dependencies.include?(name)||modulize(name).safe_constantize# if name = .foo.bar.Baz look for classes / modules named ::Foo::Bar and ::Foo# module == pure namespace (e.g. the descriptor package name)# class == nested messagescreate_ruby_namespace_heiarchy(name)if(message=@@all_messages[name])# Create the blank namespace in case there are nested typeseval_message_code(name)message.nested_type.eachdo|nested_type|eval_dependencies(nested_type.name,name)unlessnested_type.name.empty?endmessage.field.eachdo|field|eval_dependencies(field.type_name,name)unlessfield.type_name.empty?endmessage.enum_type.eachdo|enum_type|eval_dependencies(enum_type.name,name)end# Check @@evaled_dependencies again in case there was a dependency# loop that already loaded this messagereturnif@@evaled_dependencies.include?(name)eval_message_code(name,message.field)@@evaled_dependencies<<nameelsif(enum=@@all_enums[name])# Check @@evaled_dependencies again in case there was a dependency# loop that already loaded this enumreturnif@@evaled_dependencies.include?(name)namespace=name.split(".")eval_enum_code(enum,namespace[0..-2].join("."))@@evaled_dependencies<<nameelsefail"Error loading unknown dependencies, could not find message or enum #{name.inspect}"endenddefeval_message_code(fully_qualified_namespace,fields=[])group=GroupGenerator.new(0)group.add_extended_messages({fully_qualified_namespace=>fields},false)printgroup.to_seval_codeenddefeval_enum_code(enum,fully_qualified_namespace)group=GroupGenerator.new(0)group.add_enums([enum],:namespace=>[fully_qualified_namespace])printgroup.to_seval_code(modulize(fully_qualified_namespace).safe_constantize||Object)enddefeval_code(context=Object)warn"#{context.inspect}.module_eval #{print_contents.inspect}"ifENV['PB_DEBUG']context.module_evalprint_contents.to_s@io.truncate(0)@io.rewindenddefcreate_ruby_namespace_heiarchy(namespace)loopdonamespace,_match,_tail=namespace.rpartition(".")breakifnamespace.empty?eval_dependencies(namespace)endenddefinject_optionablereturnifdescriptor.package.empty?&&!ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')puts"::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }"endendendend