twirp 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd5d364eb9a55aa4f9f80a217d0c25a9a3b5377d
4
- data.tar.gz: add09813fd7965e1c510b5774a30445e66859b3e
3
+ metadata.gz: 2de989bef622a106065d7cad486cd575cc10d783
4
+ data.tar.gz: 5e01d8fae314ab0f4c53e64f9ede154aef54eafb
5
5
  SHA512:
6
- metadata.gz: 1a0e61629575ec564449543c16b6c4842541abaea0c97e944318aea5ed385941b155371cbe2926faf2fe0c50824d46d1eb44302bed983749859599b6906d9063
7
- data.tar.gz: f4113090daee32f775653c563fdb2ba60bad0d34ccc0b2287e8636b820288411933d20e41988d43ae17035db737e3e7cdce4079ad888fd16a4fc14a4eb8ee608
6
+ metadata.gz: 609f958dec7ba47552c36bd54a96aa7404e602f56ed669e22401deccf9e4568852beac96d09fe40cf81bf42bc601c811d6165fc1a2b1d67c6b92fa1412c26307
7
+ data.tar.gz: a7414cf878277e142d4b52a1492f03f8e37bfe71fe82ff1046c29199cd9405a5e8e59f4be13b26ecb69ed0d9d689eef98d5378da93ea6fbfa6e365ada542709f
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/README.md CHANGED
@@ -1,3 +1,81 @@
1
1
  # Ruby Twirp
2
2
 
3
3
  Twirp services and clients in Ruby.
