/* * * Copyright 2015, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include "src/compiler/config.h" #include "src/compiler/ruby_generator.h" #include "src/compiler/ruby_generator_helpers-inl.h" #include "src/compiler/ruby_generator_map-inl.h" #include "src/compiler/ruby_generator_string-inl.h" using grpc::protobuf::FileDescriptor; using grpc::protobuf::ServiceDescriptor; using grpc::protobuf::MethodDescriptor; using grpc::protobuf::io::Printer; using grpc::protobuf::io::StringOutputStream; using std::map; using std::vector; namespace grpc_ruby_generator { namespace { // Prints out the method using the ruby gRPC DSL. void PrintMethod(const MethodDescriptor *method, const grpc::string &package, Printer *out) { grpc::string input_type = RubyTypeOf(method->input_type()->name(), package); if (method->client_streaming()) { input_type = "stream(" + input_type + ")"; } grpc::string output_type = RubyTypeOf(method->output_type()->name(), package); if (method->server_streaming()) { output_type = "stream(" + output_type + ")"; } std::map method_vars = ListToDict({"mth.name", method->name(), "input.type", input_type, "output.type", output_type, }); out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n"); } // Prints out the service using the ruby gRPC DSL. void PrintService(const ServiceDescriptor *service, const grpc::string &package, Printer *out) { if (service->method_count() == 0) { return; } // Begin the service module std::map module_vars = ListToDict({"module.name", CapitalizeFirst(service->name()), }); out->Print(module_vars, "module $module.name$\n"); out->Indent(); // TODO(temiola): add documentation grpc::string doc = "TODO: add proto service documentation here"; std::map template_vars = ListToDict({"Documentation", doc, }); out->Print("\n"); out->Print(template_vars, "# $Documentation$\n"); out->Print("class Service\n"); // Write the indented class body. out->Indent(); out->Print("\n"); out->Print("include GRPC::GenericService\n"); out->Print("\n"); out->Print("self.marshal_class_method = :encode\n"); out->Print("self.unmarshal_class_method = :decode\n"); std::map pkg_vars = ListToDict({"service.name", service->name(), "pkg.name", package, }); out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n"); out->Print("\n"); for (int i = 0; i < service->method_count(); ++i) { PrintMethod(service->method(i), package, out); } out->Outdent(); out->Print("end\n"); out->Print("\n"); out->Print("Stub = Service.rpc_stub_class\n"); // End the service module out->Outdent(); out->Print("end\n"); } } // namespace grpc::string GetServices(const FileDescriptor *file) { grpc::string output; StringOutputStream output_stream(&output); Printer out(&output_stream, '$'); // Don't write out any output if there no services, to avoid empty service // files being generated for proto files that don't declare any. if (file->service_count() == 0) { return output; } // Write out a file header. std::map header_comment_vars = ListToDict( {"file.name", file->name(), "file.package", file->package(), }); out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n"); out.Print(header_comment_vars, "# Source: $file.name$ for package '$file.package$'\n"); out.Print("\n"); out.Print("require 'grpc'\n"); // Write out require statemment to import the separately generated file // that defines the messages used by the service. This is generated by the // main ruby plugin. std::map dep_vars = ListToDict({"dep.name", MessagesRequireName(file), }); out.Print(dep_vars, "require '$dep.name$'\n"); // Write out services within the modules out.Print("\n"); std::vector modules = Split(file->package(), '.'); for (size_t i = 0; i < modules.size(); ++i) { std::map module_vars = ListToDict({"module.name", CapitalizeFirst(modules[i]), }); out.Print(module_vars, "module $module.name$\n"); out.Indent(); } for (int i = 0; i < file->service_count(); ++i) { auto service = file->service(i); PrintService(service, file->package(), &out); } for (size_t i = 0; i < modules.size(); ++i) { out.Outdent(); out.Print("end\n"); } return output; } } // namespace grpc_ruby_generator