undef - Почему вы хотите отменить определение метода в ruby? - PullRequest
10 голосов
/ 13 февраля 2009

Я никогда не видел undef - или чего-то еще, что позволяет вам определять метод - ни в каких других языках программирования. Зачем это нужно в Ruby?

РЕДАКТИРОВАТЬ: Я не утверждаю, что с этим что-то не так. Я просто не понимаю цель определения методов во время выполнения? Какова цель этого? Как это используется? Я никогда не делал этого на C или Java.

Ответы [ 7 ]

18 голосов
/ 13 февраля 2009

Существует также пустой шаблон класса в Ruby, который нуждается в функциональности undef.

Идея состоит в том, чтобы убрать каждый метод из вашего нового класса, чтобы каждый вызов, который вы делаете к нему, заканчивался на #method_missing. Таким образом, вы можете реализовать настоящий прокси, который просто перетасовывает все. Реализация шаблона декоратора с этим занимает около десяти строк кода, независимо от того, насколько велик ваш целевой класс.

Если вы хотите увидеть эту идиому в действии, взгляните на одну из насмешливых платформ Руби, они часто ее используют. Что-то вроде flexmock .

Другой пример - когда вы динамически добавляете функции в класс на основе некоторого условия. В игре вы можете добавить метод #attack на объект игрока, а затем убрать его, когда он парализован, вместо того, чтобы делать это с логическим флагом. Таким образом, вызывающий класс может проверять наличие метода, а не флаг. Я не говорю, что это хорошая идея, просто она стала возможной, и есть гораздо более умные люди, чем я, которые придумывают полезные вещи, связанные с этим.

2 голосов
/ 13 февраля 2009

Определение методов, классов и объектов во время выполнения - очень приятная особенность Ruby. Это позволяет расширять классы (помните, что они «открыты»). Если вы посмотрите на Rails, у него есть метод #find для поиска объектов в модели, но вы также можете использовать find_by_user; этот метод не существует (поэтому вызывается #method_missing), но создается во время выполнения.

Если вы хотите создать специфичный для домена язык или DSL, использование #missing_method может быть полезным.

1 голос
/ 01 декабря 2017

Я видел, как это используется в сочетании с Mixins; так что вы можете включить все это, а затем отменить определение методов, которые он не должен поддерживать ... например графическая библиотека ruby ​​ shoes .

Класс button смешивается в модуле clickable, а затем undef - это метод release, потому что кнопки не поддерживают его.

Еще один быстрый пример, так что он доступен здесь:

module Walkable
  attr_accessor :location
  def walk(steps)
    @location += steps
  end
  def walk_back(steps)
    @location -= steps
  end
end
class Zombie
  include Walkable
  undef walk_back #zombies can only walk forwards
end
1 голос
/ 27 марта 2011

С определением методов во время выполнения связана техника включения модулей по мере необходимости. Я работаю над приложением Rails, где нам иногда приходится экспортировать данные в различных форматах. В 99% случаев объекту Form не нужны методы, связанные с экспортом, но в нашей задаче экспорта Rake мы делаем что-то вроде:

Form.send(:include, FormExportingMethods)

Так что у него есть только те методы, которые ему нужны.

Этот вид динамизма - одна из вещей, которые мне нравятся в Ruby. В то время как в некоторых языках вы должны заранее определить свои классы и объекты, Руби позволяет вам сказать: «О, мне нужна моя свинья, чтобы иметь крылья прямо сейчас? Я просто прикреплю их».

Обратите внимание, что в моем примере определенные объекты формы не изменяются; Форма класса есть. Это работает, потому что, когда вы отправляете сообщение объекту, он ищет в цепочке поиска метода ответ в тот момент, когда вы спрашиваете . Таким образом, вы можете создать объект, затем добавить метод в любом месте его цепочки наследования, затем вызвать метод объекта, и он будет иметь его. Очевидно, что просмотр всей цепочки наследования для каждого вызова метода стоит дорого, но это компромисс для такой гибкости.

0 голосов
/ 28 ноября 2013

Я использую внешний API, и один из ответов JSON содержит поле с именем «method». Я создаю OpenStruct вокруг json, просто чтобы сделать json более управляемым. При вызове openStruct.methods он возвращает результат метода экземпляра Object «методы».

Так я и сделал:

class MyOpenStruct < OpenStruct
   def methods
   end

   undef :methods
end 

openStruct = OpenStruct.new(my_json)
0 голосов
/ 18 декабря 2011

Если вы используете Single Table Inheritance с ORM, например ActiveRecord, вы можете отменить определение методов для полей, которые не используются для определенного класса / объекта.

# table: shapes, with columns: name, sides, radius, type
class Shape < ActiveRecord::Base
end

class Circle < Shape
end

class Square < Shape
  undefine_method :radius
end

Примечание. На самом деле это не работает в ActiveRecord, поскольку он ожидает, что метод для каждого поля будет всегда определен.

Примечание: у квадрата есть радиус, который обычно не используется, но вы понимаете суть? Подумайте о каком-либо свойстве, которое вы храните в базе данных, которое есть у Круга, но не у Квадрата.

0 голосов
/ 13 февраля 2009

Вы можете посмотреть на все Rails для примеров определения методов во время выполнения (или метапрограммирование). Вызывая один метод в вашем определении класса, он может определить целый набор методов для всех экземпляров этого класса ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...