twirp-on-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1bb31fa12f51069d7d6e447901646dd1ebfdc657d59bc670fffc57f8f858b34e
4
+ data.tar.gz: 414f84e6b7b655fabad364721fc6ea31ee94300674303ff633b5bf49434610cd
5
+ SHA512:
6
+ metadata.gz: 986ee79625c2cea727ebbb09b0efb0f110a5e64f3ce5d186dfd2786ceb35d48f88935a43335f4c6740144fa6023cc12107288554d2a3389f37bf3f6ad2b01f21
7
+ data.tar.gz: 68c86eb0918f123e6b96457944347893f96bdfbabe91c4c3f1bd8b0ae75c6eac3b590856f6156c3488ade4a58ebcc906dc566b8c255326da3eb89344796e4a5f
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.standard.yml ADDED
@@ -0,0 +1,4 @@
1
+ ruby_version: 2.7
2
+ plugins:
3
+ - standard-performance
4
+ - standard-rails
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-12-23
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in twirp-rails.gemspec
6
+ gemspec
7
+
8
+ gem "rake"
9
+
10
+ gem "debug"
11
+ gem "rspec-rails"
12
+ gem "sqlite3", "~> 1.4"
13
+ gem "standard"
14
+ gem "standard-performance"
15
+ gem "standard-rails"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022–2023 Collective Idea
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ [![CI](https://github.com/collectiveidea/twirp-rails/actions/workflows/ci.yml/badge.svg)](https://github.com/collectiveidea/twirp-rails/actions/workflows/ci.yml)
2
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
3
+
4
+ # Twirp on Rails (Twirp::Rails)
5
+
6
+ ## Motivation
7
+
8
+ Make serving [Twirp](https://twitchtv.github.io/twirp/) RPC Services as easy and familiar as Rails controllers. Add a few helpful abstractions, but don't hide [Twirp](https://twitchtv.github.io/twirp/), [Protobufs](https://protobuf.dev), or make it seem too magical.
9
+
10
+ Out of the box, the [`twirp` gem](http://github.com/github/twirp-ruby) makes it easy to add [Services](https://github.com/github/twirp-ruby/wiki/Service-Handlers), but it feels clunky coming from Rails REST-ful APIs. We make it simple to build full-featured APIs. Hook in authorization, use `before_action` and more.
11
+
12
+ Extracted from a real, production application with many thousands of users.
13
+
14
+ ## Installation
15
+
16
+ Install the gem and add to the application's Gemfile by executing:
17
+
18
+ $ bundle add twirp-on-rails
19
+
20
+ If bundler is not being used to manage dependencies, install the gem by executing:
21
+
22
+ $ gem install twirp-on-rails
23
+
24
+ ## Usage
25
+
26
+ Add to your `routes.rb`:
27
+
28
+ ```ruby
29
+ mount Twirp::Rails::Engine, at: "/twirp"
30
+ ```
31
+
32
+ ### Configuration
33
+
34
+ Twirp::Rails will automatically load any `*_twirp.rb` files in your app's `lib/` directory (and subdirectories). To modify the location, add this to an initializer:
35
+
36
+ ```ruby
37
+ Rails.application.config.load_paths = ["lib", "app/twirp"]
38
+ ```
39
+
40
+ ## Features
41
+
42
+ ### Easy Routing
43
+
44
+ Add one line to your `config/routes.rb` and routes are built automatically from your Twirp Services:
45
+
46
+ ```ruby
47
+ mount Twirp::Rails::Engine, at: "/twirp"
48
+ ```
49
+
50
+ `/twirp/twirp.example.haberdasher.HaberdasherService/MakeHat`
51
+
52
+ These are routed to Handlers in `app/handlers/` based on expected naming conventions.
53
+
54
+ For example if you have this service defined:
55
+
56
+ ```protobuf
57
+ package twirp.example.haberdasher;
58
+
59
+ service HaberdasherService {
60
+ rpc MakeHat(Size) returns (Hat);
61
+ }
62
+ ```
63
+
64
+ it will expect to find `app/handlers/haberdasher_service_handler.rb` with a `make_hat` method.
65
+
66
+ ```ruby
67
+ class HaberdasherServiceHandler < Twirp::Rails::Handler
68
+ def make_hat
69
+
70
+ end
71
+ end
72
+ ```
73
+
74
+ Each handler method should return the appropriate Protobuf, or a `Twirp::Error`.
75
+
76
+ TODO: Give more examples of both
77
+
78
+ ### Familiar Callbacks
79
+
80
+ Use `before_action`, `around_action`, and other callbacks you're used to, as we build on [AbstractController::Callbacks](https://api.rubyonrails.org/classes/AbstractController/Callbacks.html).
81
+
82
+ ### DRY Service Hooks
83
+
84
+ Apply [Service Hooks](https://github.com/twitchtv/twirp-ruby/wiki/Service-Hooks) one time across multiple services.
85
+
86
+ For example, we can add hooks in an initializer:
87
+
88
+ ```ruby
89
+ # Make IP address accessible to the handlers
90
+ Rails.application.config.twirp.service_hooks[:before] = lambda do |rack_env, env|
91
+ env[:ip] = rack_env["REMOTE_ADDR"]
92
+ end
93
+
94
+ # Send exceptions to Honeybadger
95
+ Rails.application.config.twirp.service_hooks[:exception_raised] = ->(exception, _env) { Honeybadger.notify(exception) }
96
+ ```
97
+
98
+ ### Middleware
99
+
100
+ As an Engine, we avoid all the standard Rails middleware. That's nice for simplicity, but sometimes you want to add your own middleware. You can do that by specifying it in an initializer:
101
+
102
+ ```ruby
103
+ Rails.application.config.twirp.middleware = [Rack::Deflater]
104
+ ```
105
+
106
+ ## Bonus Features
107
+
108
+ Outside the [Twirp spec](https://twitchtv.github.io/twirp/docs/spec_v7.html), we have some (optional) extra magic. They might be useful to you, but you can easily ignore them too.
109
+
110
+ ### Basic Caching with ETags/If-None-Match Headers
111
+
112
+ Like Rails GET actions, Twirp::Rails handlers add [`ETag` headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) based on the response's content.
113
+
114
+ If you have RPCs that can be cached, you can have your Twirp clients send an [`If-None-Match` Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match). Twirp::Rails will return a `304 Not Modified` HTTP status and not re-send the body if the ETag matches.
115
+
116
+ Enable by adding this to an initializer:
117
+
118
+ ```ruby
119
+ Rails.application.config.twirp.middleware = [
120
+ Twirp::Rails::Rack::ConditionalPost,
121
+ Rack::ETag
122
+ ]
123
+ ```
124
+
125
+ ## TODO
126
+
127
+ * More docs!
128
+ * More tests!
129
+ * installer generator to add `ApplicationHandler`
130
+ * Maybe a generator for individual handlers that adds that if needed?
131
+ * Auto reload.
132
+ * Make service hooks more configurable? Apply to one service instead of all?
133
+ * Loosen Rails version requirement? Probably works, but haven't tested.
134
+
135
+ ## Prior Art
136
+
137
+ We evaluated all these projects and found them to be bad fits for us, for one reason or another. We're grateful to all for their work, and hope they continue and flourish. Some notes from our initial evaluation:
138
+
139
+ [nikushi/twirp-rails](https://github.com/nikushi/twirp-rails)
140
+
141
+ * Nice routing abstraction
142
+ * Minimal Handler abstraction
143
+ * Untouched for 4 years
144
+
145
+ [cheddar-me/rails-twirp](https://github.com/cheddar-me/rails-twirp)
146
+
147
+ * Too much setup.
148
+ * Nice controllers, but expects you to use their [pbbuilder](https://github.com/cheddar-me/pbbuilder) which I find unnecessary.
149
+
150
+ [severgroup-tt/twirp_rails-1](https://github.com/severgroup-tt/twirp_rails-1)
151
+
152
+ * Some nice things
153
+ * No Handler abstractions
154
+ * Archived and not touched for 3 years
155
+
156
+ [dudo/rails_respond_to_pb](https://github.com/dudo/rails_respond_to_pb)
157
+
158
+ * Allows routing to existing controllers
159
+ * I dislike the `respond_to` stuff. That shouldn't be something you think about. We have a better way to do that in other recent apps anyway.
160
+
161
+ ## Contributing
162
+
163
+ Bug reports and pull requests are welcome on GitHub at https://github.com/danielmorrison/twirp-rails.
164
+
165
+ ## Development
166
+
167
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
168
+
169
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
170
+
171
+ ## License
172
+
173
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[spec standard]
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ Rails.application.routes.draw do
2
+ if Rails.application.config.twirp.auto_mount
3
+ mount Twirp::Rails::Engine => Rails.application.config.twirp.endpoint
4
+ end
5
+ end
6
+
7
+ Twirp::Rails::Engine.routes.draw do
8
+ Twirp::Rails.services.each do |service|
9
+ mount service, at: service.full_name
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ # The gem _should_ put everyting in twirp/on/rails but I don't like "on"
2
+ # being a directory, so this file just requires twirp/rails.rb.
3
+ require_relative "../rails"
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/callbacks"
5
+ require "abstract_controller/callbacks"
6
+
7
+ module Twirp
8
+ module Rails
9
+ # = Twirp Rails Callbacks
10
+ #
11
+ # Based on Abstract Controller Callbacks with the terminator changed.
12
+ #
13
+ # A before_action that returns a Twirp::Error will halt the action.
14
+ #
15
+ # Abstract Controller provides hooks during the life cycle of a controller action.
16
+ # Callbacks allow you to trigger logic during this cycle. Available callbacks are:
17
+ #
18
+ # * <tt>after_action</tt>
19
+ # * <tt>append_after_action</tt>
20
+ # * <tt>append_around_action</tt>
21
+ # * <tt>append_before_action</tt>
22
+ # * <tt>around_action</tt>
23
+ # * <tt>before_action</tt>
24
+ # * <tt>prepend_after_action</tt>
25
+ # * <tt>prepend_around_action</tt>
26
+ # * <tt>prepend_before_action</tt>
27
+ # * <tt>skip_after_action</tt>
28
+ # * <tt>skip_around_action</tt>
29
+ # * <tt>skip_before_action</tt>
30
+ #
31
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
32
+ #
33
+ module Callbacks
34
+ extend ActiveSupport::Concern
35
+
36
+ include AbstractController::Callbacks
37
+
38
+ included do
39
+ define_callbacks :process_action,
40
+ terminator: ->(controller, result_lambda) {
41
+ # save off the error and terminate if a callback returns a Twirp::Error
42
+ result = result_lambda.call
43
+
44
+ if result.is_a?(Twirp::Error)
45
+ controller.error = result
46
+ true
47
+ else
48
+ false
49
+ end
50
+ },
51
+ skip_after_callbacks_if_terminated: true
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twirp
4
+ module Rails
5
+ class Configuration
6
+ # Whether to automatically mount routes at endpoint. Defaults to false
7
+ attr_accessor :auto_mount
8
+
9
+ # Where to mount twirp routes. Defaults to /twirp
10
+ attr_accessor :endpoint
11
+
12
+ # An array of directories to search for *_twirp.rb files
13
+ # Defaults to ["lib"]
14
+ attr_accessor :load_paths
15
+
16
+ # An array of Rack middleware to use
17
+ attr_accessor :middleware
18
+
19
+ # A hash of lambdas that accepts |rack_env, env| and is passed to Twirp::Service
20
+ # See: https://github.com/twitchtv/twirp-ruby/wiki/Service-Hooks
21
+ # for available hooks
22
+ attr_accessor :service_hooks
23
+
24
+ def initialize
25
+ @auto_mount = false
26
+ @endpoint = "/twirp"
27
+ @load_paths = ["lib"]
28
+ @middleware = []
29
+ @service_hooks = {}
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twirp
4
+ module Rails
5
+ class Dispatcher
6
+ def initialize(service_class)
7
+ @service_handler = "#{service_class.service_name}Handler".constantize
8
+ end
9
+
10
+ def respond_to_missing?(method, *)
11
+ true
12
+ end
13
+
14
+ def method_missing(name, *args)
15
+ request = args[0]
16
+ env = args[1]
17
+ @service_handler.new.process(name, request, env)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/engine"
4
+ require "rack/etag"
5
+ require_relative "rack/conditional_post"
6
+
7
+ module Twirp
8
+ module Rails
9
+ class Engine < ::Rails::Engine
10
+ isolate_namespace Twirp::Rails
11
+ engine_name "twirp"
12
+ # endpoint MyRackApplication
13
+ # # Add a load path for this specific Engine
14
+ # config.autoload_paths << File.expand_path("lib/some/path", __dir__)
15
+
16
+ config.twirp = Configuration.new
17
+
18
+ initializer "twirp.configure.defaults", before: "twirp.configure" do |app|
19
+ twirp = app.config.twirp
20
+ # twirp.auto_mount = true if twirp.auto_mount.nil?
21
+ twirp.load_paths ||= ["lib"]
22
+ end
23
+
24
+ initializer "twirp.configure" do |app|
25
+ [:auto_mount, :endpoint, :load_paths, :middleware, :service_hooks].each do |key|
26
+ app.config.twirp.send(key)
27
+ end
28
+
29
+ app.config.twirp.middleware.each do |middleware|
30
+ app.config.middleware.use middleware
31
+ end
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def services
37
+ if @services.nil?
38
+ ::Rails.application.config.twirp.load_paths.each do |directory|
39
+ ::Rails.root.glob("#{directory}/**/*_twirp.rb").sort.each { |file| require file }
40
+ end
41
+
42
+ @services = Twirp::Service.subclasses.map(&:new)
43
+
44
+ # Install hooks that may be defined in the config
45
+ @services.each do |service|
46
+ ::Rails.application.config.twirp.service_hooks.each do |hook_name, hook|
47
+ service.send(hook_name, &hook)
48
+ end
49
+ end
50
+ end
51
+
52
+ @services
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ class Twirp::Service
59
+ # Override inspect to show all available RPCs
60
+ # This is used when displaying routes.
61
+ def inspect
62
+ self.class.rpcs.map { |rpc| "#{self.class.name.demodulize.underscore}_handler##{rpc[1][:ruby_method]}" }.join("\n")
63
+ end
64
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twirp
4
+ module Rails
5
+ class Handler
6
+ include Twirp::Rails::Callbacks
7
+
8
+ attr_reader :request, :env
9
+ attr_reader :action_name
10
+ attr_accessor :error
11
+
12
+ # @param name [Symbol] The method name to invoke in the handler
13
+ # @param request [Object] The protobuf message request parameter
14
+ # @param env [Hash] The Twirp environment
15
+ def process(name, request, env)
16
+ @request = request
17
+ @env = env
18
+ @error = nil
19
+ @action_name = name.to_s
20
+
21
+ response = process_action(action_name)
22
+ error || response
23
+ end
24
+
25
+ private
26
+
27
+ # Call the action. Override this in a subclass to modify the
28
+ # behavior around processing an action. This, and not #process,
29
+ # is the intended way to override action dispatching.
30
+ #
31
+ # Notice that the first argument is the method to be dispatched
32
+ # which is *not* necessarily the same as the action name.
33
+ def process_action(name)
34
+ ActiveSupport::Notifications.instrument("handler_run_callbacks.twirp_rails", handler: self.class.name, action: action_name, env: @env, request: @request) do
35
+ run_callbacks(:process_action) do
36
+ ActiveSupport::Notifications.instrument("handler_run.twirp_rails", handler: self.class.name, action: action_name, env: @env, request: @request) do |payload|
37
+ payload[:response] = send_action(name)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ # Actually call the method associated with the action. Override
44
+ # this method if you wish to change how action methods are called,
45
+ # not to add additional behavior around it. For example, you would
46
+ # override #send_action if you want to inject arguments into the
47
+ # method.
48
+ alias_method :send_action, :send
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/conditional_get"
4
+
5
+ module Twirp
6
+ module Rails
7
+ module Rack
8
+ # Middleware that enables conditional POST using If-None-Match and
9
+ # If-Modified-Since. The application should set either or both of the
10
+ # Last-Modified or Etag response headers according to RFC 2616. When
11
+ # either of the conditions is met, the response body is set to be zero
12
+ # length and the response status is set to 304 Not Modified.
13
+ #
14
+ # Applications that defer response body generation until the body's each
15
+ # message is received will avoid response body generation completely when
16
+ # a conditional POST matches.
17
+ #
18
+ # Based on Rack::ConditionalGet
19
+ #
20
+ # Twirp requests are, be design, always POST.
21
+ # We want the logic of Rack::ConditionalGet but applied to POSTs.
22
+ #
23
+ # Not all Twirp calls are idemtpotent, so it is left up to the client
24
+ # to know when 304 Not Modified responses are desirable, and send the
25
+ # appropriate header(s).
26
+ class ConditionalPost < ::Rack::ConditionalGet
27
+ # Return empty 304 response if the response has not been
28
+ # modified since the last request.
29
+ def call(env)
30
+ case env[::Rack::REQUEST_METHOD]
31
+ when "POST"
32
+ status, headers, body = @app.call(env)
33
+ headers = ::Rack::Utils::HeaderHash[headers]
34
+ if status == 200 && fresh?(env, headers)
35
+ status = 304
36
+ headers.delete(::Rack::CONTENT_TYPE)
37
+ headers.delete(::Rack::CONTENT_LENGTH)
38
+ original_body = body
39
+ body = ::Rack::BodyProxy.new([]) do
40
+ original_body.close if original_body.respond_to?(:close)
41
+ end
42
+ end
43
+ [status, headers, body]
44
+ else
45
+ @app.call(env)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twirp
4
+ module Rails
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rails/version"
4
+
5
+ module Twirp
6
+ module Rails
7
+ class Error < StandardError; end
8
+ # Your code goes here...
9
+ end
10
+ end
11
+
12
+ require "twirp"
13
+ require "active_support/notifications"
14
+ require_relative "rails/callbacks"
15
+ require_relative "rails/configuration"
16
+ require_relative "rails/dispatcher"
17
+ require_relative "rails/engine"
18
+ require_relative "rails/handler"
19
+
20
+ module Twirp
21
+ class Service
22
+ # Override initialize to make handler argument optional.
23
+ # When left nil, we will use our dispatcher.
24
+ alias_method :original_initialize, :initialize
25
+ def initialize(handler = nil)
26
+ handler ||= Twirp::Rails::Dispatcher.new(self.class)
27
+ original_initialize(handler)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module Twirp
2
+ module Rails
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/twirp/rails/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "twirp-on-rails"
7
+ spec.version = Twirp::Rails::VERSION
8
+ spec.authors = ["Daniel Morrison", "Darron Schall"]
9
+ spec.email = ["info@collectiveidea.com"]
10
+
11
+ spec.summary = "Use Twirp RPC with Rails"
12
+ spec.description = "A simple way to serve Twirp RPC services in a Rails app. Minimial configuration and familiar Rails conventions."
13
+ spec.homepage = "https://github.com/collectiveidea/twirp-rails"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.7.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/collectiveidea/twirp-rails"
19
+ spec.metadata["changelog_uri"] = "https://github.com/collectiveidea/twirp-rails/blob/main/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_dependency "rails", ">= 7.0.0"
33
+ spec.add_dependency "twirp", ">= 1.8.0"
34
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twirp-on-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Morrison
8
+ - Darron Schall
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2024-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 7.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 7.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: twirp
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.8.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 1.8.0
42
+ description: A simple way to serve Twirp RPC services in a Rails app. Minimial configuration
43
+ and familiar Rails conventions.
44
+ email:
45
+ - info@collectiveidea.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - ".rspec"
51
+ - ".standard.yml"
52
+ - CHANGELOG.md
53
+ - Gemfile
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - config/routes.rb
58
+ - lib/twirp/on/rails.rb
59
+ - lib/twirp/rails.rb
60
+ - lib/twirp/rails/callbacks.rb
61
+ - lib/twirp/rails/configuration.rb
62
+ - lib/twirp/rails/dispatcher.rb
63
+ - lib/twirp/rails/engine.rb
64
+ - lib/twirp/rails/handler.rb
65
+ - lib/twirp/rails/rack/conditional_post.rb
66
+ - lib/twirp/rails/version.rb
67
+ - sig/twirp/rails.rbs
68
+ - twirp-rails.gemspec
69
+ homepage: https://github.com/collectiveidea/twirp-rails
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ homepage_uri: https://github.com/collectiveidea/twirp-rails
74
+ source_code_uri: https://github.com/collectiveidea/twirp-rails
75
+ changelog_uri: https://github.com/collectiveidea/twirp-rails/blob/main/CHANGELOG.md
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.7.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.5.9
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Use Twirp RPC with Rails
95
+ test_files: []