require "protobuf_descriptor/enum_descriptor" require "protobuf_descriptor/message_descriptor" require "protobuf_descriptor/service_descriptor" require "active_support" require "active_support/core_ext/object/blank" require "active_support/core_ext/string/inflections" class ProtobufDescriptor # Describes a complete .proto file. # # See {+FileDescriptorProto+}[https://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/descriptor.proto#56] class FileDescriptor # The parent {ProtobufDescriptor} attr_reader :file_descriptor_set # The +FileDescriptorProto+ this +FileDescriptor+ is wrapping. attr_reader :file_descriptor_proto # List of the message types that are defined at the top level of this file, # as a NamedCollection of {ProtobufDescriptor::MessageDescriptor} attr_reader :message_type # List of the enum types that are defined at the top level of this file, # as a NamedCollection of {ProtobufDescriptor::EnumDescriptor} attr_reader :enum_type # List of the services that are defined at the top level of this file, as a # NamedCollection of {ProtobufDescriptor::ServiceDescriptor} attr_reader :service def initialize(file_descriptor_set, file_descriptor_proto) #:nodoc: # This is basically a parent pointer. @file_descriptor_set = file_descriptor_set @file_descriptor_proto = file_descriptor_proto @message_type = ProtobufDescriptor::NamedCollection.new( file_descriptor_proto.message_type.map { |m| ProtobufDescriptor::MessageDescriptor.new(self, m) }) @enum_type = ProtobufDescriptor::NamedCollection.new( file_descriptor_proto.enum_type.map { |m| ProtobufDescriptor::EnumDescriptor.new(self, m) }) @service = ProtobufDescriptor::NamedCollection.new( file_descriptor_proto.service.map { |m| ProtobufDescriptor::ServiceDescriptor.new(self, m) }) end alias_method :parent, :file_descriptor_set alias_method :message_types, :message_type alias_method :messages, :message_type alias_method :enum_types, :enum_type alias_method :enums, :enum_types alias_method :services, :service # Set of all top-level messages, enums and services that are defined inside # of this file def children @children ||= ProtobufDescriptor::NamedCollection.new( @message_type.collection + @enum_type.collection + @service.collection) end # Filename relative to root of source tree. def name file_descriptor_proto.name end # The package name defined by the .proto file. E.G. "foo", "foo.bar", etc. def package file_descriptor_proto.package end # The Java package where classes generated from this .proto will be # placed. By default, the proto package is used, but this is often # inappropriate because proto packages do not normally start with backwards # domain names. def java_package if file_descriptor_proto.has_field?(:options) && file_descriptor_proto.options.java_package.present? return file_descriptor_proto.options.java_package else return file_descriptor_proto.package end end # If set, all the classes from the .proto file are wrapped in a single # outer class with the given name. This applies to both Proto1 # (equivalent to the old "--one_java_file" option) and Proto2 (where # a .proto always translates to a single class, but you may want to # explicitly choose the class name). def java_outer_classname if file_descriptor_proto.has_field?(:options) && file_descriptor_proto.options.java_multiple_files.present? return nil elsif file_descriptor_proto.has_field?(:options) && file_descriptor_proto.options.java_outer_classname.present? return file_descriptor_proto.options.java_outer_classname else basename = name.split('/').last basename = basename.gsub('.proto', '') return basename.camelize end end # Returns the fully qualified name, as used by the +resolve_type+ methods. def fully_qualified_name return ".#{self.package}" end # Returns the fully qualified Java class name. def fully_qualified_java_name return [java_package, java_outer_classname].compact.join('.') end # Returns the fully qualified Java name as Wire would generate it. Wire # never wraps the definitions in a class named after the .proto file # (essentially behaving as if +java_outer_classname+ were always true) def fully_qualified_wire_name return java_package end # Returns the fully qualified Ruby class name as generated by various # protobuf gems. def fully_qualified_ruby_name return "::#{self.package.gsub('.', '::')}" end end end