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