Ruby: Proc для переворота строки

Я работаю над некоторыми домашними заданиями для курса рубина, и у меня возникли проблемы с моим ответом. В основном мне нужно создать программу, которая удовлетворяет этим условиям:

describe "reverser" do
 it "reverses the string returned by the default block" do
  result = reverser do
    "hello"
  end
  result.should == "olleh"
 end

 it "reverses each word in the string returned by the default block" do
  result = reverser do
    "hello dolly"
  end
  result.should == "olleh yllod"
 end
end

Я собрал вместе некоторый код, который, как мне кажется, должен удовлетворять этим условиям:

reverser = Proc.new do |string|

 words = string.split(/\b/)

 answer = ''

 i = 0
 while i < words.count
     answer = answer + words[i].reverse
     i += 1
 end
 answer
end


def reverser
 yield

end

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

expected: "olleh"
got: "hello"

Что-то мне не хватает? Я просто не разбираюсь в процессах?

Этот вопрос в той или иной форме уже был задан участником по имени pete, и на него довольно хорошо ответил другой пользователь с именем mind.blank. Это источник:

RSpec для начинающих: необходимость помогите написать код Ruby для прохождения тестов RSpec (упражнение "Глупые блоки").

Код mind.blank был прост и работал правильно, но я не хочу просто копировать его, не понимая, почему мой не работает. Заранее благодарю за любую помощь.


person zethsaber    schedule 09.02.2014    source источник


Ответы (3)


Итак, у вас есть локальная переменная с именем «reverser» и метод с именем «reverser» (который будет «затенять» локальный реверсор).

Ваш код никогда не выполняется.

Итак - что вы хотите сделать, это ... взять результат yield и проделать с ним обратную операцию. (Не говоря уже о том, насколько странным является это требование на мгновение.)

def reverser
  string = yield
  # ... all of your reverser code ...
end

Теперь возвращаемся обратно - это странный способ использования блока. Блок предназначен для передачи дополнительного выполнения методу, а не для передачи ему аргумента. Итак, если вы хотите сказать, выполняйте обратный вызов для каждого символа в реверсоре (в обратном порядке?), Это было бы правильным использованием yield.

Кроме того, в Ruby уже есть String#reverse метод, так что самый простой способ пройти тесты - это что-то вроде.

def reverser
  (yield).split(/\b/).map(&:reverse).join
end
person prater    schedule 09.02.2014
comment
Спасибо за совет. Это был ответ, который написал парень из другой ветки. Я просто не хотел украсть его код, не зная почему. Но теперь я понимаю это немного больше. - person zethsaber; 09.02.2014

Ваш reverser proc работает, если вы скажете reverser.call('abc') (или reverser['abc'] или reverser.('abc')), вы получите ожидаемый 'cba' обратно.

Проблема в том, что ваш тест использует не ваш reverser proc, а ваш reverser метод. Это вызов метода reverser с блоком:

result = reverser do
  "hello"
end

но метод reverser не делает ничего интересного, он просто уступает место блоку:

def reverser
  yield
end

так что result становится значением блока, а это 'hello'.

Либо протестируйте процесс:

it "reverses the string returned by the default block" do
  result = reverser['hello']
  result.should == "olleh"
end

или переместите кишки процесса в метод reverser и проверьте, что:

def reverser
  string = yield
  words  = string.split(/\b/)
  answer = ''

  i = 0
  while i < words.count
    answer = answer + words[i].reverse
    i += 1
  end
  answer
end

Есть более эффективные способы написать этот код (например, words.map(&:reverse).join вместо вида while), но ваша логика реверсирования работает, вам просто нужно убедиться, что вы вызываете правильную версию.

person mu is too short    schedule 09.02.2014
comment
Большое спасибо. Так что, оказывается, мое понимание rspec немного сомнительно. Я должен признать, что меня это расстраивало, но ваше объяснение многое прояснило. Я бы поддержал вас, ребята, но я новичок на сайте: D. Спасибо еще раз - person zethsaber; 09.02.2014
comment
Не стоит беспокоиться. Реквизит для желания понять, что происходит, а не слепо спотыкаться на чужом коде, это хорошее отношение. - person mu is too short; 09.02.2014

Этот код перевернет строки, переданные методу в виде блока.

def reverser
    # yield is the string given in the block
    words = yield.split(' ')
    final = []
    words.each do |word|
        final.push(word.reverse)
    end
    final.join(' ')
end
person Connor Leech    schedule 15.05.2014