Removing code duplication using Ruby Procs


Refactoring to remove code duplication is one of the most common refactor patterns. In Ruby, one way to remove this duplication is via the use of Procs. This is not a new technique, but rather an example of its use.

We’re going to look at some contrived (but functional) code.

  
  #...
  #ENTRY POINT
  def make_change( amount )
    coins = pull_out_coins( amount )
    bills = pull_out_bills( amount )
    #...
  end

  private

  def pull_out_coins( amount )
    s = Float( amount ).to_s
    idx = s.index( "." )
    cents = s[ idx + 1..-1 ]
    cents.to_i
  end
    
  def pull_out_bills( amount )
    s = Float( amount ).to_s
    idx = s.index( "." )
    bill = s[ 0...idx ]
    bill.to_i
  end

  #...

The obvious duplication here is in the methods #pull_cents_from_input(), and #pull_bills_from_input(). All the lines of code are duplicated, save the line that accesses either the cents or bills (the third line in both functions, displayed in bold text). BUT, if we pull out the code that changes, so we can inject it into the code that stays the same, we can do something like this:

  
  #...
  
  def make_change( amount )
    coins = pull_out_coins( amount )
    bills = pull_out_bills( amount )
    coins = pull_currency( amount ){ | s, idx | s[ idx + 1..-1 ] }
    bills = pull_currency( amount ){ | s, idx | s[ 0...idx     ] }
    #...
  end

  private
    
  def pull_currency( amount, &block )
    s         = Float( amount ).to_s
    idx       = s.index( "." )
    currency  = block.call( s, idx )
    currency.to_i
  end

  #...

So now, instead of calling two separate methods, we are only calling a single method created from the refactor:: #pull_currency(), that is comprised of the code that was the same in both methods. When we call #pull_currency(), we are adding a block (highlighted in bold) to the method call. Inside this block (highlighted in bold) is the code that varied for each previous method.

The resulting code better reflects the fact that the code in #pull_currency() is largely duplicated, varying only by the injected blocks.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s