Разве методы Ruby instance_eval () и send () не сводят на нет преимущества частной видимости? - PullRequest
2 голосов
/ 22 мая 2009
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

Ответы [ 5 ]

12 голосов
/ 22 мая 2009

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

5 голосов
/ 22 мая 2009

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

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

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

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

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

4 голосов
/ 22 мая 2009

Если вы действительно хотите защитить экземпляры 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
1 голос
/ 22 мая 2009

По крайней мере, вы выражаете открытый API класса Widget.

0 голосов
/ 06 декабря 2011

Сообщение о возвращении домой: не беспокойтесь.

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

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

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

...