diff options
author | tompng <[email protected]> | 2024-06-07 02:05:22 +0900 |
---|---|---|
committer | Yusuke Endoh <[email protected]> | 2024-10-03 18:47:09 +0900 |
commit | a8a059125314a411eaf879a9fbfdc68d6c01a667 (patch) | |
tree | f85d3d1e48a18b49d031d260068fcea3d00976f2 | |
parent | 2c0149d330d3068272eed785d627d9f0daa95bbf (diff) |
Hash#inspect with colon style
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/10924
-rw-r--r-- | hash.c | 51 | ||||
-rw-r--r-- | test/ruby/test_hash.rb | 27 |
2 files changed, 75 insertions, 3 deletions
@@ -3405,20 +3405,65 @@ rb_hash_to_a(VALUE hash) return ary; } +static bool +symbol_key_needs_quote(VALUE str) +{ + long len = RSTRING_LEN(str); + if (len == 0 || !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 + len - 1, RSTRING_END(str), rb_enc_get(str))) return false; + switch (s[len - 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); diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index f60ba0cffd..8219abc678 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -869,6 +869,33 @@ class TestHash < Test::Unit::TestCase $, = nil end + def test_inspect + no_quote = '{a: 1, a!: 1, a?: 1}' + quote0 = '{"": 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(no_quote, eval(no_quote).inspect) + assert_equal(quote0, eval(quote0).inspect) + assert_equal(quote1, eval(quote1).inspect) + assert_equal(quote2, eval(quote2).inspect) + assert_equal(quote3, eval(quote3).inspect) + begin + enc = Encoding.default_external + Encoding.default_external = Encoding::ASCII + utf8_ascii_hash = '{"\\u3042": 1}' + assert_equal(eval(utf8_ascii_hash).inspect, utf8_ascii_hash) + Encoding.default_external = Encoding::UTF_8 + utf8_hash = "{\u3042: 1}" + assert_equal(eval(utf8_hash).inspect, utf8_hash) + 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' ] |