sorbet-runtime 0.5.5439 → 0.5.5449

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15b884405afe5ef1a9261206433553142c10166302d6bcc80e9ffed82343ac4c
4
- data.tar.gz: 2c5a550e1d9b9363cacefc36ce53fa86a3b36bde40f6f018e8bfad4632130a5b
3
+ metadata.gz: 86d060de12c48696ab8a6c9647bb57c006d71c23cd8e1256796b3057a436c050
4
+ data.tar.gz: 16a69f327d8477a9f8c0ea2320a226037489ad58fa0dab940a863819365c6ad5
5
5
  SHA512:
6
- metadata.gz: '0038a4dd9590fd6c8cdd30c41eea8767f2ad6c30e779979e8d4b880132c8d352343d0a46ef1ef1852edcadc157b28b09e498d356721d518734817e0759958aa1'
7
- data.tar.gz: c6e0dad262a7105db18b126d8fc01168ec3a3a7c5f6982f1753368561d77540b40384f7cfaed50e38e94767ff136a306c22d377b0c6db6ee965cd3d44f14a793
6
+ metadata.gz: eee05964b0496ec92f20dd35f425c375b7e5f20a856ef84a450383a5f164e62a76d0c94cda65074624b9730c6975563e3e9946525acccc532530d8fbce93540a
7
+ data.tar.gz: 0eed76a0fa31537f0362bc779b8787d59457c3c882d53432412b03a20015d77dbccb89556235a412d91a966fe45f8866e313dc9b352b6f53c52a7de38ae0ddc9
@@ -148,7 +148,24 @@ module T::Props
148
148
  assert_equal(s(:op_asgn, s(:lvasgn, :found), :-, s(:int, 1)), found_else_body)
149
149
 
150
150
  validate_deserialize_handle_nil(handle_nil)
151
- validate_lack_of_side_effects(else_body, whitelisted_methods_for_deserialize)
151
+
152
+ if else_body.type == :kwbegin
153
+ rescue_expression, = else_body.children
154
+ assert_equal(:rescue, rescue_expression.type)
155
+
156
+ try, rescue_body = rescue_expression.children
157
+ validate_lack_of_side_effects(try, whitelisted_methods_for_deserialize)
158
+
159
+ assert_equal(:resbody, rescue_body.type)
160
+ exceptions, assignment, handler = rescue_body.children
161
+ assert_equal(:array, exceptions.type)
162
+ exceptions.children.each {|c| assert_equal(:const, c.type)}
163
+ assert_equal(:lvasgn, assignment.type)
164
+ assert_equal([:e], assignment.children)
165
+ validate_lack_of_side_effects(handler, whitelisted_methods_for_deserialize)
166
+ else
167
+ validate_lack_of_side_effects(else_body, whitelisted_methods_for_deserialize)
168
+ end
152
169
  end
153
170
 
154
171
  private_class_method def self.validate_deserialize_handle_nil(node)
@@ -244,7 +261,7 @@ module T::Props
244
261
  private_class_method def self.whitelisted_methods_for_deserialize
245
262
  @whitelisted_methods_for_deserialize ||= {
246
263
  :lvar => %i{dup map transform_values transform_keys each_with_object nil? []=},
247
- :const => %i{deserialize from_hash deep_clone_object},
264
+ :const => %i{deserialize from_hash deep_clone_object soft_assert_handler},
248
265
  }
249
266
  end
250
267
  end
@@ -43,11 +43,33 @@ module T::Props
43
43
  ivar_name = rules.fetch(:accessor_key).to_s
44
44
  raise unless ivar_name.start_with?('@') && T::Props::Decorator::SAFE_NAME.match?(ivar_name[1..-1])
45
45
 
46
- transformed_val = SerdeTransform.generate(
46
+ transformation = SerdeTransform.generate(
47
47
  T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)),
48
48
  SerdeTransform::Mode::DESERIALIZE,
49
49
  'val'
50
- ) || 'val'
50
+ )
51
+ if transformation
52
+ # Rescuing exactly NoMethodError is intended as a temporary hack
53
+ # to preserve the semantics from before codegen. More generally
54
+ # we are inconsistent about typechecking on deser and need to decide
55
+ # our strategy here.
56
+ transformed_val = <<~RUBY
57
+ begin
58
+ #{transformation}
59
+ rescue NoMethodError => e
60
+ T::Configuration.soft_assert_handler(
61
+ 'Deserialization error (probably unexpected stored type)',
62
+ klass: self.class,
63
+ prop: #{prop.inspect},
64
+ value: val,
65
+ error: e.message
66
+ )
67
+ val
68
+ end
69
+ RUBY
70
+ else
71
+ transformed_val = 'val'
72
+ end
51
73
 
