sorbet_typed-props 1.4.0 → 1.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d75d26f9d4ce8fae5a4d485cdc0f34b48022b858cf9858d07abb1350cd318f08
4
- data.tar.gz: 71d4cb2814dfcf770731d42d0837d4eb12ac165888de3071d12231d6f7be80a2
3
+ metadata.gz: 9f174dad33ad91ad3f978dca0a7048436f5174ddc4697d986352eea398efe3ce
4
+ data.tar.gz: 0425e0dbfc6549cccdac000060c1f968d7877fb815c2f7e0374e494101887d40
5
5
  SHA512:
6
- metadata.gz: 6f32d2099bde759467ed2228fd35faf17f3512ea42943cd26d82b44ec0a82ef52fd9d77ebda87529dcf5846066f8308a2708144b4ffbb86b245b46346064b8e1
7
- data.tar.gz: d277f49266b116d6d9050dfb88a09bd1ed7def6504aed453af804f0b7902011f495ff26f555b80d61ac4916c45aedcffdf153c1259e54d42a3ba3da4361923db
6
+ metadata.gz: 1e63e26d0ad9e645e56efeda20b3df2aab26f0fac3da887a175c8d1b75dc8062a1360b6e615f370b8b6f065f93c93961e7947006a1840d76e89c2014c233c5c0
7
+ data.tar.gz: 9e7310699fe6272d445e59a46b1c08c17fc3ccf0e27c0aecf3b41b8a595415ab5bcf52919db8a40d43e2efe4b971dc2516df2bf76c017ad87d07c7ed35fb7e27
data/.cz.yaml CHANGED
@@ -15,7 +15,7 @@ commitizen:
15
15
  - mise run format
16
16
  tag_format: v$version
17
17
  update_changelog_on_bump: true
18
- version: 1.4.0
18
+ version: 1.5.0
19
19
  version_files:
20
20
  - lib/sorbet_typed/props/version.rb
21
21
  version_scheme: semver2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## v1.5.0 (2026-06-22)
2
+
3
+ ### Feat
4
+
5
+ - **mocks**: make doubles work for props
6
+
1
7
  ## v1.4.0 (2026-05-29)
2
8
 
3
9
  ### Feat
@@ -5,7 +5,7 @@
5
5
 
6
6
  module SorbetTyped
7
7
  module Props
8
- VERSION = '1.4.0'
8
+ VERSION = '1.5.0'
9
9
  end
10
10
  end
11
11
 
@@ -21,14 +21,60 @@ module SorbetTyped
21
21
  end
22
22
  def prop_get(instance, prop, rules = T.unsafe(self).prop_rules(prop))
23
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"
24
+ if prop_read_before_set?(value, rules)
25
+ raise TypeError,
26
+ "Property `#{prop}` of `#{T.unsafe(instance).class.name}` was read before being set"
27
27
  end
28
-
29
28
  value
30
29
  end
31
30
 
31
+ private
32
+
33
+ sig { params(value: T.untyped, rules: T::Props::Decorator::Rules).returns(T::Boolean) }
34
+ def prop_read_before_set?(value, rules)
35
+ !!(rules.dig(:extra, :initializer) == false &&
36
+ !rules[:type_object].valid?(value) &&
37
+ !rspec_double_valid_for_type?(value, rules[:type_object]))
38
+ end
39
+
40
+ # NOTE: allows RSpec verifying doubles (e.g. instance_double) to be used
41
+ # as values for props with `extra: { initializer: false }` without
42
+ # triggering the "read before being set" error. This mirrors the approach
43
+ # taken by the rspec-sorbet gem for T.let/T.cast type checks.
44
+ sig { params(value: T.untyped, type_object: T::Types::Base).returns(T::Boolean) }
45
+ def rspec_double_valid_for_type?(value, type_object)
46
+ # :nocov: -- entry guard not testable without loading a non-RSpec
47
+ # environment
48
+ return false unless defined?(RSpec::Mocks::InstanceVerifyingDouble)
49
+ # :nocov:
50
+
51
+ return false unless value.is_a?(RSpec::Mocks::InstanceVerifyingDouble)
52
+
53
+ # :nocov: -- nil cases not really testable without constructing
54
+ # pathological doubles from scratch
55
+ target = value.instance_variable_get(:@doubled_module)&.target
56
+ return false if target.nil?
57
+ # :nocov:
58
+
59
+ rspec_double_target_matches_type?(target, type_object)
60
+ end
61
+
62
+ sig { params(target: T::Module[T.anything], type_object: T::Types::Base).returns(T::Boolean) }
63
+ def rspec_double_target_matches_type?(target, type_object)
64
+ case type_object
65
+ when T::Types::Simple
66
+ target.ancestors.include?(type_object.raw_type)
67
+ when T::Types::Union
68
+ type_object.types.any? { |t| t.is_a?(T::Types::Simple) && target.ancestors.include?(t.raw_type) }
69
+ # :nocov: -- else false not reachable with standard Sorbet type objects (always Simple or Union)
70
+ else
71
+ false
72
+ end
73
+ # :nocov:
74
+ end
75
+
76
+ public
77
+
32
78
  # DEBT: is there a better way to do this without duplicating so much code?
33
79
  #
34
80
  # source: https://github.com/sorbet/sorbet/blob/e554cf64fa404eb5ee5fdc87186968a190613759/gems/sorbet-runtime/lib/types/props/constructor.rb#L19-L39
@@ -3,5 +3,5 @@
3
3
  #
4
4
  # Each value is the definitive upper bound (patch-level inclusive); update:appraisal
5
5
  # tests all minors from the gemspec lower bound up to and including this exact version.
6
- sorbet-runtime: '0.6.13256'
6
+ sorbet-runtime: '0.6.13298'
7
7
  tapioca: '0.19.1'
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.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Kramer