rspec-sorbet-types 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a22cc57159bb8fcf6011e4f526f04da73e7cb0c6a0f8ba2be14b2fda79f1a516
4
+ data.tar.gz: 7d4cd90ee0792e2b7bd2c8aa64348b8ec2006f57133774d5d6606518a93b3604
5
+ SHA512:
6
+ metadata.gz: 4f8dea02beb1c65684aa54552cbfa96b8d7335d1da3f36c866b6fba677f88e9debe451f836c633e4053700768de559449266599bb42e9974b641f8034744245f
7
+ data.tar.gz: 80b33d85703d7b9ebdcc0e8f37c8f3ce7718af361413a2491731895fa6c44825634a5a2e17318ed65a3950c77b156d75c3361cc925b82034d3732799a0e962db
@@ -0,0 +1,22 @@
1
+ # typed: true
2
+
3
+ module RSpec
4
+ module Sorbet
5
+ module Types
6
+ module Sig
7
+ include Kernel
8
+
9
+ def self.extended(sub)
10
+ super
11
+ sub.extend(T::Sig)
12
+ end
13
+
14
+ T::Sig::WithoutRuntime.sig { params(decl: T.proc.bind(T::Private::Methods::DeclBuilder).void).void }
15
+ def rsig(&decl)
16
+ # It would be better if we could simply use the name "sig", but Sorbet falsely reports that as an overload
17
+ send(:sig, &decl)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,2 @@
1
+ require "sorbet-runtime"
2
+ require_relative "types/sig"
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ require "rspec/core"
5
+
6
+ module Tapioca
7
+ module Dsl
8
+ module Compilers
9
+ class RSpec < Compiler
10
+ extend T::Sig
11
+
12
+ ConstantType = type_member { {fixed: T.class_of(::RSpec::Core::ExampleGroup)} }
13
+
14
+ class << self
15
+ extend T::Sig
16
+
17
+ sig { override.returns(T::Enumerable[Module]) }
18
+ def gather_constants
19
+ all_classes.select { |c| c < ::RSpec::Core::ExampleGroup }
20
+ end
21
+
22
+ private
23
+
24
+ sig { void }
25
+ def require_spec_files!
26
+ Dir.glob(spec_glob).each do |file|
27
+ require(file)
28
+ end
29
+ end
30
+
31
+ sig { returns(String) }
32
+ def spec_glob
33
+ ENV["SORBET_RSPEC_GLOB"] || File.join(".", "spec", "**", "*.rb")
34
+ end
35
+ end
36
+
37
+ # Set environment variable, allowing other code to detect that we're compiling
38
+ ENV["SORBET_RSPEC_TYPES_COMPILING"] = "1"
39
+
40
+ # Load all spec files during compiler definition
41
+ require_spec_files!
42
+
43
+ sig { override.void }
44
+ def decorate
45
+ klass = root.create_class(T.must(constant.name), superclass_name: T.must(constant.superclass).name)
46
+ create_includes(klass)
47
+ create_example_group_submodules(klass)
48
+ create_singleton_methods(klass)
49
+ end
50
+
51
+ private
52
+
53
+ sig { params(klass: RBI::Scope).void }
54
+ def create_includes(klass)
55
+ directly_included_modules_for(constant).each do |mod|
56
+ klass.create_include("::#{mod}")
57
+ end
58
+ end
59
+
60
+ # A method can have a signature even if the method is defined dynamically with define_method
61
+ # The next call to def or define_method will be the one associated with the signature
62
+ # However, an exception will be raised if we have two signature declarations in a row
63
+ # without a method definition.
64
+ sig { params(method_name: Symbol).returns(String) }
65
+ def return_type_for_let_declaration(method_name)
66
+ T::Utils.signature_for_instance_method(constant, method_name)&.return_type&.to_s || "T.untyped"
67
+ end
68
+
69
+ sig { params(klass: RBI::Scope).void }
70
+ def create_example_group_submodules(klass)
71
+ modules = directly_included_modules_for(constant).select { |mod| mod.name&.start_with?("RSpec::ExampleGroups::") }
72
+ modules.each do |mod|
73
+ scope = root.create_module(T.must(mod.name))
74
+ direct_public_instance_methods_for(mod).each do |method_name|
75
+ method_def = mod.instance_method(method_name)
76
+ return_type = return_type_for_let_declaration(method_name)
77
+
78
+ scope.create_method(
79
+ method_def.name.to_s,
80
+ parameters: compile_method_parameters_to_rbi(method_def),
81
+ return_type:,
82
+ class_method: false
83
+ )
84
+ end
85
+ end
86
+ end
87
+
88
+ sig { params(klass: RBI::Scope).void }
89
+ def create_singleton_methods(klass)
90
+ scope = klass.create_class("<< self")
91
+ scope.create_method(
92
+ "let",
93
+ parameters: [
94
+ create_rest_param("name", type: "T.untyped"),
95
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
96
+ ]
97
+ )
98
+ scope.create_method(
99
+ "let!",
100
+ parameters: [
101
+ create_rest_param("name", type: "T.untyped"),
102
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
103
+ ]
104
+ )
105
+
106
+ scope.create_method(
107
+ "before",
108
+ parameters: [
109
+ create_rest_param("args", type: "T.untyped"),
110
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
111
+ ]
112
+ )
113
+
114
+ scope.create_method(
115
+ "after",
116
+ parameters: [
117
+ create_rest_param("args", type: "T.untyped"),
118
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
119
+ ]
120
+ )
121
+
122
+ scope.create_method(
123
+ "it",
124
+ parameters: [
125
+ create_rest_param("all_args", type: "T.untyped"),
126
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
127
+ ]
128
+ )
129
+
130
+ scope.create_method(
131
+ "specify",
132
+ parameters: [
133
+ create_rest_param("all_args", type: "T.untyped"),
134
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
135
+ ]
136
+ )
137
+
138
+ scope.create_method(
139
+ "subject",
140
+ parameters: [
141
+ create_block_param("block", type: "T.proc.bind(#{constant.name}).void")
142
+ ]
143
+ )
144
+
145
+ singleton_class = constant.singleton_class
146
+ direct_public_instance_methods_for(singleton_class).each do |method_name|
147
+ create_method_from_def(scope, singleton_class.instance_method(method_name))
148
+ end
149
+ end
150
+
151
+ sig { params(constant: Module).returns(T::Enumerable[Module]) }
152
+ def directly_included_modules_for(constant)
153
+ result = constant.included_modules
154
+ result -= constant.included_modules.map do |included_mod|
155
+ included_mod.ancestors - [included_mod]
156
+ end.flatten
157
+ if constant.is_a?(Class) && constant.superclass
158
+ result -= T.must(constant.superclass).included_modules
159
+ end
160
+ result
161
+ end
162
+
163
+ sig { params(constant: Module).returns(T::Enumerable[Symbol]) }
164
+ def direct_public_instance_methods_for(constant)
165
+ result = constant.public_instance_methods
166
+ constant.included_modules.each do |included_mod|
167
+ result -= included_mod.public_instance_methods
168
+ end
169
+ if constant.is_a?(Class) && constant.superclass
170
+ result -= T.must(constant.superclass).public_instance_methods
171
+ end
172
+ result
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module RSpec
5
+ class << self
6
+ sig do
7
+ params(
8
+ args: T.untyped,
9
+ example_group_block: T.proc.bind(T.class_of(RSpec::Core::ExampleGroup)).void,
10
+ ).void
11
+ end
12
+
13
+ def describe(*args, &example_group_block); end
14
+ end
15
+ end
16
+
17
+ class RSpec::Core::ExampleGroup
18
+ include ::RSpec::Matchers
19
+ include ::RSpec::Mocks::ExampleMethods
20
+
21
+ class << self
22
+ sig do
23
+ params(
24
+ all_args: T.untyped,
25
+ block: T.proc.bind(RSpec::Core::ExampleGroup).void,
26
+ ).void
27
+ end
28
+
29
+ def it(*all_args, &block); end
30
+
31
+ sig do
32
+ params(
33
+ all_args: T.untyped,
34
+ block: T.proc.bind(RSpec::Core::ExampleGroup).void,
35
+ ).void
36
+ end
37
+
38
+ def specify(*all_args, &block); end
39
+
40
+ sig do
41
+ params(
42
+ args: T.untyped,
43
+ block: T.proc.bind(RSpec::Core::ExampleGroup).void,
44
+ ).void
45
+ end
46
+
47
+ def before(*args, &block); end
48
+
49
+ sig do
50
+ params(
51
+ args: T.untyped,
52
+ block: T.proc.bind(RSpec::Core::ExampleGroup).void,
53
+ ).void
54
+ end
55
+
56
+ def after(*args, &block); end
57
+
58
+ sig do
59
+ params(
60
+ args: T.untyped,
61
+ block: T.proc.bind(RSpec::Core::ExampleGroup).void,
62
+ ).void
63
+ end
64
+
65
+ def around(*args, &block); end
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-sorbet-types
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hongli Lai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-01-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sorbet-runtime
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tapioca
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: A gem that provides integration between Sorbet type checking and RSpec
56
+ testing framework
57
+ email:
58
+ - hongli@hongli.nl
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - lib/rspec/sorbet/types.rb
64
+ - lib/rspec/sorbet/types/sig.rb
65
+ - lib/tapioca/dsl/compilers/rspec.rb
66
+ - rbi/rspec-core.rbi
67
+ homepage: https://github.com/FooBarWidget/sorbet-rspec
68
+ licenses:
69
+ - MIT
70
+ metadata:
71
+ homepage_uri: https://github.com/FooBarWidget/sorbet-rspec
72
+ source_code_uri: https://github.com/FooBarWidget/sorbet-rspec
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 2.7.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.5.3
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Sorbet integration for RSpec
92
+ test_files: []