[#26463] New Features for the Array Module — Daniel Cohen <danielc2017@...>
To Whom it May Concern:
[#26488] Add Standard Deviation Function to Math Module — Daniel Cohen <danielc2017@...>
This patch adds a Standard Deviation function to the Math Module. It takes
Hi,
OK,
Hi,
Matz,
Hi,
On Tue, Nov 3, 2009 at 16:56, Yusuke ENDOH <mame@tsg.ne.jp> wrote:
2009/11/4 Yusuke ENDOH <mame@tsg.ne.jp>:
[#26492] HashWithIndifferentAccess to core — Urabe Shyouhei <shyouhei@...>
Hello,
Hi,
On Tue, Nov 3, 2009 at 6:48 AM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
Just a thought: What about implementing this with an option on Hash:new,
Hi,
Hi,
2009/11/6 Yukihiro Matsumoto <matz@ruby-lang.org>:
Hi,
Hi,
Hi,
I'm not sure that it really makes sense to add any of this to core.
On Sat, Nov 7, 2009 at 10:21 AM, Rick DeNatale <rick.denatale@gmail.com> wrote:
On Nov 7, 2009, at 1:57 PM, Jeremy Kemper wrote:
On Sat, Nov 7, 2009 at 3:14 PM, James Edward Gray II
[#26497] [Bug #2326] 1.8.7 Segmentation fault — Johan Holmberg <redmine@...>
Bug #2326: 1.8.7 Segmentation fault
Issue #2326 has been updated by Hongli Lai.
[#26523] [Bug #2330] Non systematic segmentation fault with autoload rubyspec — Marc-Andre Lafortune <redmine@...>
Bug #2330: Non systematic segmentation fault with autoload rubyspec
Issue #2330 has been updated by Marc-Andre Lafortune.
Hi,
Argh... I can't reproduce my minimal case scenario anymore. Maybe
1) The minimal test case
Hi,
[#26540] [Bug #2336] pathname compare fails in windows — Roger Pack <redmine@...>
Bug #2336: pathname compare fails in windows
[#26560] [Feature #2340] Removing YAML/Syck — Yui NARUSE <redmine@...>
Feature #2340: Removing YAML/Syck
Issue #2340 has been updated by Yui NARUSE.
On Nov 6, 2009, at 4:02 AM, Yui NARUSE wrote:
On Fri, Nov 6, 2009 at 16:00, James Edward Gray II
On Nov 6, 2009, at 9:48 AM, Nikolai Weibull wrote:
James Edward Gray II wrote:
On Fri, Nov 6, 2009 at 18:38, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> > Issue #2340 has been updated by Yui NARUSE.
Jon wrote:
> > If you're looking at alternatives, does http://pyyaml.org/wiki/LibYAML
On Sat, Nov 07, 2009 at 12:59:25AM +0900, NARUSE, Yui wrote:
Aaron Patterson wrote:
On Sat, Nov 07, 2009 at 09:21:06PM +0900, NARUSE, Yui wrote:
On Sat, Nov 7, 2009 at 2:52 PM, Aaron Patterson
2009/11/12 5:47, Charles Oliver Nutter wrote:
Issue #2340 has been updated by Yui NARUSE.
[#26563] [Bug #2343] Timeout.timeout doesn't raise Timeout::Error by default — Hongli Lai <redmine@...>
Bug #2343: Timeout.timeout doesn't raise Timeout::Error by default
[#26623] Re: [ruby-cvs:32896] Ruby:r25678 (trunk): * ext/dl/cptr.c (rb_dlptr_s_malloc, rb_dlptr_initialize): adding — Tanaka Akira <akr@...>
In article <200911062250.nA6Mo69d010341@ci.ruby-lang.org>,
In article <87y6mhb180.fsf@fsij.org>,
On Thu, Nov 12, 2009 at 11:54:49AM +0900, Tanaka Akira wrote:
[#26632] [Feature #2347] Math::INFINITY — Marc-Andre Lafortune <redmine@...>
Feature #2347: Math::INFINITY
2009/11/9 Marc-Andre Lafortune <redmine@ruby-lang.org>:
[#26635] [Feature #2348] RBTree Should be Added to the Standard Library — James Gray <redmine@...>
Feature #2348: RBTree Should be Added to the Standard Library
Issue #2348 has been updated by James Gray.
Hi,
Hi,
Hi,
Yusuke ENDOH wrote:
[#26650] [Feature #2350] Unicode specific functionality on String in 1.9 — Manfred Stienstra <redmine@...>
Feature #2350: Unicode specific functionality on String in 1.9
Issue #2350 has been updated by Yusuke Endoh.
On Thu, Mar 25, 2010 at 14:45, Yusuke Endoh <redmine@ruby-lang.org> wrote:
(2010/03/26 0:02), Nikolai Weibull wrote:
On Thu, Mar 25, 2010 at 18:24, NARUSE, Yui <naruse@airemix.jp> wrote:
On Thu, Mar 25, 2010 at 19:33, Nikolai Weibull <now@bitwi.se> wrote:
The problem is that the definition of #upcase doesn't only depend on the
On Fri, Mar 18, 2011 at 11:53, Magnus Holm <judofyr@gmail.com> wrote:
[#26652] [Bug #2351] system() hardlinked to /bin/sh — Marcus Franke <redmine@...>
Bug #2351: system() hardlinked to /bin/sh
Issue #2351 has been updated by Motohiro KOSAKI.
[#26668] [Bug #2353] hash.c:setenv causes crashes in Solaris — Christian Höltje <redmine@...>
Bug #2353: hash.c:setenv causes crashes in Solaris
[#26704] Maintainer confirmation process done. — "Yugui (Yuki Sonoda)" <yugui@...>
I'm sorry for my closing the maintainer confirmation process so late.
On Thu, Nov 12, 2009 at 05:29:55PM +0900, Yugui (Yuki Sonoda) wrote:
Aaron Patterson wrote:
[#26722] [Bug #2362] undefined variable has value? — Vit Ondruch <redmine@...>
Bug #2362: undefined variable has value?
[#26736] [Bug #2365] Matrix: poor handling of coercion errors [patch] — Marc-Andre Lafortune <redmine@...>
Bug #2365: Matrix: poor handling of coercion errors [patch]
Issue #2365 has been updated by Marc-Andre Lafortune.
Hi,
Hi,
[#26745] [Bug #2371] [BUG] thread_free: locking _mutex must be NULL — Chris Schlaeger <redmine@...>
Bug #2371: [BUG] thread_free: locking _mutex must be NULL
[#26753] (send #2) cgi.rb cleanup — Ryan Davis <ryand-ruby@...>
(not sure why my previous email about this got dropped)
Hi,
[#26767] [Bug #2376] Kernel.__method__ rubyspec failures for 1.8.* — Vladimir Sizikov <redmine@...>
Bug #2376: Kernel.__method__ rubyspec failures for 1.8.*
[#26771] [Bug #2377] update documentation for IO#eof? — Roger Pack <redmine@...>
Bug #2377: update documentation for IO#eof?
[#26772] [Bug #2378] Regression in ParseDate.parsedate('nn-nn') — Vladimir Sizikov <redmine@...>
Bug #2378: Regression in ParseDate.parsedate('nn-nn')
Issue #2378 has been updated by Hiro Asari.
[#26774] Ruby constant lookup — Yehuda Katz <wycats@...>
Over the past six months or so, I have been working with the new Ruby 1.9
Hi,
Shugo,
Hi,
On Tue, Nov 17, 2009 at 1:29 AM, Shugo Maeda <shugo@ruby-lang.org> wrote:
Hi,
On Sun, Nov 22, 2009 at 8:08 PM, Shugo Maeda <shugo@ruby-lang.org> wrote:
On Mon, Nov 23, 2009 at 8:08 AM, Rick DeNatale <rick.denatale@gmail.com> wrote:
Hi,
Shugo,
[#26788] [Bug #2380] IO#eof? behavior different with 1.9.1p243-mingw32 than other platforms — Ian Dees <redmine@...>
Bug #2380: IO#eof? behavior different with 1.9.1p243-mingw32 than other platforms
Issue #2380 has been updated by Vit Ondruch.
[#26837] [Bug #2389] REXML rails to format parsed SVGs created with inkscape — Alexey Froloff <redmine@...>
Bug #2389: REXML rails to format parsed SVGs created with inkscape
[#26852] Internals: #to_s .vs. #to_str? — Kurt Stephens <ks@...>
Is there a description of the semantic differences between #to_s and
[#26868] [Bug #2392] "Date.valid_civil?" issue in p383 — Ozgun Koyun <redmine@...>
Bug #2392: "Date.valid_civil?" issue in p383
[#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
> t reduces the number of #to_s Strings created during the MRI test suite
The attached patch add caching of #to_s results to the main immutable
> Yes. he MRI test suite runs at 45 sec with these changes and at 53 sec
I just ran rubyspec against it; ~ 5% time improvement.
Attached is a new version of the patch.
Hi,
On Tue, Dec 1, 2009 at 18:19, Yusuke ENDOH <mame@tsg.ne.jp> wrote:
Nikolai Weibull wrote:
[#26877] [Bug #2394] [BUG] pthread_mutex_lock: 22 revisited — Roger Pack <redmine@...>
Bug #2394: [BUG] pthread_mutex_lock: 22 revisited
[#26889] email from redmine — danielcavanagh@...
hi
[#26931] Re: something broke ruby floats — Ryan Davis <ryand-ruby@...>
CC'ing ruby-core@
[#26939] Methods with default params not at the end and with rest params — Vladimir Sizikov <vsizikov@...>
Hi,
Hi,
Hi Matz,
[#26943] [Bug #2412] CSV regression after revision 25952 — Alexey Froloff <redmine@...>
Bug #2412: CSV regression after revision 25952
[ruby-core:26492] HashWithIndifferentAccess to core
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)