Spiderman’s Extension Methods

by Alexander SologubMarch 25, 2013
This is one and only Spiderman's cheat sheet about Active Support core extension methods.

Spiderman is on duty every day (except Sunday, maybe). The thing is that he finds time to develop Ruby-on-Rails applications. So, I have a friend of a friend with a friend knowing some random person who asked Spiderman about his favourite core extension methods. The first thing Spiderman told: ‘Dude, call them Hardcore extension methods.’

So, let us see the list of coolest Hardcore extension methods.

 

extract_options!(), Array

The extract_options!(), Array method removes the last element of an array if it’s a hash, and returns it. If there’s no such element, it will return an empty hash.

def spin_the_web(*args)
  args.extract_options!
end

spin_the_web(:all_around)   # => {}
spin_the_web(:all_around, stickiness: => :average)  # => {:stickiness=>:average}

It can be used, for example, in methods with a variable number of arguments and in its declaration, so you can easily separate an array of parameters and options hash.

 

try(*args, &block), Object

So, you want to check if there’s an instance variable and call a method on it. Without the try(*args, &block), Object method, it looks as shown below.

@random_dude && @random_dude.spiderman?

That code is long enough and occurs too often, so there’s a shortcut presented below.

@random_dude.try(:spiderman?)

It will fail with NoMethodError if there’s no such method (unless receiver is nil). You can pass arguments to the method after its name (just like you do for the public_send method.)

 

delegate(*methods), Class

Let’s take a look at the delegate(*methods), Class method, and let’s start with an example.

class MaryJane
  def cook_soup
    'Mary is cooking'
  end
end

class Spiderman
  def initialize
    @mary_jane = MaryJane.new
  end

  delegate :cook_soup, to: :@mary_jane
end

spiderman = Spiderman.new
spiderman.cook_soup   # => "Mary is cooking"

Well, the example is very straightforward. You can delegate several methods in a single call. The delegation target can be pretty much everything: an instance variable, a class variable, a constant, or a method. There’s no need to be charming like a Spiderman to use this method.

 

sum(identity = 0, &block), Enumerable

After a hard day, Spiderman needs to calculate the total price of things he ‘expropriated.’ He can do this with the sum(identity = 0, &block), Enumerable method (if he has a PC nearby, of course).

[1,2,3,4,5].sum   # => 15

You can also call it with a block (for example, to calculate sum for some attribute).

@goods_from_the_orphanage.sum(&:price)   # => 2000

 

diff(another_hash), Hash

You can easily determine difference between superheroes and villains by using the diff(another_hash), Hash method.

spiderman = {
  racist: true,
  narcissistic: true,
  robs_the_banks: true,
  obsessed_with_his_uniqueness: true,
  wears_glasses: false }

dr_octopus = {
  racist: true,
  narcissistic: true,
  robs_the_banks: true,
  obsessed_with_his_uniqueness: true,
  wears_glasses: true }

spiderman.diff(dr_octopus)   # => {:wears_glasses=>false}

As you can see, there’s much difference here. So, duplicated key-value pairs do not belong to the result. If there are different values and the same key, the value from the receiver goes to the result. The rest is just merged.

 

except(*keys), Hash

To get a part of some hash, use the except(*keys), Hash method.

spiderman = {
  superpowers: true,
  latex_costume: true,
  camera: true
}

peter_parker = spiderman.except(:superpowers, :latex_costume)   # => {:camera=>true}

That’s the proof of Peter Parker being photographed naked without superpowers. (Sorry, I can’t post image with explicit content.)

The original except method doesn’t remove values from the receiver. However, it has a bang version which does.

 

Further reading