Класс Ruby Extended Array, поддерживающий полную цепочку методов - PullRequest
1 голос
/ 04 июля 2019

Short:

Есть ли способ создать расширенный класс 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. И Массив не понимает word метод. И вместо A.new(a).sort.word мне нужно заключить часть цепочки в конструктор A.new: A.new(a.sort).word. Это определенно разрывает чистую цепочку методов.

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

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

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

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

1 Ответ

4 голосов
/ 04 июля 2019

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

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...