diff --git a/example/hello_world_twirp.rb b/example/hello_world_twirp.rb index 6a8e9b8..8734368 100644 --- a/example/hello_world_twirp.rb +++ b/example/hello_world_twirp.rb @@ -8,14 +8,14 @@ module Example module HelloWorld - class HelloWorldServiceService < ::Twirp::Service + class HelloWorldService < ::Twirp::Service package "example.hello_world" service "HelloWorldService" rpc :Hello, HelloRequest, HelloResponse, ruby_method: :hello end - class HelloWorldServiceClient < ::Twirp::Client - client_for HelloWorldServiceService + class HelloWorldClient < ::Twirp::Client + client_for HelloWorldService end end end diff --git a/lib/twirp/protoc_plugin/code_generator.rb b/lib/twirp/protoc_plugin/code_generator.rb index a0c64e6..b478587 100644 --- a/lib/twirp/protoc_plugin/code_generator.rb +++ b/lib/twirp/protoc_plugin/code_generator.rb @@ -45,9 +45,16 @@ def generate output << "\n" if index > 0 service_name = service.name + # The generated service class name should end in "Service"; Only append the + # suffix if the service is not already well-named. + service_class_name = if service_name.end_with?("Service") + service_name + else + service_name + "Service" + end # Generate service class - output << line("class #{camel_case(service_name)}Service < ::Twirp::Service", indent_level) + output << line("class #{camel_case(service_class_name)} < ::Twirp::Service", indent_level) indent_level += 1 output << line("package \"#{@proto_file.package}\"", indent_level) unless @proto_file.package.to_s.empty? @@ -68,10 +75,14 @@ def generate output << "\n" # Generate client class - output << line("class #{camel_case(service_name)}Client < ::Twirp::Client", indent_level) + + # Strip the "Service" suffix if present for better readability. + client_class_name = service_name.delete_suffix("Service") + "Client" + + output << line("class #{camel_case(client_class_name)} < ::Twirp::Client", indent_level) indent_level += 1 - output << line("client_for #{camel_case(service_name)}Service", indent_level) + output << line("client_for #{camel_case(service_class_name)}", indent_level) indent_level -= 1 output << line("end", indent_level) diff --git a/spec/fixtures/well_named_service.proto b/spec/fixtures/well_named_service.proto new file mode 100644 index 0000000..ba730b7 --- /dev/null +++ b/spec/fixtures/well_named_service.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package example.hello_world; + + +service HelloWorldService { + rpc Hello(HelloRequest) returns (HelloResponse); +} + +message HelloRequest { + string name = 1; +} + +message HelloResponse { + string message = 1; +} diff --git a/spec/fixtures/well_named_service_code_gen_request_pb.bin b/spec/fixtures/well_named_service_code_gen_request_pb.bin new file mode 100644 index 0000000..d61e123 Binary files /dev/null and b/spec/fixtures/well_named_service_code_gen_request_pb.bin differ diff --git a/spec/twirp/protoc_plugin/process_spec.rb b/spec/twirp/protoc_plugin/process_spec.rb index 2a5e0fe..475ba30 100644 --- a/spec/twirp/protoc_plugin/process_spec.rb +++ b/spec/twirp/protoc_plugin/process_spec.rb @@ -1,42 +1,90 @@ # frozen_string_literal: true RSpec.describe Twirp::ProtocPlugin do - # Generate fixture: - # `./spec/support/create_fixture -b -f service_code_gen_request_pb.bin ./spec/fixtures/service.proto` - let(:service_code_gen_request_pb) { fixture("service_code_gen_request_pb.bin").read } + describe "#process" do + context "when using the example from the original go plugin" do + # The `service.proto` fixture is from: + # https://github.com/arthurnn/twirp-ruby/blob/v1.11.0/example/hello_world/service.proto + # + # Generate code gen request fixture: + # `./spec/support/create_fixture -b -f service_code_gen_request_pb.bin ./spec/fixtures/service.proto` + let(:service_code_gen_request_pb) { fixture("service_code_gen_request_pb.bin").read } - it "generates expected output" do - response_pb = Twirp::ProtocPlugin.process(service_code_gen_request_pb) - response = Google::Protobuf::Compiler::CodeGeneratorResponse.decode(response_pb) + it "generates expected output" do + response_pb = Twirp::ProtocPlugin.process(service_code_gen_request_pb) + response = Google::Protobuf::Compiler::CodeGeneratorResponse.decode(response_pb) - expect(response.supported_features).to eq(Google::Protobuf::Compiler::CodeGeneratorResponse::Feature::FEATURE_PROTO3_OPTIONAL) - expect(response.file.size).to eq(1) - expect(response.file.first.name).to eq("spec/fixtures/service_twirp.rb") - # Match the general output of the 1.10.0 go plugin when ran against the same service.proto. - # See: https://github.com/arthurnn/twirp-ruby/blob/1a653da2aec51723a403e6741dbebfefd38b0730/example/hello_world/service_twirp.rb - expect(response.file.first.content).to eq <<~EOF - # frozen_string_literal: true - - # Generated by the protoc-gen-twirp_ruby gem v0.1.0. DO NOT EDIT! - # source: spec/fixtures/service.proto + expect(response.supported_features).to eq(Google::Protobuf::Compiler::CodeGeneratorResponse::Feature::FEATURE_PROTO3_OPTIONAL) + expect(response.file.size).to eq(1) + expect(response.file.first.name).to eq("spec/fixtures/service_twirp.rb") + # Match the general output of the 1.11.0 go plugin when ran against the same service.proto. + # See: https://github.com/arthurnn/twirp-ruby/blob/v1.11.0/example/hello_world/service_twirp.rb + expect(response.file.first.content).to eq <<~EOF + # frozen_string_literal: true + + # Generated by the protoc-gen-twirp_ruby gem v0.1.0. DO NOT EDIT! + # source: spec/fixtures/service.proto + + require "twirp" + require_relative "service_pb" + + module Example + module HelloWorld + class HelloWorldService < ::Twirp::Service + package "example.hello_world" + service "HelloWorld" + rpc :Hello, HelloRequest, HelloResponse, ruby_method: :hello + end + + class HelloWorldClient < ::Twirp::Client + client_for HelloWorldService + end + end + end + EOF + end + end - require "twirp" - require_relative "service_pb" + context "when using a well-named service" do + # The `well_named_service.proto` fixture is copied from `service.proto` and updated + # to name the service properly according to convention. + # + # Generate code gen request fixture: + # `./spec/support/create_fixture -b -f well_named_service_code_gen_request_pb.bin ./spec/fixtures/well_named_service.proto` + let(:well_named_service_code_gen_request_pb) { fixture("well_named_service_code_gen_request_pb.bin").read } - module Example - module HelloWorld - class HelloWorldService < ::Twirp::Service - package "example.hello_world" - service "HelloWorld" - rpc :Hello, HelloRequest, HelloResponse, ruby_method: :hello - end + it "generates expected output" do + response_pb = Twirp::ProtocPlugin.process(well_named_service_code_gen_request_pb) + response = Google::Protobuf::Compiler::CodeGeneratorResponse.decode(response_pb) - class HelloWorldClient < ::Twirp::Client - client_for HelloWorldService + expect(response.supported_features).to eq(Google::Protobuf::Compiler::CodeGeneratorResponse::Feature::FEATURE_PROTO3_OPTIONAL) + expect(response.file.size).to eq(1) + expect(response.file.first.name).to eq("spec/fixtures/well_named_service_twirp.rb") + expect(response.file.first.content).to eq <<~EOF + # frozen_string_literal: true + + # Generated by the protoc-gen-twirp_ruby gem v0.1.0. DO NOT EDIT! + # source: spec/fixtures/well_named_service.proto + + require "twirp" + require_relative "well_named_service_pb" + + module Example + module HelloWorld + class HelloWorldService < ::Twirp::Service + package "example.hello_world" + service "HelloWorldService" + rpc :Hello, HelloRequest, HelloResponse, ruby_method: :hello + end + + class HelloWorldClient < ::Twirp::Client + client_for HelloWorldService + end + end end - end + EOF end - EOF + end end describe "#strip_extension" do