sonic-pi
https://github.com/sonic-pi-net/sonic-pi
C++
Code. Music. Live.
Module#delegate
Provides a +delegate+ class method to easily expose contained objects'
public methods as your own.
==== Options
* <tt>:to</tt> - Specifies the target object
* <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
* <tt>:allow_nil</tt> - if set to true, prevents a +NoMethodError+ 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 <tt>:to</tt> option
(also a symbol or string).
Delegation is particularly useful with Active Record associations:
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:
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:
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+:
class Foo
def self.hello
"world"
end
delegate :hello, to: :class
end
Foo.new.hello # => "world"
Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
delegated to.
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.
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
<tt>:allow_nil</tt> 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.
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:
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
<tt>:allow_nil</tt> option, and thus an exception is still raised if said object
does not respond to the method:
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+.Edit
git clone [email protected]:sonic-pi-net/sonic-pi.git
cd sonic-pi
open app/server/ruby/vendor/activesupport-7.0.6/lib/active_support/core_ext/module/delegation.rb
Contribute
# Make a new branchgit checkout -b -your-name--update-docs-Module-delegate-for-pr
# Commit to gitgit add app/server/ruby/vendor/activesupport-7.0.6/lib/active_support/core_ext/module/delegation.rbgit commit -m "better docs for Module#delegate"
# Open pull requestgem install hub # on a mac you can `brew install hub`
hub fork
git push <your name> -your-name--update-docs-Module-delegate-for-pr
hub pull-request
# Celebrate!