I'm writing a simple event bus to use in an application. This part works fine:
#!/usr/bin/env ruby
module EventBus
@callbacks = {}
module_function
def on event, &callback
@callbacks[event] ||= []
@callbacks[event].push callback
end
def fire event, *data
@callbacks[event].each do |callback|
callback.call *data
end
end
end
EventBus.on :foo do |x| puts x end
EventBus.fire :foo, "test"
# => test
Because of the complex nature of my program, and the fact that Proc
s take arguments in a very loosey-goosey fashion, I want some argument checking on my events. lambda
is the obvious choice for this:
EventBus.on :bar, &(lambda do |x| puts x end)
# Will raise an ArgumentError, since the event was fired without any arguments
# Remember that this is the desired behavior
EventBus.fire :bar
Clearly, the syntax of the on
call is ugly due to the &(lambda do ... end)
. I'd rather be able to just use do ... end
(i.e. just pass it a normal block without the unary ampersand operator) and convert that into a lambda. I tried the obvious:
...
def on_lambda event, &callback
@callbacks[event] ||= []
@callbacks[event].push(lambda &callback)
# check if the added callback is lambda. (spoiler alert: it isn't)
puts @callbacks[event].last.lambda?
end
end
EventBus.on_lambda :baz do |x| puts x end
# I would expect the callback to be a lambda, and thus throw an ArgumentError,
# but neither of these holds.
EventBus.fire :baz
As I understand it, on_lambda
takes a block, converts it to a Proc
referenced locally by callback
(via the &
). I'm pushing the result of calling lambda
with callback
converted back in to a block. I expect this to return a lambda derived from the callback
Proc
, so my question is: why is the element on the array a normal Proc
.?
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
{ }
I looked into the ->() { }
syntax (I've seen it called the "stab" operator). It produces a lambda from the block specified. It's probably as close as I'll get to the mixture of normal block syntax and argument checking I wanted. All I have to do is tweak the on
method:
def on event, callback
@callbacks[event] ||= []
@callbacks[event].push callback
end
and then attach callbacks like so:
EventBus.on :bam, ->(x) do
puts x
end
I'm still curious as to the original question, however.
I would suggest reading this: http://ruby-doc.org/core-1.9.3/Proc.html#method-i-lambda-3F