grape_sorbet 0.0.2 → 0.0.4

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
  SHA256:
3
- metadata.gz: 3aadd0dde4fcc5037da59fbc26226c5d54d94686cc4024875e9cf9e21e547df8
4
- data.tar.gz: 9ca6394902e1aea0a6facfcb584c3bac8c03ff580f5a3c8501962fcb737d7154
3
+ metadata.gz: aa4f8d64cc6cbf5839f525d1c1e246386510695be350c4bf1ed1298b52b8c9a4
4
+ data.tar.gz: baeca4c981155f04394d3dab717a300c923f41aa063516c4eb0430943e0ba756
5
5
  SHA512:
6
- metadata.gz: 212aad3e25427f5d9329061e20d308d54daea04584c65d6cd0c5f8d542b7396287cb43a76f93999fea67c24883610e6f9d56e399bf59f7a65737ad51b21b4b41
7
- data.tar.gz: 56f4c190b13f6763ad0e2a4b051346011eb976c3664de34e5b915f886a2c2970054b8e1946b5738fa2f439c1ecb88fc1f094d80e63145529a0e9b861fb0faa69
6
+ metadata.gz: 9a7f6cb172c0c73adf41a2992b620f45962459baeeb7f19cc916036776a010018a28a5f0dac752a55a2e1c623ee4e394a6654fd3f2139750e73fdc278a5f8a6d
7
+ data.tar.gz: 59580b70030d1d8d013191c55671a82daa854e1a536ecc67acb1a1ee70e1e907086a76b9eddb5022eadb03161c0043c241c7fc5f8a831c4cdf0b1c0f12e09597
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.0.4 (2024-06-24)
2
+
3
+ - Update `grape.rbi`
4
+
5
+ ## 0.0.3 (2024-06-05)
6
+
7
+ - Better support for callbacks
8
+
1
9
  ## 0.0.2 (2024-06-05)
2
10
 
3
11
  - Added support for callbacks (`before`, `after`, etc.)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grape_sorbet (0.0.2)
4
+ grape_sorbet (0.0.4)
5
5
  activesupport
6
6
  grape (~> 2.0)
7
7
  sorbet-runtime (~> 0.5.10741)
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # grape_sorbet
2
2
 
