[前][次][番号順一覧][スレッド一覧]

ruby-changes:40437

From: nobu <ko1@a...>
Date: Tue, 10 Nov 2015 14:02:17 +0900 (JST)
Subject: [ruby-changes:40437] nobu:r52518 (trunk): hash.c: compare methods

nobu	2015-11-10 14:02:02 +0900 (Tue, 10 Nov 2015)

  New Revision: 52518

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52518

  Log:
    hash.c: compare methods
    
    * hash.c (rb_hash_{le,lt,ge,gt}): new methods, Hash#<=, Hash#<,
      Hash#>=, Hash#>, to test if all elements of a hash are also
      included in another hash, and vice versa.
      [ruby-core:68561] [Feature #10984]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/hash.c
    trunk/test/ruby/test_hash.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52517)
+++ ChangeLog	(revision 52518)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Nov 10 14:01:59 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* hash.c (rb_hash_{le,lt,ge,gt}): new methods, Hash#<=, Hash#<,
+	  Hash#>=, Hash#>, to test if all elements of a hash are also
+	  included in another hash, and vice versa.
+	  [ruby-core:68561] [Feature #10984]
+
 Tue Nov 10 11:25:29 2015  NARUSE, Yui  <naruse@r...>
 
 	* time.c (rb_timespec_now): added.
Index: hash.c
===================================================================
--- hash.c	(revision 52517)
+++ hash.c	(revision 52518)
@@ -2714,6 +2714,58 @@ rb_hash_dig(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/hash.c#L2714
     return rb_obj_dig(argc, argv, self, Qnil);
 }
 
+static int
+hash_le_i(VALUE key, VALUE value, VALUE arg)
+{
+    VALUE *args = (VALUE *)arg;
+    VALUE v = rb_hash_lookup2(args[0], key, Qundef);
+    if (v != Qundef && rb_equal(value, v)) return ST_CONTINUE;
+    args[1] = Qfalse;
+    return ST_STOP;
+}
+
+static VALUE
+hash_le(VALUE hash1, VALUE hash2)
+{
+    VALUE args[2];
+    args[0] = hash2;
+    args[1] = Qtrue;
+    rb_hash_foreach(hash1, hash_le_i, (VALUE)args);
+    return args[1];
+}
+
+static VALUE
+rb_hash_le(VALUE hash, VALUE other)
+{
+    other = to_hash(other);
+    if (RHASH_SIZE(hash) > RHASH_SIZE(other)) return Qfalse;
+    return hash_le(hash, other);
+}
+
+static VALUE
+rb_hash_lt(VALUE hash, VALUE other)
+{
+    other = to_hash(other);
+    if (RHASH_SIZE(hash) >= RHASH_SIZE(other)) return Qfalse;
+    return hash_le(hash, other);
+}
+
+static VALUE
+rb_hash_ge(VALUE hash, VALUE other)
+{
+    other = to_hash(other);
+    if (RHASH_SIZE(hash) < RHASH_SIZE(other)) return Qfalse;
+    return hash_le(other, hash);
+}
+
+static VALUE
+rb_hash_gt(VALUE hash, VALUE other)
+{
+    other = to_hash(other);
+    if (RHASH_SIZE(hash) <= RHASH_SIZE(other)) return Qfalse;
+    return hash_le(other, hash);
+}
+
 static int path_tainted = -1;
 
 static char **origenviron;
@@ -4139,6 +4191,11 @@ Init_Hash(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L4191
     rb_define_method(rb_cHash, "any?", rb_hash_any_p, 0);
     rb_define_method(rb_cHash, "dig", rb_hash_dig, -1);
 
+    rb_define_method(rb_cHash, "<=", rb_hash_le, 1);
+    rb_define_method(rb_cHash, "<", rb_hash_lt, 1);
+    rb_define_method(rb_cHash, ">=", rb_hash_ge, 1);
+    rb_define_method(rb_cHash, ">", rb_hash_gt, 1);
+
     /* Document-class: ENV
      *
      * ENV is a hash-like accessor for environment variables.
Index: NEWS
===================================================================
--- NEWS	(revision 52517)
+++ NEWS	(revision 52518)
@@ -59,6 +59,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L59
 
   * Hash#fetch_values [Feature #10017]
   * Hash#dig [Feature #11643]
+  * Hash#<=, Hash#<, Hash#>=, Hash#> [Feature #10984]
 
 * IO
 
Index: test/ruby/test_hash.rb
===================================================================
--- test/ruby/test_hash.rb	(revision 52517)
+++ test/ruby/test_hash.rb	(revision 52518)
@@ -1308,6 +1308,31 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1308
     assert_nil(h.dig(:c, 1))
   end
 
+  def test_cmp
+    h1 = {a:1, b:2}
+    h2 = {a:1, b:2, c:3}
+
+    assert_operator(h1, :<=, h1)
+    assert_operator(h1, :<=, h2)
+    assert_not_operator(h2, :<=, h1)
+    assert_operator(h2, :<=, h2)
+
+    assert_operator(h1, :>=, h1)
+    assert_not_operator(h1, :>=, h2)
+    assert_operator(h2, :>=, h1)
+    assert_operator(h2, :>=, h2)
+
+    assert_not_operator(h1, :<, h1)
+    assert_operator(h1, :<, h2)
+    assert_not_operator(h2, :<, h1)
+    assert_not_operator(h2, :<, h2)
+
+    assert_not_operator(h1, :>, h1)
+    assert_not_operator(h1, :>, h2)
+    assert_operator(h2, :>, h1)
+    assert_not_operator(h2, :>, h2)
+  end
+
   class TestSubHash < TestHash
     class SubHash < Hash
       def reject(*)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]