twirp_rails 0.4.2 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9815b0f64ccd2cf6527a6490bf58d33bf9603e50ed403977c6f2cc345fdd38e7
4
- data.tar.gz: 486da8791965cbf5c167968c1caf72651d304c5eb4f73f418bcef7c0140d2810
3
+ metadata.gz: f6df8a4134b84a9843ad8a0db616c68dee24c88e95346ef48a34db3907f5d975
4
+ data.tar.gz: b113bc311403756b83e6e1464a02504dbd37a6f849a3f3789e22e594191643b0
5
5
  SHA512:
6
- metadata.gz: 8968da209d19ab694bd5c26f3ea568dfecb7c249ddf5501b2b213b0c1502a925330ab1554344a1f862bd00a8497cf2dd51f3e0c64bfb55968ddfa89efb893dec
7
- data.tar.gz: 04040171424b881f5746ba5edad5ce19f4cf1e90155dec5eccf8e5bbee4f67b2411cd258bf4f34f8c8765b6e479aa42877addeee9235d2596464354f36e4e500
6
+ metadata.gz: 8b63a508a6319c3a1d4977c807bc95b9d262e42fca622fe04f1f350c12aa3716eb53873ce8389cc6515d1aa8a60f0c353713af12846d83d4da2a74c80098df1e
7
+ data.tar.gz: b5b8cbf244043de39bf8ae47fcc1569c877e199f9489e87db867a4ee467f099328aad9759e3d11ec34fbd8cb86761d566cdca77606f0c81e09e7ea62b64d3e6e
@@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 0.4.4 - 2020-05-05
8
+
9
+ ### Added
10
+
11
+ - ability to translate twirp errors to exceptions and vise versa.
12
+
13
+ ## 0.4.3 - 2020-04-14
14
+
15
+ ### Fixed
16
+
17
+ - autorequire all ruby files from `lib/twirp_clients` folder.
18
+
19
+ ## 0.4.2 - 2020-04-01
20
+
21
+ ### Added
22
+
23
+ - `to_twirp` extension use model method unless attribute found
24
+
7
25
  ## 0.4.1 - 2020-03-30
8
26
 
9
27
  ### Added
@@ -1,35 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- twirp_rails (0.4.2)
4
+ twirp_rails (0.4.5)
5
5
  railties (~> 6.0)
