Merge remote-tracking branch 'upstream/master'

pull/1123/head
Vijay Pai 10 years ago
commit 8ba8cfe143
  1. 48
      src/compiler/ruby_generator.cc
  2. 10
      src/compiler/ruby_generator.h
  3. 12
      src/compiler/ruby_generator_helpers-inl.h
  4. 13
      src/compiler/ruby_generator_map-inl.h
  5. 43
      src/compiler/ruby_generator_string-inl.h
  6. 30
      src/compiler/ruby_plugin.cc
  7. 31
      src/ruby/Rakefile
  8. 8
      src/ruby/spec/generic/client_stub_spec.rb

@ -32,24 +32,20 @@
*/ */
#include <cctype> #include <cctype>
#include <string>
#include <map> #include <map>
#include <vector> #include <vector>
#include "src/compiler/config.h"
#include "src/compiler/ruby_generator.h" #include "src/compiler/ruby_generator.h"
#include "src/compiler/ruby_generator_helpers-inl.h" #include "src/compiler/ruby_generator_helpers-inl.h"
#include "src/compiler/ruby_generator_map-inl.h" #include "src/compiler/ruby_generator_map-inl.h"
#include "src/compiler/ruby_generator_string-inl.h" #include "src/compiler/ruby_generator_string-inl.h"
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h> using grpc::protobuf::FileDescriptor;
#include <google/protobuf/descriptor.pb.h> using grpc::protobuf::ServiceDescriptor;
#include <google/protobuf/descriptor.h> using grpc::protobuf::MethodDescriptor;
using grpc::protobuf::io::Printer;
using google::protobuf::FileDescriptor; using grpc::protobuf::io::StringOutputStream;
using google::protobuf::ServiceDescriptor;
using google::protobuf::MethodDescriptor;
using google::protobuf::io::Printer;
using google::protobuf::io::StringOutputStream;
using std::map; using std::map;
using std::vector; using std::vector;
@ -57,38 +53,38 @@ namespace grpc_ruby_generator {
namespace { namespace {
// Prints out the method using the ruby gRPC DSL. // Prints out the method using the ruby gRPC DSL.
void PrintMethod(const MethodDescriptor *method, const std::string &package, void PrintMethod(const MethodDescriptor *method, const grpc::string &package,
Printer *out) { Printer *out) {
std::string input_type = RubyTypeOf(method->input_type()->name(), package); grpc::string input_type = RubyTypeOf(method->input_type()->name(), package);
if (method->client_streaming()) { if (method->client_streaming()) {
input_type = "stream(" + input_type + ")"; input_type = "stream(" + input_type + ")";
} }
std::string output_type = RubyTypeOf(method->output_type()->name(), package); grpc::string output_type = RubyTypeOf(method->output_type()->name(), package);
if (method->server_streaming()) { if (method->server_streaming()) {
output_type = "stream(" + output_type + ")"; output_type = "stream(" + output_type + ")";
} }
std::map<std::string, std::string> method_vars = std::map<grpc::string, grpc::string> method_vars =
ListToDict({"mth.name", method->name(), "input.type", input_type, ListToDict({"mth.name", method->name(), "input.type", input_type,
"output.type", output_type, }); "output.type", output_type, });
out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n"); out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
} }
// Prints out the service using the ruby gRPC DSL. // Prints out the service using the ruby gRPC DSL.
void PrintService(const ServiceDescriptor *service, const std::string &package, void PrintService(const ServiceDescriptor *service, const grpc::string &package,
Printer *out) { Printer *out) {
if (service->method_count() == 0) { if (service->method_count() == 0) {
return; return;
} }
// Begin the service module // Begin the service module
std::map<std::string, std::string> module_vars = std::map<grpc::string, grpc::string> module_vars =
ListToDict({"module.name", CapitalizeFirst(service->name()), }); ListToDict({"module.name", CapitalizeFirst(service->name()), });
out->Print(module_vars, "module $module.name$\n"); out->Print(module_vars, "module $module.name$\n");
out->Indent(); out->Indent();
// TODO(temiola): add documentation // TODO(temiola): add documentation
std::string doc = "TODO: add proto service documentation here"; grpc::string doc = "TODO: add proto service documentation here";
std::map<std::string, std::string> template_vars = std::map<grpc::string, grpc::string> template_vars =
ListToDict({"Documentation", doc, }); ListToDict({"Documentation", doc, });
out->Print("\n"); out->Print("\n");
out->Print(template_vars, "# $Documentation$\n"); out->Print(template_vars, "# $Documentation$\n");
@ -101,7 +97,7 @@ void PrintService(const ServiceDescriptor *service, const std::string &package,
out->Print("\n"); out->Print("\n");
out->Print("self.marshal_class_method = :encode\n"); out->Print("self.marshal_class_method = :encode\n");
out->Print("self.unmarshal_class_method = :decode\n"); out->Print("self.unmarshal_class_method = :decode\n");
std::map<std::string, std::string> pkg_vars = std::map<grpc::string, grpc::string> pkg_vars =
ListToDict({"service.name", service->name(), "pkg.name", package, }); ListToDict({"service.name", service->name(), "pkg.name", package, });
out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n"); out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n");
out->Print("\n"); out->Print("\n");
@ -121,8 +117,8 @@ void PrintService(const ServiceDescriptor *service, const std::string &package,
} // namespace } // namespace
std::string GetServices(const FileDescriptor *file) { grpc::string GetServices(const FileDescriptor *file) {
std::string output; grpc::string output;
StringOutputStream output_stream(&output); StringOutputStream output_stream(&output);
Printer out(&output_stream, '$'); Printer out(&output_stream, '$');
@ -133,7 +129,7 @@ std::string GetServices(const FileDescriptor *file) {
} }
// Write out a file header. // Write out a file header.
std::map<std::string, std::string> header_comment_vars = ListToDict( std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
{"file.name", file->name(), "file.package", file->package(), }); {"file.name", file->name(), "file.package", file->package(), });
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n"); out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print(header_comment_vars, out.Print(header_comment_vars,
@ -144,15 +140,15 @@ std::string GetServices(const FileDescriptor *file) {
// Write out require statemment to import the separately generated file // Write out require statemment to import the separately generated file
// that defines the messages used by the service. This is generated by the // that defines the messages used by the service. This is generated by the
// main ruby plugin. // main ruby plugin.
std::map<std::string, std::string> dep_vars = std::map<grpc::string, grpc::string> dep_vars =
ListToDict({"dep.name", MessagesRequireName(file), }); ListToDict({"dep.name", MessagesRequireName(file), });
out.Print(dep_vars, "require '$dep.name$'\n"); out.Print(dep_vars, "require '$dep.name$'\n");
// Write out services within the modules // Write out services within the modules
out.Print("\n"); out.Print("\n");
std::vector<std::string> modules = Split(file->package(), '.'); std::vector<grpc::string> modules = Split(file->package(), '.');
for (size_t i = 0; i < modules.size(); ++i) { for (size_t i = 0; i < modules.size(); ++i) {
std::map<std::string, std::string> module_vars = std::map<grpc::string, grpc::string> module_vars =
ListToDict({"module.name", CapitalizeFirst(modules[i]), }); ListToDict({"module.name", CapitalizeFirst(modules[i]), });
out.Print(module_vars, "module $module.name$\n"); out.Print(module_vars, "module $module.name$\n");
out.Indent(); out.Indent();

@ -34,17 +34,11 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
#include <string> #include "src/compiler/config.h"
namespace google {
namespace protobuf {
class FileDescriptor;
} // namespace protobuf
} // namespace google
namespace grpc_ruby_generator { namespace grpc_ruby_generator {
std::string GetServices(const google::protobuf::FileDescriptor *file); grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
} // namespace grpc_ruby_generator } // namespace grpc_ruby_generator

@ -34,15 +34,13 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
#include <string> #include "src/compiler/config.h"
#include <google/protobuf/descriptor.h>
#include "src/compiler/ruby_generator_string-inl.h" #include "src/compiler/ruby_generator_string-inl.h"
namespace grpc_ruby_generator { namespace grpc_ruby_generator {
inline bool ServicesFilename(const google::protobuf::FileDescriptor *file, inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
std::string *file_name_or_error) { grpc::string *file_name_or_error) {
// Get output file name. // Get output file name.
static const unsigned proto_suffix_length = 6; // length of ".proto" static const unsigned proto_suffix_length = 6; // length of ".proto"
if (file->name().size() > proto_suffix_length && if (file->name().size() > proto_suffix_length &&
@ -57,8 +55,8 @@ inline bool ServicesFilename(const google::protobuf::FileDescriptor *file,
} }
} }
inline std::string MessagesRequireName( inline grpc::string MessagesRequireName(
const google::protobuf::FileDescriptor *file) { const grpc::protobuf::FileDescriptor *file) {
return Replace(file->name(), ".proto", ""); return Replace(file->name(), ".proto", "");
} }

@ -34,11 +34,12 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
#include "src/compiler/config.h"
#include <iostream> #include <iostream>
#include <initializer_list> #include <initializer_list>
#include <map> #include <map>
#include <ostream> // NOLINT #include <ostream> // NOLINT
#include <string>
#include <vector> #include <vector>
using std::initializer_list; using std::initializer_list;
@ -49,18 +50,18 @@ namespace grpc_ruby_generator {
// Converts an initializer list of the form { key0, value0, key1, value1, ... } // Converts an initializer list of the form { key0, value0, key1, value1, ... }
// into a map of key* to value*. Is merely a readability helper for later code. // into a map of key* to value*. Is merely a readability helper for later code.
inline std::map<std::string, std::string> ListToDict( inline std::map<grpc::string, grpc::string> ListToDict(
const initializer_list<std::string> &values) { const initializer_list<grpc::string> &values) {
if (values.size() % 2 != 0) { if (values.size() % 2 != 0) {
std::cerr << "Not every 'key' has a value in `values`." std::cerr << "Not every 'key' has a value in `values`."
<< std::endl; << std::endl;
} }
std::map<std::string, std::string> value_map; std::map<grpc::string, grpc::string> value_map;
auto value_iter = values.begin(); auto value_iter = values.begin();
for (unsigned i = 0; i < values.size() / 2; ++i) { for (unsigned i = 0; i < values.size() / 2; ++i) {
std::string key = *value_iter; grpc::string key = *value_iter;
++value_iter; ++value_iter;
std::string value = *value_iter; grpc::string value = *value_iter;
value_map[key] = value; value_map[key] = value;
++value_iter; ++value_iter;
} }

@ -34,8 +34,9 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
#include "src/compiler/config.h"
#include <algorithm> #include <algorithm>
#include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -45,10 +46,10 @@ using std::transform;
namespace grpc_ruby_generator { namespace grpc_ruby_generator {
// Split splits a string using char into elems. // Split splits a string using char into elems.
inline std::vector<std::string> &Split(const std::string &s, char delim, inline std::vector<grpc::string> &Split(const grpc::string &s, char delim,
std::vector<std::string> *elems) { std::vector<grpc::string> *elems) {
std::stringstream ss(s); std::stringstream ss(s);
std::string item; grpc::string item;
while (getline(ss, item, delim)) { while (getline(ss, item, delim)) {
elems->push_back(item); elems->push_back(item);
} }
@ -56,17 +57,17 @@ inline std::vector<std::string> &Split(const std::string &s, char delim,
} }
// Split splits a string using char, returning the result in a vector. // Split splits a string using char, returning the result in a vector.
inline std::vector<std::string> Split(const std::string &s, char delim) { inline std::vector<grpc::string> Split(const grpc::string &s, char delim) {
std::vector<std::string> elems; std::vector<grpc::string> elems;
Split(s, delim, &elems); Split(s, delim, &elems);
return elems; return elems;
} }
// Replace replaces from with to in s. // Replace replaces from with to in s.
inline std::string Replace(std::string s, const std::string &from, inline grpc::string Replace(grpc::string s, const grpc::string &from,
const std::string &to) { const grpc::string &to) {
size_t start_pos = s.find(from); size_t start_pos = s.find(from);
if (start_pos == std::string::npos) { if (start_pos == grpc::string::npos) {
return s; return s;
} }
s.replace(start_pos, from.length(), to); s.replace(start_pos, from.length(), to);
@ -74,10 +75,10 @@ inline std::string Replace(std::string s, const std::string &from,
} }
// ReplaceAll replaces all instances of search with replace in s. // ReplaceAll replaces all instances of search with replace in s.
inline std::string ReplaceAll(std::string s, const std::string &search, inline grpc::string ReplaceAll(grpc::string s, const grpc::string &search,
const std::string &replace) { const grpc::string &replace) {
size_t pos = 0; size_t pos = 0;
while ((pos = s.find(search, pos)) != std::string::npos) { while ((pos = s.find(search, pos)) != grpc::string::npos) {
s.replace(pos, search.length(), replace); s.replace(pos, search.length(), replace);
pos += replace.length(); pos += replace.length();
} }
@ -85,10 +86,10 @@ inline std::string ReplaceAll(std::string s, const std::string &search,
} }
// ReplacePrefix replaces from with to in s if search is a prefix of s. // ReplacePrefix replaces from with to in s if search is a prefix of s.
inline bool ReplacePrefix(std::string *s, const std::string &from, inline bool ReplacePrefix(grpc::string *s, const grpc::string &from,
const std::string &to) { const grpc::string &to) {
size_t start_pos = s->find(from); size_t start_pos = s->find(from);
if (start_pos == std::string::npos || start_pos != 0) { if (start_pos == grpc::string::npos || start_pos != 0) {
return false; return false;
} }
s->replace(start_pos, from.length(), to); s->replace(start_pos, from.length(), to);
@ -96,7 +97,7 @@ inline bool ReplacePrefix(std::string *s, const std::string &from,
} }
// CapitalizeFirst capitalizes the first char in a string. // CapitalizeFirst capitalizes the first char in a string.
inline std::string CapitalizeFirst(std::string s) { inline grpc::string CapitalizeFirst(grpc::string s) {
if (s.empty()) { if (s.empty()) {
return s; return s;
} }
@ -105,15 +106,15 @@ inline std::string CapitalizeFirst(std::string s) {
} }
// RubyTypeOf updates a proto type to the required ruby equivalent. // RubyTypeOf updates a proto type to the required ruby equivalent.
inline std::string RubyTypeOf(const std::string &a_type, inline grpc::string RubyTypeOf(const grpc::string &a_type,
const std::string &package) { const grpc::string &package) {
std::string res(a_type); grpc::string res(a_type);
ReplacePrefix(&res, package, ""); // remove the leading package if present ReplacePrefix(&res, package, ""); // remove the leading package if present
ReplacePrefix(&res, ".", ""); // remove the leading . (no package) ReplacePrefix(&res, ".", ""); // remove the leading . (no package)
if (res.find('.') == std::string::npos) { if (res.find('.') == grpc::string::npos) {
return res; return res;
} else { } else {
std::vector<std::string> prefixes_and_type = Split(res, '.'); std::vector<grpc::string> prefixes_and_type = Split(res, '.');
for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) { for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) {
if (i != 0) { if (i != 0) {
res += "::"; // switch '.' to the ruby module delim res += "::"; // switch '.' to the ruby module delim

@ -32,43 +32,35 @@
*/ */
// Generates Ruby gRPC service interface out of Protobuf IDL. // Generates Ruby gRPC service interface out of Protobuf IDL.
//
// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
// and net/proto2/compiler/public/plugin.h for more information on plugins.
#include <memory> #include <memory>
#include <string>
#include "src/compiler/config.h"
#include "src/compiler/ruby_generator.h" #include "src/compiler/ruby_generator.h"
#include "src/compiler/ruby_generator_helpers-inl.h" #include "src/compiler/ruby_generator_helpers-inl.h"
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.h>
class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator { class RubyGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public: public:
RubyGrpcGenerator() {} RubyGrpcGenerator() {}
~RubyGrpcGenerator() {} ~RubyGrpcGenerator() {}
bool Generate(const google::protobuf::FileDescriptor *file, bool Generate(const grpc::protobuf::FileDescriptor *file,
const std::string &parameter, const grpc::string &parameter,
google::protobuf::compiler::GeneratorContext *context, grpc::protobuf::compiler::GeneratorContext *context,
std::string *error) const { grpc::string *error) const {
std::string code = grpc_ruby_generator::GetServices(file); grpc::string code = grpc_ruby_generator::GetServices(file);
if (code.size() == 0) { if (code.size() == 0) {
return true; // don't generate a file if there are no services return true; // don't generate a file if there are no services
} }
// Get output file name. // Get output file name.
std::string file_name; grpc::string file_name;
if (!grpc_ruby_generator::ServicesFilename(file, &file_name)) { if (!grpc_ruby_generator::ServicesFilename(file, &file_name)) {
return false; return false;
} }
std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output( std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
context->Open(file_name)); context->Open(file_name));
google::protobuf::io::CodedOutputStream coded_out(output.get()); grpc::protobuf::io::CodedOutputStream coded_out(output.get());
coded_out.WriteRaw(code.data(), code.size()); coded_out.WriteRaw(code.data(), code.size());
return true; return true;
} }
@ -76,5 +68,5 @@ class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
RubyGrpcGenerator generator; RubyGrpcGenerator generator;
return google::protobuf::compiler::PluginMain(argc, argv, &generator); return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
} }

@ -2,14 +2,17 @@
require 'rake/extensiontask' require 'rake/extensiontask'
require 'rspec/core/rake_task' require 'rspec/core/rake_task'
require 'rubocop/rake_task' require 'rubocop/rake_task'
require 'bundler/gem_tasks'
desc 'Run Rubocop to check for style violations' # Add rubocop style checking tasks
RuboCop::RakeTask.new RuboCop::RakeTask.new
# Add the extension compiler task
Rake::ExtensionTask.new 'grpc' do |ext| Rake::ExtensionTask.new 'grpc' do |ext|
ext.lib_dir = File.join('lib', 'grpc') ext.lib_dir = File.join('lib', 'grpc')
end end
# Define the test suites
SPEC_SUITES = [ SPEC_SUITES = [
{ id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) }, { id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) },
{ id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic), { id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic),
@ -19,19 +22,18 @@ SPEC_SUITES = [
{ id: :server, title: 'rpc server thread tests', dir: %w(spec/generic), { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
tag: 'server' } tag: 'server' }
] ]
desc 'Run all RSpec tests'
namespace :spec do
namespace :suite do namespace :suite do
SPEC_SUITES.each do |suite| SPEC_SUITES.each do |suite|
desc "Run all specs in #{suite[:title]} spec suite" desc "Run all specs in the #{suite[:title]} spec suite"
RSpec::Core::RakeTask.new(suite[:id]) do |t| RSpec::Core::RakeTask.new(suite[:id]) do |t|
spec_files = [] spec_files = []
suite[:files].each { |f| spec_files += Dir[f] } if suite[:files] suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
if suite[:dirs] if suite[:dir]
suite[:dirs].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] } suite[:dir].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] }
end end
helper = 'spec/spec_helper.rb'
spec_files << helper unless spec_files.include?(helper)
t.pattern = spec_files t.pattern = spec_files
t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag] t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
@ -41,14 +43,13 @@ namespace :spec do
end end
end end
end end
end
desc 'Compiles the extension then runs all the tests' # Define dependencies between the suites.
task :all task 'suite:wrapper' => [:compile, :rubocop]
task 'suite:idiomatic' => 'suite:wrapper'
task 'suite:bidi' => 'suite:wrapper'
task 'suite:server' => 'suite:wrapper'
desc 'Compiles the gRPC extension then runs all the tests'
task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
task default: :all task default: :all
task 'spec:suite:wrapper' => [:compile, :rubocop]
task 'spec:suite:idiomatic' => 'spec:suite:wrapper'
task 'spec:suite:bidi' => 'spec:suite:wrapper'
task 'spec:suite:server' => 'spec:suite:wrapper'
task all: ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server']

@ -384,13 +384,7 @@ describe 'ClientStub' do
th.join th.join
end end
# disabled because an unresolved wire-protocol implementation feature it 'supports a server-initiated ping pong', bidi: true do
#
# - servers should be able initiate messaging, however, as it stand
# servers don't know if all the client metadata has been sent until
# they receive a message from the client. Without receiving all the
# metadata, the server does not accept the call, so this test hangs.
xit 'supports a server-initiated ping pong', bidi: true do
server_port = create_test_server server_port = create_test_server
host = "localhost:#{server_port}" host = "localhost:#{server_port}"
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false) th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)

Loading…
Cancel
Save