[#26488] Add Standard Deviation Function to Math Module — Daniel Cohen <danielc2017@...>

This patch adds a Standard Deviation function to the Math Module. It takes

25 messages 2009/11/02
[#26489] Re: Add Standard Deviation Function to Math Module — Yukihiro Matsumoto <matz@...> 2009/11/03

Hi,

[#26490] Re: Add Standard Deviation Function to Math Module — Daniel Cohen <danielc2017@...> 2009/11/03

OK,

[#26493] Re: Add Standard Deviation Function to Math Module — Yukihiro Matsumoto <matz@...> 2009/11/03

Hi,

[#26511] Re: Add Standard Deviation Function to Math Module — Yusuke ENDOH <mame@...> 2009/11/03

Hi,

[#26492] HashWithIndifferentAccess to core — Urabe Shyouhei <shyouhei@...>

Hello,

35 messages 2009/11/03
[#26496] Re: HashWithIndifferentAccess to core — Yukihiro Matsumoto <matz@...> 2009/11/03

Hi,

[#26507] Re: HashWithIndifferentAccess to core — Jeremy Kemper <jeremy@...> 2009/11/03

On Tue, Nov 3, 2009 at 6:48 AM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

[#26514] Re: HashWithIndifferentAccess to core — "Martin J. Dst" <duerst@...> 2009/11/04

Just a thought: What about implementing this with an option on Hash:new,

[#26522] Re: HashWithIndifferentAccess to core — Yusuke ENDOH <mame@...> 2009/11/04

Hi,

[#26555] Re: HashWithIndifferentAccess to core — Yukihiro Matsumoto <matz@...> 2009/11/05

Hi,

[#26584] Re: HashWithIndifferentAccess to core — Yugui <yugui@...> 2009/11/07

2009/11/6 Yukihiro Matsumoto <matz@ruby-lang.org>:

[#26589] Re: HashWithIndifferentAccess to core — Yukihiro Matsumoto <matz@...> 2009/11/07

Hi,

[#26593] Re: HashWithIndifferentAccess to core — Lourens Naud<lourens@...> 2009/11/07

Hi,

[#26523] [Bug #2330] Non systematic segmentation fault with autoload rubyspec — Marc-Andre Lafortune <redmine@...>

Bug #2330: Non systematic segmentation fault with autoload rubyspec

12 messages 2009/11/04

[#26560] [Feature #2340] Removing YAML/Syck — Yui NARUSE <redmine@...>

Feature #2340: Removing YAML/Syck

38 messages 2009/11/06
[#26562] [Feature #2340] Removing YAML/Syck — Yui NARUSE <redmine@...> 2009/11/06

Issue #2340 has been updated by Yui NARUSE.

[#26567] Re: [Feature #2340] Removing YAML/Syck — James Edward Gray II <james@...> 2009/11/06

On Nov 6, 2009, at 4:02 AM, Yui NARUSE wrote:

[#26568] Re: [Feature #2340] Removing YAML/Syck — Jon <jon.forums@...> 2009/11/06

> > Issue #2340 has been updated by Yui NARUSE.

[#26571] Re: [Feature #2340] Removing YAML/Syck — "NARUSE, Yui" <naruse@...> 2009/11/06

Jon wrote:

[#26574] Re: [Feature #2340] Removing YAML/Syck — Aaron Patterson <aaron@...> 2009/11/06

On Sat, Nov 07, 2009 at 12:59:25AM +0900, NARUSE, Yui wrote:

[#26635] [Feature #2348] RBTree Should be Added to the Standard Library — James Gray <redmine@...>

Feature #2348: RBTree Should be Added to the Standard Library

20 messages 2009/11/08
[#28842] [Feature #2348] RBTree Should be Added to the Standard Library — James Gray <redmine@...> 2010/03/21

Issue #2348 has been updated by James Gray.

[#26650] [Feature #2350] Unicode specific functionality on String in 1.9 — Manfred Stienstra <redmine@...>

Feature #2350: Unicode specific functionality on String in 1.9

12 messages 2009/11/09
[#28985] [Feature #2350](Rejected) Unicode specific functionality on String in 1.9 — Yusuke Endoh <redmine@...> 2010/03/25

Issue #2350 has been updated by Yusuke Endoh.

[#28993] Re: [Feature #2350](Rejected) Unicode specific functionality on String in 1.9 — Nikolai Weibull <now@...> 2010/03/25

On Thu, Mar 25, 2010 at 14:45, Yusuke Endoh <redmine@ruby-lang.org> wrote:

[#26704] Maintainer confirmation process done. — "Yugui (Yuki Sonoda)" <yugui@...>

I'm sorry for my closing the maintainer confirmation process so late.

13 messages 2009/11/12

[#26736] [Bug #2365] Matrix: poor handling of coercion errors [patch] — Marc-Andre Lafortune <redmine@...>

Bug #2365: Matrix: poor handling of coercion errors [patch]

12 messages 2009/11/14

[#26772] [Bug #2378] Regression in ParseDate.parsedate('nn-nn') — Vladimir Sizikov <redmine@...>

Bug #2378: Regression in ParseDate.parsedate('nn-nn')

10 messages 2009/11/16

[#26774] Ruby constant lookup — Yehuda Katz <wycats@...>

Over the past six months or so, I have been working with the new Ruby 1.9

22 messages 2009/11/16
[#26775] Re: Ruby constant lookup — Shugo Maeda <shugo@...> 2009/11/17

Hi,

[#26777] Re: Ruby constant lookup — Yehuda Katz <wycats@...> 2009/11/17

Shugo,

[#26778] Re: Ruby constant lookup — Shugo Maeda <shugo@...> 2009/11/17

Hi,

[#26869] Caching #to_s for immutables (and a possible future for constant-folding) — Kurt Stephens <ks@...>

I have a proof-of-concept patch to MRI that caches #to_s values for

16 messages 2009/11/23
[#26936] Re: Caching #to_s for immutables (and a possible future for constant-folding) — Roger Pack <rogerdpack@...> 2009/11/29

> t reduces the number of #to_s Strings created during the MRI test suite

[#26958] Re: Caching #to_s for immutables (and a possible future for constant-folding) [with patch] — Kurt Stephens <ks@...> 2009/11/30

The attached patch add caching of #to_s results to the main immutable

[#26960] Re: Caching #to_s for immutables (and a possible future for constant-folding) [with patch] — Roger Pack <rogerdpack@...> 2009/11/30

> Yes. he MRI test suite runs at 45 sec with these changes and at 53 sec

[#26963] Re: Caching #to_s for immutables (and a possible future for constant-folding) [with patch] — Kurt Stephens <ks@...> 2009/11/30

I just ran rubyspec against it; ~ 5% time improvement.

[ruby-core:26492] HashWithIndifferentAccess to core

From: Urabe Shyouhei <shyouhei@...>
Date: 2009-11-03 11:12:08 UTC
List: ruby-core #26492
Hello,

I got a pull request for a HashWithIndifferentAccess implementation to merge
into core.  I think it's almost OK to make it so (except few minor bugs that can
easily be handled).  How about it?  I'm also attaching a patch file for people who
are not used to git (mainly nobu).

-------- Original Message --------
Subject: [GitHub] methodmissing sent you a message
Date: Mon, 2 Nov 2009 12:40:24 -0800
From: GitHub <noreply@github.com>
To: shyouhei@ruby-lang.org



methodmissing wants you to pull from methodmissing/ruby at hwia

Body: Hi,

I've played extensively with a HashWithIndifferentAccess (hwia / Mash)
implementation as an extension to both ruby 1.9.x and ruby 1.8.7 (
http://github.com/methodmissing/hwia and
http://blog.methodmissing.com/2009/08/29/alternative-hashwithindifferentaccess/)
before and recently took the leap to patch against 1.9.2 as a Hash subclass.

I've tried to conform to recommended code conventions, tried to not inject this
into the critical path of common Hash use cases and abstracted to macros where
possible.

Wycats suggested to send the pull request - naming conventions at the moment is
dangling - StrHash, IndifferentHash etc. I'll make myself available with
whatever time is required to have this conform to current ruby-core
standards.I'm also open to moving the recursive conversion to an extension and
implement a thin API as per identhash on Hash instead.

It passes against today's (Nov 2) trunk with "make check" and related.Feedback
much appreciated if and when there's a moment.

- Lourens

View repository: http://github.com/methodmissing/ruby/tree/hwia

-------- patch --------

% git diff --patch-with-stat origin/trunk..HEAD
 hash.c                   |  185 +++++++++++++++++++++++++++++++--
 include/ruby/intern.h    |    1 +
 string.c                 |   12 ++
 test/ruby/test_hash.rb   |  252 ++++++++++++++++++++++++++++++++++++++++++++++
 test/ruby/test_symbol.rb |    7 ++
 5 files changed, 445 insertions(+), 12 deletions(-)

diff --git a/hash.c b/hash.c
index ef8b9a8..332f89d 100644
--- a/hash.c
+++ b/hash.c
@@ -23,6 +23,27 @@ static VALUE rb_hash_s_try_convert(VALUE, VALUE);
 
 #define HASH_DELETED  FL_USER1
 #define HASH_PROC_DEFAULT FL_USER2
+#define STR_HASH FL_USER3
+
+static VALUE rb_hash_rehash(VALUE hash);
+static VALUE rb_hash_update(VALUE hash1, VALUE hash2);
+static VALUE rb_hash_strhash(VALUE hash);
+static void rb_strhash_convert(VALUE *value);
+
+#define NEW_STR_HASH(hash,other) do {\
+   FL_SET(RHASH(hash), STR_HASH); \
+   RHASH(hash)->ntbl->type = &strhash; \
+   RHASH(hash)->ifnone = RHASH(other)->ifnone; \
+   return rb_hash_rehash(rb_convert_type(hash, T_HASH, "StrHash", "to_hash")); \
+} while (0)
+
+#define STR_HASH_P(hash) (FL_TEST(RHASH(hash), STR_HASH) || RBASIC(hash)->klass == rb_cStrHash)
+
+#define CONVERT_STR_HASH(hash,value) do {\
+   if STR_HASH_P(hash){ \
+   rb_strhash_convert(&value); \
+   } \
+} while (0)
 
 VALUE
 rb_hash_freeze(VALUE hash)
@@ -31,6 +52,7 @@ rb_hash_freeze(VALUE hash)
 }
 
 VALUE rb_cHash;
+VALUE rb_cStrHash;
 
 static VALUE envtbl;
 static ID id_hash, id_yield, id_default;
@@ -54,6 +76,37 @@ rb_any_cmp(VALUE a, VALUE b)
     return !rb_eql(a, b);
 }
 
+int
+strhash_cmp(VALUE *s1,VALUE *s2)
+{
+    int s1_hash = SYMBOL_P(*s1) ? rb_sym_hash(*s1) : rb_str_hash(*s1);
+    int s2_hash = SYMBOL_P(*s2) ? rb_sym_hash(*s2) : rb_str_hash(*s2);
+    if (s1_hash == s2_hash) return 0;
+    if (s1_hash > s2_hash) return 1;
+    return -1;	
+}
+
+static int
+rb_strhash_cmp(VALUE a, VALUE b)
+{
+    if (a == b) return 0;
+    if (FIXNUM_P(a) && FIXNUM_P(b)) {
+	return a != b;
+    }
+    if (a == Qundef || b == Qundef) return -1;
+    if (SYMBOL_P(a) && SYMBOL_P(b)) {
+	return a != b;
+    }
+    if ((TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString && SYMBOL_P(b)) || (TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString && SYMBOL_P(a))) {
+	return strhash_cmp(&a, &b);
+    }
+    if (TYPE(a) == T_STRING && RBASIC(a)->klass == rb_cString &&
+    TYPE(b) == T_STRING && RBASIC(b)->klass == rb_cString) {
+	return rb_str_cmp(a, b);
+    }
+    return !rb_eql(a, b);
+}
+
 VALUE
 rb_hash(VALUE obj)
 {
@@ -99,11 +152,44 @@ rb_any_hash(VALUE a)
     return (st_index_t)RSHIFT(hnum, 1);
 }
 
+static st_index_t
+rb_strhash_hash(VALUE a)
+{
+    VALUE hval;
+    st_index_t hnum;
+
+    switch (TYPE(a)) {
+      case T_FIXNUM:
+      case T_NIL:
+      case T_FALSE:
+      case T_TRUE:
+	hnum = rb_hash_end(rb_hash_start((unsigned int)a));
+	break;
+      case T_SYMBOL:
+	hnum = rb_sym_hash(a);  
+	break;
+      case T_STRING:
+	hnum = rb_str_hash(a);
+	break;
+
+      default:
+        hval = rb_hash(a);
+	hnum = FIX2LONG(hval);
+    }
+    hnum <<= 1;
+    return (st_index_t)RSHIFT(hnum, 1);
+}
+
 static const struct st_hash_type objhash = {
     rb_any_cmp,
     rb_any_hash,
 };
 
+static const struct st_hash_type strhash = {
+    rb_strhash_cmp,
+    rb_strhash_hash,
+};
+
 static const struct st_hash_type identhash = {
     st_numcmp,
     st_numhash,
@@ -219,7 +305,7 @@ hash_alloc(VALUE klass)
     OBJSETUP(hash, klass, T_HASH);
 
     hash->ifnone = Qnil;
-
+    if (klass == rb_cStrHash) FL_SET(hash, STR_HASH);
     return (VALUE)hash;
 }
 
@@ -230,6 +316,12 @@ rb_hash_new(void)
 }
 
 VALUE
+rb_strhash_new(void)
+{
+    return hash_alloc(rb_cStrHash);
+}
+
+VALUE
 rb_hash_dup(VALUE hash)
 {
     NEWOBJ(ret, struct RHash);
@@ -240,8 +332,33 @@ rb_hash_dup(VALUE hash)
     if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
         FL_SET(ret, HASH_PROC_DEFAULT);
     }
-    ret->ifnone = RHASH(hash)->ifnone;
-    return (VALUE)ret;
+    if STR_HASH_P(hash){
+       NEW_STR_HASH(ret,hash);
+    }else{ 
+      ret->ifnone = RHASH(hash)->ifnone;
+      return (VALUE)ret;
+    }
+}
+
+static void
+rb_strhash_convert(VALUE *val)
+{
+    int i;
+    VALUE values;
+
+    switch (TYPE(*val)) {
+      case T_HASH:
+           *val = rb_hash_strhash(*val); 
+           break;   
+      case T_ARRAY:
+            values = rb_ary_new2(RARRAY_LEN(*val));
+            for (i = 0; i < RARRAY_LEN(*val); i++) {
+               VALUE el = RARRAY_PTR(*val)[i];
+               rb_ary_push(values, (TYPE(el) == T_HASH) ? rb_hash_strhash(el) : el);
+            } 
+           *val = values;
+           break;
+    }
 }
 
 static void
@@ -256,7 +373,7 @@ struct st_table *
 rb_hash_tbl(VALUE hash)
 {
     if (!RHASH(hash)->ntbl) {
-        RHASH(hash)->ntbl = st_init_table(&objhash);
+	RHASH(hash)->ntbl = STR_HASH_P(hash) ? st_init_table(&strhash) : st_init_table(&objhash);
     }
     return RHASH(hash)->ntbl;
 }
@@ -318,7 +435,9 @@ static VALUE
 rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
 {
     VALUE ifnone;
-
+    VALUE constructor;
+    rb_scan_args(argc, argv, "01", &constructor);
+    if(TYPE(constructor) == T_HASH) return rb_hash_update(hash,constructor);
     rb_hash_modify(hash);
     if (rb_block_given_p()) {
 	if (argc > 0) {
@@ -333,7 +452,6 @@ rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
 	rb_scan_args(argc, argv, "01", &ifnone);
 	RHASH(hash)->ifnone = ifnone;
     }
-
     return hash;
 }
 
@@ -366,8 +484,11 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
 	    hash = hash_alloc(klass);
 	    if (RHASH(tmp)->ntbl) {
 		RHASH(hash)->ntbl = st_copy(RHASH(tmp)->ntbl);
+		if (FL_TEST(RHASH(tmp), STR_HASH) || klass == rb_cStrHash){
+		  NEW_STR_HASH(hash,tmp);
+		}else
+		return hash;
 	    }
-	    return hash;
 	}
 
 	tmp = rb_check_array_type(argv[0]);
@@ -426,12 +547,21 @@ rb_hash_s_try_convert(VALUE dummy, VALUE hash)
     return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
 }
 
+static VALUE
+rb_strhash_s_try_convert(VALUE dummy, VALUE hash)
+{
+    return rb_check_convert_type(hash, T_HASH, "StrHash", "to_hash");
+}
+
 static int
 rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
 {
     st_table *tbl = (st_table *)arg;
 
-    if (key != Qundef) st_insert(tbl, key, value);
+    if (key != Qundef){ 
+      if (tbl->type == &strhash) rb_strhash_convert(&value);
+      st_insert(tbl, key, value);
+    }
     return ST_CONTINUE;
 }
 
@@ -459,7 +589,6 @@ static VALUE
 rb_hash_rehash(VALUE hash)
 {
     st_table *tbl;
-
     if (RHASH(hash)->iter_lev > 0) {
 	rb_raise(rb_eRuntimeError, "rehash during iteration");
     }
@@ -470,7 +599,6 @@ rb_hash_rehash(VALUE hash)
     rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
     st_free_table(RHASH(hash)->ntbl);
     RHASH(hash)->ntbl = tbl;
-
     return hash;
 }
 
@@ -974,7 +1102,7 @@ rb_hash_select(VALUE hash)
     VALUE result;
 
     RETURN_ENUMERATOR(hash, 0, 0);
-    result = rb_hash_new();
+    result = STR_HASH_P(hash) ? rb_strhash_new() : rb_hash_new();
     rb_hash_foreach(hash, select_i, result);
     return result;
 }
@@ -1046,6 +1174,13 @@ rb_hash_aset(VALUE hash, VALUE key, VALUE val)
     return val;
 }
 
+VALUE
+rb_strhash_aset(VALUE hash, VALUE key, VALUE val)
+{
+    CONVERT_STR_HASH(hash,val);
+    rb_hash_aset(hash, key, val);
+}
+
 static int
 replace_i(VALUE key, VALUE val, VALUE hash)
 {
@@ -1617,7 +1752,7 @@ rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
 static VALUE
 rb_hash_invert(VALUE hash)
 {
-    VALUE h = rb_hash_new();
+	VALUE h = STR_HASH_P(hash) ? rb_strhash_new() : rb_hash_new();
 
     rb_hash_foreach(hash, rb_hash_invert_i, h);
     return h;
@@ -1627,6 +1762,7 @@ static int
 rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
 {
     if (key == Qundef) return ST_CONTINUE;
+    CONVERT_STR_HASH(hash,value);
     st_insert(RHASH(hash)->ntbl, key, value);
     return ST_CONTINUE;
 }
@@ -1637,6 +1773,7 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
     if (key == Qundef) return ST_CONTINUE;
     if (rb_hash_has_key(hash, key)) {
 	value = rb_yield_values(3, key, rb_hash_aref(hash, key), value);
+    CONVERT_STR_HASH(hash,value);
     }
     st_insert(RHASH(hash)->ntbl, key, value);
     return ST_CONTINUE;
@@ -1852,6 +1989,24 @@ rb_hash_compare_by_id_p(VALUE hash)
     return Qfalse;
 }
 
+static VALUE
+rb_hash_strhash(VALUE hash)
+{
+    if STR_HASH_P(hash)
+    return hash;
+    VALUE args[1];
+    args[0] = hash;
+    return rb_hash_s_create(1, (VALUE *)args, rb_cStrHash);
+}
+
+static VALUE
+rb_strhash_to_hash(VALUE hash)
+{
+    VALUE args[1];
+    args[0] = hash;
+    return rb_hash_s_create(1, (VALUE *)args, rb_cHash);
+}
+
 static int path_tainted = -1;
 
 static char **origenviron;
@@ -2649,6 +2804,8 @@ Init_Hash(void)
     id_default = rb_intern("default");
 
     rb_cHash = rb_define_class("Hash", rb_cObject);
+    rb_cStrHash = rb_define_class("StrHash", rb_cHash);
+    rb_define_singleton_method(rb_cStrHash, "try_convert", rb_strhash_s_try_convert, 1);
 
     rb_include_module(rb_cHash, rb_mEnumerable);
 
@@ -2715,6 +2872,10 @@ Init_Hash(void)
 
     rb_define_method(rb_cHash,"compare_by_identity", rb_hash_compare_by_id, 0);
     rb_define_method(rb_cHash,"compare_by_identity?", rb_hash_compare_by_id_p, 0);
+    rb_define_method(rb_cHash, "strhash", rb_hash_strhash, 0);
+    rb_define_method(rb_cStrHash, "to_hash", rb_strhash_to_hash, 0);
+    rb_define_method(rb_cStrHash, "[]=", rb_strhash_aset, 2);
+    rb_define_method(rb_cStrHash, "store", rb_strhash_aset, 2);
 
     origenviron = environ;
     envtbl = rb_obj_alloc(rb_cObject);
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index fd37eca..c97caef 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -660,6 +660,7 @@ void rb_str_associate(VALUE, VALUE);
 VALUE rb_str_associated(VALUE);
 void rb_str_setter(VALUE, ID, VALUE*);
 VALUE rb_str_intern(VALUE);
+st_index_t rb_sym_hash(VALUE);
 VALUE rb_sym_to_s(VALUE);
 VALUE rb_str_length(VALUE);
 long rb_str_offset(VALUE, long);
diff --git a/string.c b/string.c
index e7f7e86..cc4ff34 100644
--- a/string.c
+++ b/string.c
@@ -7025,6 +7025,17 @@ sym_equal(VALUE sym1, VALUE sym2)
     return Qfalse;
 }
 
+st_index_t
+rb_sym_hash(VALUE sym){
+   ID id = SYM2ID(sym);
+   return rb_str_hash(rb_id2str(id));  
+}
+
+static VALUE
+rb_sym_hash_m(VALUE sym){
+    st_index_t hval = rb_sym_hash(sym);
+    return INT2FIX(hval);
+}
 
 static int
 sym_printable(const char *s, const char *send, rb_encoding *enc)
@@ -7508,6 +7519,7 @@ Init_String(void)
     rb_define_method(rb_cSymbol, "===", sym_equal, 1);
     rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
     rb_define_method(rb_cSymbol, "to_s", rb_sym_to_s, 0);
+    rb_define_method(rb_cSymbol, "hash", rb_sym_hash_m, 0);
     rb_define_method(rb_cSymbol, "id2name", rb_sym_to_s, 0);
     rb_define_method(rb_cSymbol, "intern", sym_to_sym, 0);
     rb_define_method(rb_cSymbol, "to_sym", sym_to_sym, 0);
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index c860b25..b3145e9 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -872,3 +872,255 @@ class TestHash < Test::Unit::TestCase
     assert_equal({x=>1}.hash, {x=>1}.hash)
   end
 end
+
+class HashToStrHash < Test::Unit::TestCase
+  def test_strhash
+    hash = { 'a' => 1, 'b' => 2 }
+    assert_instance_of StrHash, hash.strhash
+    assert_equal %w(a b), hash.keys
+    assert_equal [1,2], hash.values
+  end  
+end
+
+class TestStrHash < Test::Unit::TestCase
+  def setup
+    @strings = { 'a' => 1, 'b' => 2 }.strhash
+    @symbols = { :a  => 1, :b  => 2 }.strhash
+    @mixed   = { :a  => 1, 'b' => 2 }.strhash
+    @fixnums = {  0  => 1,  1  => 2 }.strhash
+  end
+
+  def test_inherits_hash
+    assert_equal Hash, StrHash.superclass
+  end
+
+  def test_strhash
+    assert_equal @strings.object_id, @strings.strhash.object_id
+    assert_instance_of StrHash, { 'a' => 1, 'b' => 2 }.strhash
+  end
+  
+  def test_initialize
+    strhash = StrHash.new({ 'a' => 1, 'b' => 2 })
+    assert_equal 1, strhash[:a] 
+    strhash = StrHash.new
+    strhash[:a] = 'a'
+    assert_equal 'a', strhash[:a]
+  end
+
+  def test_set
+    array = [{ 'a' => 1, 'b' => 2 }, [:a,:b,:c]]
+    @strings[:array] = array
+    assert_instance_of StrHash, @strings[:array].shift
+    assert_instance_of Array, @strings[:array] = array    
+    @strings[:hash] = { 'a' => 1, 'b' => 2 }
+    assert_instance_of StrHash, @strings[:hash]
+  end
+  
+  def test_dup
+    assert_equal @strings, @strings.dup
+    assert_equal @mixed, @mixed.dup
+    assert_not_equal @mixed.object_id, @mixed.dup.object_id
+  end
+
+  def test_keys
+    assert_equal ["a", "b"], @strings.keys
+    assert_equal [:a, :b], @symbols.keys
+    assert_equal [:a, "b"], @mixed.keys
+    assert_equal [0, 1], @fixnums.keys            
+  end
+  
+  def test_values
+    assert_equal [1, 2], @strings.values
+    assert_equal [1, 2], @symbols.values
+    assert_equal [1, 2], @mixed.values
+    assert_equal [1, 2], @fixnums.values         
+  end  
+ 
+  def test_fetch
+    assert_equal 1, @strings.fetch('a')
+    assert_equal 1, @strings.fetch(:a.to_s)
+    assert_equal 1, @strings.fetch(:a)
+  end
+
+  def test_key?
+    assert @strings.key?(:a)
+    assert @strings.include?('a')
+    assert @mixed.has_key?('b')
+  end
+  
+  def test_delete
+    @strings.delete('a')
+    assert !@strings.key?(:a)
+  end
+
+  def test_assorted
+    hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed }
+    method_map = { :'[]' => 1, :fetch => 1, :values_at => [1],
+      :has_key? => true, :include? => true, :key? => true,
+      :member? => true }
+
+    hashes.each do |name, hash|
+      method_map.sort_by { |m| m.to_s }.each do |meth, expected|
+        assert_equal(expected, hash.__send__(meth, 'a'),
+                     "Calling #{name}.#{meth} 'a'")
+        assert_equal(expected, hash.__send__(meth, :a),
+                     "Calling #{name}.#{meth} :a")
+      end
+    end
+
+    assert_equal [1, 2], @strings.values_at('a', 'b')
+    assert_equal [1, 2], @strings.values_at(:a, :b)
+    assert_equal [1, 2], @symbols.values_at('a', 'b')
+    assert_equal [1, 2], @symbols.values_at(:a, :b)
+    assert_equal [1, 2], @mixed.values_at('a', 'b')
+    assert_equal [1, 2], @mixed.values_at(:a, :b)
+  end
+  
+  def test_reading
+    hash = StrHash.new
+    hash["a"] = 1
+    hash["b"] = true
+    hash["c"] = false
+    hash["d"] = nil
+
+    assert_equal 1, hash[:a]
+    assert_equal true, hash[:b]
+    assert_equal false, hash[:c]
+    assert_equal nil, hash[:d]
+    assert_equal nil, hash[:e]
+  end  
+
+  def test_reading_with_nonnil_default
+    hash = StrHash.new(1)
+    hash["a"] = 1
+    hash["b"] = true
+    hash["c"] = false
+    hash["d"] = nil
+
+    assert_equal 1, hash[:a]
+    assert_equal true, hash[:b]
+    assert_equal false, hash[:c]
+    assert_equal nil, hash[:d]
+    assert_equal 1, hash[:e]
+  end
+  
+  def test_writing
+    hash = StrHash.new
+    hash[:a] = 1
+    hash['b'] = 2
+    hash[3] = 3
+
+    assert_equal hash['a'], 1
+    assert_equal hash['b'], 2
+    assert_equal hash[:a], 1
+    assert_equal hash[:b], 2
+    assert_equal hash[3], 3
+  end  
+
+  def test_update
+    hash = StrHash.new
+    hash[:a] = 'a'
+    hash['b'] = 'b'
+
+    updated_with_strings = hash.update(@strings)
+    updated_with_symbols = hash.update(@symbols)
+    updated_with_mixed = hash.update(@mixed)
+
+    assert_equal updated_with_strings[:a], 1
+    assert_equal updated_with_strings['a'], 1
+    assert_equal updated_with_strings['b'], 2
+
+    assert_equal updated_with_symbols[:a], 1
+    assert_equal updated_with_symbols['b'], 2
+    assert_equal updated_with_symbols[:b], 2
+
+    assert_equal updated_with_mixed[:a], 1
+    assert_equal updated_with_mixed['b'], 2
+
+    assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 }
+  end  
+
+  def test_merging
+    hash = StrHash.new
+    hash[:a] = 'failure'
+    hash['b'] = 'failure'
+
+    other = { 'a' => 1, :b => 2 }
+
+    merged = hash.merge(other)
+
+    assert_equal StrHash, merged.class
+    assert_equal 1, merged[:a]
+    assert_equal 2, merged['b']
+
+    hash.update(other)
+
+    assert_equal 1, hash[:a]
+    assert_equal 2, hash['b']
+  end  
+
+  def test_deleting
+    get_hash = proc{ StrHash[ :a => 'foo' ] }
+    hash = get_hash.call
+    assert_equal hash.delete(:a), 'foo'
+    assert_equal hash.delete(:a), nil
+    hash = get_hash.call
+    assert_equal hash.delete('a'), 'foo'
+    assert_equal hash.delete('a'), nil
+  end  
+
+  def test_to_hash
+    assert_instance_of Hash, @strings.to_hash
+    assert_equal %w(a b), @strings.to_hash.keys
+    # Should convert to a Hash with String keys.
+    assert_equal @strings, @mixed.strhash.to_hash
+
+    # Should preserve the default value.
+    mixed_with_default = @mixed.dup
+    mixed_with_default.default = '1234'
+    roundtrip = mixed_with_default.strhash.to_hash
+    assert_equal @strings, roundtrip
+    assert_equal '1234', roundtrip.default    
+  end
+
+  def test_hash_with_array_of_hashes
+    hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}
+    strhash = StrHash[hash]
+    assert_equal "1", strhash[:urls][:url].first[:address]
+  end
+
+  def test_indifferent_subhashes
+    h = {'user' => {'id' => 5}}.strhash
+    ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
+
+    h = {:user => {:id => 5}}.strhash
+    ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
+  end  
+
+  def test_assorted_keys_not_stringified
+    original = {Object.new => 2, 1 => 2, [] => true}
+    indiff = original.strhash
+    assert(!indiff.keys.any? {|k| k.kind_of? String}, "A key was converted to a string!")
+  end
+
+  def test_should_use_default_value_for_unknown_key
+    strhash = StrHash.new(3)
+    assert_equal 3, strhash[:new_key]
+  end
+
+  def test_should_use_default_value_if_no_key_is_supplied
+    strhash = StrHash.new(3)
+    assert_equal 3, strhash.default
+  end
+
+  def test_should_nil_if_no_default_value_is_supplied
+    strhash = StrHash.new
+    assert_nil strhash.default
+  end
+
+  def test_should_copy_the_default_value_when_converting_to_hash_with_indifferent_access
+    hash = Hash.new(3)
+    strhash = hash.strhash
+    assert_equal 3, strhash.default
+  end  
+end
\ No newline at end of file
diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb
index f402da3..c181b19 100644
--- a/test/ruby/test_symbol.rb
+++ b/test/ruby/test_symbol.rb
@@ -1,6 +1,13 @@
 require 'test/unit'
 
 class TestSymbol < Test::Unit::TestCase
+  def test_hash
+    assert_instance_of Fixnum, :symbol.hash
+    assert_equal 'symbol'.hash, :symbol.hash
+    assert_equal :"!".hash, :"!".hash
+    assert_not_equal :"$1".hash, :"@@1".hash
+  end
+  
   # [ruby-core:3573]
 
   def assert_eval_inspected(sym)

Attachments (1)

signature.asc (260 Bytes, application/pgp-signature)

In This Thread

Prev Next