Provides a delegate
class method to easily expose contained
objects' public methods as your own.
Options
-
:to
- Specifies the target object -
:prefix
- Prefixes the new method with the target name or a custom prefix -
:allow_nil
- if set to true, prevents aNoMethodError
to be raised
The macro receives one or more method names (specified as symbols or
strings) and the name of the target object via the :to
option
(also a symbol or string).
Delegation is particularly useful with Active Record associations:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Greeter < ActiveRecord::Base def hello 'hello' end def goodbye 'goodbye' end end class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello , to: :greeter end Foo. new .hello # => "hello" Foo. new .goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c> |
Multiple delegates to the same target are allowed:
1 2 3 4 5 6 | class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello , :goodbye , to: :greeter end Foo. new .goodbye # => "goodbye" |
Methods can be delegated to instance variables, class variables, or constants by providing them as a symbols:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Foo CONSTANT_ARRAY = [ 0 , 1 , 2 , 3 ] @@class_array = [ 4 , 5 , 6 , 7 ] def initialize @instance_array = [ 8 , 9 , 10 , 11 ] end delegate :sum , to: : CONSTANT_ARRAY delegate :min , to: : @@class_array delegate :max , to: : @instance_array end Foo. new .sum # => 6 Foo. new .min # => 4 Foo. new .max # => 11 |
It's also possible to delegate a method to the class by using
:class
:
1 2 3 4 5 6 7 8 9 | class Foo def self .hello "world" end delegate :hello , to: :class end Foo. new .hello # => "world" |
Delegates can optionally be prefixed using the :prefix
option.
If the value is true
, the delegate methods are prefixed with
the name of the object being delegated to.
1 2 3 4 5 6 7 8 9 10 | Person = Struct. new ( :name , :address ) class Invoice < Struct. new ( :client ) delegate :name , :address , to: :client , prefix: true end john_doe = Person. new ( 'John Doe' , 'Vimmersvej 13' ) invoice = Invoice. new (john_doe) invoice.client_name # => "John Doe" invoice.client_address # => "Vimmersvej 13" |
It is also possible to supply a custom prefix.
1 2 3 4 5 6 7 | class Invoice < Struct. new ( :client ) delegate :name , :address , to: :client , prefix: :customer end invoice = Invoice. new (john_doe) invoice.customer_name # => 'John Doe' invoice.customer_address # => 'Vimmersvej 13' |
If the target is nil
and does not respond to the delegated
method a NoMethodError
is raised, as with any other value.
Sometimes, however, it makes sense to be robust to that situation and that
is the purpose of the :allow_nil
option: If the target is not
nil
, or it is and responds to the method, everything works as
usual. But if it is nil
and does not respond to the delegated
method, nil
is returned.
1 2 3 4 5 6 | class User < ActiveRecord::Base has_one :profile delegate :age , to: :profile end User. new .age # raises NoMethodError: undefined method `age' |
But if not having a profile yet is fine and should not be an error condition:
1 2 3 4 5 6 | class User < ActiveRecord::Base has_one :profile delegate :age , to: :profile , allow_nil: true end User. new .age # nil |
Note that if the target is not nil
then the call is attempted
regardless of the :allow_nil
option, and thus an exception is
still raised if said object does not respond to the method:
1 2 3 4 5 6 7 8 9 | class Foo def initialize(bar) @bar = bar end delegate :name , to: : @bar , allow_nil: true end Foo. new ( "Bar" ).name # raises NoMethodError: undefined method `name' |
The target method must be public, otherwise it will raise
NoMethodError
.
Please login to continue.