From d787d207ffa5642ebffd0bbc65bef8f9ab04f025 Mon Sep 17 00:00:00 2001 From: mynyml Date: Fri, 3 Apr 2009 20:06:48 -0400 Subject: [PATCH 1/2] Add Enumerable#every functionality. --- .../lib/active_support/core_ext/enumerable.rb | 24 ++++++++++++++++++++ .../active_support/core_ext/enumerable/proxy.rb | 13 ++++++++++ .../test/core_ext/enumerable/proxy_test.rb | 10 ++++++++ activesupport/test/core_ext/enumerable_test.rb | 10 ++++++++ 4 files changed, 57 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..29b0512 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/enumerable/proxy.rb @@ -0,0 +1,13 @@ +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 + 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..2001d4b --- /dev/null +++ b/activesupport/test/core_ext/enumerable/proxy_test.rb @@ -0,0 +1,10 @@ +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 +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.6.2.1 From 638602e06317180a56c44d2001a67f3ad9f84c83 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Mon, 6 Apr 2009 22:34:02 -0400 Subject: [PATCH 2/2] Additional functionality for Enumerable#every --- .../active_support/core_ext/enumerable/proxy.rb | 13 +++++++++++- .../test/core_ext/enumerable/proxy_test.rb | 21 +++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/enumerable/proxy.rb b/activesupport/lib/active_support/core_ext/enumerable/proxy.rb index 29b0512..473910e 100644 --- a/activesupport/lib/active_support/core_ext/enumerable/proxy.rb +++ b/activesupport/lib/active_support/core_ext/enumerable/proxy.rb @@ -6,8 +6,19 @@ module Enumerable @enum, @method = enum, method end + def proxy_target; @enum; end + def proxy_method; @method; end + + def proxy_send(method, *args, &block) + proxy_target.__send__(proxy_method) {|o| o.__send__(method, *args, &block) } + end + + def respond_to?(*args) + proxy_target.inject(true){|res, o| res && o.respond_to?(*args) } + end + def method_missing(method, *args, &block) - @enum.__send__(@method) {|o| o.__send__(method, *args, &block) } + proxy_send(method, *args, &block) end end end diff --git a/activesupport/test/core_ext/enumerable/proxy_test.rb b/activesupport/test/core_ext/enumerable/proxy_test.rb index 2001d4b..ce4b41a 100644 --- a/activesupport/test/core_ext/enumerable/proxy_test.rb +++ b/activesupport/test/core_ext/enumerable/proxy_test.rb @@ -2,9 +2,28 @@ require 'abstract_unit' class EnumerableProxyTests < Test::Unit::TestCase def test_is_basic_object - whitelist = %w( __id__ __send__ method_missing __metaclass__ __is_a__ ) + whitelist = %w( __id__ __send__ method_missing __metaclass__ __is_a__ respond_to? proxy_send proxy_target proxy_method ) 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 + + def test_responds_to + assert [1,2,3].every.respond_to?(:to_i) + assert ![1,2,3].every.respond_to?(:blah) + end + + def test_proxy_send + assert_equal [true, true, true], [1,2,3].every.proxy_send(:respond_to?, :to_i) + assert_equal [false, false, false], [1,2,3].every.proxy_send(:respond_to?, :blah) + end end -- 1.6.2.1