From d4e16d760ad84cfb16f047868ffd1a43eb91f3e4 Mon Sep 17 00:00:00 2001 From: Adam Keys Date: Wed, 3 Sep 2008 05:17:15 -0500 Subject: [PATCH] Add injecting to enumerable --- .../lib/active_support/core_ext/enumerable.rb | 25 +++++++++++++++++++- activesupport/test/core_ext/enumerable_test.rb | 5 ++++ 2 files changed, 29 insertions(+), 1 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index e451e99..61a9d4e 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -63,7 +63,30 @@ module Enumerable inject { |sum, element| sum + element } end end - + + # Syntactic sugar for inject, doesn't require you to return a value from the block parameter + # + # Injecting is just sugar on top of Ruby's inject. The sugar is in + # using the same accumulator reference every time the block is executed, + # rather than requiring you to return the accumulator at the end of your + # block. + # + # With Ruby's standard inject, this code would fail in a peculiar way: + # + # %w(foo bar).injecting({}) { |hsh, str| hsh[str] = str.upcase } + # + # However with injecting, we'll get something useful: + # + # {'foo' => 'FOO', 'bar' => 'BAR'} + # + def injecting(accumulator, &block) + inject(accumulator) do |accumulator, element| + returning accumulator do |accumulator| + block.call(accumulator, element) + end + end + end + # Convert an enumerable to a hash. Examples: # # people.index_by(&:login) diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 2315d8f..2395ada 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -58,6 +58,11 @@ class EnumerableTests < Test::Unit::TestCase assert_equal Payment.new(0), [].sum(Payment.new(0)) end + def test_injecting + result = %w(foo bar).injecting({}) { |hsh, str| hsh[str] = str.upcase } + assert_equal({'foo' => 'FOO', 'bar' => 'BAR'}, result) + end + def test_index_by payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ] assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] }, -- 1.5.5.3 From 59a927ccfd617d1189a3f58a0530aee8ec982436 Mon Sep 17 00:00:00 2001 From: Adam Keys Date: Wed, 3 Sep 2008 09:13:17 -0500 Subject: [PATCH] This time, more like each_with_object --- .../lib/active_support/core_ext/enumerable.rb | 29 +++++++++----------- activesupport/test/core_ext/enumerable_test.rb | 4 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 61a9d4e..cd861c2 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -64,28 +64,25 @@ module Enumerable end end - # Syntactic sugar for inject, doesn't require you to return a value from the block parameter + # Iterates over a collection, passing the current element *and* the + # +memo+ to the block. Handy for building up hashes or + # reducing collections down to one object. Examples: # - # Injecting is just sugar on top of Ruby's inject. The sugar is in - # using the same accumulator reference every time the block is executed, - # rather than requiring you to return the accumulator at the end of your - # block. + # %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } #=> {'foo' => 'FOO', 'bar' => 'BAR'} # - # With Ruby's standard inject, this code would fail in a peculiar way: + # *Note* that you can't use immutable objects like numbers, true or false as + # the memo. You would think the following returns 120, but since the memo is + # never changed, it does not. # - # %w(foo bar).injecting({}) { |hsh, str| hsh[str] = str.upcase } + # (1..5).each_with_object(1) { |value, memo| memo *= value } # => 1 # - # However with injecting, we'll get something useful: - # - # {'foo' => 'FOO', 'bar' => 'BAR'} - # - def injecting(accumulator, &block) - inject(accumulator) do |accumulator, element| - returning accumulator do |accumulator| - block.call(accumulator, element) + def each_with_object(memo, &block) + returning memo do |memo| + each do |element| + block.call(element, memo) end end - end + end unless [].respond_to?(:each_with_object) # Convert an enumerable to a hash. Examples: # diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 2395ada..aa57312 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -58,8 +58,8 @@ class EnumerableTests < Test::Unit::TestCase assert_equal Payment.new(0), [].sum(Payment.new(0)) end - def test_injecting - result = %w(foo bar).injecting({}) { |hsh, str| hsh[str] = str.upcase } + def test_each_with_object + result = %w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } assert_equal({'foo' => 'FOO', 'bar' => 'BAR'}, result) end -- 1.5.5.3