52
74
  nil_handler = generate_nil_handler(
53
75
  prop: prop,
@@ -69,6 +69,16 @@ module T::Props
69
69
  handle_serializable_subtype(varname, raw, mode)
70
70
  elsif raw.singleton_class < T::Props::CustomType
71
71
  handle_custom_type(varname, T.unsafe(raw), mode)
72
+ elsif T::Configuration.scalar_types.include?(raw.name)
73
+ # It's a bit of a hack that this is separate from NO_TRANSFORM_TYPES
74
+ # and doesn't check inheritance (like `T::Props::CustomType.scalar_type?`
75
+ # does), but it covers the main use case (pay-server's custom `Boolean`
76
+ # module) without either requiring `T::Configuration.scalar_types` to
77
+ # accept modules instead of strings (which produces load-order issues
78
+ # and subtle behavior changes) or eating the performance cost of doing
79
+ # an inheritance check by manually crawling a class hierarchy and doing
80
+ # string comparisons.
81
+ nil
72
82
  else
73
83
  "T::Props::Utils.deep_clone_object(#{varname})"
74
84
  end
@@ -82,7 +92,12 @@ module T::Props
82
92
  "#{varname}.nil? ? nil : #{inner}"
83
93
  end
84
94
  else
85
- "T::Props::Utils.deep_clone_object(#{varname})"
95
+ # Handle, e.g., T::Boolean
96
+ if type.types.all? {|t| generate(t, mode, varname).nil?}
97
+ nil
98
+ else
99
+ "T::Props::Utils.deep_clone_object(#{varname})"
100
+ end
86
101
  end
87
102
  when T::Types::Enum
88
103
  generate(T::Utils.lift_enum(type), mode, varname)
@@ -16,7 +16,21 @@ module T::Props::Serializable
16
16
  # values.
17
17
  # @return [Hash] A serialization of this object.
18
18
  def serialize(strict=true)
19
- h = __t_props_generated_serialize(strict)
19
+ begin
20
+ h = __t_props_generated_serialize(strict)
21
+ rescue => e
22
+ msg = self.class.decorator.message_with_generated_source_context(
23
+ e,
24
+ :__t_props_generated_serialize,
25
+ :generate_serialize_source
26
+ )
27
+ if msg
28
+ raise T::Props::InvalidValueError.new(msg)
29
+ else
30
+ raise
31
+ end
32
+ end
33
+
20
34
  h.merge!(@_extra_props) if @_extra_props
21
35
  h
22
36
  end
@@ -39,7 +53,21 @@ module T::Props::Serializable
39
53
  # props on this instance.
40
54
  # @return [void]
41
55
  def deserialize(hash, strict=false)
42
- hash_keys_matching_props = __t_props_generated_deserialize(hash)
56
+ begin
57
+ hash_keys_matching_props = __t_props_generated_deserialize(hash)
58
+ rescue => e
59
+ msg = self.class.decorator.message_with_generated_source_context(
60
+ e,
61
+ :__t_props_generated_deserialize,
62
+ :generate_deserialize_source
63
+ )
64
+ if msg
65
+ raise T::Props::InvalidValueError.new(msg)
66
+ else
67
+ raise
68
+ end
69
+ end
70
+
43
71
  if hash.size > hash_keys_matching_props
44
72
  serialized_forms = self.class.decorator.prop_by_serialized_forms
45
73
  extra = hash.reject {|k, _| serialized_forms.key?(k)}
@@ -181,6 +209,24 @@ module T::Props::Serializable::DecoratorMethods
181
209
  )
182
210
  end
183
211
 
212
+ def message_with_generated_source_context(error, generated_method, generate_source_method)
213
+ line_label = error.backtrace.find {|l| l.end_with?("in `#{generated_method}'")}
214
+ return unless line_label
215
+
216
+ line_num = line_label.split(':')[1]&.to_i
217
+ return unless line_num
218
+
219
+ source_lines = self.send(generate_source_method).split("\n")
220
+ previous_blank = source_lines[0...line_num].rindex(&:empty?) || 0
221
+ next_blank = line_num + (source_lines[line_num..-1].find_index(&:empty?) || 0)
222
+ context = " " + source_lines[(previous_blank + 1)...(next_blank)].join("\n ")
223
+ <<~MSG
224
+ Error in #{decorated_class.name}##{generated_method}: #{error.message}
225
+ at line #{line_num-previous_blank-1} in:
226
+ #{context}
227
+ MSG
228
+ end
229
+
184
230
  def raise_nil_deserialize_error(hkey)
185
231
  msg = "Tried to deserialize a required prop from a nil value. It's "\
186
232
  "possible that a nil value exists in the database, so you should "\
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorbet-runtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5439
4
+ version: 0.5.5449
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-14 00:00:00.000000000 Z
11
+ date: 2020-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest