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 include ProtobufDescriptor::HasChildren # 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 # Field index is hard-coded since these are a bit annoying to grab # consistently with the different protocol buffer implementations. self.register_children(:message_type, 4) self.register_children(:enum_type, 5) self.register_children(:service, 6) 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 # Whether source code info is associated with this descriptor def has_source_code_info? file_descriptor_proto.has_field?(:source_code_info) end def source_code_info file_descriptor_proto.source_code_info 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) && present?(file_descriptor_proto.options.java_package) 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) && present?(file_descriptor_proto.options.java_multiple_files) return nil elsif file_descriptor_proto.has_field?(:options) && present?(file_descriptor_proto.options.java_outer_classname) return file_descriptor_proto.options.java_outer_classname else basename = name.split('/').last basename = basename.gsub('.proto', '') return camelize(basename) 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 [ present?(java_package) ? java_package : nil, present?(java_outer_classname) ? java_outer_classname : nil ].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 private # Copy over a bunch of methods that are normally part of active_support: def present?(string) return !blank?(string) end def blank?(string) string.respond_to?(:empty?) ? !!string.empty? : !string end def camelize(string) if string.respond_to?(:camelize) return string.camelize else return string.split("_").map { |s| s.capitalize }.join("") end end end end