rails_twirp 0.2.0 → 0.3.0

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +21 -0
  3. data/.gitignore +1 -0
  4. data/.standard.yml +4 -0
  5. data/Gemfile +3 -3
  6. data/lib/rails_twirp.rb +1 -0
  7. data/lib/rails_twirp/base.rb +29 -10
  8. data/lib/rails_twirp/engine.rb +11 -6
  9. data/lib/rails_twirp/errors.rb +11 -0
  10. data/lib/rails_twirp/render_pb.rb +18 -0
  11. data/lib/rails_twirp/rescue.rb +14 -0
  12. data/lib/rails_twirp/route_set.rb +3 -0
  13. data/lib/rails_twirp/testing/integration_test.rb +6 -1
  14. data/lib/rails_twirp/version.rb +1 -1
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/config/manifest.js +2 -0
  17. data/test/dummy/app/assets/images/.keep +0 -0
  18. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  19. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  20. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  21. data/test/dummy/app/controllers/application_controller.rb +2 -0
  22. data/test/dummy/app/controllers/application_twirp_controller.rb +7 -0
  23. data/test/dummy/app/controllers/concerns/.keep +0 -0
  24. data/test/dummy/app/controllers/pings_controller.rb +39 -0
  25. data/test/dummy/app/helpers/application_helper.rb +2 -0
  26. data/test/dummy/app/javascript/packs/application.js +15 -0
  27. data/test/dummy/app/jobs/application_job.rb +7 -0
  28. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  29. data/test/dummy/app/models/application_record.rb +3 -0
  30. data/test/dummy/app/models/concerns/.keep +0 -0
  31. data/test/dummy/app/twirp/views/pings/ping_template.pb.pbbuilder +1 -0
  32. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  33. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  34. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  35. data/test/dummy/bin/generate +3 -0
  36. data/test/dummy/bin/rails +4 -0
  37. data/test/dummy/bin/rake +4 -0
  38. data/test/dummy/bin/setup +33 -0
  39. data/test/dummy/config.ru +6 -0
  40. data/test/dummy/config/application.rb +23 -0
  41. data/test/dummy/config/boot.rb +5 -0
  42. data/test/dummy/config/cable.yml +10 -0
  43. data/test/dummy/config/database.yml +25 -0
  44. data/test/dummy/config/environment.rb +5 -0
  45. data/test/dummy/config/environments/development.rb +76 -0
  46. data/test/dummy/config/environments/production.rb +120 -0
  47. data/test/dummy/config/environments/test.rb +59 -0
  48. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  49. data/test/dummy/config/initializers/assets.rb +12 -0
  50. data/test/dummy/config/initializers/backtrace_silencers.rb +8 -0
  51. data/test/dummy/config/initializers/content_security_policy.rb +28 -0
  52. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  53. data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  54. data/test/dummy/config/initializers/inflections.rb +16 -0
  55. data/test/dummy/config/initializers/mime_types.rb +4 -0
  56. data/test/dummy/config/initializers/permissions_policy.rb +11 -0
  57. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/test/dummy/config/locales/en.yml +33 -0
  59. data/test/dummy/config/puma.rb +43 -0
  60. data/test/dummy/config/routes.rb +3 -0
  61. data/test/dummy/config/storage.yml +34 -0
  62. data/test/dummy/config/twirp/routes.rb +13 -0
  63. data/test/dummy/lib/assets/.keep +0 -0
  64. data/test/dummy/log/.keep +0 -0
  65. data/test/dummy/proto/api.proto +23 -0
  66. data/test/dummy/proto/api_pb.rb +22 -0
  67. data/test/dummy/proto/api_twirp.rb +23 -0
  68. data/test/dummy/public/404.html +67 -0
  69. data/test/dummy/public/422.html +67 -0
  70. data/test/dummy/public/500.html +66 -0
  71. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  72. data/test/dummy/public/apple-touch-icon.png +0 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/ping_controller_test.rb +55 -0
  75. data/test/test_helper.rb +10 -1
  76. metadata +127 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4aa4bf745efcab88ddcf8cc58f6bf76e482901d37c8736102a5c32a6f20d0892