3
3
  [![Build Status](https://github.com/thatch-health/grape_sorbet/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/thatch-health/grape_sorbet/actions?query=branch%3Amain)
4
+ [![Gem Version ](https://img.shields.io/gem/v/grape_sorbet.svg?style=flat)](https://rubygems.org/gems/grape_sorbet)
4
5
 
5
6
  grape_sorbet is a gem that provides hand written signatures and a Tapioca DSL compiler that makes it more pleasant to use the [Grape](https://github.com/ruby-grape/grape) API framework in Ruby projects that use the [Sorbet](https://sorbet.org/) typechecker.
6
7
 
@@ -90,7 +91,29 @@ module Twitter
90
91
  end
91
92
  ```
92
93
 
93
- At this point Sorbet is still reporting errors in the `get :home_timeline` block, because it doesn't know that these blocks are executed in a context where the `Helpers` module methods will be available. The Tapioca compiler provided by this gem will fix that. Run `bundle exec tapioca dsl`. This should generate a `sorbet/rbi/dsl/twitter/api.rbi` file (assuming the source file is in `lib/twitter/api.rb`). After this,
94
+ At this point Sorbet is still reporting errors in the `get :home_timeline` block, because it doesn't know that these blocks are executed in a context where the `Helpers` module methods will be available. The Tapioca compiler provided by this gem will fix that. Run `bundle exec tapioca dsl`. This should generate a `sorbet/rbi/dsl/twitter/api.rbi` file (assuming the source file is in `lib/twitter/api.rb`).
95
+
96
+ After this, Sorbet should no longer report any errors.
97
+
98
+ ## Limitations and known issues
99
+
100
+ ### Subclassing from `Grape::API::Instance` instead of `Grape::API`
101
+
102
+ Grape overrides `Grape::API.new` and uses the `inherited` hook so that subclasses of `Grape::API` are really subclasses of `Grape::API::Instance`.
103
+
104
+ This might be fixable in a future update of grape_sorbet, but is very low priority.
105
+
106
+ ### Not being able to call `helpers` with block arguments
107
+
108
+ Possibly fixable in a future update.
109
+
110
+ ### Having to use `T.bind(self, T.any(Grape::Endpoint, <HelpersModuleName>))` in helper methods
111
+
112
+ Possibly fixable in a future update.
113
+
114
+ ### Having to use `T.bind(self, T.any(Grape::Endpoint, <HelpersModuleName>))` in `before` and `after` callback blocks
115
+
116
+ The compiler already generates proper signatures for callback methods so `T.bind` should not be needed (and is in fact unneeded for the other callback methods, `before_validation`, `after_validation` and `finally`). The reason it doesn't work for `before` and `after` is because of a [bug](https://github.com/sorbet/sorbet/issues/7950) in Sorbet itself.
94
117
 
95
118
  ## Development
96
119
 
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module GrapeSorbet
5
- VERSION = "0.0.2"
5
+ VERSION = "0.0.4"
6
6
  end
@@ -80,13 +80,13 @@ module Tapioca
80
80
  end
81
81
  end
82
82
 
83
- HTTP_VERB_METHODS = T.let(
84
- [:get, :post, :put, :patch, :delete, :head, :options].freeze,
83
+ CALLBACKS_METHODS = T.let(
84
+ [:before, :before_validation, :after_validation, :after, :finally].freeze,
85
85
  T::Array[Symbol],
86
86
  )
87
87
 
88
- CALLBACKS_METHODS = T.let(
89
- [:before, :before_validation, :after_validation, :after, :finally].freeze,
88
+ HTTP_VERB_METHODS = T.let(
89
+ [:get, :post, :put, :patch, :delete, :head, :options].freeze,
90
90
  T::Array[Symbol],
91
91
  )
92
92
 
@@ -100,6 +100,14 @@ module Tapioca
100
100
  )
101
101
  end
102
102
 
103
+ sig { returns(RBI::Scope) }
104
+ def callbacks_methods_module
105
+ @callbacks_methods_module ||= T.let(
106
+ api.create_module(CallbacksMethodsModuleName),
107
+ T.nilable(RBI::Scope),
108
+ )
109
+ end
110
+
103
111
  sig { returns(RBI::Scope) }
104
112
  def routing_methods_module
105
113
  @routing_methods_module ||= T.let(
@@ -110,6 +118,7 @@ module Tapioca
110
118
 
111
119
  sig { void }
112
120
  def create_classes_and_includes
121
+ api.create_extend(CallbacksMethodsModuleName)
113
122
  api.create_extend(RoutingMethodsModuleName)
114
123
  create_api_class
115
124
  create_endpoint_class
@@ -141,6 +150,19 @@ module Tapioca
141
150
  end
142
151
  end
143
152
 
153
+ sig { void }
154
+ def create_callbacks_methods
155
+ CALLBACKS_METHODS.each do |callback|
156
+ callbacks_methods_module.create_method(
157
+ callback.to_s,
158
+ parameters: [
159
+ create_block_param("block", type: "T.proc.bind(#{EndpointClassName}).void"),
160
+ ],
161
+ return_type: "void",
162
+ )
163
+ end
164
+ end
165
+
144
166
  sig { void }
145
167
  def create_routing_methods
146
168
  HTTP_VERB_METHODS.each do |verb|
@@ -148,7 +170,7 @@ module Tapioca
148
170
  verb.to_s,
149
171
  parameters: [
150
172
  create_rest_param("args", type: "T.untyped"),
151
- create_block_param("blk", type: "T.nilable(T.proc.bind(#{EndpointClassName}).void)"),
173
+ create_block_param("block", type: "T.nilable(T.proc.bind(#{EndpointClassName}).void)"),
152
174
  ],
153
175
  return_type: "void",
154
176
  )
@@ -158,26 +180,12 @@ module Tapioca
158
180
  "route_param",
159
181
  parameters: [
160
182
  create_param("param", type: "Symbol"),
161
- create_opt_param("options", type: "T.nilable(T::Hash[Symbol, T.untyped])", default: "nil"),
162
- create_block_param("blk", type: "T.nilable(T.proc.bind(T.class_of(#{APIInstanceClassName})).void)"),
183
+ create_opt_param("options", type: "T::Hash[Symbol, T.untyped]", default: "{}"),
184
+ create_block_param("block", type: "T.nilable(T.proc.bind(T.class_of(#{APIInstanceClassName})).void)"),
163
185
  ],
164
186
  return_type: "void",
165
187
  )
166
188
  end
167
-
168
- sig { void }
169
- def create_callbacks_methods
170
- CALLBACKS_METHODS.each do |callback|
171
- routing_methods_module.create_method(
172
- callback.to_s,
173
- parameters: [
174
- create_rest_param("args", type: "T.untyped"),
175
- create_block_param("blk", type: "T.nilable(T.proc.bind(#{EndpointClassName}).void)"),
176
- ],
177
- return_type: "void",
178
- )
179
- end
180
- end
181
189
  end
182
190
  end
183
191
  end
@@ -7,6 +7,7 @@ module Tapioca
7
7
  module GrapeConstantsHelper
8
8
  extend T::Sig
9
9
 
10
+ CallbacksMethodsModuleName = "GeneratedCallbacksMethods"
10
11
  RoutingMethodsModuleName = "GeneratedRoutingMethods"
11
12
 
12
13
  APIInstanceClassName = "PrivateAPIInstance"
data/rbi/grape.rbi CHANGED
@@ -2,107 +2,122 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Grape
5
- module DSL::Callbacks::ClassMethods
6
- sig { params(block: T.proc.bind(Grape::Endpoint).void).void }
7
- def before(&block); end
8
- end
9
-
10
- module DSL::Desc
11
- # grape evaluates config_block in the context of a dynamically created module that implements the DSL it exposes
12
- # at runtime. There's no good way to represent this statically, so block is just typed as T.untyped to prevent
13
- # Sorbet from complaining that the DSL methods don't exist.
14
- sig do
15
- params(
16
- description: String,
17
- options: T.nilable(T::Hash[Symbol, T.untyped]),
18
- config_block: T.nilable(T.proc.bind(T.untyped).void),
19
- ).void
5
+ module DSL
6
+ module Desc
7
+ # grape evaluates config_block in the context of a dynamically created module that implements the DSL it exposes
8
+ # at runtime. There's no good way to represent this statically, so block is just typed as T.untyped to prevent
9
+ # Sorbet from complaining that the DSL methods don't exist.
10
+ sig do
11
+ params(
12
+ description: String,
13
+ options: T.nilable(T::Hash[Symbol, T.untyped]),
14
+ config_block: T.nilable(T.proc.bind(T.untyped).void),
15
+ ).void
16
+ end
17
+ def desc(description, options = T.unsafe(nil), &config_block); end
20
18
  end
21
- def desc(description, options = T.unsafe(nil), &config_block); end
22
- end
23
19
 
24
- module DSL::RequestResponse::ClassMethods
25
- sig { params(args: T.untyped, block: T.proc.bind(Grape::Endpoint).void).void }
26
- def rescue_from(*args, &block); end
27
- end
28
-
29
- module DSL::Routing::ClassMethods
30
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
31
- sig do
32
- params(
33
- args: T.untyped,
34
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
35
- ).void
20
+ module Helpers
21
+ module BaseHelper
22
+ sig { params(name: Symbol, block: T.proc.bind(Grape::Validations::ParamsScope).void).void }
23
+ def params(name, &block); end
24
+ end
36
25
  end
37
- def delete(*args, &block); end
38
26
 
39
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
40
- sig do
41
- params(
42
- args: T.untyped,
43
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
44
- ).void
27
+ module RequestResponse
28
+ module ClassMethods
29
+ sig { params(args: T.untyped, block: T.proc.bind(Grape::Endpoint).void).void }
30
+ def rescue_from(*args, &block); end
31
+ end
45
32
  end
46
- def get(*args, &block); end
47
33
 
48
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
49
- sig do
50
- params(
51
- args: T.untyped,
52
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
53
- ).void
54
- end
55
- def options(*args, &block); end
34
+ module Routing
35
+ module ClassMethods
36
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
37
+ sig do
38
+ params(
39
+ args: T.untyped,
40
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
41
+ ).void
42
+ end
43
+ def delete(*args, &block); end
56
44
 
57
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
58
- sig do
59
- params(
60
- args: T.untyped,
61
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
62
- ).void
63
- end
64
- def patch(*args, &block); end
45
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
46
+ sig do
47
+ params(
48
+ args: T.untyped,
49
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
50
+ ).void
51
+ end
52
+ def get(*args, &block); end
65
53
 
66
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
67
- sig do
68
- params(
69
- args: T.untyped,
70
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
71
- ).void
72
- end
73
- def post(*args, &block); end
54
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
55
+ sig do
56
+ params(
57
+ args: T.untyped,
58
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
59
+ ).void
60
+ end
61
+ def options(*args, &block); end
74
62
 
75
- # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
76
- sig do
77
- params(
78
- args: T.untyped,
79
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
80
- ).void
81
- end
82
- def put(*args, &block); end
63
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
64
+ sig do
65
+ params(
66
+ args: T.untyped,
67
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
68
+ ).void
69
+ end
70
+ def patch(*args, &block); end
71
+
72
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
73
+ sig do
74
+ params(
75
+ args: T.untyped,
76
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
77
+ ).void
78
+ end
79
+ def post(*args, &block); end
80
+
81
+ # @shim: https://github.com/ruby-grape/grape/blob/v2.0.0/lib/grape/dsl/routing.rb#L148-L154
82
+ sig do
83
+ params(
84
+ args: T.untyped,
85
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
86
+ ).void
87
+ end
88
+ def put(*args, &block); end
89
+
90
+ sig do
91
+ params(
92
+ methods: T.any(Symbol, String, T::Array[String]),
93
+ paths: T.nilable(T.any(String, T::Array[String])),
94
+ route_options: T.nilable(T::Hash[Symbol, T.untyped]),
95
+ block: T.nilable(T.proc.bind(Grape::Endpoint).void),
96
+ ).void
97
+ end
98
+ def route(methods, paths = T.unsafe(nil), route_options = T.unsafe(nil), &block); end
83
99
 
84
- sig do
85
- params(
86
- methods: T.any(Symbol, String, T::Array[String]),
87
- paths: T.nilable(T.any(String, T::Array[String])),
88
- route_options: T.nilable(T::Hash[Symbol, T.untyped]),
89
- block: T.nilable(T.proc.bind(Grape::Endpoint).void),
90
- ).void
100
+ sig do
101
+ params(
102
+ param: Symbol,
103
+ options: T.nilable(T::Hash[Symbol, T.untyped]),
104
+ block: T.nilable(T.proc.bind(T.class_of(Grape::API::Instance)).void),
105
+ ).void
106
+ end
107
+ def route_param(param, options = T.unsafe(nil), &block); end
108
+ end
91
109
  end
92
- def route(methods, paths = T.unsafe(nil), route_options = T.unsafe(nil), &block); end
93
110
 
94
- sig do
95
- params(
96
- param: Symbol,
97
- options: T.nilable(T::Hash[Symbol, T.untyped]),
98
- block: T.nilable(T.proc.bind(T.class_of(Grape::API::Instance)).void),
99
- ).void
111
+ module Validations
112
+ module ClassMethods
113
+ sig { params(block: T.proc.bind(Grape::Validations::ParamsScope).void).void }
114
+ def params(&block); end
115
+ end
100
116
  end
101
- def route_param(param, options = T.unsafe(nil), &block); end
102
117
  end
103
118
 
104
- module DSL::Validations::ClassMethods
105
- sig { params(block: T.proc.bind(Grape::Validations::ParamsScope).void).void }
106
- def params(&block); end
119
+ class Endpoint
120
+ sig { returns(Grape::Request) }
121
+ def request; end
107
122
  end
108
123
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape_sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thatch Health, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-05 00:00:00.000000000 Z
11
+ date: 2024-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 3.5.9
101
+ rubygems_version: 3.5.13
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Sorbet signatures and Tapioca DSL compiler for Grape.