샘플
json 2.9.1: Parse and serialize Ruby data structures with JSON.[] dispatch, decimal_class precision, custom container classes, streaming JSON.dump depth checks, and core type additions
검증된 샘플 — gem json 2.9.1: Parse and serialize Ruby data structures with JSON.[] dispatch, decimal_class precision, custom container classes, streaming…
sha256:a87be603acbde77905b8b59ae00abe846be04ddcac05e754dcc29647170a50de
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 2
- 빌드한 서명 키
- 2
선언된 환경
ruby linux x64 ruby ruby rubygems
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| ruby 3 · linux debian/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · rubygems@1 |
2026-08-17 |
| ruby 3 · linux debian/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · rubygems@1 |
2026-08-18 |
케이스
HOW- 목표
- Parse and serialize Ruby data structures with JSON.[] dispatch, decimal_class precision, custom container classes, streaming JSON.dump depth checks, and core type additions
- 패키지
- 심벌
-
- JSON.[]
- JSON.parse
- JSON.dump
- JSON.create_id
- json/add/time
- json/add/date
- json/add/struct
- json/add/set
- json/add/symbol
- 환경
- ruby
- 생성일
- 2026-08-17T12:28:09Z
컨트랙트
- assert JSON.[] operates as a polymorphic dispatch method that delegates String arguments to JSON.parse and non-String Ruby objects to JSON.generate
- assert JSON.parse with decimal_class: BigDecimal preserves exact arbitrary-precision decimal representations without IEEE 754 float rounding loss
- assert JSON.parse supports custom collection containers via array_class and object_class
- assert JSON.dump streams serialized output directly to IO destinations when provided and enforces strict recursion depth limits raising ArgumentError when exceeded
- assert requiring json/add core extensions enables bidirectional JSON serialization for Time, Date, Struct, Set, and Symbol types using create_additions: true
- assert JSON.create_id configures the addition type identifier attribute and setting custom values alters the tag matched during deserialization
파일
- Gemfile
- Gemfile.lock
- NOTES.md
- csx.json
- src/json_features.rb
- test/contract.rb
소스
source "https://rubygems.org"
gem "json", "2.9.1"
gem "bigdecimal"
GEM
remote: https://rubygems.org/
specs:
bigdecimal (4.1.2)
json (2.9.1)
PLATFORMS
ruby
x64-mingw-ucrt
DEPENDENCIES
bigdecimal
json (= 2.9.1)
CHECKSUMS
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac
json (2.9.1) sha256=d2bdef4644052fad91c1785d48263756fe32fcac08b96a20bb15840e96550d11
BUNDLED WITH
4.0.18
# Ruby `json` Library: Dispatch, Precision, Containers, IO Streaming, and Core Type Additions
## 1. What `search_known_solution` answered
`search_known_solution` returned existing published samples:
- `sha256:872c9e461ccac83e7b19625704d8e2280fefb4903330c45f8b5925114ada2453`: Focused on `JSON.load` positional keyword-proc collision with `create_additions`, `max_nesting: 0` vs `max_nesting: false` depth limit bypasses, `freeze: true` deep immutability, and generator `script_safe` tag escaping.
- `sha256:bc062acc906536678976cf1c339f352acd1b7ab93a8126083d2e995f58c8816b`: Focused on `JSON.parse!` relaxed parsing limits, core additions for `Range`, `Regexp`, `Complex`, and `Rational`, custom `to_json` arity and `JSON::State` whitespace formatting.
This sample proves a distinct set of behaviors in the Ruby `json` library:
1. Polymorphic dispatch through `JSON.[]`: `JSON[string]` delegates to `JSON.parse`, while `JSON[object]` delegates to `JSON.generate`, forwarding optional configuration arguments.
2. Precision preservation with `decimal_class: BigDecimal`: Default parsing coerces fractional numbers to standard `Float` instances, truncating long decimal sequences; configuring `decimal_class: BigDecimal` preserves arbitrary-precision values exactly.
3. Custom collection parsing with `array_class` and `object_class`: Custom container subclasses can be designated to hold parsed arrays and objects.
4. `JSON.dump` IO destination streaming and recursion depth limit: Passing an `IO` (or `StringIO`) object streams serialized output directly to the destination and returns the stream instance; specifying a shallow recursion limit enforces depth checks and raises `ArgumentError` when exceeded.
5. Standard library additions: Requiring `json/add/time`, `json/add/date`, `json/add/struct`, `json/add/set`, and `json/add/symbol` enables bidirectional serialization with `"json_class"` metadata and `create_additions: true` restoration.
6. Tag configuration with `JSON.create_id`: Modifying `JSON.create_id` customizes the addition identifier key looked up during addition creation.
## 2. Pinned Version
- Pinned release: `pkg:gem/json@2.9.1`
## 3. Observed Behavior
- `JSON['{"service":"catalog"}']` returns a `Hash` (`{"service"=>"catalog"}`), whereas `JSON[{ service: "catalog" }]` returns a `String` (`"{\"service\":\"catalog\"}"`).
- Parsing `'{"val":0.12345678901234567890123456789}'` yields a `Float` with lost precision by default, but yields an exact `BigDecimal` matching the original decimal literal when `decimal_class: BigDecimal` is supplied.
- `JSON.parse(..., array_class: CustomArray, object_class: CustomObject)` populates the specified container types instead of generic `Array` and `Hash` instances.
- `JSON.dump(payload, io)` writes JSON to the IO stream and returns `io`, while `JSON.dump(deep_array, limit)` raises `ArgumentError: exceed depth limit` if nesting exceeds `limit`.
- Native `Time` instances serialize with seconds and nanoseconds (`{"json_class":"Time","s":...,"n":...}`); deserializing with `create_additions: true` recovers the exact `Time` instance with matching `.nsec`.
- Native `Date`, `Struct`, `Set`, and `Symbol` instances serialize to structured JSON hashes with `"json_class"` and reconstruct to identical Ruby objects when `create_additions: true` is active.
- Changing `JSON.create_id` to a custom string shifts addition deserialization to match only hashes containing that custom key.
{"case":{"caseId":"case:sha256:cce90ff524e10afe1292b6b7dc75e7de763ddf949a34b0cc39679f55926584e7","contract":["assert JSON.[] operates as a polymorphic dispatch method that delegates String arguments to JSON.parse and non-String Ruby objects to JSON.generate","assert JSON.parse with decimal_class: BigDecimal preserves exact arbitrary-precision decimal representations without IEEE 754 float rounding loss","assert JSON.parse supports custom collection containers via array_class and object_class","assert JSON.dump streams serialized output directly to IO destinations when provided and enforces strict recursion depth limits raising ArgumentError when exceeded","assert requiring json/add core extensions enables bidirectional JSON serialization for Time, Date, Struct, Set, and Symbol types using create_additions: true","assert JSON.create_id configures the addition type identifier attribute and setting custom values alters the tag matched during deserialization"],"goal":"Parse and serialize Ruby data structures with JSON.[] dispatch, decimal_class precision, custom container classes, streaming JSON.dump depth checks, and core type additions","kind":"HOW","packages":["pkg:gem/json@2.9.1"],"schemaVersion":1,"symbols":["JSON.[]","JSON.parse","JSON.dump","JSON.create_id","json/add/time","json/add/date","json/add/struct","json/add/set","json/add/symbol"]},"contractCommand":["bundle","exec","ruby","test/contract.rb"],"environment":{"arch":"x64","ecosystem":"gem","executionContext":"ruby","language":"ruby","os":"linux","packageManager":"rubygems","runtime":"ruby","schemaVersion":1},"license":"MIT-0","packages":["pkg:gem/json@2.9.1"],"schemaVersion":1,"symbols":["JSON.[]","JSON.parse","JSON.dump","JSON.create_id","json/add/time","json/add/date","json/add/struct","json/add/set","json/add/symbol"],"verifierAdapter":"rubygems@1"}
# frozen_string_literal: true
require "json"
require "bigdecimal"
require "stringio"
require "date"
require "json/add/time"
require "json/add/date"
require "json/add/struct"
require "json/add/set"
require "json/add/symbol"
module JsonFeatures
# Custom Array container class for array_class option
class CustomArray < Array
end
# Custom Hash container class for object_class option
class CustomObject < Hash
end
# Polymorphic JSON gateway: parses strings and generates from objects
def self.dispatch(input, *opts)
JSON[input, *opts]
end
# Parses JSON with high decimal precision using BigDecimal
def self.parse_exact_decimal(json_str)
JSON.parse(json_str, decimal_class: BigDecimal)
end
# Parses JSON into customized collection types
def self.parse_custom_containers(json_str, array_class: CustomArray, object_class: CustomObject)
JSON.parse(json_str, array_class: array_class, object_class: object_class)
end
# Streams serialized JSON into an IO destination with optional recursion limit
def self.dump_to_stream(object, io, limit = nil)
if limit
JSON.dump(object, io, limit)
else
JSON.dump(object, io)
end
end
# Serializes to String enforcing depth limits
def self.dump_with_depth_limit(object, limit)
JSON.dump(object, limit)
end
end
# frozen_string_literal: true
require "bundler/setup"
require_relative "../src/json_features"
def assert(condition, message = "Assertion failed")
raise message unless condition
end
def assert_equal(expected, actual, message = nil)
msg = message || "Expected #{expected.inspect}, got #{actual.inspect}"
raise msg unless expected == actual
end
def assert_instance_of(klass, actual, message = nil)
msg = message || "Expected instance of #{klass}, got #{actual.class}"
raise msg unless actual.is_a?(klass)
end
def assert_raises(exception_klass)
raised = false
begin
yield
rescue exception_klass => e
raised = true
return e
rescue => e
raise "Expected #{exception_klass}, but got #{e.class} (#{e.message})"
end
raise "Expected #{exception_klass} to be raised, but nothing was raised"
end
# ---------------------------------------------------------------------------
# 1. Polymorphic JSON.[] gateway dispatch
# ---------------------------------------------------------------------------
raw_json = '{"service":"catalog","port":8080}'
parsed_subscript = JSON[raw_json]
assert_instance_of(Hash, parsed_subscript)
assert_equal("catalog", parsed_subscript["service"])
assert_equal(8080, parsed_subscript["port"])
parsed_with_opts = JSON[raw_json, symbolize_names: true]
assert_equal([:service, :port], parsed_with_opts.keys)
assert_equal("catalog", parsed_with_opts[:service])
data_obj = { service: "catalog", port: 8080 }
generated_subscript = JSON[data_obj]
assert_instance_of(String, generated_subscript)
assert_equal('{"service":"catalog","port":8080}', generated_subscript)
via_helper_parse = JsonFeatures.dispatch(raw_json)
assert_equal(parsed_subscript, via_helper_parse)
via_helper_gen = JsonFeatures.dispatch(data_obj)
assert_equal(generated_subscript, via_helper_gen)
# ---------------------------------------------------------------------------
# 2. Arbitrary decimal precision via decimal_class: BigDecimal
# ---------------------------------------------------------------------------
high_precision_json = '{"constant":0.12345678901234567890123456789}'
# Default Float parsing suffers IEEE 754 precision loss
default_parsed = JSON.parse(high_precision_json)
float_val = default_parsed["constant"]
assert_instance_of(Float, float_val)
assert(float_val.to_s != "0.12345678901234567890123456789", "Float was expected to truncate precision")
# Parsing with decimal_class: BigDecimal retains complete precision
exact_parsed = JsonFeatures.parse_exact_decimal(high_precision_json)
dec_val = exact_parsed["constant"]
assert_instance_of(BigDecimal, dec_val)
assert_equal(BigDecimal("0.12345678901234567890123456789"), dec_val)
# ---------------------------------------------------------------------------
# 3. Custom container classes with array_class and object_class
# ---------------------------------------------------------------------------
container_json = '{"nodes":[{"id":1},{"id":2}]}'
custom_result = JsonFeatures.parse_custom_containers(container_json)
assert_instance_of(JsonFeatures::CustomObject, custom_result)
assert_instance_of(JsonFeatures::CustomArray, custom_result["nodes"])
assert_instance_of(JsonFeatures::CustomObject, custom_result["nodes"][0])
assert_equal(1, custom_result["nodes"][0]["id"])
# ---------------------------------------------------------------------------
# 4. JSON.dump IO streaming and recursion depth limit enforcement
# ---------------------------------------------------------------------------
payload = { "host" => "example.com", "metrics" => [10, 20, 30] }
destination_stream = StringIO.new
# Dumping to IO writes to stream and returns the exact IO object
returned_io = JsonFeatures.dump_to_stream(payload, destination_stream)
assert(returned_io.equal?(destination_stream), "JSON.dump should return the destination IO object")
assert_equal('{"host":"example.com","metrics":[10,20,30]}', destination_stream.string)
# Enforcing depth limits via JSON.dump raises ArgumentError on exceed
shallow_limit_err = assert_raises(ArgumentError) do
JsonFeatures.dump_with_depth_limit([[[[1]]]], 3)
end
assert(shallow_limit_err.message.include?("exceed depth limit"), "Expected depth limit message in ArgumentError")
# Within depth limit, JSON.dump returns formatted string
allowed_depth_str = JsonFeatures.dump_with_depth_limit([[[1]]], 5)
assert_equal("[[[1]]]", allowed_depth_str)
# ---------------------------------------------------------------------------
# 5. Core type additions (Time, Date, Struct, Set, Symbol) bidirectional round-trip
# ---------------------------------------------------------------------------
# Time with nanosecond precision
time_source = Time.utc(2026, 8, 17, 14, 45, 30, 987654)
time_json = time_source.to_json
assert_equal("Time", JSON.parse(time_json)["json_class"])
restored_time = JSON.parse(time_json, create_additions: true)
assert_instance_of(Time, restored_time)
assert_equal(time_source, restored_time)
assert_equal(time_source.nsec, restored_time.nsec)
# Date
date_source = Date.new(2026, 8, 17)
date_json = date_source.to_json
assert_equal("Date", JSON.parse(date_json)["json_class"])
restored_date = JSON.parse(date_json, create_additions: true)
assert_instance_of(Date, restored_date)
assert_equal(date_source, restored_date)
# Struct
Employee = Struct.new("Employee", :id, :title) unless defined?(Employee)
struct_source = Employee.new(42, "lead")
struct_json = struct_source.to_json
assert_equal("Struct::Employee", JSON.parse(struct_json)["json_class"])
restored_struct = JSON.parse(struct_json, create_additions: true)
assert_instance_of(Employee, restored_struct)
assert_equal(struct_source, restored_struct)
# Set containing Symbols
set_source = Set.new([:read, :write])
set_json = set_source.to_json
assert_equal("Set", JSON.parse(set_json)["json_class"])
restored_set = JSON.parse(set_json, create_additions: true)
assert_instance_of(Set, restored_set)
assert_equal(set_source, restored_set)
assert(restored_set.all? { |item| item.is_a?(Symbol) }, "Set elements should remain Symbol instances")
# Without create_additions: true, outputs remain plain Hash representations
plain_hash = JSON.parse(time_json)
assert_instance_of(Hash, plain_hash)
assert_equal("Time", plain_hash["json_class"])
# ---------------------------------------------------------------------------
# 6. JSON.create_id customization
# ---------------------------------------------------------------------------
saved_create_id = JSON.create_id
begin
# Changing create_id changes which key is recognized as the addition class name
JSON.create_id = "_class"
custom_tag_json = '{"_class":"Time","s":1786968000,"n":0}'
# Standard json_class is ignored when create_id is changed
ignored_standard = JSON.parse(time_json, create_additions: true)
assert_instance_of(Hash, ignored_standard)
# Custom tag is instantiated
instantiated_custom = JSON.parse(custom_tag_json, create_additions: true)
assert_instance_of(Time, instantiated_custom)
ensure
JSON.create_id = saved_create_id
end
puts "Contract passed: all JSON behaviors verified successfully."