Block / Proc Возвращает массив в массиве Объяснение - PullRequest
0 голосов
/ 08 января 2019

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

class Array
  def my_each(&prc)
    if block_given?
      proc.call(self)
    else
      for i in (0..self.length-1)
        puts self[i]
      end
    end
    self
  end
end

Это то, что я собрал, и я не очень хорошо понимаю, как работают блоки / процессы в этом контексте, но каким-то образом я волшебным образом написал код, который прошел 3 из 4 тестов RSPEC.

  describe "#my_each" do
    it "calls the block passed to it" do
      expect do |block|
        ["test array"].my_each(&block)
      end.to yield_control.once
    end

    it "yields each element to the block" do
      expect do |block|
        ["el1", "el2"].my_each(&block)
      end.to yield_successive_args("el1", "el2")
    end

    it "does NOT call the built-in #each method" do
      original_array = ["original array"]
      expect(original_array).not_to receive(:each)
      original_array.my_each {}
    end

    it "is chainable and returns the original array" do
      original_array = ["original array"]
      expect(original_array.my_each {}).to eq(original_array)
    end
  end

Все вышеперечисленные тесты RSPEC проходят, за исключением второго, где мой код возвращает [["el1", "el2"]], когда ожидается ["el1", "el2"]. Может кто-нибудь дать мне объяснение того, как или почему я получаю вложенный массив здесь?

Может ли кто-нибудь также дать мне объяснение того, как код выполняется, когда блок проходит через этот метод? Я не уверен, действительно ли мое условие «else» действительно необходимо в контексте тестов RSPEC. Меня обычно смущает концепция передачи блоков через самописные методы и то, как они взаимодействуют с самим методом.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 08 января 2019
  proc.call(self)

виновник. self - это весь массив.

Расширение класса Array для включения метода с именем my_each

class Array
  def my_each
  end
end

который занимает блок,

#every method in ruby accepts a block, it is just ignored when not used (yielded to). Do nothing.

вызывает блок для каждого элемента массива,

class Array
  def my_each
    for element in self
      yield element
    end
  end
end

и затем возвращает исходный массив.

# "for" loops do this. Do nothing. It should pass.
0 голосов
/ 08 января 2019

В первой части вашего условия вы передаете весь массив в блок:

if block_given?
  proc.call(self)
else
# ...

например. для массива ["el1", "el2"] вы делаете proc.call(["el1", "el2"]). В тесте вы ожидаете двух последовательных вызовов:

proc.call("el1")
proc.call("el2")

Для этого вам нужно использовать цикл также в первой части условия и передавать туда элемент массива, а не весь массив:

if block_given?
  for i in (0..self.length-1)
     proc.call(self[i])
  end
else
  for i in (0..self.length-1)
    puts self[i]
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...