Project

General

Profile

Feature #14869 » hash_eqq.patch

to_hash のサポート - osyo (manga osyo), 08/09/2018 02:08 AM

View differences:

hash.c
2415 2415
    return hash_equal(hash1, hash2, TRUE);
2416 2416
}
2417 2417

  
2418

  
2419
static int
2420
eqq_i(VALUE key, VALUE val1, VALUE arg)
2421
{
2422
    struct equal_data *data = (struct equal_data *)arg;
2423
    st_data_t val2;
2424

  
2425
    if (!st_lookup(data->tbl, key, &val2)) {
2426
	data->result = Qfalse;
2427
	return ST_STOP;
2428
    }
2429
    if (!rb_funcall(val1, idEqq, 1, (VALUE)val2)) {
2430
	data->result = Qfalse;
2431
	return ST_STOP;
2432
    }
2433
    return ST_CONTINUE;
2434
}
2435

  
2436
static VALUE
2437
recursive_eqq(VALUE hash, VALUE dt, int recur)
2438
{
2439
    struct equal_data *data;
2440

  
2441
    if (recur) return Qtrue;	/* Subtle! */
2442
    data = (struct equal_data*)dt;
2443
    data->result = Qtrue;
2444
    rb_hash_foreach(hash, eqq_i, dt);
2445

  
2446
    return data->result;
2447
}
2448

  
2449
/*
2450
 *  call-eqq:
2451
 *     hsh === other_hash    -> true or false
2452
 *
2453
 *  Equality(===)---Two hashes are equal if they each contain the same number
2454
 *  of keys and if each key-value pair is equal to (according to
2455
 *  <code>Object#===</code>) the corresponding elements in the other
2456
 *  hash.
2457
 *
2458
 *     h1 = { "a" => "hoge", "b" => 2 }
2459
 *     h2 = { "a" => 1, "b" => 2, "c" => 35 }
2460
 *     { "a" => String, "c" => Integer } === h1     #=> true
2461
 *     { "a" => String } === h1                     #=> true
2462
 *     { "a" => Integer, "c" => String } === h1     #=> false
2463
 *     { "b" => Integer, "c" => (1..100) } === h2   #=> true
2464
 *
2465
 */
2466

  
2467
static VALUE
2468
rb_hash_eqq(VALUE hash1, VALUE hash2)
2469
{
2470
    struct equal_data data;
2471

  
2472
    if (hash1 == hash2) return Qtrue;
2473
    if (!RB_TYPE_P(hash2, T_HASH)) {
2474
	if (rb_respond_to(hash2, idTo_hash)) {
2475
	    return rb_hash_eqq(hash1, to_hash(hash2));
2476
	}
2477
	else {
2478
	    return Qfalse;
2479
	}
2480
    }
2481
    if (RHASH_EMPTY_P(hash1))
2482
	return RHASH_EMPTY_P(hash2) ? Qtrue : Qfalse;
2483
    if (RHASH_SIZE(hash1) > RHASH_SIZE(hash2))
2484
	return Qfalse;
2485
    if (!RHASH(hash1)->ntbl || !RHASH(hash2)->ntbl)
2486
        return Qtrue;
2487
    if (RHASH(hash1)->ntbl->type != RHASH(hash2)->ntbl->type)
2488
	return Qfalse;
2489

  
2490
    data.tbl = RHASH(hash2)->ntbl;
2491
    return rb_exec_recursive_paired(recursive_eqq, hash1, hash2, (VALUE)&data);
2492
}
2493

  
2418 2494
static int
2419 2495
hash_i(VALUE key, VALUE val, VALUE arg)
2420 2496
{
......
4696 4772
    rb_define_method(rb_cHash, "to_proc", rb_hash_to_proc, 0);
4697 4773

  
4698 4774
    rb_define_method(rb_cHash, "==", rb_hash_equal, 1);
4775
    rb_define_method(rb_cHash, "===", rb_hash_eqq, 1);
4699 4776
    rb_define_method(rb_cHash, "[]", rb_hash_aref, 1);
4700 4777
    rb_define_method(rb_cHash, "hash", rb_hash_hash, 0);
4701 4778
    rb_define_method(rb_cHash, "eql?", rb_hash_eql, 1);
test/ruby/test_hash.rb
1107 1107
    assert_not_send([@cls[], :eql?, o])
1108 1108
  end
1109 1109

  
1110
  def test_eqq
1111
    user = { id: 1, name: "homu", age: 14 }
1112
    assert_operator({ id: 1 }, :===, user)
1113
    assert_operator({ id: 1, age: 14 }, :===, user)
1114
    assert_operator({ id: Integer }, :===, user)
1115
    assert_operator({ name: String, age: Integer }, :===, user)
1116
    assert_operator({ name: /m/ }, :===, user)
1117
    assert_operator({ number: nil }, :===, { number: nil })
1118
    assert_operator({}, :===, {})
1119
    obj = Object.new
1120
    def obj.=== other
1121
      true
1122
    end
1123
    assert_operator({ id: obj }, :===, user)
1124
    a = { name: String }
1125
    a[:a] = a
1126
    assert_operator(a, :===, a)
1127
    b = { name: "homu" }
1128
    b[:a] = b
1129
    assert_operator(a, :===, b)
1130

  
1131
    o2 = Object.new
1132
    def o2.to_hash
1133
      { name: "homu", age: 14 }
1134
    end
1135
    assert_operator({ name: /^h/ }, :===, o2)
1136

  
1137
    assert_not_operator({ id: 2 }, :===, user)
1138
    assert_not_operator({ name: Integer }, :===, user)
1139
    assert_not_operator({ number: 42 }, :===, user)
1140
    assert_not_operator({ number: nil }, :===, {})
1141
    assert_not_operator({ number: 42 }, :===, {})
1142
    assert_not_operator({ number: 42 }, :===, 42)
1143
    assert_not_operator({ number: 42 }, :===, [])
1144
    assert_not_operator({}, :===, user)
1145
    assert_not_operator({}, :===, 42)
1146
    assert_not_operator({}, :===, { name: "homu" })
1147
    obj2 = Object.new
1148
    def obj2.=== other
1149
      false
1150
    end
1151
    assert_not_operator({ id: obj2 }, :===, user)
1152
    a = { name: Integer }
1153
    a[:a] = a
1154
    b = { name: "homu" }
1155
    b[:a] = b
1156
    assert_not_operator(a, :===, b)
1157
  end
1158

  
1110 1159
  def test_hash2
1111 1160
    assert_kind_of(Integer, @cls[].hash)
1112 1161
    h = @cls[1=>2]