-
Notifications
You must be signed in to change notification settings - Fork 1
Json
Ori Pekelman edited this page May 11, 2026
·
1 revision
JSON encoder + flat-key decoder for JSON-over-HTTP. Hand-written
because the canonical json gem leans on classes and method_missing
patterns spinel doesn't lower.
- Encoder: primitives + Tep's typed hashes / arrays.
-
Decoder: flat-key reads (
Tep::Json.get_str(body, "name")). No nested traversal, no full AST. For nested JSON, use the dot notation in the key ("user.name"). - No streaming / SAX. Bodies are typically API responses up to a few KB.
Tep::Json.escape("hello \"world\"") # \" inside the string
Tep::Json.quote("hello") # "hello" (wrapped + escaped)
Tep::Json.encode_pair_str("name", "alice") # "name":"alice"
Tep::Json.encode_pair_int("age", 42) # "age":42For full hashes/arrays:
h = Tep.str_hash
h["name"] = "alice"
h["city"] = "tlv"
Tep::Json.from_str_hash(h)
# => {"name":"alice","city":"tlv"}
h2 = {"" => 0}; h2.delete("")
h2["a"] = 1; h2["b"] = 2
Tep::Json.from_int_hash(h2)
# => {"a":1,"b":2}
arr = [""]; arr.delete_at(0)
arr.push("x"); arr.push("y")
Tep::Json.from_str_array(arr)
# => ["x","y"]
arr2 = [0]; arr2.delete_at(0)
arr2.push(1); arr2.push(2)
Tep::Json.from_int_array(arr2)
# => [1,2]The empty-then-delete-at-0 idiom is the type-seed pattern spinel needs to pin the element type of an otherwise-empty array/hash.
body = '{"user": {"name": "alice"}, "age": 42, "active": true}'
Tep::Json.get_str(body, "user.name") # "alice"
Tep::Json.get_int(body, "age") # 42
Tep::Json.has_key?(body, "active") # true
Tep::Json.has_key?(body, "deleted") # false-
get_strreturns""if the key is missing. -
get_intreturns0if the key is missing or non-numeric. - Dot notation walks nested objects:
user.namereadsbody["user"]["name"]. - Arrays aren't supported in the decoder (yet). For an array response, treat it as opaque body bytes and parse downstream.
h = Tep.str_hash
h["name"] = params[:name]
h["email"] = params[:email]
req = Tep::Json.from_str_hash(h)
hdr = Tep.str_hash
hdr["Content-Type"] = "application/json"
res = Tep::Http.send_req("POST", "http://api.local/users", req, hdr)res = Tep::Http.get("http://api.local/users/42")
if res.status == 200
name = Tep::Json.get_str(res.body, "name")
age = Tep::Json.get_int(res.body, "age")
name + " (" + age.to_s + ")"
endget '/users/:id' do
content_type 'application/json'
h = Tep.str_hash
h["id"] = params[:id]
h["name"] = "alice"
Tep::Json.from_str_hash(h)
end-
No floats. Numbers round-trip as
INTEGERonly. If you need1.5, encode it as a string and parse on the other side. -
No arrays in the decoder. A response body
[1,2,3]won't decode throughget_int; treat array responses as opaque strings and parse by hand (split(",")on the trimmed body, etc.). - Whitespace tolerance. The decoder skips ASCII whitespace between tokens but is otherwise strict. Tabs and unicode-space characters aren't handled — fine for real JSON, surprising if you're feeding it hand-formatted data.
-
The encoder doesn't escape U+2028 / U+2029. These are valid in
JSON but invalid in JavaScript string literals. If your output
goes straight into a
<script>tag, post-process.