Redefining a Private Method in Ruby

Objective


To learn different ways to redefine a private method in Ruby.

Why ?

It is not a good idea to redefine a private method. This can be found in code written by bad developers and you will encounter this kind of horrible code in real life projects. If you know how this works, you will be able to understand existing code base and be able to upgrade and maintain.

Redefine a Private Method by Opening an Existing Class

Let's see how to redefine a private method in an existing class called ActiveRecord.

class ActiveRecord

  private

  def hi
    'I am private'
  end
end

Assume that the above class is defined in the Rails framework. Now open the ActiveRecord class and put your implementation of hi() private method like this:

class ActiveRecord

  def greet
    hi
  end

  private

  def hi
    'I am redefining you'
  end

end

a = ActiveRecord.new
p a.greet

This will print I am redefining you.

Using Inheritance to Redefine a Private Method

Assume ActiveRecord is in the Rails framework code.

class ActiveRecord

  private

  def hi
    'I am private'
  end
end

In your project you create a subclass that over-rides the private method, like this:

class MyActiveRecord < ActiveRecord

  def greet
    hi
  end

  private

  def hi
    'I am redefining you'
  end

end

a = MyActiveRecord.new

p a.greet

This is not a good solution. You have to look at the parent class which has a gazillion of methods to figure out that the private method is being redefined in your code base. When you upgrade your Rails version, it is very likely that the private method has changed and things will break causing headaches and slowing down the upgrade process. If you take this approach, your cats will die of cancer.

Inheritance creates tight coupling to the super class. Prefer delegation over inheritance to create elegant designs.

Using Meta-Programming to Redefine a Private Method

class Client

  def print
    say
  end

  private

  def say
    "hello"
  end
end

# Create a subclass of Client
MyClient = Class.new(Client) do
  define_method(:say) do
    "hello from an over-ridden private method"
  end
end

puts MyClient.superclass

my_client = MyClient.new
puts my_client.print

We create a subclass of the original class and use define_method to over-ride the private method. This prints hello from an over-ridden private method. Note that we don't even have to make the redefined method private to over-ride the private method of the parent class.

This solution has unnecessary complexity and I would not recommend it unless it allows us to solve some problem that other approaches cannot solve. The above implementation can be simplified to accomplish the same thing like this:

class Client

  def print
    say
  end

  private

  def say
    "hello"
  end
end

class MyClient < Client
  def say
    "hello from an overridden private method"
  end
end

puts MyClient.superclass

my_client = MyClient.new
puts my_client.print

Summary


In this article you learned how to redefine a private method in Ruby. You can avoid unnecessary complexity and headaches during upgrade by using the simpler solution as discussed in this article.

Feedback


Tim Case pointed out on rubyflow.com:

The variable scoping in Ruby (public, protected, private) is merely a suggestion and not a hard barrier like it is in other languages. There’s also this way of calling a private method: obj.send(:any_private_method?)


Related Articles


Create your own user feedback survey