Skip to content

Instantly share code, notes, and snippets.

@dbi

dbi/README.rb Secret

Created October 10, 2011 19:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dbi/201a7613e812a3446b98 to your computer and use it in GitHub Desktop.
Save dbi/201a7613e812a3446b98 to your computer and use it in GitHub Desktop.
Entry for the "Methods taking multiple blocks" contest
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
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
@JEG2
Copy link

JEG2 commented Oct 17, 2011

I worry the changing of self in the blocks would break a lot of code.

@elight
Copy link

elight commented Oct 17, 2011

Concise! But monkey patching Ruby considered harmful.

@jeremyevans
Copy link

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.

@dbi
Copy link
Author

dbi commented Oct 17, 2011

@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