blob: a0bb92848b877f095d07d3ad714fc373972b7ffa [file] [log] [blame]
nnobleebebb7e2014-12-10 16:31:01 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
nnobleebebb7e2014-12-10 16:31:01 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <cctype>
35#include <map>
36#include <vector>
37
Yang Gao478568e2015-03-23 22:09:22 -070038#include "src/compiler/config.h"
nnobleebebb7e2014-12-10 16:31:01 -080039#include "src/compiler/ruby_generator.h"
40#include "src/compiler/ruby_generator_helpers-inl.h"
41#include "src/compiler/ruby_generator_map-inl.h"
42#include "src/compiler/ruby_generator_string-inl.h"
nnobleebebb7e2014-12-10 16:31:01 -080043
Yang Gao478568e2015-03-23 22:09:22 -070044using grpc::protobuf::FileDescriptor;
45using grpc::protobuf::ServiceDescriptor;
46using grpc::protobuf::MethodDescriptor;
47using grpc::protobuf::io::Printer;
48using grpc::protobuf::io::StringOutputStream;
nnobleebebb7e2014-12-10 16:31:01 -080049using std::map;
50using std::vector;
51
52namespace grpc_ruby_generator {
53namespace {
54
55// Prints out the method using the ruby gRPC DSL.
Yang Gao478568e2015-03-23 22:09:22 -070056void PrintMethod(const MethodDescriptor *method, const grpc::string &package,
Craig Tillerecd49342015-01-18 14:36:47 -080057 Printer *out) {
Yang Gao478568e2015-03-23 22:09:22 -070058 grpc::string input_type = RubyTypeOf(method->input_type()->name(), package);
nnoblec78b3402014-12-11 16:06:57 -080059 if (method->client_streaming()) {
nnobleebebb7e2014-12-10 16:31:01 -080060 input_type = "stream(" + input_type + ")";
61 }
Yang Gao478568e2015-03-23 22:09:22 -070062 grpc::string output_type = RubyTypeOf(method->output_type()->name(), package);
nnoblec78b3402014-12-11 16:06:57 -080063 if (method->server_streaming()) {
nnobleebebb7e2014-12-10 16:31:01 -080064 output_type = "stream(" + output_type + ")";
65 }
Yang Gao478568e2015-03-23 22:09:22 -070066 std::map<grpc::string, grpc::string> method_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -080067 ListToDict({"mth.name", method->name(), "input.type", input_type,
68 "output.type", output_type, });
nnobleebebb7e2014-12-10 16:31:01 -080069 out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
70}
71
72// Prints out the service using the ruby gRPC DSL.
Yang Gao478568e2015-03-23 22:09:22 -070073void PrintService(const ServiceDescriptor *service, const grpc::string &package,
Craig Tillerecd49342015-01-18 14:36:47 -080074 Printer *out) {
nnobleebebb7e2014-12-10 16:31:01 -080075 if (service->method_count() == 0) {
76 return;
77 }
78
79 // Begin the service module
Yang Gao478568e2015-03-23 22:09:22 -070080 std::map<grpc::string, grpc::string> module_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -080081 ListToDict({"module.name", CapitalizeFirst(service->name()), });
nnobleebebb7e2014-12-10 16:31:01 -080082 out->Print(module_vars, "module $module.name$\n");
83 out->Indent();
84
85 // TODO(temiola): add documentation
Yang Gao478568e2015-03-23 22:09:22 -070086 grpc::string doc = "TODO: add proto service documentation here";
87 std::map<grpc::string, grpc::string> template_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -080088 ListToDict({"Documentation", doc, });
nnobleebebb7e2014-12-10 16:31:01 -080089 out->Print("\n");
90 out->Print(template_vars, "# $Documentation$\n");
91 out->Print("class Service\n");
92
93 // Write the indented class body.
94 out->Indent();
95 out->Print("\n");
temiola3d726cf2015-01-06 18:25:06 -080096 out->Print("include GRPC::GenericService\n");
nnobleebebb7e2014-12-10 16:31:01 -080097 out->Print("\n");
98 out->Print("self.marshal_class_method = :encode\n");
99 out->Print("self.unmarshal_class_method = :decode\n");
Yang Gao478568e2015-03-23 22:09:22 -0700100 std::map<grpc::string, grpc::string> pkg_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -0800101 ListToDict({"service.name", service->name(), "pkg.name", package, });
temiolad6fd84a2015-01-08 09:59:08 -0800102 out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n");
nnobleebebb7e2014-12-10 16:31:01 -0800103 out->Print("\n");
104 for (int i = 0; i < service->method_count(); ++i) {
105 PrintMethod(service->method(i), package, out);
106 }
107 out->Outdent();
108
109 out->Print("end\n");
110 out->Print("\n");
111 out->Print("Stub = Service.rpc_stub_class\n");
112
113 // End the service module
114 out->Outdent();
115 out->Print("end\n");
116}
117
118} // namespace
119
Yang Gao478568e2015-03-23 22:09:22 -0700120grpc::string GetServices(const FileDescriptor *file) {
121 grpc::string output;
nnobleebebb7e2014-12-10 16:31:01 -0800122 StringOutputStream output_stream(&output);
123 Printer out(&output_stream, '$');
124
temiolae5206aa2015-01-07 11:43:05 -0800125 // Don't write out any output if there no services, to avoid empty service
126 // files being generated for proto files that don't declare any.
127 if (file->service_count() == 0) {
128 return output;
129 }
130
131 // Write out a file header.
Yang Gao478568e2015-03-23 22:09:22 -0700132 std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
Yang Gao5fd0d292015-01-26 00:19:48 -0800133 {"file.name", file->name(), "file.package", file->package(), });
temiola54535552015-01-06 17:50:59 -0800134 out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
nnobleebebb7e2014-12-10 16:31:01 -0800135 out.Print(header_comment_vars,
temiola54535552015-01-06 17:50:59 -0800136 "# Source: $file.name$ for package '$file.package$'\n");
nnobleebebb7e2014-12-10 16:31:01 -0800137
138 out.Print("\n");
139 out.Print("require 'grpc'\n");
140 // Write out require statemment to import the separately generated file
141 // that defines the messages used by the service. This is generated by the
142 // main ruby plugin.
Yang Gao478568e2015-03-23 22:09:22 -0700143 std::map<grpc::string, grpc::string> dep_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -0800144 ListToDict({"dep.name", MessagesRequireName(file), });
nnobleebebb7e2014-12-10 16:31:01 -0800145 out.Print(dep_vars, "require '$dep.name$'\n");
146
147 // Write out services within the modules
148 out.Print("\n");
Yang Gao478568e2015-03-23 22:09:22 -0700149 std::vector<grpc::string> modules = Split(file->package(), '.');
nnobleebebb7e2014-12-10 16:31:01 -0800150 for (size_t i = 0; i < modules.size(); ++i) {
Yang Gao478568e2015-03-23 22:09:22 -0700151 std::map<grpc::string, grpc::string> module_vars =
Yang Gao5fd0d292015-01-26 00:19:48 -0800152 ListToDict({"module.name", CapitalizeFirst(modules[i]), });
nnobleebebb7e2014-12-10 16:31:01 -0800153 out.Print(module_vars, "module $module.name$\n");
154 out.Indent();
155 }
156 for (int i = 0; i < file->service_count(); ++i) {
157 auto service = file->service(i);
158 PrintService(service, file->package(), &out);
159 }
160 for (size_t i = 0; i < modules.size(); ++i) {
161 out.Outdent();
162 out.Print("end\n");
163 }
164
165 return output;
166}
167
Craig Tiller190d3602015-02-18 09:23:38 -0800168} // namespace grpc_ruby_generator