Разве Ruby-методы instance_eval() и send() не сводят на нет преимущества частной видимости?

StackOverflow https://stackoverflow.com/questions/896606

Вопрос

w = Widget.new # Create a Widget
w.send :utility_method # Invoke private method!
w.instance_eval { utility_method } # Another way to invoke it
w.instance_eval { @x } # Read instance variable of w

Если посмотреть на приведенный выше пример, относящийся к классу Widget (ниже), методы send и instance_eval нарушают все меры защиты, предоставляемые частной и защищенной видимостью.Если да, то зачем вообще беспокоиться о частном и защищенном доступе в Ruby, поскольку нет никакой гарантии, что ваши определения будут соблюдены?

class Widget
  def x # Accessor method for @x
   @x
  end
  protected :x # Make it protected
  def utility_method # Define a method
   nil
  end
  private :utility_method # And make it private
end
Это было полезно?

Решение

Если вы Действительно хотите защитить экземпляры Widget, вы можете сделать это (и кучу других вещей;код здесь нет полное решение безопасности, просто ориентировочное):

class Widget

  def some_public_method
    ...
  end

  private

  def utility_method
    ...
  end

  def send(method, *args, &block)
    raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
  end

  def instance_eval(&block)
    raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
  end

  class <<self
    private
    def class_eval(&block)
      raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
    end
  end
end

Widget.freeze

Другие советы

Ruby верит в то, что дает вам возможность делать то, что вы хотите.это просто не облегчает задачу случайно отбросьте ногу - если вы хотите нарушить частные объявления, вам придется использовать синтаксис, который ясно дает понять, что вы это делаете.обратите внимание, что окончательное решение о том, что должен или не должен делать код, принимает человек, использующий библиотеку, а не тот, кто ее пишет.

Я не могу комментировать из-за низкой репутации :/.

Переопределение send бесполезно, потому что send — это просто общее имя для __отправлять__ (это подчеркивание, подчеркивание, «отправить», подчеркивание, подчеркивание), который фактически реализует отправку сообщения.Переопределение любого __метод__ не рекомендуется.Кроме того, другой человек также может повторно открыть класс и отменить определение:

class Widget
  def send(method, *args, &block)
    super
  end
  #and so on
end

В Ruby 1.9 поведение немного другое:#send на самом деле обеспечивает видимость, __отправлять__ нет.

Private в Ruby имеет скорее декларативную цель:методы, объявленные как частные, являются деталями реализации, а не деталями API.Вам не разрешено случайно отправить сообщение извне.Но любой желающий по-прежнему может принудительно обойти это ограничение, если сочтет нужным — за свой счет.

По крайней мере, вы выражаете, что такое общедоступный API класса Widget.

Итоговое послание таково:не беспокойся.

Ruby, как и Python, абсолютно не справляется с песочницей.Если вы попытаетесь что-то заблокировать, скорее всего, всегда найдется способ обойти это.Множество способов получить приватный атрибут в Ruby доказывают мою точку зрения.

Почему?Потому что они созданы для этого.Оба языка спроектированы так, чтобы с ними можно было работать во время выполнения — именно это придает им силу.Запечатывая свой класс, вы лишаете других возможностей, которые предоставляет метапрограммирование Руби.

В Java есть отражение.В C++ есть указатели.Даже в Haskell есть unsafePerformIO.Если вы хотите защитить свою программу, вам необходимо защитить ее на уровне операционной системы, а не на уровне языка.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top