Search code examples
rubyproc

Having trouble calling a Proc within a Method within a Class


I am struggling to debug my issue; I am trying to use a Proc within a method, all inside a class. When I don't type in the "class" details, my program compiles fine; when I specify the class name, however, I get a variety of different errors.

Note: I posted this question on CodeReview.StackExchange.com, but it was off-topic there; the mods (?) recommended I ask the question here.

Background. Here is the prompt that I was given, taken directly from pine.fm:

Grandfather Clock. Write a method which takes a block and calls it once for each hour that has passed today. That way, if I were to pass in the block do puts 'DING!' end, it would chime (sort of) like a grandfather clock. Test your method out with a few different blocks (including the one I just gave you). Hint: You can use Time.now.hour to get the current hour. However, this returns a number between 0 and 23, so you will have to alter those numbers in order to get ordinary clock-face numbers (1 to 12).

The code that works:

def hourlyRing ring
    time = Time.now.hour%12;
    hour_set =[12, 1, 2, 3, 4, 5, 6, 7, 8 , 9 , 10, 11];
    (hour_set[time].to_i).times do 
        ring.call
    end
end

ring = Proc.new do 
    puts 'DING!'
end 

hourlyRing ring

It produces the following (correct, since it's 4 p.m. here) output:

~$ ruby GrandfatherClock.rb
DING!
DING!
DING!
DING!

The code that doesn't work:

class GrandfatherClock  

    def hourlyRing ring
        time = Time.now.hour%12;
        hour_set =[12, 1, 2, 3, 4, 5, 6, 7, 8 , 9 , 10, 11];
        (hour_set[time].to_i).times do 
            ring.call
        end
    end

    ring = Proc.new do 
        puts 'DING!'
    end 
end

# Here's where I try to call it:
ringtime = GrandfatherClock.new
ringtime.hourlyRing ring

Can anyone see the error in my code? It is a short enough code, in my humble opinion, but I cannot understand why it won't compile. Perhaps I am fundamentally misunderstanding something about Procs, but I can't understand what exactly. Thank you in advance.


Solution

  • It's about the context.
    In the 2nd example you are putting the ring proc inside the class, so when you actually call ringtime.hourlyRing ring, ring is not defined in that scope.

    You could alter the code to:

    class GrandfatherClock  
    
        def hourlyRing ring
            time = Time.now.hour%12;
            hour_set =[12, 1, 2, 3, 4, 5, 6, 7, 8 , 9 , 10, 11];
            (hour_set[time].to_i).times do 
                ring.call
            end
        end
    end
    
    ring = Proc.new do 
       puts 'DING!'
    end 
    
    # Here's where I try to call it:
    ringtime = GrandfatherClock.new
    ringtime.hourlyRing ring
    

    Furthermore, the problem statements explicitly ask you about a block, so the hourlyRing should be something along the lines of:

    def hourlyRing
        time = Time.now.hour%12;
        hour_set =[12, 1, 2, 3, 4, 5, 6, 7, 8 , 9 , 10, 11];
        (hour_set[time].to_i).times do 
            yield
        end
    end
    

    You would call it like this:

    hourlyRing { puts 'RING'}
    

    or

     hourlyRing do
        puts 'RING'
     end