mirror of
https://github.com/github/rails.git
synced 2026-01-28 15:58:03 -05:00
Added delegation support to Module that allows multiple delegations at once (unlike Forwardable in the stdlib) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3535 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
*SVN*
|
||||
|
||||
* Added delegation support to Module that allows multiple delegations at once (unlike Forwardable in the stdlib) [DHH]. Example:
|
||||
|
||||
class Account < ActiveRecord::Base
|
||||
has_one :subscription
|
||||
delegate :free?, :paying?, :to => :subscription
|
||||
delegate :overdue?, :to => "subscription.last_payment"
|
||||
end
|
||||
|
||||
account.free? # => account.subscription.free?
|
||||
account.overdue? # => account.subscription.last_payment.overdue?
|
||||
|
||||
* Fix Reloadable to handle the case where a class that has been 'removed' has not yet been garbage collected. [Nicholas Seckar]
|
||||
|
||||
* Don't allow Reloadable to be included into Modules.
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
require File.dirname(__FILE__) + '/module/inclusion'
|
||||
require File.dirname(__FILE__) + '/module/attribute_accessors'
|
||||
require File.dirname(__FILE__) + '/module/attribute_accessors'
|
||||
require File.dirname(__FILE__) + '/module/delegation'
|
||||
@@ -0,0 +1,16 @@
|
||||
class Module
|
||||
def delegate(*methods)
|
||||
options = methods.pop
|
||||
unless options.is_a?(Hash) && to = options[:to]
|
||||
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key"
|
||||
end
|
||||
|
||||
methods.each do |method|
|
||||
module_eval(<<-EOS, "(__DELEGATION__)", 1)
|
||||
def #{method}(*args, &block)
|
||||
#{to}.__send__(#{method.inspect}, *args, &block)
|
||||
end
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -26,6 +26,34 @@ end
|
||||
class De
|
||||
end
|
||||
|
||||
Somewhere = Struct.new(:street, :city)
|
||||
|
||||
Someone = Struct.new(:name, :place) do
|
||||
delegate :street, :city, :to => :place
|
||||
delegate :state, :to => :@place
|
||||
delegate :upcase, :to => "place.city"
|
||||
end
|
||||
|
||||
class Name
|
||||
delegate :upcase, :to => :@full_name
|
||||
|
||||
def initialize(first, last)
|
||||
@full_name = "#{first} #{last}"
|
||||
end
|
||||
end
|
||||
|
||||
$nowhere = <<-EOF
|
||||
class Name
|
||||
delegate :nowhere
|
||||
end
|
||||
EOF
|
||||
|
||||
$noplace = <<-EOF
|
||||
class Name
|
||||
delegate :noplace, :tos => :hollywood
|
||||
end
|
||||
EOF
|
||||
|
||||
class ModuleTest < Test::Unit::TestCase
|
||||
def test_included_in_classes
|
||||
assert One.included_in_classes.include?(Ab)
|
||||
@@ -34,4 +62,24 @@ class ModuleTest < Test::Unit::TestCase
|
||||
assert !One.included_in_classes.include?(De)
|
||||
end
|
||||
|
||||
def test_delegation_to_methods
|
||||
david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
|
||||
assert_equal "Paulina", david.street
|
||||
assert_equal "Chicago", david.city
|
||||
end
|
||||
|
||||
def test_delegation_down_hierarchy
|
||||
david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
|
||||
assert_equal "CHICAGO", david.upcase
|
||||
end
|
||||
|
||||
def test_delegation_to_instance_variable
|
||||
david = Name.new("David", "Hansson")
|
||||
assert_equal "DAVID HANSSON", david.upcase
|
||||
end
|
||||
|
||||
def test_missing_delegation_target
|
||||
assert_raises(ArgumentError) { eval($nowhere) }
|
||||
assert_raises(ArgumentError) { eval($noplace) }
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user