blob: 5ac56ad289cb1f8f8e0000bb6601b783beb7727f [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) {
Jun Mukaicac9ba42016-04-06 15:21:13 -070058 grpc::string input_type = RubyTypeOf(method->input_type()->full_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 }
Jun Mukaicac9ba42016-04-06 15:21:13 -070062 grpc::string output_type = RubyTypeOf(method->output_type()->full_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;
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700122 {
123 // Scope the output stream so it closes and finalizes output to the string.
nnobleebebb7e2014-12-10 16:31:01 -0800124
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700125 StringOutputStream output_stream(&output);
126 Printer out(&output_stream, '$');
127
128 // Don't write out any output if there no services, to avoid empty service
129 // files being generated for proto files that don't declare any.
130 if (file->service_count() == 0) {
131 return output;
132 }
133
134 // Write out a file header.
135 std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
136 {"file.name", file->name(), "file.package", file->package(), });
137 out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
138 out.Print(header_comment_vars,
139 "# Source: $file.name$ for package '$file.package$'\n");
140
141 out.Print("\n");
142 out.Print("require 'grpc'\n");
143 // Write out require statemment to import the separately generated file
144 // that defines the messages used by the service. This is generated by the
145 // main ruby plugin.
146 std::map<grpc::string, grpc::string> dep_vars =
147 ListToDict({"dep.name", MessagesRequireName(file), });
148 out.Print(dep_vars, "require '$dep.name$'\n");
149
150 // Write out services within the modules
151 out.Print("\n");
152 std::vector<grpc::string> modules = Split(file->package(), '.');
153 for (size_t i = 0; i < modules.size(); ++i) {
154 std::map<grpc::string, grpc::string> module_vars =
155 ListToDict({"module.name", CapitalizeFirst(modules[i]), });
156 out.Print(module_vars, "module $module.name$\n");
157 out.Indent();
158 }
159 for (int i = 0; i < file->service_count(); ++i) {
160 auto service = file->service(i);
161 PrintService(service, file->package(), &out);
162 }
163 for (size_t i = 0; i < modules.size(); ++i) {
164 out.Outdent();
165 out.Print("end\n");
166 }
temiolae5206aa2015-01-07 11:43:05 -0800167 }
nnobleebebb7e2014-12-10 16:31:01 -0800168 return output;
169}
170
Craig Tiller190d3602015-02-18 09:23:38 -0800171} // namespace grpc_ruby_generator