4
+
5
+ ### Installation
6
+ Use `go get` to install the ruby_twirp protoc plugin:
7
+ ```
8
+ ➜ go get github.com/cyrusaf/ruby-twirp/protoc-gen-twirp_ruby
9
+ ```
10
+
11
+ You will also need:
12
+ - [protoc](https://github.com/golang/protobuf), the protobuf compiler. You need
13
+ version 3+.
14
+
15
+ ### Haberdasher Example
16
+ See the `examples/` folder for the final product.
17
+
18
+ First create a basic `.proto` file:
19
+ ```
20
+ // haberdasher.proto
21
+ syntax = "proto3";
22
+ package examples;
23
+
24
+ service Haberdasher {
25
+ rpc HelloWorld(HelloWorldRequest) returns (HelloWorldResponse);
26
+ }
27
+
28
+ message HelloWorldRequest {
29
+ string name = 1;
30
+ }
31
+
32
+ message HelloWorldResponse {
33
+ string message = 1;
34
+ }
35
+
36
+ ```
37
+
38
+ Run the `protoc` binary to generate `gen/haberdasher_pb.rb` and `gen/haberdasher_twirp.rb`.
39
+ ```
40
+ ➜ protoc --proto_path=. ./haberdasher.proto --ruby_out=gen --twirp_ruby_out=gen
41
+ ```
42
+
43
+ Write an implementation of our haberdasher service and attach to a rack server:
44
+ ```
45
+ # config.ru
46
+ require 'rack'
47
+ require_relative 'gen/haberdasher_pb.rb'
48
+ require_relative 'gen/haberdasher_twirp.rb'
49
+
50
+ class HaberdasherImplementation
51
+ def HelloWorld(req)
52
+ return Examples::HelloWorldResponse.new(message: "Hello #{req.name}")
53
+ end
54
+ end
55
+
56
+ svc = HaberdasherImplementation.new()
57
+ run Rack::URLMap.new HaberdasherService::PATH_PREFIX => HaberdasherService.new(svc).handler
58
+ ```
59
+
60
+ You can also mount onto a rails service:
61
+ ```
62
+ App::Application.routes.draw do
63
+ svc = HaberdasherImplementation.new()
64
+ mount HaberdasherServer.new(svc).handler, at: HaberdasherServer::PATH_PREFIX
65
+ end
66
+ ```
67
+
68
+ Run `config.ru` to start the server on port 8080:
69
+ ```
70
+ ➜ rackup
71
+ ```
72
+
73
+ `curl` your server to get a response:
74
+ ```
75
+ ➜ curl --request POST \
76
+ --url http://localhost:8080/twirp/examples.Haberdasher/HelloWorld \
77
+ --header 'content-type: application/json' \
78
+ --data '{
79
+ "name": "World"
80
+ }'
81
+ ```
data/examples/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+
2
+ source "https://rubygems.org"
3
+
4
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
5
+
6
+ gem 'twirp'
7
+ gem "rack"
@@ -0,0 +1,17 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ google-protobuf (3.5.1.2)
5
+ rack (2.0.1)
6
+ twirp (0.0.1)
7
+ google-protobuf (>= 3.0.0)
8
+
9
+ PLATFORMS
10
+ ruby
11
+
12
+ DEPENDENCIES
13
+ rack
14
+ twirp
15
+
16
+ BUNDLED WITH
17
+ 1.16.1
@@ -0,0 +1,12 @@
1
+ require 'rack'
2
+ require_relative 'gen/haberdasher_pb.rb'
3
+ require_relative 'gen/haberdasher_twirp.rb'
4
+
5
+ class HaberdasherImplementation
6
+ def HelloWorld(req)
7
+ return Examples::HelloWorldResponse.new(message: "Hello #{req.name}")
8
+ end
9
+ end
10
+
11
+ svc = HaberdasherImplementation.new()
12
+ run Rack::URLMap.new HaberdasherService::PATH_PREFIX => HaberdasherService.new(svc).handler
@@ -0,0 +1,18 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: haberdasher.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "examples.HelloWorldRequest" do
8
+ optional :name, :string, 1
9
+ end
10
+ add_message "examples.HelloWorldResponse" do
11
+ optional :message, :string, 1
12
+ end
13
+ end
14
+
15
+ module Examples
16
+ HelloWorldRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.HelloWorldRequest").msgclass
17
+ HelloWorldResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.HelloWorldResponse").msgclass
18
+ end
@@ -0,0 +1,7 @@
1
+ # Code generated by protoc-gen-twirp_ruby, DO NOT EDIT.
2
+ require 'twirp'
3
+
4
+ class HaberdasherService < Twirp::Service
5
+ PATH_PREFIX = "/twirp/examples.Haberdasher"
6
+ rpc :HelloWorld, Examples::HelloWorldRequest, Examples::HelloWorldResponse
7
+ end
@@ -0,0 +1,14 @@
1
+ syntax = "proto3";
2
+ package examples;
3
+
4
+ service Haberdasher {
5
+ rpc HelloWorld(HelloWorldRequest) returns (HelloWorldResponse);
6
+ }
7
+
8
+ message HelloWorldRequest {
9
+ string name = 1;
10
+ }
11
+
12
+ message HelloWorldResponse {
13
+ string message = 1;
14
+ }
data/lib/twirp.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require_relative 'twirp/version'
2
2
  require_relative 'twirp/error'
3
+ require_relative 'twirp/service'
@@ -1,5 +1,5 @@
1
1
  module Twirp
2
- class Server
2
+ class Service
3
3
  @@rpcs = {}
4
4
 
5
5
  def initialize(svc)
@@ -34,13 +34,13 @@ module Twirp
34
34
 
35
35
  def serve_json(req, method_name, request_class, response_class)
36
36
  params = request_class.decode_json(req.body.read)
37
- resp = @svc.send(method_name.underscore, params)
37
+ resp = @svc.send(method_name, params)
38
38
  self.serve_success_json(response_class.encode_json(resp))
39
39
  end
40
40
 
41
41
  def serve_proto(req, method_name, request_class, response_class)
42
42
  params = request_type.decode(req.body.read)
43
- resp = @svc.send(method_name.underscore, params)
43
+ resp = @svc.send(method_name, params)
44
44
  self.serve_success_proto(response_class.encode(resp))
45
45
  end
46
46
 
data/lib/twirp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Twirp
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -72,14 +72,15 @@ func (g *generator) generateFile(file *descriptor.FileDescriptorProto) *plugin.C
72
72
  g.P(`# Code generated by protoc-gen-twirp_ruby, DO NOT EDIT.`)
73
73
  for _, service := range file.Service {
74
74
  serviceName := serviceName(service)
75
+ g.P(`require 'twirp'`)
75
76
  g.P(``)
76
- g.P(fmt.Sprintf("class %s < Twirp::Server", serviceName))
77
- g.P(fmt.Sprintf(`PATH_PREFIX = "/twirp/%s.%s"`, pkgName, serviceName))
77
+ g.P(fmt.Sprintf("class %sService < Twirp::Service", serviceName))
78
+ g.P(fmt.Sprintf(` PATH_PREFIX = "/twirp/%s.%s"`, pkgName, serviceName))
78
79
  for _, method := range service.GetMethod() {
79
80
  methName := methodName(method)
80
81
  inputName := methodInputName(method)
81
82
  outputName := methodOutputName(method)
82
- g.P(fmt.Sprintf(" rpc :%s, %s, %s", methName, inputName, outputName))
83
+ g.P(fmt.Sprintf(" rpc :%s, %s::%s, %s::%s", methName, CamelCase(pkgName), inputName, CamelCase(pkgName), outputName))
83
84
  }
84
85
  g.P(`end`)
85
86
  }
@@ -183,3 +184,61 @@ func writeResponse(w io.Writer, resp *plugin.CodeGeneratorResponse) {
183
184
  Fail(err.Error(), "writing response")
184
185
  }
185
186
  }
