-
-
Save dbi/201a7613e812a3446b98 to your computer and use it in GitHub Desktop.
Entry for the "Methods taking multiple blocks" contest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "codebrawl" | |
puts "Entry for the codebrawl contest at http://codebrawl.com/contests/methods-taking-multiple-blocks" | |
# Defining the method that will be sent multiple blocks, do some business logic and run the corresponding block. | |
# | |
def do_thing(&block) | |
# Business logic here, sometimes it fails sometimes it doesn't | |
random_work = rand(2) == 1 ? :success : :failure | |
block.exec_submethod(random_work, self) | |
end | |
# This is what it is going to look like sending multiple blocks to a method | |
# | |
do_thing do | |
success { puts "success" } | |
failure { puts "failure" } | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Proc | |
def exec_submethod(method, on=self) | |
instance_exec &self # running the first level of the original block in the scope of the proc | |
# itself to record and store second level method calls | |
on.instance_exec &@data[method] # executing the right method inside the original scope | |
end | |
def method_missing(method, *args, &block) | |
(@data ||= {})[method] = block # recording second level method calls | |
end | |
end |
Concise! But monkey patching Ruby considered harmful.
The usage of the DSL is nice in your example case because of the simplicity, but because it depends on instance_exec, you won't be able to reference methods from the surrounding scope, which may cause issues in more complex cases.
@jeremyevans The blocks sent to success and failure are actually executed in the original scope, which means that code like this will work.
def success_method
puts "yeah!"
end
do_thing do
success { puts success_method }
failure { puts "failure" }
end
It would be important not to have any other logic than assigning the callback blocks at the "first level" when calling #do_thing tho as it is executed in the Proc scope.
do_thing do
puts success_method # this will not work
success { puts "success" }
failure { puts "failure" }
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I worry the changing of self in the blocks would break a lot of code.