4
- data.tar.gz: 8d6dbf635e44bf444d16d2eeaa7046a53027767745972a7add35e204ae73eaec
3
+ metadata.gz: 78af7d754c6fbaf90cbf22f5ef83b116c54840ab97fc2daffb09a5a37bcd7c91
4
+ data.tar.gz: '0078e09678ea09ccda0d2db94c1ff241222cf3074f4febd580197efc9d257cd1'
5
5
  SHA512:
6
- metadata.gz: b48547bdb5e77c0c508f1e5dcdce7b01a692d94ce79aac38f837b0397adb696a6f68d36f116e02221ed24c04152b8fb3cdb77072bfbda81fe4b5247bcf359c1e
7
- data.tar.gz: e4ed631582628257e281c78201177f351a6855f9bb9ebdfe6bb3ca0bc52349a59f56995cbcaa8c781640308bd4f032cd8fee7d5bc18191bb239082874379e2bc
6
+ metadata.gz: fd943fdaa9b54614c268b6d7471bec3726bffb2125f5afa6992b9b30db2c03bbc2027869e1b23f449addf81cd2140d3abe97677f35d6a5ba924be515b01998b4
7
+ data.tar.gz: ab7b4e53cdfc9eb84a6f4875674b643c668adc15f103cf60ba367078393e23257477b13a0eb5355e69248eb1250feb73a37eb5e689a7a501cd9236c4630a600a
@@ -0,0 +1,21 @@
1
+ name: Ruby Test
2
+ on: push
3
+
4
+ jobs:
5
+ test:
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - name: Checkout code
9
+ uses: actions/checkout@v2
10
+
11
+ - name: Setup Ruby
12
+ uses: ruby/setup-ruby@v1
13
+ with:
14
+ ruby-version: 3.0.0
15
+ bundler-cache: true
16
+
17
+ - name: Run tests
18
+ run: bin/test
19
+
20
+ - name: Run standardrb
21
+ run: bundle exec standardrb
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  .byebug_history
12
12
  Gemfile.lock
13
13
  *.gem
14
+ /.idea
data/.standard.yml ADDED
@@ -0,0 +1,4 @@
1
+ ignore:
2
+ - 'test/dummy/proto/*'
3
+ - '**/*':
4
+ - Lint/RescueException
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
1
  source "https://rubygems.org"
2
- git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
2
 
4
3
  # Specify your gem's dependencies in rails_twirp.gemspec.
5
4
  gemspec
6
5
 
7
- # To use a debugger
8
- # gem 'byebug', group: [:development, :test]
6
+ gem "sqlite3"
7
+ gem "pbbuilder", "~> 0.3.0"
8
+ gem "standard"
data/lib/rails_twirp.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rails_twirp/version"
2
2
 
3
+ require "rails_twirp/application"
3
4
  require "rails_twirp/base"
4
5
  require "rails_twirp/route_set"
5
6
  require "rails_twirp/testing/integration_test"
@@ -1,13 +1,33 @@
1
+ require "abstract_controller/base"
2
+ require "abstract_controller/rendering"
3
+ require "action_view/rendering"
4
+ require "rails_twirp/render_pb"
5
+ require "rails_twirp/errors"
6
+ require "abstract_controller/asset_paths"
7
+ require "abstract_controller/caching"
8
+ require "abstract_controller/logger"
9
+ require "abstract_controller/callbacks"
10
+ require "rails_twirp/rescue"
11
+
1
12
  module RailsTwirp
2
13
  class Base < AbstractController::Base
3
14
  abstract!
4
15
 
