Класс Ruby Extended Array, который поддерживает полную цепочку методов

Короткий:

Есть ли способ создать расширенный класс Array с именем A, который поддерживает полную цепочку методов с map, sort, sort_by и новым методом word и не вредит классу Array?

Пример:

 [
    A.new(a).word,
    A.new(a).sort.word,
    A.new(a).sort_by(&:-@).word,
    A.new(a).map(&:chr).sort.map(&:ord).word
  ]

Длинная история:

Я решил эту ката и создал код, который расширяет класс Array новым методом word:

class Array
  def word
    [*self[0..1],*self[-2..-1]].map(&:chr).join
  end
end
def sort_transform(a)
  [
    a.word,
    a.sort.word,
    a.sort_by(&:-@).word,
    a.map(&:chr).sort.map(&:ord).word
  ].join ?-
end

Тогда я подумал, что не стоит добавлять метод для таких базовых классов. И я попытался реализовать новый класс, который унаследовал бы все поведение от Array.

class A < Array
  def word
    [*self[0..1],*self[-2..-1]].map(&:chr).join
  end
end

Это дополнение ломает мой код, потому что map, sort, sort_by возвращает экземпляр Array: A.new([1,2,3]).sort.class # Array. И Array не понимает метод word. И вместо A.new(a).sort.word я должен инкапсулировать часть цепочки в конструктор A.new: A.new(a.sort).word. Это определенно ломает цепочку методов чистый.

Можно ли расширить Array таким образом, чтобы достичь таких чистых цепочек методов; A.new(a).sort.word?

Когда я попытался написать строку: класс А <массив

def word
    [*self[0..1],*self[-2..-1]].map(&:chr).join
  end
  def sort
    A.new(self.sort)
  end
end

Это приносит мне main.rb:8:in 'sort': stack level too deep (SystemStackError) Наконец, уже написав эти строки, я нашел способ избежать дипстека: преобразовать себя в Array, а затем снова преобразовать в A.

class A < Array
  def word
    [*self[0..1],*self[-2..-1]].map(&:chr).join
  end
  def sort
    A.new(self.to_a.sort)
  end
end

Так это единственный способ реализовать такое расширение?

Статья была передана мне words.steveklabnik.com/beware-subclassing-ruby-core-classes И разработчик, который дал мне эту статью, сказал, что экземпляры возвращаются к Array в цепочке методов в Ruby из-за C кода. Он реализует для скорости.

Dmitry Dmitriev 04.07.2019 08:06

Вместо этого я бы использовал уточнение Array. Почему никто не использует уточнения?

Amadan 04.07.2019 08:18

@ Амадан, вот почему я написал этот вопрос :) Чтобы получить информацию, которую вы дали.

Dmitry Dmitriev 04.07.2019 08:25

Зачем вам добавлять метод экземпляра в Array, подкласс Array или уточнять Array. Почему бы просто не определить метод word с одним аргументом для данного массива?

Cary Swoveland 04.07.2019 23:19

@CarySwoveland: Почему бы вам не уточнить? Вот почему они для. Зачем уточнять функцию? Потому что это связывает лучше, и связывание читается более естественно, поскольку оно линейно представляет причинно-следственную связь. f.each_line.map(&:length).max есть поток. find_max(get_lines(f).map(&:length)) ходит туда-сюда и несет более высокую умственную нагрузку. Непараллелизм между синтаксисом и порядком выполнения — одна из причин, почему я не люблю Python: почему len функция, а lower метод, но map функция, но join метод на нить, но sorted функция, но sort метод... И понимание... >.<

Amadan 10.07.2019 12:27

@ Амадан, твой аргумент убедителен. Хороший ответ!

Cary Swoveland 10.07.2019 15:50
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
6
178
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

module ArrayWithWord
  refine Array do
    def word
      [*self[0..1],*self[-2..-1]].map(&:chr).join
    end
  end
end

class WordTest
  using ArrayWithWord

  # [].word works here
  def self.sort_transform(a)
    [
      a.word,
      a.sort.word,
      a.sort_by(&:-@).word,
      a.map(&:chr).sort.map(&:ord).word
    ].join ?-
  end
end

WordTest.sort_transform(%w(foo bar baz quux))
# => "fbbq-bbfq-bbfq-bbfq"

# [].word doesn't work here
[].word
# => NoMethodError (undefined method `word' for []:Array)

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