How to implement a "callback" in Ruby?

Viewed 61012

I'm not sure of the best idiom for C style call-backs in Ruby - or if there is something even better ( and less like C ). In C, I'd do something like:

void DoStuff( int parameter, CallbackPtr callback )
{
  // Do stuff
  ...
  // Notify we're done
  callback( status_code )
}

Whats a good Ruby equivalent? Essentially I want to call a passed in class method, when a certain condition is met within "DoStuff"

8 Answers

If you are willing to use ActiveSupport (from Rails), you have a straightforward implementation

class ObjectWithCallbackHooks
  include ActiveSupport::Callbacks
  define_callbacks :initialize # Your object supprots an :initialize callback chain

  include ObjectWithCallbackHooks::Plugin 

  def initialize(*)
    run_callbacks(:initialize) do # run `before` callbacks for :initialize
      puts "- initializing" # then run the content of the block
    end # then after_callbacks are ran
  end
end

module ObjectWithCallbackHooks::Plugin
  include ActiveSupport::Concern

  included do 
    # This plugin injects an "after_initialize" callback 
    set_callback :initialize, :after, :initialize_some_plugin
  end
end

I know this is an old post, but I found it when tried to solve a similar problem.

It's a really elegant solution, and most importantly, it can work with and without a callback.


Let's say we have the Arithmetic class which implements basic operations on them — addition and subtraction.

class Arithmetic
  def addition(a, b)
    a + b
  end

  def subtraction(a, b)
    a - b
  end
end

And we want to add a callback for each operation which will do something with the input data and result.

In the below example we will implement the after_operation method which accepts the Ruby block which will be executed after an operation.

class Arithmetic
  def after_operation(&block)
    @after_operation_callback = block
  end

  def addition(a, b)
    do_operation('+', a, b)
  end

  def subtraction(a, b)
    do_operation('-', a, b)
  end

  private

  def do_operation(sign, a, b)
    result =
      case sign
      when '+'
        a + b
      when '-'
        a - b
      end

    if callback = @after_operation_callback
      callback.call(sign, a, b, result)
    end

    result
  end
end

Using with callback:

callback = -> (sign, a, b, result) do
  puts "#{a} #{sign} #{b} = #{result}"
end

arithmetic = Arithmetic.new
arithmetic.after_operation(&callback)

puts arithmetic.addition(1, 2)
puts arithmetic.subtraction(3, 1)

Output:

1 + 2 = 3
3
3 - 1 = 2
2
Related