187
+
188
+ // CamelCase converts a string from snake_case to CamelCased.
189
+ //
190
+ // If there is an interior underscore followed by a lower case letter, drop the
191
+ // underscore and convert the letter to upper case. There is a remote
192
+ // possibility of this rewrite causing a name collision, but it's so remote
193
+ // we're prepared to pretend it's nonexistent - since the C++ generator
194
+ // lowercases names, it's extremely unlikely to have two fields with different
195
+ // capitalizations. In short, _my_field_name_2 becomes XMyFieldName_2.
196
+ func CamelCase(s string) string {
197
+ if s == "" {
198
+ return ""
199
+ }
200
+ t := make([]byte, 0, 32)
201
+ i := 0
202
+ if s[0] == '_' {
203
+ // Need a capital letter; drop the '_'.
204
+ t = append(t, 'X')
205
+ i++
206
+ }
207
+ // Invariant: if the next letter is lower case, it must be converted
208
+ // to upper case.
209
+ //
210
+ // That is, we process a word at a time, where words are marked by _ or upper
211
+ // case letter. Digits are treated as words.
212
+ for ; i < len(s); i++ {
213
+ c := s[i]
214
+ if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
215
+ continue // Skip the underscore in s.
216
+ }
217
+ if isASCIIDigit(c) {
218
+ t = append(t, c)
219
+ continue
220
+ }
221
+ // Assume we have a letter now - if not, it's a bogus identifier. The next
222
+ // word is a sequence of characters that must start upper case.
223
+ if isASCIILower(c) {
224
+ c ^= ' ' // Make it a capital letter.
225
+ }
226
+ t = append(t, c) // Guaranteed not lower case.
227
+ // Accept lower case sequence that follows.
228
+ for i+1 < len(s) && isASCIILower(s[i+1]) {
229
+ i++
230
+ t = append(t, s[i])
231
+ }
232
+ }
233
+ return string(t)
234
+ }
235
+
236
+ // Is c an ASCII lower-case letter?
237
+ func isASCIILower(c byte) bool {
238
+ return 'a' <= c && c <= 'z'
239
+ }
240
+
241
+ // Is c an ASCII digit?
242
+ func isASCIIDigit(c byte) bool {
243
+ return '0' <= c && c <= '9'
244
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twirp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyrus A. Forbes
@@ -48,12 +48,19 @@ executables: []
48
48
  extensions: []
49
49
  extra_rdoc_files: []
50
50
  files:
51
+ - ".gitignore"
51
52
  - Gemfile
52
53
  - Gemfile.lock
53
54
  - README.md
55
+ - examples/Gemfile
56
+ - examples/Gemfile.lock
57
+ - examples/config.ru
58
+ - examples/gen/haberdasher_pb.rb
59
+ - examples/gen/haberdasher_twirp.rb
60
+ - examples/haberdasher.proto
54
61
  - lib/twirp.rb
55
62
  - lib/twirp/error.rb
56
- - lib/twirp/server.rb
63
+ - lib/twirp/service.rb
57
64
  - lib/twirp/version.rb
58
65
  - protoc-gen-twirp_ruby/main.go
59
66
  - test/error_test.rb