sorbet_typed-props 1.2.26 → 1.3.1
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 +4 -4
- data/.cz.yaml +1 -1
- data/CHANGELOG.md +13 -0
- data/lib/sorbet_typed/props/version.rb +1 -1
- data/lib/sorbet_typed/props/without_init_param_and_no_default_plugin.rb +70 -0
- data/lib/sorbet_typed/props.rb +32 -3
- data/lib/tapioca/dsl/compilers/sorbet_typed_props_constructor.rb +17 -4
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6f80c4674a08ae9058e8a570f722b2ccfda210ef3f43b336f00e910845ad088a
|
|
4
|
+
data.tar.gz: c405cd17902a32f07aa9a1d6313b5abe1f5d64680afc0031a96ed921e5e452bb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d50b7877a06e1fbb804cca98972cf8d74f71ce3c18424e0982264d750f5af5c9b28e7068140693cb80f939c3bcefd8e71a0a6e477c0bb45a5791e32ed95751f
|
|
7
|
+
data.tar.gz: 57614b08bfc8fb4a246446645ae0045229c53885becc044f88fdc5ea5ffed6fecc5834ac2464b0afedeb0bf670944997a976702b7e4d47eecf1a2170759d8c4d
|
data/.cz.yaml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## v1.3.1 (2026-01-29)
|
|
2
|
+
|
|
3
|
+
### Fix
|
|
4
|
+
|
|
5
|
+
- **deps**: update sorbet to v0.6.12904
|
|
6
|
+
- **deps**: update sorbet to v0.6.12903
|
|
7
|
+
|
|
8
|
+
## v1.3.0 (2026-01-27)
|
|
9
|
+
|
|
10
|
+
### Feat
|
|
11
|
+
|
|
12
|
+
- add a way to define props that should not be part of the initializer
|
|
13
|
+
|
|
1
14
|
## v1.2.26 (2026-01-24)
|
|
2
15
|
|
|
3
16
|
### Fix
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module SorbetTyped
|
|
5
|
+
module Props
|
|
6
|
+
class WithoutInitParamAndNoDefaultPlugin
|
|
7
|
+
# this overrides how T::Props::Constructor builds props without defaults.
|
|
8
|
+
# It allows defining props excluded from the initializer without setting a
|
|
9
|
+
# default.
|
|
10
|
+
module DecoratorMethods
|
|
11
|
+
extend T::Sig
|
|
12
|
+
include Kernel
|
|
13
|
+
|
|
14
|
+
sig do
|
|
15
|
+
params(
|
|
16
|
+
instance: T::Props::Decorator::DecoratedInstance,
|
|
17
|
+
prop: Symbol,
|
|
18
|
+
rules: T::Props::Decorator::Rules
|
|
19
|
+
).
|
|
20
|
+
returns(T.untyped)
|
|
21
|
+
end
|
|
22
|
+
def prop_get(instance, prop, rules = T.unsafe(self).prop_rules(prop))
|
|
23
|
+
value = super
|
|
24
|
+
|
|
25
|
+
if rules.dig(:extra, :initializer) == false && !rules[:type_object].valid?(value)
|
|
26
|
+
raise TypeError, "Property `#{prop}` of `#{T.unsafe(instance).class.name}` was read before being set"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# DEBT: is there a better way to do this without duplicating so much code?
|
|
33
|
+
#
|
|
34
|
+
# source: https://github.com/sorbet/sorbet/blob/e554cf64fa404eb5ee5fdc87186968a190613759/gems/sorbet-runtime/lib/types/props/constructor.rb#L19-L39
|
|
35
|
+
sig { params(instance: T::Props::Constructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never) }
|
|
36
|
+
# :reek:DuplicateMethodCall :reek:TooManyStatements
|
|
37
|
+
# :reek:UncommunicativeVariableName -- We ignore these smells, as they
|
|
38
|
+
# are already present in the original code and I don't want to modify
|
|
39
|
+
# it.
|
|
40
|
+
def construct_props_without_defaults(instance, hash) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength -- we ignore these warnings as they stem from the original implementation which we keep as much as possible
|
|
41
|
+
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
|
|
42
|
+
# and therefore allocates for each entry.
|
|
43
|
+
result = 0
|
|
44
|
+
|
|
45
|
+
# :nocov: -- NOTE: There is no test covering the nil-scenario. But this
|
|
46
|
+
# code is taken straight from sorbet, so there shouldn't really be a
|
|
47
|
+
# need to retest it. I also couldn't even construct a scenario where
|
|
48
|
+
# props_without_defaults would be nil.
|
|
49
|
+
T.unsafe(self).props_without_defaults&.each_pair do |p, setter_proc|
|
|
50
|
+
# :nocov:
|
|
51
|
+
|
|
52
|
+
# NOTE: this is the only change to this method taken from T::Props::Constructor::DecoratorMethods
|
|
53
|
+
next if T.unsafe(self).props.dig(p, :extra, :initializer) == false
|
|
54
|
+
|
|
55
|
+
val = hash[p]
|
|
56
|
+
instance.instance_exec(val, &setter_proc)
|
|
57
|
+
result += 1 if val || hash.key?(p)
|
|
58
|
+
rescue TypeError, T::Props::InvalidValueError
|
|
59
|
+
unless hash.key?(p)
|
|
60
|
+
raise ArgumentError, "Missing required prop `#{p}` for class `#{T.unsafe(instance).class.name}`"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
raise
|
|
64
|
+
end
|
|
65
|
+
result
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/sorbet_typed/props.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require 'sorbet-runtime'
|
|
5
5
|
require_relative 'props/version'
|
|
6
|
+
require_relative 'props/without_init_param_and_no_default_plugin'
|
|
6
7
|
|
|
7
8
|
module SorbetTyped
|
|
8
9
|
# an abstraction module to be included in any class to make the sorbet props
|
|
@@ -20,10 +21,29 @@ module SorbetTyped
|
|
|
20
21
|
include T::Props
|
|
21
22
|
include T::Props::Constructor
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
include Kernel
|
|
25
|
+
|
|
26
|
+
plugin(WithoutInitParamAndNoDefaultPlugin)
|
|
27
|
+
|
|
28
|
+
# Methods injected into the including class singleton
|
|
29
|
+
module ClassMethods
|
|
30
|
+
extend T::Sig
|
|
31
|
+
include T::Props::ClassMethods
|
|
32
|
+
|
|
33
|
+
sig { returns(T::Hash[Symbol, T::Props::Decorator::Rules]) }
|
|
34
|
+
def props_in_initializer
|
|
35
|
+
props.reject do |_, prop_parameters|
|
|
36
|
+
prop_parameters.dig(:extra, :initializer) == false
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
mixes_in_class_methods(ClassMethods)
|
|
42
|
+
|
|
43
|
+
sig { params(hash: T::Hash[Symbol, T.untyped]).void }
|
|
44
|
+
def initialize(hash = {})
|
|
45
|
+
reject_unknown_parameters(hash)
|
|
24
46
|
|
|
25
|
-
sig { params(args: T.anything, kwargs: T.anything).void }
|
|
26
|
-
def initialize(*args, **kwargs)
|
|
27
47
|
super
|
|
28
48
|
post_props_initialize
|
|
29
49
|
end
|
|
@@ -32,5 +52,14 @@ module SorbetTyped
|
|
|
32
52
|
|
|
33
53
|
sig { overridable.void }
|
|
34
54
|
def post_props_initialize; end
|
|
55
|
+
|
|
56
|
+
sig { params(parameters: T::Hash[Symbol, T.anything]).void }
|
|
57
|
+
# :reek:DuplicateMethodCall { allow_calls: ["self.class"] }
|
|
58
|
+
def reject_unknown_parameters(parameters)
|
|
59
|
+
unknown_parameters = parameters.keys - self.class.props_in_initializer.keys
|
|
60
|
+
return unless unknown_parameters.any?
|
|
61
|
+
|
|
62
|
+
raise ArgumentError, "#{self.class}: Unrecognized properties: #{unknown_parameters.join(', ')}"
|
|
63
|
+
end
|
|
35
64
|
end
|
|
36
65
|
end
|
|
@@ -11,7 +11,7 @@ module Tapioca
|
|
|
11
11
|
extend T::Sig
|
|
12
12
|
extend T::Generic
|
|
13
13
|
|
|
14
|
-
ConstantType = type_member { { upper: T::Class[SorbetTyped::Props] } }
|
|
14
|
+
ConstantType = type_member { { upper: T.all(T::Class[SorbetTyped::Props], T::Props::ClassMethods) } }
|
|
15
15
|
|
|
16
16
|
sig { override.returns(T::Enumerable[T::Module[T.anything]]) }
|
|
17
17
|
def self.gather_constants
|
|
@@ -25,7 +25,7 @@ module Tapioca
|
|
|
25
25
|
return if T::AbstractUtils.abstract_module?(constant)
|
|
26
26
|
# NOTE: do not generate a new initializer signature, if the class sets
|
|
27
27
|
# its own and doesn't use the prop generated one.
|
|
28
|
-
return if constant.
|
|
28
|
+
return if constant.private_method_defined?(:initialize, false)
|
|
29
29
|
return if props.empty?
|
|
30
30
|
|
|
31
31
|
define_initializer_sig
|
|
@@ -35,16 +35,29 @@ module Tapioca
|
|
|
35
35
|
|
|
36
36
|
sig { returns(T::Hash[Symbol, T::Hash[Symbol, T.untyped]]) }
|
|
37
37
|
def props
|
|
38
|
+
@props ||= T.let(
|
|
39
|
+
constant.props,
|
|
40
|
+
T.nilable(T::Hash[Symbol, T::Hash[Symbol, T.untyped]])
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
sig { returns(T::Hash[Symbol, T::Hash[Symbol, T.untyped]]) }
|
|
45
|
+
def props_in_initializer
|
|
38
46
|
# NOTE: we already filtered in `::gather_constants` for classes that
|
|
39
47
|
# include `SorbetTyped::Props`, so we know it must be this type and
|
|
40
48
|
# has method `props`.
|
|
41
|
-
@
|
|
49
|
+
@props_in_initializer ||= T.let(
|
|
50
|
+
props.reject do |_name, rules|
|
|
51
|
+
rules.dig(:extra, :initializer) == false
|
|
52
|
+
end,
|
|
53
|
+
T.nilable(T::Hash[Symbol, T::Hash[Symbol, T.untyped]])
|
|
54
|
+
)
|
|
42
55
|
end
|
|
43
56
|
|
|
44
57
|
sig { returns(T::Array[RBI::TypedParam]) }
|
|
45
58
|
def params
|
|
46
59
|
@params ||= T.let(
|
|
47
|
-
|
|
60
|
+
props_in_initializer.map do |name, details|
|
|
48
61
|
create_param_from_prop(name:, details:)
|
|
49
62
|
end,
|
|
50
63
|
T.nilable(T::Array[RBI::TypedParam])
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sorbet_typed-props
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Richard Kramer
|
|
@@ -18,7 +18,7 @@ dependencies:
|
|
|
18
18
|
version: 0.6.0
|
|
19
19
|
- - "<="
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.6.
|
|
21
|
+
version: 0.6.12904
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -28,7 +28,7 @@ dependencies:
|
|
|
28
28
|
version: 0.6.0
|
|
29
29
|
- - "<="
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
|
-
version: 0.6.
|
|
31
|
+
version: 0.6.12904
|
|
32
32
|
- !ruby/object:Gem::Dependency
|
|
33
33
|
name: tapioca
|
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -68,6 +68,7 @@ files:
|
|
|
68
68
|
- README.md
|
|
69
69
|
- lib/sorbet_typed/props.rb
|
|
70
70
|
- lib/sorbet_typed/props/version.rb
|
|
71
|
+
- lib/sorbet_typed/props/without_init_param_and_no_default_plugin.rb
|
|
71
72
|
- lib/tapioca/dsl/compilers/sorbet_typed_props_constructor.rb
|
|
72
73
|
- lib/tapioca/dsl/compilers/sorbet_typed_props_constructor/prop_to_param_converter.rb
|
|
73
74
|
homepage: https://gitlab.com/sorbet_typed/props
|