One of the most commendable features of Ruby is its support for a technique known as duck typing. Despite its humorous name, Duck Typing allows Ruby developers to write compressed, clean, and readable code with minimal effort – all of what drew us to Ruby.
"What would the Dodgers Duck do?"
The basic premise of duck typing is simple. If an entity looks, walks, and quacks like a duck, it is fair for every sense and purpose to assume that it is dealing with a member of the species anas platyrhynchos. In practical Ruby terms, this means that you can try calling any method on any object, regardless of its class.
To demonstrate, here's a simple scenario: You're working with a system that tracks shipping manifests for each container on the ship. The data for each manifest is easily retrieved through the RESTful web service:
# Fields: # * package_count: number of packages in manifest (integer) # * mass: total mass of all packages, in kilograms (BigDecimal) class ShippingManifest attr_accessor :package_count, :mass end
ShippingManifest Your task is to take a set of manifests (provided in
"Are you saying that the monster Loch Ness lives in your hot tub?"
The problem looks simple enough, right? Perhaps we could break it down into nine or ten lines of code:
def summarise_manifests # Grab the latest set of Manifests (returns an Array) manifest_set = ShippingManifest.all # Initialize our counters total_package_count = 0 total_mass = BigDecimal("0") manifest_set.each do |m| total_package_count += m.package_count total_mass += m.mass end return [total_package_count, total_mass] end
Easy, but verbose. You can reduce this method to a single line of code:
def summarise_manifests ShippingManifest.all.sum end
How? Duck prints!
"The key to the skeleton, eh? Where did you get that?
Our one-line solution uses one of Ruby's most powerful features:
Specifically, we use the method defined in
sum, which is available in every Rails project. As the name suggests, it is used to calculate the sum of a set of features. This is done using
an inject function that uses a block to reduce a set of objects to a single value. In the case
This makes sense when we're talking about numbers:
1 + 1 = 2 It's also easy to see how it can be used to concatenate strings:
['foo', 'bar', 'baz'].sum # => 'foobarbaz'
But how does Ruby know how to add two instances of our
It's easy. We say it like.
"It's only part of who I am. I'm actually pretty complicated.
"Everything is an object" is one of Ruby's main mantras. The consequence of this is that (almost) every operator is actually a method call to an instance of an object, which gives us the ability to define our own implementation for that operator. This means that we can do this:
class ShippingManifest < ActiveResource::Base # Returns a new instance of ShippingManifest containing the # sum of both `mass` and `package_count` def +(other) self.dup.tap do |neu| neu.mass = @mass + other.mass neu.package_count = @package_count + other.package_count end end end
By adding a few simple lines of code, we added functionality that made a potential
"And let me remind you guys once again that you are listening to the Truth or... Aaaaaaa
Implementing Custom Behavior for the
+ Operator There are other operators for which custom behavior is implemented:
== Need to sort the recordset? Implement a comparison operator (
As always, some code examples for this post are available on our GitHub account – feel free to fork them out and experiment! To get started, try implementing the
behavior for -