5
- include AbstractController::Logger
6
- include AbstractController::AssetPaths
7
- include AbstractController::Callbacks
8
- include AbstractController::Caching
16
+ # The order of these includes matter.
17
+ # The rendering modules extend each other, so need to be in this order.
9
18
  include AbstractController::Rendering
10
19
  include ActionView::Rendering
20
+ include RenderPb
21
+ include Errors
22
+
23
+ # These add helpers for the controller
24
+ include AbstractController::AssetPaths
25
+ include AbstractController::Caching
26
+ include AbstractController::Logger
27
+
28
+ # These need to be last so errors can be handled as early as possible.
29
+ include AbstractController::Callbacks
30
+ include Rescue
11
31
 
12
32
  attr_internal :request, :env, :response_class
13
33
  def initialize
@@ -35,16 +55,15 @@ module RailsTwirp
35
55
  response_body
36
56
  end
37
57
 
38
- def render(*args)
39
- options = {formats: :pb, handlers: :pbbuilder, locals: {response_class: response_class}}
40
- options.deep_merge! args.extract_options!
41
- super(*args, options)
42
- end
43
-
44
58
  def self.dispatch(action, request, response_class, env = {})
45
59
  new.dispatch(action, request, response_class, env)
46
60
  end
47
61
 
62
+ # Used by the template renderer to figure out which template to use
63
+ def details_for_lookup
64
+ {formats: [:pb], handlers: [:pbbuilder]}
65
+ end
66
+
48
67
  ActiveSupport.run_load_hooks(:rails_twirp, self)
49
68
  end
50
69
  end
@@ -1,5 +1,6 @@
1
- require "rails/railtie"
2
1
  require "rails_twirp/application"
2
+ require "rails_twirp/route_set"
3
+ require "rails/railtie"
3
4
 
4
5
  module RailsTwirp
5
6
  # Even though this is an engine, we don't inherit from Rails::Engine because we don't want anything it provides.
@@ -26,8 +27,11 @@ module RailsTwirp
26
27
  app.config.paths.add "app/twirp/views", load_path: true
27
28
  end
28
29
 
29
- initializer :set_controller_view_path do
30
- ActiveSupport.on_load(:rails_twirp) { prepend_view_path "app/twirp/views" }
30
+ initializer :set_controller_view_path do |app|
31
+ views = app.config.paths["app/twirp/views"].existent
32
+ unless views.empty?
33
+ ActiveSupport.on_load(:rails_twirp) { prepend_view_path views }
34
+ end
31
35
  end
32
36
 
33
37
  initializer :add_twirp do |app|
@@ -37,11 +41,12 @@ module RailsTwirp
37
41
 
38
42
  initializer :load_twirp_routes do |app|
39
43
  # Load route files
40
- route_configs = [
44
+ [
41
45
  *app.config.paths["config/twirp/routes.rb"].existent,
42
46
  *app.config.paths["config/twirp/routes"].existent
43
- ]
44
- load(*route_configs)
47
+ ].each do |path|
48
+ load path
49
+ end
45
50
 
46
51
  # Create a router that knows how to route all the registered services
47
52
  services = app.twirp.routes.to_services
@@ -0,0 +1,11 @@
1
+ require "twirp/error"
2
+
3
+ module RailsTwirp
4
+ module Errors
5
+ # Helper that sets the response to a Twirp Error
6
+ # The valid error codes can be found in Twirp::ERROR_CODES
7
+ def error(code, message, meta = nil)
8
+ self.response_body = Twirp::Error.new(code, message, meta)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module RailsTwirp
2
+ # RenderPb makes it possible to do 'render pb: <proto object>', skipping templates
3
+ # The way this module is written is inspired by ActionController::Renderers
4
+ module RenderPb
5
+ def render_to_body(options)
6
+ _render_to_body_with_pb(options) || super
7
+ end
8
+
9
+ def _render_to_body_with_pb(options)
10
+ if options.include? :pb
11
+ _process_options(options)
12
+ return options[:pb]
13
+ end
14
+
15
+ nil
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module RailsTwirp
2
+ module Rescue
3
+ extend ActiveSupport::Concern
4
+ include ActiveSupport::Rescuable
5
+
6
+ private
7
+
8
+ def process_action(*)
9
+ super
10
+ rescue Exception => exception
11
+ rescue_with_handler(exception) || raise
12
+ end
13
+ end
14
+ end
@@ -1,6 +1,8 @@
1
1
  # Most of this logic is stolen from Rails ActionDispatch::Routing::RouteSet
