`alias_method` частный метод

У меня есть класс, который предоставляет два метода интерфейса client_options и user_options, и на этом уровне происхождения они эквивалентны default_options. Я не хочу, чтобы другие разработчики реализовывали default_options напрямую, поэтому это конфиденциально.

class Foo
  def client_options
    default_options
  end
  def user_options
    default_options
  end

  private
    def default_options
      { foo: :bar }
    end
end

Чтобы сохранить некоторые строки кода, я хотел дать псевдоним методам:

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

  private
    def default_options
      { foo: :bar }
    end
end

но alias_method использует только общедоступные методы.

Я нашел, как создавать псевдонимы частных методов, в этом блоге:

class Foo
  def default_options
    { foo: :bar}
  end

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

но это немного нечитаемо.

Есть ли более прямое решение для псевдонима частного метода?


person equivalent8    schedule 13.08.2015    source источник
comment
Если бы мне нужно было реализовать подкласс Foo, я был бы признателен за явные определения методов. Использование alias_method может сэкономить пару строк, но усложняет понимание вашего класса.   -  person Stefan    schedule 13.08.2015


Ответы (3)


Псевдоним, затем приватизировать:

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

Или, знаете ли вы об этом «правиле ножниц»:

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

Или создайте свой собственный метод, похожий на alias_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 }
person Aleksei Matiushkin    schedule 13.08.2015
comment
привет, спасибо за ответ, но это то же самое, что я написал в вопросе - person equivalent8; 13.08.2015
comment
Действительно? Вероятно, SO показывает мне урезанную версию вопроса, но я не вижу, что опубликовано. Что не так с этим подходом тогда? - person Aleksei Matiushkin; 13.08.2015
comment
это правильный подход, я не говорю, что это просто я искал решение, которое будет соблюдать правило ножниц .... достаточно забавно, я не могу найти в Google какую-либо статью об этом правиле, кроме Роберта С. Мартина (создатель видеороликов Clean Coders) говорил об этом. Это старое правило, когда вы пытаетесь держать общедоступные методы/методы интерфейса в верхней части кода, а приватные методы — ниже. Ruby хорошо реализует это, когда вы размещаете частные методы под ключевым словом private . Итак, представьте, что если в моем классе есть больше приватных методов, они ниже приватных, но default_options должны быть выше приватных. - person equivalent8; 13.08.2015
comment
Надеюсь, я понимаю, я использовал разрешенный размер комментария, чтобы объяснить это :) - person equivalent8; 13.08.2015
comment
@equivalent8 ваш последний пример также не соблюдает это правило. - person Stefan; 13.08.2015
comment
вы человек пример в моем вопросе или в ответе ??? ... если вы имеете в виду пример в вопросе ... да, именно поэтому я разместил этот вопрос, потому что думал, что есть какой-то встроенный метод, например alias_private_method или что-то в этом роде, но похоже, что это не так :( - person equivalent8; 13.08.2015
comment
Я полностью согласен, что это хорошее решение, но дело в том, что если разработчик должен определить метод private, а затем снова сделать его общедоступным, я думаю, будет лучше, если он делегирует метод себе (как в моем ответе stackoverflow.com/a/31983509/473040) просто мое мнение - person equivalent8; 13.08.2015
comment
только что написал статью, объясняющую правило ножниц, если кто-то хочет узнать о нем больше eq8.eu/blogs/16-scissors-rule-in-coding - person equivalent8; 13.08.2015

Один из подходов, который я считаю хорошей альтернативой, - делегировать частный метод 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 }
person equivalent8    schedule 13.08.2015

Как насчет реализации метода, который вы хотите скрыть в предустановленном модуле?

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

Даже если пользователь перезапишет default_options в Foo, это не повлияет.

Если вы настаиваете на написании скрытых вещей после открытых вещей, вы можете сделать:

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
person sawa    schedule 13.08.2015