twirp 1.2.0 → 1.7.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
- SHA1:
3
- metadata.gz: 83302ec929694b2ac96f016518ad5585de1fa65e
4
- data.tar.gz: c79097cde99163118952b003b1402332f83b8c7f
2
+ SHA256:
3
+ metadata.gz: 3f17d89c29073da7ebffa780c9e8577e10f2537e28900344d8a055e098aa5f3d
4
+ data.tar.gz: 2932fb1abec1db6b14c3b39e8b7d2f81e318c0bdc02639d83a99bdfacd26001f
5
5
  SHA512:
6
- metadata.gz: ba357830275b3b4af11bc6f7319118a17a4405c338592ccb26293a0fed95622612b7f6d167214254eb6b0c05664d91f2ca5c847aeceb171e7c3dd0395f73d7ec
7
- data.tar.gz: '05581b8cb43081e0e0103f6e3c50af6dfa0280b67355307418d287086e0c109e335bd0708f84eed4561eca7c288f1aa98884e71524a797ad07fe081a737efa3f'
6
+ metadata.gz: aca9edc089a15abfe4426880e8db8a8e2cac3f47ff056703e686dc14a3fe879a952a2b96c2de8bb06301b7406262601102c29fe48af6f9ead8775e9e2c76e35b
7
+ data.tar.gz: 10fc31c496e2fa4020ff9a643e08aa9ba333b0baa2324d1a42444ca6916d672a449eeef7ab22e674de81cc7a3e906d82fc97736714dfab29a999bfb4dd191f75
data/README.md CHANGED
@@ -2,19 +2,21 @@
2
2
 