2
2
 
3
3
  module RailsTwirp
4
+ class UnknownRpcError < StandardError; end
5
+
4
6
  class RouteSet
5
7
  attr_reader :services
6
8
 
@@ -42,6 +44,7 @@ module RailsTwirp
42
44
  handler = Class.new
43
45
  @rpcs.each do |name, mapping|
44
46
  rpc_info = @service_class.rpcs[name]
47
+ raise UnknownRpcError, "Unknown RPC #{name} on #{@service_class.service_name} service" unless rpc_info
45
48
  method_name = rpc_info[:ruby_method]
46
49
 
47
50
  # Stolen from Rails in ActionDispatch::Request#controller_class_for
@@ -30,7 +30,12 @@ module RailsTwirp
30
30
  hook.call(env)
31
31
  end
32
32
 
33
- response = service.call_rpc rpc, request, env
33
+ response = begin
34
+ service.call_rpc rpc, request, env
35
+ rescue => e
36
+ Twirp::Error.internal_with(e)
37
+ end
38
+
34
39
  @response = response
35
40
  @controller = http_request.controller_instance
36
41
  response
@@ -1,3 +1,3 @@
1
1
  module RailsTwirp
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,2 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,7 @@
1
+ class ApplicationTwirpController < RailsTwirp::Base
2
+ rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
3
+
4
+ def handle_not_found
5
+ error :not_found, "Not found"
6
+ end
7
+ end
File without changes
@@ -0,0 +1,39 @@
1
+ class PingsController < ApplicationTwirpController
2
+ before_action :respond_error, only: :before_error
3
+
4
+ def ping
5
+ response = RPC::DummyAPI::PingResponse.new(double_name: request.name * 2)
6
+ self.response_body = response
7
+ end
8
+
9
+ def ping_render
10
+ response = RPC::DummyAPI::PingResponse.new(double_name: request.name * 2)
11
+ render pb: response
12
+ end
13
+
14
+ def ping_template
15
+ @double_name = request.name * 2
16
+ end
17
+
18
+ def error_response
19
+ error :unauthenticated, "You are not authenticated!!"
20
+ end
21
+
22
+ def raise_error
23
+ # This error is rescued in ApplicationTwirpController
24
+ raise ActiveRecord::RecordNotFound, "Not found"
25
+ end
26
+
27
+ def uncaught_raise
28
+ raise StandardError, "Uncaught"
29
+ end
30
+
31
+ def before_error
32
+ # This error won't be reached because of the before_action
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def respond_error
37
+ error :malformed, "yOuR ReQuEsT Is mAlFoRmEd"
38
+ end
39
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,7 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ # Automatically retry jobs that encountered a deadlock
3
+ # retry_on ActiveRecord::Deadlocked
4
+
5
+ # Most jobs are safe to ignore if the underlying records are no longer available
6
+ # discard_on ActiveJob::DeserializationError
7
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: "from@example.com"
3
+ layout "mailer"
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
File without changes
@@ -0,0 +1 @@
1
+ pb.double_name @double_name
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+
9
+ <%= stylesheet_link_tag 'application', media: 'all' %>
10
+ </head>
11
+
12
+ <body>
13
+ <%= yield %>
14
+ </body>
15
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ protoc --twirp_ruby_out=proto/ --ruby_out=proto/ -I proto/ proto/api.proto