6
6
  twirp (~> 1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionpack (6.0.2.1)
12
- actionview (= 6.0.2.1)
13
- activesupport (= 6.0.2.1)
11
+ actionpack (6.0.3.1)
12
+ actionview (= 6.0.3.1)
13
+ activesupport (= 6.0.3.1)
14
14
  rack (~> 2.0, >= 2.0.8)
15
15
  rack-test (>= 0.6.3)
16
16
  rails-dom-testing (~> 2.0)
17
17
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
- actionview (6.0.2.1)
19
- activesupport (= 6.0.2.1)
18
+ actionview (6.0.3.1)
19
+ activesupport (= 6.0.3.1)
20
20
  builder (~> 3.1)
21
21
  erubi (~> 1.4)
22
22
  rails-dom-testing (~> 2.0)
23
23
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
- activesupport (6.0.2.1)
24
+ activesupport (6.0.3.1)
25
25
  concurrent-ruby (~> 1.0, >= 1.0.2)
26
26
  i18n (>= 0.7, < 2)
27
27
  minitest (~> 5.1)
28
28
  tzinfo (~> 1.1)
29
- zeitwerk (~> 2.2)
29
+ zeitwerk (~> 2.2, >= 2.2.2)
30
30
  builder (3.2.4)
31
31
  coderay (1.1.2)
32
- concurrent-ruby (1.1.5)
32
+ concurrent-ruby (1.1.6)
33
33
  crass (1.0.6)
34
34
  diff-lcs (1.3)
35
35
  erubi (1.9.0)
@@ -38,22 +38,22 @@ GEM
38
38
  generator_spec (0.9.4)
39
39
  activesupport (>= 3.0.0)
40
40
  railties (>= 3.0.0)
41
- google-protobuf (3.11.4-universal-darwin)
41
+ google-protobuf (3.12.0)
42
42
  i18n (1.8.2)
43
43
  concurrent-ruby (~> 1.0)
44
- loofah (2.4.0)
44
+ loofah (2.5.0)
45
45
  crass (~> 1.0.2)
46
46
  nokogiri (>= 1.5.9)
47
47
  method_source (0.9.2)
48
48
  mini_portile2 (2.4.0)
49
- minitest (5.14.0)
49
+ minitest (5.14.1)
50
50
  multipart-post (2.1.1)
51
- nokogiri (1.10.8)
51
+ nokogiri (1.10.9)
52
52
  mini_portile2 (~> 2.4.0)
53
53
  pry (0.12.2)
54
54
  coderay (~> 1.1.0)
55
55
  method_source (~> 0.9.0)
56
- rack (2.1.1)
56
+ rack (2.2.2)
57
57
  rack-test (1.1.0)
58
58
  rack (>= 1.0, < 3)
59
59
  rails-dom-testing (2.0.3)
@@ -61,9 +61,9 @@ GEM
61
61
  nokogiri (>= 1.6)
62
62
  rails-html-sanitizer (1.3.0)
63
63
  loofah (~> 2.3)
64
- railties (6.0.2.1)
65
- actionpack (= 6.0.2.1)
66
- activesupport (= 6.0.2.1)
64
+ railties (6.0.3.1)
65
+ actionpack (= 6.0.3.1)
66
+ activesupport (= 6.0.3.1)
67
67
  method_source
68
68
  rake (>= 0.8.7)
69
69
  thor (>= 0.20.3, < 2.0)
@@ -91,12 +91,12 @@ GEM
91
91
  rspec-support (3.9.2)
92
92
  thor (1.0.1)
93
93
  thread_safe (0.3.6)
94
- twirp (1.4.1)
95
- faraday (~> 0)
94
+ twirp (1.5.0)
95
+ faraday (< 2)
96
96
  google-protobuf (~> 3.0, >= 3.0.0)
97
- tzinfo (1.2.6)
97
+ tzinfo (1.2.7)
98
98
  thread_safe (~> 0.1)
99
- zeitwerk (2.2.2)
99
+ zeitwerk (2.3.0)
100
100
 
101
101
  PLATFORMS
102
102
  ruby
data/README.md CHANGED
@@ -9,6 +9,7 @@ TwirpRails helps to use [twirp-ruby gem](https://github.com/twitchtv/twirp-ruby)
9
9
  * `mount_twirp` route helper to mount handlers
10
10
  * `rpc` helper to dry your handlers specs
11
11
  * ability to log twirp calls by Rails logger
12
+ * DSL to translate handler exceptions to twirp errors and client twirp errors to ruby exceptions
12
13
 
13
14
  ## Installation
14
15
 
@@ -151,6 +152,53 @@ generated by
151
152
  $ rails g twirp:init
152
153
  ```
153
154
 
155
+ ## Exception handling
156
+
157
+ Translate handler exceptions to twirp errors and client twirp errors to ruby exceptions.
158
+
159
+ This feature allow to use ruby style exception handling flow in ruby code.
160
+
161
+ Create class to describe translate error rules
162
+ ```ruby
163
+ class ErrorTranslator < TwirpRails::ErrorHandling::Base
164
+ # rules to translate exception raised by handler to twirp
165
+ translate_exception ArgumentError, with: :invalid_argument
166
+ translate_exception ActiveRecord::NotFound do |exception, handler|
167
+ Twirp::Error.not_found
168
+ end
169
+
170
+ # rules to translate twirp errors returned from client to exception
171
+ translate_error :invalid_argument, with: ArgumentError
172
+ translate_error :not_found do |error, client|
173
+ ActiveRecord::NotFound.new(error.msg)
174
+ end
175
+ end
176
+ ```
177
+
178
+ And configure TwirpRails to use it:
179
+ ```ruby
180
+ # config/initializers/twirp_ruby.rb
181
+ # ...
182
+ config.twirp_exception_translator_class = 'ErrorTranslator'
183
+ # ...
184
+ ```
185
+
186
+ Services mounted by ```mount_twirp``` translates raised exception to twirp errors by this rules.
187
+
188
+ To raise errors by clients, you should create client by `TwirpRails.client`
189
+
190
+ ```ruby
191
+ client = TwirpRails.client(PeopleClient, 'http://localhost:3000/twirp')
192
+
193
+ client.get_name(uid: 'not found').error
194
+ # Twirp::Error code:not_found msg:"Couldn't find User with 'uid'='not found'"
195
+ client.get_name(uid: 'not found').data.name # NoMethodError: undefined method `name' for nil:NilClass
196
+
197
+ # use bang method to raise translated error and didn't check each twirp call result error
198
+ client.get_name!(uid: 'not found').data.name # ActiveRecord::NotFound: undefined method `name' for nil:NilClass
199
+ ```
200
+
201
+
154
202
  ## API acronym
155
203
 
156
204
  Gem adds inflector acronym `API` to correct using services with suffix `API`.
@@ -5,6 +5,7 @@ require 'twirp_rails/engine'
5
5
  require 'twirp_rails/generators/generators'
6
6
  require 'twirp_rails/active_record_extension'
7
7
  require 'twirp_rails/log_subscriber'
8
+ require 'twirp_rails/error_handling/error_handling'
8
9
 
9
10
  module TwirpRails
10
11
  class Error < StandardError; end
@@ -61,6 +62,8 @@ module TwirpRails
61
62
  config_param :purge_old_twirp_code, true
62
63
 
63
64
  config_param :add_api_acronym, true
65
+
66
+ config_param :twirp_exception_translator_class, nil
64
67
  end
65
68
 
66
69
  def self.configuration
@@ -119,4 +122,21 @@ module TwirpRails
119
122
 
120
123
  Time.zone.at seconds
121
124
  end
125
+
126
+ # Utility for converting a Ruby Time instance to a
127
+ # Google::Protobuf::Timestamp.
128
+ #
129
+ # @param time [Time] The Time to be converted.
130
+ #
131
+ # @return [Google::Protobuf::Timestamp] The converted
132
+ # Google::Protobuf::Timestamp.
133
+ def self.time_to_timestamp(time)
134
+ Google::Protobuf::Timestamp.new(seconds: time.to_i, nanos: time.nsec)
135
+ end
136
+
137
+ def self.client(klass, url)
138
+ client = klass.new(url)
139
+
140
+ TwirpRails::ErrorHandling.wrap_client(client)
141
+ end
122
142
  end
@@ -0,0 +1,114 @@
1
+ require 'twirp'
2
+
3
+ module TwirpRails
4
+ module ErrorHandling
5
+ class Base
6
+ ExceptionHandler = Struct.new(:exception, :proc) do
7
+ def match?(exception)
8
+ exception.is_a?(self.exception)
9
+ end
10
+
11
+ def handle(exception, handler)
12
+ proc.call(exception, handler)
13
+ end
14
+
15
+ def process(exception, handler)
16
+ match?(exception) ? handle(exception, handler) : nil
17
+ end
18
+ end
19
+
20
+ ErrorHandler = Struct.new(:code, :proc) do
21
+ def match?(error)
22
+ error.code == self.code
23
+ end
24
+
25
+ def handle(error, client)
26
+ proc.call(error, client)
27
+ end
28
+
29
+ def process(error, client)
30
+ match?(error) ? handle(error, client) : nil
31
+ end
32
+ end
33
+
34
+ class << self
35
+ # translate_exception InvalidArgument, :invalid_argument
36
+ #
37
+ # translate_exception StandardError { |exception, service| Twirp::Error.internal_with exception }
38
+ def translate_exception(*exceptions, with: nil, &block)
39
+ raise 'unexpected with and block' if block_given? && with
40
+ raise 'with or block must be defined' unless block_given? || with
41
+
42
+
43
+ proc = if with
44
+ raise "invalid twirp code #{with}" unless ::Twirp::ERROR_CODES.include?(with)
45
+
46
+ proc do |exception, _service|
47
+ ::Twirp::Error.new(with, exception.message).tap { |t| t.cause = exception }
48
+ end
49
+ else
50
+ proc { |exception, service| block.call(exception, service) }
51
+ end
52
+
53
+ exceptions.each do |exception|
54
+ exception_handlers << ExceptionHandler.new(exception, proc)
55
+ end
56
+ end
57
+
58
+ # translate_error :invalid_argument, InvalidArgument
59
+ #
60
+ # translate_error :internal_error { |error, client| StandardError.new(error.msg) }
61
+ def translate_error(*codes, with: nil, &block)
62
+ raise 'unexpected with and block' if block_given? && with.nil?
63
+ raise 'with or block must be defined' unless block_given? || !with.nil?
64
+ raise "invalid twirp code(s) #{codes - ::Twirp::ERROR_CODES}" if (codes - ::Twirp::ERROR_CODES).any?
65
+
66
+ proc = if with
67
+ raise 'with should be a exception class' unless with.is_a?(Class)
68
+
69
+ proc { |error, _client| with.new error.msg }
70
+ else
71
+ proc { |error, client| block.call(error, client) }
72
+ end
73
+
74
+ codes.each do |code|
75
+ error_handlers << ErrorHandler.new(code, proc)
76
+ end
77
+ end
78
+
79
+ def exception_handlers
80
+ @exception_handlers ||= []
81
+ end
82
+
83
+ def error_handlers
84
+ @error_handlers ||= []
85
+ end
86
+
87
+ def exception_to_twirp(exception, handler)
88
+ result = nil
89
+
90
+ exception_handlers.take_while do |exception_handler|
91
+ result = exception_handler.process(exception, handler)
92
+
93
+ result.nil?
94
+ end
95
+
96
+ result || ::Twirp::Error.internal_with(exception)
97
+ end
98
+
99
+ def twirp_to_exception(error, client)
100
+ result = nil
101
+
102
+ error_handlers.take_while do |handler|
103
+ result = handler.process(error, client)
104
+
105
+ result.nil?
106
+ end
107
+
108
+ result || StandardError.new(error.msg)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,2 @@
1
+ require 'twirp_rails/error_handling/base'
2
+ require 'twirp_rails/error_handling/error_handling_factory'
@@ -0,0 +1,82 @@
1
+ module TwirpRails
2
+ class ErrorHandlingFactory
3
+ class HandlerProxy
4
+ attr_reader :handler, :translator_class
5
+
6
+ def initialize(handler, translator_class)
7
+ @handler = handler
8
+ @translator_class = translator_class
9
+ end
10
+
11
+ # rubocop:disable Style/MethodMissingSuper
12
+ def method_missing(method, *args)
13
+ handler.public_send method, *args
14
+ rescue => e
15
+ translator_class.exception_to_twirp(e, handler)
16
+ end
17
+ # rubocop:enable Style/MethodMissingSuper
18
+
19
+ def respond_to_missing?(method, include_all = false)
20
+ handler.respond_to?(method, include_all)
21
+ end
22
+ end
23
+
24
+ class ClientProxy
25
+ attr_reader :client, :translator_class
26
+
27
+ def initialize(client, translator_class)
28
+ @client = client
29
+ @translator_class = translator_class
30
+ end
31
+
32
+ def raise_on_error(twirp_result)
33
+ if twirp_result.error
34
+ exception = translator_class.twirp_to_exception(twirp_result.error)
35
+ raise exception
36
+ else
37
+ twirp_result
38
+ end
39
+ end
40
+
41
+ # rubocop:disable Style/MethodMissingSuper
42
+ def method_missing(method, *args)
43
+ if method =~ /!$/
44
+ # when we call a bang version of client method - raise exception translated from error
45
+ method = method[0..-2]
46
+ raise_on_error client.public_send(method, args)
47
+ else
48
+ client.public_send method, args
49
+ end
50
+ end
51
+ # rubocop:enable Style/MethodMissingSuper
52
+
53
+ def respond_to_missing?(method, include_all = false)
54
+ handler.respond_to?(method, include_all)
55
+ end
56
+ end
57
+
58
+ class << self
59
+ attr_reader :translator_class
60
+
61
+ def wrap_handler(handler)
62
+ enable_handling? ? HandlerProxy.new(handler, translator_class) : handler
63
+ end
64
+
65
+ def wrap_client(client)
66
+ enable_handling? ? ClientProxy.new(client, translator_class) : client
67
+ end
68
+
69
+ def enable_handling?
70
+ if @enable_handling.nil?
71
+ if (@translator_class = TwirpRails.configuration.twirp_exception_translator_class)
72
+ @translator_class = @translator_class.constantize unless @translator_class.is_a?(Class)
73
+ @enable_handling = true
74
+ else
75
+ @enable_handling = false
76
+ end
77
+ end
78
+ @enable_handling
79
+ end
80
+ end
81
+ end
82
+ end
@@ -25,4 +25,18 @@ TwirpRails.configure do |config|
25
25
  #
26
26
  # Add API acronym to inflector
27
27
  # config.add_api_acronym = true
28
+ #
29
+ # Translate exceptions to Twirp::Error on services and
30
+ # Twirp::Error to exceptions. To use service translation you
31
+ # should mount service via mount_twirp. To use client translation
32
+ # create client via TwirpRails.client(ClientClass, url) and
33
+ # call bang methods. E.g. client.hello! throws exception if returns error.
34
+ #
35
+ # class SampleTranslator < TwirpRails::ErrorHandling::Base
36
+ # translate_exception Mongoid::Errors::DocumentNotFound, with: :not_found
37
+ # translate_error :not_found, with: Mongoid::Errors::DocumentNotFound
38
+ # end
39
+ # config.twirp_exception_translator_class = 'SampleTranslator'
40
+ # default:
41
+ # config.twirp_exception_translator_class = nil
28
42
  end
@@ -3,7 +3,7 @@ class ProtocAdapter
3
3
 
4
4
  attr_reader :twirp_plugin_path, :swagger_plugin_path, :protoc_path
5
5
 
6
- def initialize(src_path, dst_path, swagger_out_path: nil)
6
+ def initialize(src_path, dst_path, swagger_out_path)
7
7
  @src_path = src_path
8
8
  @dst_path = dst_path
9
9
  @swagger_out_path = swagger_out_path
@@ -28,17 +28,8 @@ class ProtocAdapter
28
28
  end
29
29
  end
30
30
 
31
- def cmd(files, gen_swagger: false)
32
- flags = "--proto_path=#{src_path} " \
33
- "--ruby_out=#{dst_path} --twirp_ruby_out=#{dst_path} " \
34
- "--plugin=#{twirp_plugin_path}"
35
-
36
- if gen_swagger
37
- flags += " --plugin=#{swagger_plugin_path}" \
38
- " --twirp_swagger_out=#{swagger_out_path}"
39
- end
40
-
41
- "#{protoc_path} #{flags} #{files}"
31
+ def cmd(files, gen_swagger)
32
+ "#{protoc_path} #{flags(gen_swagger)} #{files}"
42
33
  end
43
34
 
44
35
  def check_requirements(check_swagger: false)
@@ -62,4 +53,20 @@ class ProtocAdapter
62
53
  TEXT
63
54
  end
64
55
  end
56
+
57
+ private
58
+
59
+ def flags(gen_swagger)
60
+ [].tap do |flags|
61
+ flags << "--proto_path=#{src_path}"
62
+ flags << "--ruby_out=#{dst_path}"
63
+ flags << "--twirp_ruby_out=#{dst_path}"
64
+ flags << "--plugin=#{twirp_plugin_path}"
65
+
66
+ if gen_swagger
67
+ flags << "--plugin=#{swagger_plugin_path}"
68
+ flags << "--twirp_swagger_out=#{swagger_out_path}"
69
+ end
70
+ end.join(' ')
71
+ end
65
72
  end
@@ -3,7 +3,7 @@ require 'rails/generators'
3
3
  class TwirpGenerator < Rails::Generators::NamedBase
4
4
  source_root File.expand_path('templates', __dir__)
5
5
 
6
- class_option :skip_swagger, type: :boolean, default: false
6
+ class_option :gen_swagger, type: :boolean, default: false
7
7
  class_option :swagger_out, type: :string, default: nil
8
8
 
9
9
  def smart_detect_proto_file_name
@@ -67,9 +67,9 @@ class TwirpGenerator < Rails::Generators::NamedBase
67
67
  proto_files.each do |file|
68
68
  gen_swagger = gen_swagger? && file =~ %r{/#{file_name}\.proto$}
69
69
 
70
- FileUtils.mkdir_p swagger_out_path if gen_swagger
70
+ FileUtils.mkdir_p cfg.swagger_output_path if gen_swagger
71
71
 
72
- cmd = protoc.cmd(file, gen_swagger: gen_swagger)
72
+ cmd = protoc.cmd(file, gen_swagger)
73
73
 
74
74
  protoc_files_count += 1
75
75
  swagger_files_count += gen_swagger ? 1 : 0
@@ -188,11 +188,7 @@ class TwirpGenerator < Rails::Generators::NamedBase
188
188
  end
189
189
 
190
190
  def gen_swagger?
191
- !options[:skip_swagger] && cfg.swagger_output_path
192
- end
193
-
194
- def swagger_out_path
195
- options[:swagger_out] || cfg.swagger_output_path
191
+ options[:gen_swagger] && cfg.swagger_output_path.present?
196
192
  end
197
193
 
198
194
  def abort(msg)
@@ -200,6 +196,6 @@ class TwirpGenerator < Rails::Generators::NamedBase
200
196
  end
201
197
 
202
198
  def protoc
203
- @protoc ||= ProtocAdapter.new(src_path, dst_path, swagger_out_path: swagger_out_path)
199
+ @protoc ||= ProtocAdapter.new(src_path, dst_path, cfg.swagger_output_path)
204
200
  end
205
201
  end
@@ -25,7 +25,7 @@ module TwirpRails
25
25
  raise 'twirp service name required'
26
26
  end
27
27
 
28
- service = service_class.new(handler.new)
28
+ service = service_class.new(ErrorHandlingFactory.wrap_handler(handler.new))
29
29
  Helper.run_create_hooks service
30
30
 
31
31
  if scope
@@ -65,7 +65,7 @@ module TwirpRails
65
65
  end
66
66
 
67
67
  included do
68
- let(:handler) { described_class.new }
68
+ let(:handler) { TwirpRails::ErrorHandlingFactory.wrap_handler(described_class.new) }
69
69
  let(:service) { service_class.new(handler) }
70
70
  end
71
71
  end
@@ -4,7 +4,7 @@ module TwirpRails
4
4
  # protoc generates require without path in a _pb files
5
5
  $LOAD_PATH.unshift(twirp_path) unless $LOAD_PATH.include?(twirp_path)
6
6
 
7
- Dir.glob(Rails.root.join('lib/twirp/**/*_twirp.rb')).sort.each do |file|
7
+ Dir.glob(Rails.root.join(twirp_path, '**/*_twirp.rb')).sort.each do |file|
8
8
  require file
9
9
  end
10
10
  end
@@ -1,3 +1,3 @@
1
1
  module TwirpRails
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '0.4.7'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twirp_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandr Zimin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-01 00:00:00.000000000 Z
11
+ date: 2020-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: twirp
@@ -142,6 +142,9 @@ files:
142
142
  - lib/twirp_rails.rb
143
143
  - lib/twirp_rails/active_record_extension.rb
144
144
  - lib/twirp_rails/engine.rb
145
+ - lib/twirp_rails/error_handling/base.rb
146
+ - lib/twirp_rails/error_handling/error_handling.rb
147
+ - lib/twirp_rails/error_handling/error_handling_factory.rb
145
148
  - lib/twirp_rails/generators/generators.rb
146
149
  - lib/twirp_rails/generators/twirp/USAGE
147
150
  - lib/twirp_rails/generators/twirp/clients/USAGE
@@ -179,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
182
  - !ruby/object:Gem::Version
180
183
  version: '0'
181
184
  requirements: []
182
- rubygems_version: 3.0.6
185
+ rubygems_version: 3.1.3
183
186
  signing_key:
184
187
  specification_version: 4
185
188
  summary: Use twirp-ruby from rails.