Skip to content

Commit

Permalink
Hash#inspect with colon style
Browse files Browse the repository at this point in the history
  • Loading branch information
tompng committed Jun 6, 2024
1 parent 78d7b47 commit d372955
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
50 changes: 47 additions & 3 deletions hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -3436,20 +3436,64 @@ rb_hash_to_a(VALUE hash)
return ary;
}

static bool
symbol_key_needs_quote(VALUE str)
{
if (!rb_str_symname_p(str)) return true;
const char *s = RSTRING_PTR(str);
char first = s[0];
if (first == '@' || first == '$' || first == '!') return true;
if (!at_char_boundary(s, s + RSTRING_LEN(str) - 1, RSTRING_END(str), rb_enc_get(str))) return false;
switch (s[RSTRING_LEN(str) - 1]) {
case '+':
case '-':
case '*':
case '/':
case '`':
case '%':
case '^':
case '&':
case '|':
case ']':
case '<':
case '=':
case '>':
case '~':
case '@':
return true;
default:
return false;
}
}

static int
inspect_i(VALUE key, VALUE value, VALUE str)
{
VALUE str2;

str2 = rb_inspect(key);
bool is_symbol = SYMBOL_P(key);
bool quote = false;
if (is_symbol) {
str2 = rb_sym2str(key);
quote = symbol_key_needs_quote(str2);
}
else {
str2 = rb_inspect(key);
}
if (RSTRING_LEN(str) > 1) {
rb_str_buf_cat_ascii(str, ", ");
}
else {
rb_enc_copy(str, str2);
}
rb_str_buf_append(str, str2);
rb_str_buf_cat_ascii(str, "=>");
if (quote) {
rb_str_buf_append(str, rb_str_inspect(str2));
}
else {
rb_str_buf_append(str, str2);
}

rb_str_buf_cat_ascii(str, is_symbol ? ": " : " => ");
str2 = rb_inspect(value);
rb_str_buf_append(str, str2);

Expand Down
18 changes: 18 additions & 0 deletions test/ruby/test_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,24 @@ def test_to_s
$, = nil
end

def test_inspect
no_quote = "{a: 1, a!: 1, a?: 1, \u{3042}: 1}"
quote1 = '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}'
quote2 = '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}'
quote3 = '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}'
assert_equal(eval(no_quote), no_quote)
assert_equal(eval(quote1), quote1)
assert_equal(eval(quote2), quote2)
assert_equal(eval(quote3), quote3)
begin
enc, Encoding.default_external = Encoding.default_external, Encoding::Windows_31J
sjis_hash = "{\x87]: 1}".force_encoding('sjis')
assert_equal(eval(sjis_hash).inspect, sjis_hash)
ensure
Encoding.default_external = enc
end
end

def test_update
h1 = @cls[ 1 => 2, 2 => 3, 3 => 4 ]
h2 = @cls[ 2 => 'two', 4 => 'four' ]
Expand Down

0 comments on commit d372955

Please sign in to comment.