summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-10-23 15:10:48 +0000
committermarcandre <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-10-23 15:10:48 +0000
commitdc215dcd9f96620b7c06a25a741d13b19c2f130b (patch)
tree760deacf8def453cd813b896dbac2b2927f85cf0
parent57e52dea773cd51ed943ae1df142f65b725103a3 (diff)
* array.c: Add Array#to_h [Feature #7292]
* enum.c: Add Enumerable#to_h git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43401 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--NEWS8
-rw-r--r--array.c27
-rw-r--r--enum.c34
-rw-r--r--test/ruby/test_array.rb15
-rw-r--r--test/ruby/test_enum.rb27
6 files changed, 117 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 4908c6b15a..f677d271c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Oct 24 00:10:22 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * array.c: Add Array#to_h [Feature #7292]
+
+ * enum.c: Add Enumerable#to_h
+
Wed Oct 23 23:48:28 2013 Aman Gupta <ruby@tmm1.net>
* gc.c: Rename free_min to min_free_slots and free_min_page to
diff --git a/NEWS b/NEWS
index fe4ae53cd5..3e68c40df3 100644
--- a/NEWS
+++ b/NEWS
@@ -31,12 +31,20 @@ with all sufficient information, see the ChangeLog file.
=== Core classes updates (outstanding ones only)
+* Array
+ * New methods
+ * Array#to_h converts an array of key-value pairs into a Hash.
+
* Binding
* New methods
* Binding#local_variable_get(symbol)
* Binding#local_variable_set(symbol, obj)
* Binding#local_variable_defined?(symbol)
+* Enumerable
+ * New methods
+ * Enumerable#to_h converts a list of key-value pairs into a Hash.
+
* GC
* added environment variable:
* RUBY_HEAP_SLOTS_GROWTH_FACTOR: growth rate of the heap.
diff --git a/array.c b/array.c
index 54ddff47e6..7e4d4185ae 100644
--- a/array.c
+++ b/array.c
@@ -2126,6 +2126,32 @@ rb_ary_to_a(VALUE ary)
/*
* call-seq:
+ * ary.to_h -> hash
+ *
+ * Returns the result of interpreting <i>ary</i> as an array of
+ * <tt>[key, value]</tt> pairs. Elements other than pairs of
+ * values are ignored.
+ *
+ * [[:foo, :bar], [1, 2]].to_h
+ * # => {:foo => :bar, 1 => 2}
+ */
+
+static VALUE
+rb_ary_to_h(VALUE ary)
+{
+ long i;
+ VALUE hash = rb_hash_new();
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ VALUE key_value_pair = rb_check_array_type(rb_ary_elt(ary, i));
+ if (!NIL_P(key_value_pair) && (RARRAY_LEN(key_value_pair) == 2)) {
+ rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1));
+ }
+ }
+ return hash;
+}
+
+/*
+ * call-seq:
* ary.to_ary -> ary
*
* Returns +self+.
@@ -5564,6 +5590,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0);
rb_define_alias(rb_cArray, "to_s", "inspect");
rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0);
+ rb_define_method(rb_cArray, "to_h", rb_ary_to_h, 0);
rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0);
rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0);
diff --git a/enum.c b/enum.c
index df3c5636ec..ce7d22434b 100644
--- a/enum.c
+++ b/enum.c
@@ -510,6 +510,39 @@ enum_to_a(int argc, VALUE *argv, VALUE obj)
}
static VALUE
+enum_to_h_i(VALUE i, VALUE hash, int argc, VALUE *argv)
+{
+ ENUM_WANT_SVALUE();
+ rb_thread_check_ints();
+ i = rb_check_array_type(i);
+ if (!NIL_P(i) && RARRAY_LEN(i) == 2) {
+ rb_hash_aset(hash, RARRAY_AREF(i, 0), RARRAY_AREF(i, 1));
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.to_h(*args) -> hash
+ *
+ * Returns the result of interpreting <i>enum</i> as a list of
+ * <tt>[key, value]</tt> pairs. Elements other than pairs of
+ * values are ignored.
+ *
+ * %i[hello world].each_with_index.to_h
+ * # => {:hello => 0, :world => 1}
+ */
+
+static VALUE
+enum_to_h(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE hash = rb_hash_new();
+ rb_block_call(obj, id_each, argc, argv, enum_to_h_i, hash);
+ OBJ_INFECT(hash, obj);
+ return hash;
+}
+
+static VALUE
inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
{
NODE *memo = RNODE(p);
@@ -2758,6 +2791,7 @@ Init_Enumerable(void)
rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
+ rb_define_method(rb_mEnumerable, "to_h", enum_to_h, -1);
rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index f4faa9bedc..d7e1c365dd 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -1456,6 +1456,21 @@ class TestArray < Test::Unit::TestCase
$, = nil
end
+ def test_to_h
+ kvp = Object.new
+ def kvp.to_ary
+ [:obtained, :via_to_ary]
+ end
+ array = [
+ [:key, :value],
+ [:ignore_me],
+ [:ignore, :me, :too],
+ :ignore_me,
+ kvp,
+ ]
+ assert_equal({key: :value, obtained: :via_to_ary}, array.to_h)
+ end
+
def test_uniq
a = []
b = a.uniq
diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb
index ea873a4069..b86ae274d1 100644
--- a/test/ruby/test_enum.rb
+++ b/test/ruby/test_enum.rb
@@ -103,6 +103,33 @@ class TestEnumerable < Test::Unit::TestCase
assert_equal([1, 2, 3, 1, 2], @obj.to_a)
end
+ def test_to_h
+ assert_equal({}, @obj.to_h)
+ obj = Object.new
+ def obj.each(*args)
+ yield args
+ yield [:key, :value]
+ yield [:ignore_me]
+ yield [:ignore, :me, :too]
+ yield :other_key, :other_value
+ yield :ignore_me
+ yield :ignore, :me, :too
+ yield
+ kvp = Object.new
+ def kvp.to_ary
+ [:obtained, :via_to_ary]
+ end
+ yield kvp
+ end
+ obj.extend Enumerable
+ assert_equal({
+ :hello => :world,
+ :key => :value,
+ :other_key => :other_value,
+ :obtained => :via_to_ary,
+ }, obj.to_h(:hello, :world))
+ end
+
def test_inject
assert_equal(12, @obj.inject {|z, x| z * x })
assert_equal(48, @obj.inject {|z, x| z * 2 + x })