3
3
  [Twirp is a protocol](https://twitchtv.github.io/twirp/docs/spec_v5.html) for routing and serialization of services defined in a [.proto file](https://developers.google.com/protocol-buffers/docs/proto3), allowing easy implementation of RPC services with auto-generated clients in different languages.
4
4
 
5
- The [canonical implementation](https://github.com/twitchtv/twirp) is in Golang. The Twirp-Ruby project in this repository is the Ruby implementation.
5
+ The [canonical implementation](https://github.com/twitchtv/twirp) is in Golang. The Twirp-Ruby project is the official implementation in Ruby for both server and clients.
6
6
 
7
7
 
8
8
  ## Install
9
9
 
10
10
  Add `gem "twirp"` to your Gemfile, or install with `gem install twirp`.
11
11
 
12
+ To auto-generate Ruby code from a proto file, use the `protoc` plugin and the `--ruby_out` option ([see Wiki page](https://github.com/twitchtv/twirp-ruby/wiki/Code-Generation)).
13
+
12
14
 
13
15
  ## Documentation
14
16
 
15
- [Go to the Wiki](https://github.com/twitchtv/twirp-ruby/wiki).
17
+ [On the wiki](https://github.com/twitchtv/twirp-ruby/wiki).
16
18
 
17
19
 
18
20
  ## Contributing
19
21
 
20
- [Go to the CONTRIBUTING file](CONTRIBUTING.md).
22
+ [On the CONTRIBUTING file](CONTRIBUTING.md).
@@ -24,6 +24,7 @@ module Twirp
24
24
 
25
25
  package = opts[:package].to_s
26
26
  service = opts[:service].to_s
27
+ @strict = opts.fetch( :strict, false )
27
28
  raise ArgumentError.new("Missing option :service") if service.empty?
28
29
  @service_full_name = package.empty? ? service : "#{package}.#{service}"
29
30
  end
@@ -33,7 +34,8 @@ module Twirp
33
34
  def rpc(rpc_method, attrs={}, req_opts=nil)
34
35
  body = Encoding.encode_json(attrs)
35
36
 
36
- resp = self.class.make_http_request(@conn, @service_full_name, rpc_method, Encoding::JSON, req_opts, body)
37
+ encoding = @strict ? Encoding::JSON_STRICT : Encoding::JSON
38
+ resp = self.class.make_http_request(@conn, @service_full_name, rpc_method, encoding, req_opts, body)
37
39
  if resp.status != 200
38
40
  return ClientResp.new(nil, self.class.error_from_response(resp))
39
41
  end
@@ -17,13 +17,18 @@ module Twirp
17
17
 
18
18
  module Encoding
19
19
  JSON = "application/json"
20
+ # An opt-in content type useful when curling or manually testing a twirp
21
+ # service. This will fail if unknown fields are encountered. The return
22
+ # content type will be application/json.
23
+ JSON_STRICT = "application/json; strict=true"
20
24
  PROTO = "application/protobuf"
21
25
 
22
26
  class << self
23
27
 
24
28
  def decode(bytes, msg_class, content_type)
25
29
  case content_type
26
- when JSON then msg_class.decode_json(bytes)
30
+ when JSON then msg_class.decode_json(bytes, ignore_unknown_fields: true)
31
+ when JSON_STRICT then msg_class.decode_json(bytes, ignore_unknown_fields: false)
27
32
  when PROTO then msg_class.decode(bytes)
28
33
  else raise ArgumentError.new("Invalid content_type")
29
34
  end
@@ -31,7 +36,7 @@ module Twirp
31
36
 
32
37
  def encode(msg_obj, msg_class, content_type)
33
38
  case content_type
34
- when JSON then msg_class.encode_json(msg_obj)
39
+ when JSON, JSON_STRICT then msg_class.encode_json(msg_obj, emit_defaults: true)
35
40
  when PROTO then msg_class.encode(msg_obj)
36
41
  else raise ArgumentError.new("Invalid content_type")
37
42
  end
@@ -46,7 +51,7 @@ module Twirp
46
51
  end
47
52
 
48
53
  def valid_content_type?(content_type)
49
- content_type == JSON || content_type == PROTO
54
+ content_type == JSON || content_type == PROTO || content_type == JSON_STRICT
50
55
  end
51
56
 
52
57
  def valid_content_types
@@ -16,15 +16,16 @@ module Twirp
16
16
  # Valid Twirp error codes and their mapping to related HTTP status.
17
17
  # This can also be used to check if a code is valid (check if not nil).
18
18
  ERROR_CODES_TO_HTTP_STATUS = {
19
- canceled: 408, # RequestTimeout
20
- invalid_argument: 400, # BadRequest
21
- deadline_exceeded: 408, # RequestTimeout
19
+ canceled: 408, # Request Timeout
20
+ invalid_argument: 400, # Bad Request
21
+ malformed: 400, # Bad Request
22
+ deadline_exceeded: 408, # Request Timeout
22
23
  not_found: 404, # Not Found
23
24
  bad_route: 404, # Not Found
24
25
  already_exists: 409, # Conflict
25
26
  permission_denied: 403, # Forbidden
26
27
  unauthenticated: 401, # Unauthorized
27
- resource_exhausted: 403, # Forbidden
28
+ resource_exhausted: 429, # Too Many Requests
28
29
  failed_precondition: 412, # Precondition Failed
29
30
  aborted: 409, # Conflict
30
31
  out_of_range: 400, # Bad Request
@@ -49,10 +50,10 @@ module Twirp
49
50
  ERROR_CODES_TO_HTTP_STATUS.key? code # one of the valid symbols
50
51
  end
51
52
 
52
- # Use this constructors to ensure the errors have valid error codes. Example:
53
+ # Code constructors to ensure valid error codes. Example:
53
54
  # Twirp::Error.internal("boom")
54
- # Twirp::Error.invalid_argument("foo is mandatory", argument: "foo")
55
- # Twirp::Error.permission_denied("thou shall not pass!", target: "Balrog")
55
+ # Twirp::Error.invalid_argument("foo is mandatory", mymeta: "foobar")
56
+ # Twirp::Error.permission_denied("Thou shall not pass!", target: "Balrog")
56
57
  ERROR_CODES.each do |code|
57
58
  define_singleton_method code do |msg, meta=nil|
58
59
  new(code, msg, meta)
@@ -62,7 +63,7 @@ module Twirp
62
63
  # Wrap another error as a Twirp::Error :internal.
63
64
  def self.internal_with(err)
64
65
  twerr = internal err.message, cause: err.class.name
65
- twerr.cause = err
66
+ twerr.cause = err # availabe in error hook for inspection, but not in the response
66
67
  twerr
67
68
  end
68
69
 
@@ -80,6 +81,7 @@ module Twirp
80
81
  @meta = validate_meta(meta)
81
82
  end
82
83
 
84
+ # Key-value representation of the error. Can be directly serialized into JSON.
83
85
  def to_h
84
86
  h = {
85
87
  code: @code,
@@ -23,10 +23,19 @@ module Twirp
23
23
  extend ServiceDSL
24
24
 
25
25
  class << self
26
- # Raise exceptions instead of handling them with exception_raised hooks.
26
+
27
+ # Whether to raise exceptions instead of handling them with exception_raised hooks.
27
28
  # Useful during tests to easily debug and catch unexpected exceptions.
28
- # Default false.
29
- attr_accessor :raise_exceptions
29
+ attr_accessor :raise_exceptions # Default: false
30
+
31
+ # Rack response with a Twirp::Error
32
+ def error_response(twerr)
33
+ status = Twirp::ERROR_CODES_TO_HTTP_STATUS[twerr.code]
34
+ headers = {'Content-Type' => Encoding::JSON} # Twirp errors are always JSON, even if the request was protobuf
35
+ resp_body = Encoding.encode_json(twerr.to_h)
36
+ [status, headers, [resp_body]]
37
+ end
38
+
30
39
  end
31
40
 
32
41
  def initialize(handler)
@@ -98,29 +107,30 @@ module Twirp
98
107
  private
99
108
 
100
109
  # Parse request and fill env with rpc data.
101
- # Returns a bad_route error if something went wrong.
110
+ # Returns a bad_route error if could not be properly routed to a Twirp method.
111
+ # Returns a malformed error if could not decode the body (either bad JSON or bad Protobuf)
102
112
  def route_request(rack_env, env)
103
113
  rack_request = Rack::Request.new(rack_env)
104
114
 
105
115
  if rack_request.request_method != "POST"
106
- return bad_route_error("HTTP request method must be POST", rack_request)
116
+ return route_err(:bad_route, "HTTP request method must be POST", rack_request)
107
117
  end
108
118
 
109
119
  content_type = rack_request.get_header("CONTENT_TYPE")
110
120
  if !Encoding.valid_content_type?(content_type)
111
- return bad_route_error("Unexpected Content-Type: #{content_type.inspect}. Content-Type header must be one of #{Encoding.valid_content_types.inspect}", rack_request)
121
+ return route_err(:bad_route, "Unexpected Content-Type: #{content_type.inspect}. Content-Type header must be one of #{Encoding.valid_content_types.inspect}", rack_request)
112
122
  end
113
123
  env[:content_type] = content_type
114
124
 
115
125
  path_parts = rack_request.fullpath.split("/")
116
126
  if path_parts.size < 3 || path_parts[-2] != self.full_name
117
- return bad_route_error("Invalid route. Expected format: POST {BaseURL}/#{self.full_name}/{Method}", rack_request)
127
+ return route_err(:bad_route, "Invalid route. Expected format: POST {BaseURL}/#{self.full_name}/{Method}", rack_request)
118
128
  end
119
129
  method_name = path_parts[-1]
120
130
 
121
131
  base_env = self.class.rpcs[method_name]
122
132
  if !base_env
123
- return bad_route_error("Invalid rpc method #{method_name.inspect}", rack_request)
133
+ return route_err(:bad_route, "Invalid rpc method #{method_name.inspect}", rack_request)
124
134
  end
125
135
  env.merge!(base_env) # :rpc_method, :input_class, :output_class
126
136
 
@@ -132,7 +142,7 @@ module Twirp
132
142
  if e.is_a?(Google::Protobuf::ParseError)
133
143
  error_msg += ": #{e.message.strip}"
134
144
  end
135
- return bad_route_error(error_msg, rack_request)
145
+ return route_err(:malformed, error_msg, rack_request)
136
146
  end
137
147
 
138
148
  env[:input] = input
@@ -140,12 +150,11 @@ module Twirp
140
150
  return
141
151
  end
142
152
 
143
- def bad_route_error(msg, req)
144
- Twirp::Error.bad_route msg, twirp_invalid_route: "#{req.request_method} #{req.fullpath}"
153
+ def route_err(code, msg, req)
154
+ Twirp::Error.new code, msg, twirp_invalid_route: "#{req.request_method} #{req.fullpath}"
145
155
  end
146
156
 
147
157
 
148
-
149
158
  # Call handler method and return a Protobuf Message or a Twirp::Error.
150
159
  def call_handler(env)
151
160
  m = env[:ruby_method]
@@ -181,11 +190,7 @@ module Twirp
181
190
  def error_response(twerr, env)
182
191
  begin
183
192
  @on_error.each{|hook| hook.call(twerr, env) }
184
-
185
- status = Twirp::ERROR_CODES_TO_HTTP_STATUS[twerr.code]
186
- resp_body = Encoding.encode_json(twerr.to_h)
187
- [status, error_response_headers, [resp_body]]
188
-
193
+ self.class.error_response(twerr)
189
194
  rescue => e
190
195
  return exception_response(e, env)
191
196
  end
@@ -193,6 +198,7 @@ module Twirp
193
198
 
194
199
  def exception_response(e, env)
195
200
  raise e if self.class.raise_exceptions
201
+
196
202
  begin
197
203
  @exception_raised.each{|hook| hook.call(e, env) }
198
204
  rescue => hook_e
@@ -200,13 +206,7 @@ module Twirp
200
206
  end
201
207
 
202
208
  twerr = Twirp::Error.internal_with(e)
203
- resp_body = Encoding.encode_json(twerr.to_h)
204
- [500, error_response_headers, [resp_body]]
205
- end
206
-
207
- def error_response_headers
208
- # Twirp errors are always JSON, even if the request was protobuf
209
- {'Content-Type' => Encoding::JSON}
209
+ self.class.error_response(twerr)
210
210
  end
211
211
 
212
212
  end
@@ -12,5 +12,5 @@
12
12
  # permissions and limitations under the License.
13
13
 
14
14
  module Twirp
15
- VERSION = "1.2.0"
15
+ VERSION = "1.7.2"
16
16
  end
@@ -29,6 +29,20 @@ class ClientJSONTest < Minitest::Test
29
29
  assert_equal 3, resp.data["blah_resp"]
30
30
  end
31
31
 
32
+ def test_client_json_strict_encoding
33
+ c = Twirp::ClientJSON.new(conn_stub("/my.pkg.Talking/Blah") {|req|
34
+ assert_equal "application/json; strict=true", req.request_headers['Content-Type']
35
+ assert_equal '{"blah1":1,"blah2":2}', req.body # body is json
36
+
37
+ [200, {}, '{"blah_resp": 3}']
38
+ }, package: "my.pkg", service: "Talking", strict: true)
39
+
40
+ resp = c.rpc :Blah, blah1: 1, blah2: 2
41
+ assert_nil resp.error
42
+ refute_nil resp.data
43
+ assert_equal 3, resp.data["blah_resp"]
44
+ end
45
+
32
46
  def test_client_json_error
33
47
  c = Twirp::ClientJSON.new(conn_stub("/Foo/Foomo") {|req|
34
48
  [400, {}, '{"code": "invalid_argument", "msg": "dont like empty"}']
@@ -3,9 +3,9 @@ require 'minitest/autorun'
3
3
  require_relative '../lib/twirp/error'
4
4
 
5
5
  class TestErrorCodes < Minitest::Test
6
-
6
+
7
7
  def test_error_codes
8
- assert_equal 17, Twirp::ERROR_CODES.size
8
+ assert_equal 18, Twirp::ERROR_CODES.size
9
9
 
10
10
  # all codes should be symbols
11
11
  Twirp::ERROR_CODES.each do |code|
@@ -13,13 +13,13 @@ class TestErrorCodes < Minitest::Test
13
13
  end
14
14
 
15
15
  # check some codes
16
- assert_includes Twirp::ERROR_CODES, :internal
16
+ assert_includes Twirp::ERROR_CODES, :internal
17
17
  assert_includes Twirp::ERROR_CODES, :not_found
18
18
  assert_includes Twirp::ERROR_CODES, :invalid_argument
19
19
  end
20
20
 
21
21
  def test_codes_to_http_status
22
- assert_equal 17, Twirp::ERROR_CODES_TO_HTTP_STATUS.size
22
+ assert_equal 18, Twirp::ERROR_CODES_TO_HTTP_STATUS.size
23
23
 
24
24
  assert_equal 404, Twirp::ERROR_CODES_TO_HTTP_STATUS[:not_found]
25
25
  assert_equal 500, Twirp::ERROR_CODES_TO_HTTP_STATUS[:internal]
@@ -52,7 +52,7 @@ class TestTwirpError < Minitest::Test
52
52
  end
53
53
 
54
54
  def test_invalid_constructor # Make sure that only supported codes are implemented (prevent bad metaprogramming)
55
- assert_raises NoMethodError do
55
+ assert_raises NoMethodError do
56
56
  Twirp::invalid_code_error "should fail"
57
57
  end
58
58
  end
@@ -67,7 +67,7 @@ class TestTwirpError < Minitest::Test
67
67
  def test_new_with_valid_metadata
68
68
  err = Twirp::Error.new(:internal, "woops", "meta" => "data", "for this" => "error")
69
69
  assert_equal "data", err.meta["meta"]
70
- assert_equal "error", err.meta["for this"]
70
+ assert_equal "error", err.meta["for this"]
71
71
  assert_nil err.meta["something else"]
72
72
 
73
73
  err = Twirp::Error.new(:internal, "woops", meta: "data")
@@ -78,11 +78,11 @@ class TestTwirpError < Minitest::Test
78
78
  def test_invalid_metadata
79
79
  Twirp::Error.new(:internal, "woops") # ensure the base case doesn't error
80
80
 
81
- assert_raises ArgumentError do
81
+ assert_raises ArgumentError do
82
82
  Twirp::Error.new(:internal, "woops", "string key" => :non_string_value)
83
83
  end
84
84
 
85
- assert_raises ArgumentError do
85
+ assert_raises ArgumentError do
86
86
  Twirp::Error.new(:internal, "woops", "valid key" => "valid val", "bad_one" => 666)
87
87
  end
88
88
  end
@@ -91,8 +91,8 @@ class TestTwirpError < Minitest::Test
91
91
  # returns a hash with attributes
92
92
  err = Twirp::Error.new(:internal, "err msg", "key" => "val")
93
93
  assert_equal({code: :internal, msg: "err msg", meta: {"key" => "val"}}, err.to_h)
94
-
95
- # skips meta if not included
94
+
95
+ # skips meta if not included
96
96
  err = Twirp::Error.new(:internal, "err msg")
97
97
  assert_equal({code: :internal, msg: "err msg"}, err.to_h)
98
98
  end
@@ -12,6 +12,15 @@ class ServiceTest < Minitest::Test
12
12
  Example::Haberdasher.raise_exceptions = true # configure for testing to make debugging easier
13
13
  end
14
14
 
15
+ # Class method to make a Rack response with a Twirp errpr
16
+ def test_service_error_response
17
+ twerr = Twirp::Error.invalid_argument('foo')
18
+ resp = Twirp::Service.error_response(twerr)
19
+ assert_equal 400, resp[0]
20
+ assert_equal 'application/json', resp[1]['Content-Type']
21
+ assert_equal '{"code":"invalid_argument","msg":"foo"}', resp[2][0]
22
+ end
23
+
15
24
  # The rpc DSL should properly build the base Twirp environment for each rpc method.
16
25
  def test_rpcs_accessor
17
26
  assert_equal 1, Example::Haberdasher.rpcs.size
@@ -55,6 +64,24 @@ class ServiceTest < Minitest::Test
55
64
  assert_equal({"inches" => 10, "color" => "white"}, JSON.parse(body[0]))
56
65
  end
57
66
 
67
+ def test_successful_json_strict_request_emit_defaults
68
+ rack_env = json_strict_req "/example.Haberdasher/MakeHat", inches: 0 # default int value
69
+ status, headers, body = haberdasher_service.call(rack_env)
70
+
71
+ assert_equal 200, status
72
+ assert_equal 'application/json; strict=true', headers['Content-Type']
73
+ assert_equal({"inches" => 0, "color" => "white"}, JSON.parse(body[0]))
74
+ end
75
+
76
+ def test_successful_json_request_emit_defaults
77
+ rack_env = json_req "/example.Haberdasher/MakeHat", inches: 0 # default int value
78
+ status, headers, body = haberdasher_service.call(rack_env)
79
+
80
+ assert_equal 200, status
81
+ assert_equal 'application/json', headers['Content-Type']
82
+ assert_equal({"inches" => 0, "color" => "white"}, JSON.parse(body[0]))
83
+ end
84
+
58
85
  def test_successful_proto_request
59
86
  rack_env = proto_req "/example.Haberdasher/MakeHat", Example::Size.new(inches: 10)
60
87
  status, headers, body = haberdasher_service.call(rack_env)
@@ -136,10 +163,10 @@ class ServiceTest < Minitest::Test
136
163
  method: "POST", input: 'bad json', "CONTENT_TYPE" => "application/json"
137
164
  status, headers, body = haberdasher_service.call(rack_env)
138
165
 
139
- assert_equal 404, status
166
+ assert_equal 400, status
140
167
  assert_equal 'application/json', headers['Content-Type']
141
168
  assert_equal({
142
- "code" => 'bad_route',
169
+ "code" => 'malformed',
143
170
  "msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/json: ' +
144
171
  "Error occurred during parsing: Parse error at 'bad json'",
145
172
  "meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
@@ -151,16 +178,39 @@ class ServiceTest < Minitest::Test
151
178
  method: "POST", input: 'bad protobuf', "CONTENT_TYPE" => "application/protobuf"
152
179
  status, headers, body = haberdasher_service.call(rack_env)
153
180
 
154
- assert_equal 404, status
181
+ assert_equal 400, status
155
182
  assert_equal 'application/json', headers['Content-Type']
156
183
  assert_equal({
157
- "code" => 'bad_route',
184
+ "code" => 'malformed',
158
185
  "msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/protobuf: ' +
159
186
  'Error occurred during parsing: Unexpected EOF inside skipped data',
160
187
  "meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
161
188
  }, JSON.parse(body[0]))
162
189
  end
163
190
 
191
+ def test_json_request_ignores_unknown_fields
192
+ rack_env = json_req "/example.Haberdasher/MakeHat", inches: 10, fake: 3
193
+ status, headers, body = haberdasher_service.call(rack_env)
194
+
195
+ assert_equal 200, status
196
+ assert_equal 'application/json', headers['Content-Type']
197
+ assert_equal({"inches" => 10, "color" => "white"}, JSON.parse(body[0]))
198
+ end
199
+
200
+ def test_json_strict_request_fails_unknown_fields
201
+ rack_env = json_strict_req "/example.Haberdasher/MakeHat", inches: 10, fake: 3
202
+ status, headers, body = haberdasher_service.call(rack_env)
203
+
204
+ assert_equal 400, status
205
+ assert_equal 'application/json', headers['Content-Type']
206
+ assert_equal({
207
+ "code" => 'malformed',
208
+ "msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/json; strict=true: ' +
209
+ "Error occurred during parsing: No such field: fake",
210
+ "meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
211
+ }, JSON.parse(body[0]))
212
+ end
213
+
164
214
  def test_bad_route_triggers_on_error_hooks
165
215
  svc = haberdasher_service
166
216
 
@@ -782,6 +832,12 @@ class ServiceTest < Minitest::Test
782
832
  "CONTENT_TYPE" => "application/json"
783
833
  end
784
834
 
835
+ def json_strict_req(path, attrs)
836
+ Rack::MockRequest.env_for path, method: "POST",
837
+ input: JSON.generate(attrs),
838
+ "CONTENT_TYPE" => "application/json; strict=true"
839
+ end
840
+
785
841
  def proto_req(path, proto_message)
786
842
  Rack::MockRequest.env_for path, method: "POST",
787
843
  input: proto_message.class.encode(proto_message),
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.required_ruby_version = '>= 1.9'
22
- spec.add_runtime_dependency 'google-protobuf', '~> 3.0', '>= 3.0.0'
23
- spec.add_runtime_dependency 'faraday', '~> 0' # for clients
22
+ spec.add_runtime_dependency 'google-protobuf', '~> 3.0', '>= 3.7.0'
23
+ spec.add_runtime_dependency 'faraday', '< 2' # for clients
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1'
26
26
  spec.add_development_dependency 'minitest', '>= 5'
27
27
  spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rack', '>= 2.2.3'
28
29
  end
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: 1.2.0
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyrus A. Forbes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-11 00:00:00.000000000 Z
12
+ date: 2020-11-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-protobuf
@@ -20,7 +20,7 @@ dependencies:
20
20
  version: '3.0'
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 3.0.0
23
+ version: 3.7.0
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,21 +30,21 @@ dependencies:
30
30
  version: '3.0'
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
33
+ version: 3.7.0
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: faraday
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - "<"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2'
41
41
  type: :runtime
42
42
  prerelease: false
43
43
  version_requirements: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - "<"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '2'
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: bundler
50
50
  requirement: !ruby/object:Gem::Requirement
@@ -87,6 +87,20 @@ dependencies:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: rack
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 2.2.3
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.2.3
90
104
  description: Twirp is a simple RPC framework with protobuf service definitions. The
91
105
  Twirp gem provides native support for Ruby.
92
106
  email:
@@ -134,15 +148,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
148
  - !ruby/object:Gem::Version
135
149
  version: '0'
136
150
  requirements: []
137
- rubyforge_project:
138
- rubygems_version: 2.6.8
151
+ rubygems_version: 3.0.3
139
152
  signing_key:
140
153
  specification_version: 4
141
154
  summary: Twirp services in Ruby.
142
155
  test_files:
143
- - test/client_json_test.rb
144
156
  - test/client_test.rb
145
157
  - test/error_test.rb
146
- - test/fake_services.rb
147
158
  - test/license_header_test.rb
159
+ - test/fake_services.rb
148
160
  - test/service_test.rb
161
+ - test/client_json_test.rb