Module: Heatwave::RubyHashInspectConverter

Defined in:
app/lib/heatwave/ruby_hash_inspect_converter.rb

Overview

Converts Ruby Hash#inspect output (the symbol-shorthand form,
e.g. {label_format: "pdf", count: 3, void: nil}) into valid JSON
for display in the Shipping API Log tab.

Why: pre-fix ShipEngine label persistence (commit a16f53b528 and
earlier) stuffed label_options.to_hash.inspect strings into
shipping_api_log.request / .response. That output is not valid
JSON, so the pretty_json_tag JSON-tree renderer falls back to a
plain block — unreadable for nested payloads. New labels
persist actual Hashes; this converter lets us retro-fit the old
rows display-side without any database migration or eval on
stored strings.

Safety: a hand-rolled tokenizer, not eval. String literals are
copied verbatim so a colon inside a string value ("Mr. foo: bar")
won't be mistaken for a hash-key separator. The transform is purely
syntactic — no method dispatch, no variable resolution, no execution.

Scope: handles the subset of Ruby literals that Hash#inspect
actually emits for JSON-shaped data:

  • symbol-shorthand keys (foo:) → JSON string keys ("foo":)
  • hash-rocket old style ("foo" =>) → JSON colon ("foo":)
  • nilnull
  • true / false / numbers / strings / arrays / nested hashes
    pass through unchanged

Returns nil when the converted output still doesn't parse as JSON,
so callers can fall back to verbatim rendering.

Examples:

Heatwave::RubyHashInspectConverter.call('{a: 1, b: nil}')
# => '{"a": 1, "b": null}'

Class Method Summary collapse

Class Method Details

.call(string) ⇒ String?

Convert a Ruby Hash#inspect-style string to JSON. Validates the
output parses as JSON before returning; returns nil on failure.

Parameters:

  • string (String)

Returns:

  • (String, nil)

    JSON form on success, nil if the result
    still doesn't parse.



43
44
45
46
47
48
49
50
51
# File 'app/lib/heatwave/ruby_hash_inspect_converter.rb', line 43

def self.call(string)
  return nil unless string.is_a?(String) && string.strip.length.positive?

  converted = transform(string)
  JSON.parse(converted)
  converted
rescue JSON::ParserError
  nil
end