Class Extension Debugging Exercises

really need some help/advice on the second to last spec;
‘yields each element to the block’

this is my code:
def my_merge(hash2, &b)
new_hash = {}

self.each do |k1, v1|
  new_hash[k1] = v1
 end

hash2.each do |k2, v2|
  new_hash[k2] =
    if (block_given?)
      b.call(k2, new_hash[k2], v2)
    else
      v2
    end
end
return new_hash

end

and this is my error;

  1. Hash#my_merge yields each element to the block
    Failure/Error: expect { |b| test_hash_1.my_merge(test_hash_2, &b)}.to yield_successive_args([:b, 2, 3])
    expected given block to yield successively with arguments, but yielded with unexpected arguments
    expected: [[:b, 2, 3]]
    got: [[:b, 2, 3], [:c, nil, 4]]

    ./spec/exercises_spec.rb:191:in `block (2 levels) in <top (required)>’

for the life of me I can’t figure out what I need to do to fix this. Any help would be appreciated.

Hi,

So anytime you have a failing test, your first resource is to look at the error. As you can see, the spec expects to yield [:b, 2, 3] to the block, but your method is also yielding [:c, nil, 4].

Step 2 is to look at the spec. The spec sets the following variables:

test_hash_1 = { a: 10, b: 2}
test_hash_2 = { b: 3, c: 4 }

Clearly what the spec wants is to yield only keys that are present in both hashes, and the value at that key from each hash. By contrast, your method as it is currently written yields every key from the second hash. Hence why your method is incorrectly yielding [:c, nil, 4].

Hope this helps!

numie2,

thank you very much! I finally got it, although I don’t think it is very neat… curious as to how you would go about organizing it…

def my_merge(hash2, &b)
new_hash = self
hash2.each do |k2, v2|
    if (block_given?) && self.has_key?(k2)
        new_hash[k2] = b.call(k2, new_hash[k2], v2)
    else
        new_hash[k2] = v2
    end
end
return new_hash

end

That looks really good. One thing you could think about is that you are checking if a block is given for each key in hash2. Whether or not a block is given won’t change, so it might be slightly more efficient to only check for it once (although this won’t make it any neater).

Great job!

Hi Numie,

I’m working on the same problem. Can you explain this line of code?
{ |b| test_hash_1.my_merge(test_hash_2, &b)}

How does prc.call(k2, new_hash[k2], v2) return [:b, 2, 3]?
Is test_hash_2 going into argument k2? I’m very confused how this works? Thank you!

Hi,

{ |b| test_hash_1.my_merge(test_hash_2, &b) }

You don’t have to worry about this syntax too much right now. It is RSpec and you won’t be learning it in depth until week 2 of the course. However, essentially what is happening here is that ‘b’ is a test block, to be used solely to test your method. As you can see in this test, my_merge is called on test_hash_1 with arguments of test_hash_2 and b (the test block).

The test also sets these variables:

test_hash_1 = { a: 10, b: 2 }
test_hash_2 = { b: 3, c: 4 }

So if you run…

prc.call(k2, new_hash[k2], v2)

…we expect the block to be called with k2, new_hash[k2] and v2. Those values correspond to :b, 2 and 3 using the test variables.

It’s also important to note that we are not returning [:b, 2, 3], but merely passing those arguments to the block, which is what the test is testing for.