From 79390d19419b210e2dd982827874f9725b6cd139 Mon Sep 17 00:00:00 2001 From: mynyml Date: Wed, 8 Apr 2009 21:13:18 -0400 Subject: [PATCH] Add Enumerable#every functionality, with introspection. --- .../lib/active_support/core_ext/enumerable.rb | 24 ++++++++++++++++++++ .../active_support/core_ext/enumerable/proxy.rb | 21 +++++++++++++++++ .../test/core_ext/enumerable/proxy_test.rb | 19 +++++++++++++++ activesupport/test/core_ext/enumerable_test.rb | 10 ++++++++ 4 files changed, 74 insertions(+), 0 deletions(-) create mode 100644 activesupport/lib/active_support/core_ext/enumerable/proxy.rb create mode 100644 activesupport/test/core_ext/enumerable/proxy_test.rb diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index a7eaccf..80bebe4 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,6 +1,8 @@ require 'active_support/ordered_hash' module Enumerable + autoload :Proxy, 'active_support/core_ext/enumerable/proxy' + # Ruby 1.8.7 introduces group_by, but the result isn't ordered. Override it. remove_method(:group_by) if [].respond_to?(:group_by) && RUBY_VERSION < '1.9' @@ -113,4 +115,26 @@ module Enumerable def none?(&block) !any?(&block) end unless [].respond_to?(:none?) + + # Proxies a method onto each member of a collection. + # + # enum = [1.4, 2.4, 3.4] + # enum.every.floor #=> [1, 2, 3] + # + # enum = %w( axc dxf ) + # enum.every.gsub(/x/,'y') #=> ["ayc", "dyf"] + # enum.every.gsub(/x/) { 'y' } #=> ["ayc", "dyf"] + # enum.every.upcase! + # enum #=> ["AXC", "DXF"] + # + # enum = ['foo', 'bar', ''] + # enum.every.empty?.all? #=> false + # enum.every.empty?.any? #=> true + # + # @company.clients.every.name + # Company.all.every.clients.flatten.every.name + # + def every + Proxy.new(self, :map) + end end diff --git a/activesupport/lib/active_support/core_ext/enumerable/proxy.rb b/activesupport/lib/active_support/core_ext/enumerable/proxy.rb new file mode 100644 index 0000000..0bd24b6 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/enumerable/proxy.rb @@ -0,0 +1,21 @@ +module Enumerable + class Proxy + instance_methods.each { |m| undef_method(m) unless m.match(/^__/) } + + def initialize(enum, method=:map) + @enum, @method = enum, method + end + + def method_missing(method, *args, &block) + @enum.__send__(@method) {|o| o.__send__(method, *args, &block) } + end + + def proxy_target + @enum + end + + def proxy_method + @method + end + end +end diff --git a/activesupport/test/core_ext/enumerable/proxy_test.rb b/activesupport/test/core_ext/enumerable/proxy_test.rb new file mode 100644 index 0000000..6be4ba1 --- /dev/null +++ b/activesupport/test/core_ext/enumerable/proxy_test.rb @@ -0,0 +1,19 @@ +require 'abstract_unit' + +class EnumerableProxyTests < Test::Unit::TestCase + def test_is_basic_object + whitelist = %w( __id__ __send__ method_missing __metaclass__ __is_a__ ) + i_methods = Enumerable::Proxy.instance_methods + + assert_equal whitelist.to_set, i_methods.to_set + end + + def test_proxy_target + enum = [1,2,3] + assert_equal enum, enum.every.proxy_target + end + + def test_proxy_method + assert_equal :map, [1,2,3].every.proxy_method + end +end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 92db977..75a5207 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -90,4 +90,14 @@ class EnumerableTests < Test::Unit::TestCase assert ![ 1, 2 ].none? {|x| x > 1 } assert [ 1, 1 ].none? {|x| x > 1 } end + + def test_every + assert_equal %w( FOO BAR BAZ ), %w( foo bar baz ).every.upcase + assert_equal %w( foo xar xaz ), %w( foo bar baz ).every.gsub(/^b/,'x') + assert_equal %w( foo xar xaz ), %w( foo bar baz ).every.gsub(/^b/) { 'x' } + + enum = %w( foo bar baz ) + enum.every.upcase! + assert_equal %w( FOO BAR BAZ ), enum + end end -- 1.5.6.3