Exemplo
Show that T::Struct.from_hash bypasses the runtime type enforcement that the .new constructor applies
sha256:49b3a0ec0dc911830c4cf62df5ff6bb54e1006a59d4d7830a843495fc1ee8400
PUBLISHED
L3_CONTRACT_PASS
MIT-0
Caso
- Objetivo
- Show that T::Struct.from_hash bypasses the runtime type enforcement that the .new constructor applies HOW
- Pacotes
- sorbet-runtime 0.6.13427
- Ambiente
- ruby
- Criado
- 2026-08-17T02:49:00Z
O que costuma-se supor
Because T::Struct declares prop types and the .new constructor raises TypeError when a value does not match, from_hash — the documented deserialization path — applies the same check and raises on mismatched types.
O autor da amostra registrou aqui o que um desenvolvedor ou um modelo esperaria. O contrato abaixo é o que de fato rodou.
Contrato
- T::Struct.from_hash accepts a String value for a prop declared Integer and returns it unchanged without raising TypeError, while T::Struct.new raises TypeError for the identical input — proving that the deserialization path skips the sig-based check the constructor applies
- assert ConnectionRecord.from_hash('port' => '5432').port == '5432'
- assert ConnectionRecord.new(port: '5432') raises TypeError matching /Can't set ConnectionRecord\.port/
- assert from_hash with an unknown string key silently discards it rather than raising
- assert from_hash with symbol keys treats them as absent and raises RuntimeError about nil deserialization
- assert from_hash with Integer elements inside a T::Array[String] prop returns them unchanged — element types are not checked
Arquivos
- Gemfile
- Gemfile.lock
- NOTES.md
- csx.json
- src/model.rb
- test/contract.rb
Baixar o artefato verificado (tar.gz) — exatamente os bytes contra os quais o contrato rodou
Seeder de origem
Recibos de verificação
- ruby 3 · CONTAINER_RUN · compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS · rubygems@1 · 2026-08-17 · ed25519:d91480838ac982c9