Old Guy New Trick

An old guys journey to learn how to code.

Cover Your Private Parts


Author: John on December 29, 2015

Just before Christmas, while working on a feature, I encountered a privacy issue.  No, not personally, but Ruby was shoving the "Private, Keep Out" sign in my face.  Along my journey to learn to code I've come across the topic of using private as well as public and protected in Ruby programs.  And I have had to work with private and public methods but on a small, simplistic scale.  So today I am going to show, using a fictional program that you the reader can follow along with and execute, how to work through a privacy problem.

To set the stage, here is the problem we need to solve:

NoMethodError: private method `mix_secret_ingredients' called for #<JaxRecipe:0x007fe8fb031b00> 

To follow along, of course you need to have Ruby installed; you know how to use irb; and you will want to create three files: jax_recipe.rb, koke_recipe.rb and distribution.rb.  See the code below that you can use to populate those three files.

#koke_recipe.rb
class KokeRecipe < Object
  # This is the master class, one that we might find in a gem
  # or library.

  attr_reader :kind, :quantity, :size

  def initialize(kind, quantity, size)
    @kind     = kind
    @quantity = quantity
    @size     = size
  end

  def mix_it
    puts "Mixing to make #{kind} of size #{size} at a quantity of #{quantity}"
    serving = size * quantity
    mix_secret_ingredients(serving)
  end


  private

  def mix_secret_ingredients(serving)
    puts "Adding the secret ingredients that only Koke-Kola and licensees are allowed to add "
    puts "for a serving of #{serving}."
  end

end

#jax_recipe.rb
class JaxRecipe < KokeRecipe
  # This is a local blend, based off a licensed version
  # of Koke-Kola

  attr_reader :kind, :quantity, :size

  def initialize(kind, quantity, size)
    super
  end

  def distribution(container_type)
    Distribution.new(self, container_type).create_package
  end

  def mix_it
    puts "Mixing to make Jax Based #{kind} of size #{size} at a quantity of #{quantity}"
    serving = size * quantity

    mix_secret_ingredients(serving)
  end

end

#distribution.rb
class Distribution

  attr_reader :soda, :container_type

  def initialize(soda, container_type)
    @soda           = soda
    @container_type = container_type
  end

  def create_package
    serving = soda.size * soda.quantity

    puts "Creating the packaging for #{soda.kind}:"
    soda.mix_secret_ingredients(serving)

    puts "Creating a package of #{container_type}s"
  end

end

Now that you have the files created, fire up irb and try out the following:

➜  soda_maker  irb
2.2.3 :001 > require './koke_recipe'
 => true
2.2.3 :003 > require './jax_recipe'
 => true
2.2.3 :004 > require './distribution'
 => true
2.2.3 :005 > jax_soda = JaxRecipe.new("cola", 48, 12)
 => #
2.2.3 :006 > jax_soda.mix_it
Mixing to make Jax Based cola of size 12 at a quantity of 48
Adding the secret ingredients that only Koke-Kola and licensees are allowed to add
for a serving of 576.
 => nil
2.2.3 :007 > koke = KokeRecipe.new("root_beer", 24, 18)
 => #
2.2.3 :008 > koke.mix_it
Mixing to make root_beer of size 18 at a quantity of 24
Adding the secret ingredients that only Koke-Kola and licensees are allowed to add
for a serving of 432.
 => nil
2.2.3 :009 >


Now, try to have Jax Recipe call for distribution, who is trying to mix in
the secret ingredients:

2.2.3 :009 > jax_soda_distribution = JaxRecipe.new("cola", 48, 12).distribution("bottles")
Creating the packaging for cola:
NoMethodError: private method `mix_secret_ingredients' called for #
	from /Users/jfhogarty/Documents/Programming/Ruby/soda_maker/distribution.rb:14:in `create_package'
	from /Users/jfhogarty/Documents/Programming/Ruby/soda_maker/jax_recipe.rb:12:in `distribution'
	from (irb):9
	from /Users/jfhogarty/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `

You should have encountered the error: private method `mix_secret_ingredients`.  

Hmmm, we didn't have any issues with mix_secret_ingredients when that method was called by the owners, Koke, via the KokeRecipe class.  And we didn't have an issue as a licensee as JaxRecipe.  The problem occurred when we went to distribution and they tried to update our soda with some secret ingredients.

Our business is growing and we need our distribution center to have the ability to tweak our mixture and use the mix_secret_ingredients method.  But as you saw, we currently getting the private method error message.  How can we resolve this?  Does private really mean private?  

The good news is, we have an easy fix.  We need to update one of our files, jax_recipe.rb.  Fire up your favorite editor, *cough* vim *cough* and add the update as indicated below:

#jax_recipe.rb
class JaxRecipe < KokeRecipe
  # This is a local blend, based off a licensed version
  # of Koke-Kola

  attr_reader :kind, :quantity, :size

  def initialize(kind, quantity, size)
    super
  end

  def distribution(container_type)
    Distribution.new(self, container_type).create_package
  end

  def mix_it
    puts "Mixing to make Jax Based #{kind} of size #{size} at a quantity of #{quantity}"
    serving = size * quantity

    mix_secret_ingredients(serving)
  end

  # Added this afterwards to get rid of error message regarding private
  public
  def mix_secret_ingredients(serving)
    super
  end

end

With the new updates in place, we can now try out our program again and see if our distribution chain is able to get our product out to market:

➜  soda_maker  irb
2.2.3 :001 > require './koke_recipe'
 => true
2.2.3 :002 > require './jax_recipe'
 => true
2.2.3 :003 > require './distribution'
 => true
2.2.3 :004 > jax_soda = JaxRecipe.new("cola", 48, 12)
 => #
2.2.3 :005 > koke = KokeRecipe.new("root_beer", 24, 18)
 => #
2.2.3 :006 > jax_soda_distribution = JaxRecipe.new("cola", 48, 12).distribution("bottles")
Creating the packaging for cola:
Adding the secret ingredients that only Koke-Kola and licensees are allowed to add
for a serving of 576.
Creating a package of bottless
 => nil
2.2.3 :007 >

In closing, I hope you find this posting useful and please forgive my simplistic example.  I tried to make it fun and illustrative without being too complex.

Learn Something New Everyday

Last Edited by: John on December 29, 2015