0
votes

I'm working on some homework problems for a ruby course and I've been having some trouble with my answer. Basically I need to build a program that can satisfy these conditions:

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

I puzzled together some code that I feel should satisfy these conditions:

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

Yet when I run the rake, my error tells me I have failed the first condition.

expected: "olleh"
got: "hello"

Is there something I'm missing? Do I just not have a proper understanding of procs?

This question has been asked in some form already by a member named pete and answered quite well by another user named mind.blank. This is the source:

Beginner RSpec: Need help writing Ruby code to pass RSpec tests (Silly Blocks exercise).

mind.blank's code was straightforward and worked properly, but I don't just want to copy it without understanding why mine doesn't work. Thanks in advance for any help.

3

3 Answers

1
votes

So - what you've got there is a local variable named "reverser" and a method named "reverser" (which is going to "shadow" the reverser local)

Your code is never executing.

So - what you want to do is ... take the result of the yield and do the reverse operation on that. (Leaving aside how bizarre that requirement is for a moment.)

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

Now circling back around - that's a bizarre way to use a block. A block is for passing additional execution to a method, not for passing argument to it. So if you wanted to say, have a callback executed for each character in reverser (in reverse?) that would be the proper use of yield.

Besides, Ruby already has a String#reverse method - so the easiest possible thing to do to get your tests to pass is something like.

def reverser
  (yield).split(/\b/).map(&:reverse).join
end
1
votes

Your reverser proc does work, if you say reverser.call('abc') (or reverser['abc'] or reverser.('abc')) then you will get the expected 'cba' back.

The problem is that your test isn't using your reverser proc, it is using your reverser method. This is a call to the reverser method with a block:

result = reverser do
  "hello"
end

but the reverser method doesn't do anything interesting, it just yields to the block:

def reverser
  yield
end

so result ends up being the block's value and that's 'hello'.

Either test the proc:

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

or move the proc's guts into the reverser method and test that:

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

There are better ways to write this code (such as words.map(&:reverse).join instead of the while look) but your reversing logic works, you just have to make sure you call the right version.

0
votes

This code will reverse strings given to the method as a block

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