Ruby: извлечение особенностей стека из класса Array - PullRequest
4 голосов
/ 26 марта 2012

У меня есть необходимость использовать стековую структуру данных для программы, которую я пишу, и я знаю, что Ruby не имеет явной структуры данных Stack, но что у класса Array есть все свойства, которые делаютa Stack: push, pop, size, clear, isEmpty, inspect, to_s.

При поиске в Интернете я нашел различные посты, использующие этот синтаксис для извлечения функцийкласса Array в подкласс:

Stack = Array.extract([
  :push,
  :pop,
  :size,
  :clear,
  :inspect,
  :to_s
])

s = Stack.new
s.push 1
s.push 2
s.push 3
s       # => [1, 2, 3]
s.pop   # => 3
s       # => [1, 2]

Я хотел бы сделать что-то похожее на это, так что мой подкласс Array ограничен в том, что вызовы он может сделать, но кажется, что метод extract больше не являетсяв API класса Array.

Вопросы:

  1. Эта функция была удалена по какой-то причине, в чем же причина такого ущерба?
  2. Как добиться функциональности, аналогичной этой, с помощью Ruby 1.90,3?Прямо сейчас я просто делегирую необходимые вызовы классу Array, но все другие методы в классе Array все еще могут вызываться в моем объекте Stack, что я не хочу разрешать.

Ответы [ 3 ]

8 голосов
/ 26 марта 2012

Взять этот код, например:

class Stack
  def initialize
    @array = []
  end

  def push val
    @array.push val
  end

  def pop 
    @array.pop
  end
end

Здесь у вас есть личный экземпляр var, которому вы делегируете выбранные методы.Другие методы не могут быть вызваны напрямую.Синтаксис может быть улучшен и сделан более «изящным» с помощью некоторого метапрограммирования, но основная идея такая, как показано выше.

Конечно, всегда можно получить доступ к этому закрытому var через instance_variable_get, и вы ничего не можете сделатьоб этом.Это Ruby!

Сделать чистый безопасный публичный интерфейс.И если кто-то пытается вмешаться во внутренние части и что-то сломать, это его проблема.

Обновление

Если вы используете ActiveSupport (который поставляется с Rails), тогда есть более простой способ сделатьthis.

# load ActiveSupport if not in Rails env
require 'active_support/core_ext'

class Stack
  def initialize
    @impl = []
  end

  # the "extract" part :)
  delegate :count, :push, :pop, to: :@impl
end

s = Stack.new
s.push(3).push(4)
s.count # => 2

Или посмотрите аналогичный ответ от @ AndrewGrimm.

4 голосов
/ 28 марта 2012

Если вы собираетесь много делегировать, вы можете использовать методы делегирования, которые предоставляет Ruby.

require "forwardable"

class Stack
  extend Forwardable
  def_delegators :@array, :push, :pop

  def initialize
    @array = []
  end
end

Мало того, что это означает меньше печатать, но если вы знакомы с Forwardable, его легче читать. Вы знаете, что ваш класс просто делегирует, без необходимости читать код для Stack#push или Stack#pop.

0 голосов
/ 26 марта 2012

Может быть, вы можете отменить методы, которые вам не нравятся, хотя они выглядят проводными.

class Stack < Array
  DISLIKE_IMS = instance_methods - Object.instance_methods - [:public, :pop, :size, :to_s, :inspect, :clear]
  DISLIKE_CMS = methods - Object.methods

  DISLIKE_IMS.each do |im|
    class_eval "undef #{im}"
  end

  DISLIKE_CMS.each do |cm|
    instance_eval "undef #{cm}"
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...