Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`alias_method` a private method

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?

like image 621
equivalent8 Avatar asked Sep 21 '25 13:09

equivalent8


2 Answers

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 }
like image 170
Aleksei Matiushkin Avatar answered Sep 23 '25 20:09

Aleksei Matiushkin


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 }
like image 45
equivalent8 Avatar answered Sep 23 '25 18:09

equivalent8