`alias_method` a private method

4.5k Views Asked by At

I have a class that exposes two interface methods client_options and user_options, and at this ancestry level, they are equivalent to default_options. I don't want other developers to implement default_options directly, hence it's private.

class Foo
  def client_options
    default_options
  end
  def user_options
    default_options
  end

  private
    def default_options
      { foo: :bar }
    end
end

To save some lines of code, I wanted to alias the methods:

class Foo
  alias_method :client_options, :default_options
  alias_method :user_options, :default_options

  private
    def default_options
      { foo: :bar }
    end
end

but alias_method only aliases public methods.

I found how to alias private methods on this blog:

class Foo
  def default_options
    { foo: :bar}
  end

  private :default_options
  alias_method :client_options, :default_options
  public :client_options
end

but, it's little bit unreadable.

Is there a more straight solution to alias a private method?

3

There are 3 best solutions below

8
On BEST ANSWER

Alias, then privatize:

alias_method :client_options, :default_options
alias_method :user_options, :default_options
private :default_options

Or, whether you are so aware of this “scissors rule”:

%i(client_options user_options).each do |m|
  define_method m { default_options }
end

Or create your own alias_method alike method

  module AliasPrivateMethod
    def alias_private_method_to_interface(name, original_name)
      define_method(name) do |*args, &block|
        send(original_name, *args, &block)
      end
    end
  end

  class Foo
    extend AliasPrivateMethod
    alias_private_method_to_interface(:client_options, :default_options)
    private
      def default_options
        { foo: :bar }
      end
  end

  foo = Foo.new
  foo.public_methods(false) # => [:client_options]
  foo.client_options        # => { foo: :bar }
0
On

One approach I find good alternative is to delegate the private method to self

require 'forwardable'
class Foo
  extend Forwardable
  def_delegator :self, :default_options, :client_options
  def_delegator :self, :default_options, :user_options

  private
    def default_options
      { foo: :bar }
    end
end

f = Foo.new
f.client_options 
# => { foo: :bar }
0
On

What about implementing the method you want to hide in a prepended module?

module ProtoFoo
  protected
    def default_options
      {foo: :bar}
    end
end

class Foo
  prepend ProtoFoo
  def client_options; default_options end
  def user_options; default_options end
end

Even if a user overwrites default_options in Foo, it will not have effect.

If you insist on writing the hidden things after the exposed things, you can do:

class Foo
  def client_options; default_options end
  def user_options; default_options end
end

module ProtoFoo
  def default_options
    {foo: :bar}
  end
end
Foo.prepend ProtoFoo