How do I defer execution of some Ruby code until later and run it on demand in this scenario?
Posted
by Kyle Kaitan
on Stack Overflow
See other posts from Stack Overflow
or by Kyle Kaitan
Published on 2010-06-15T04:27:38Z
Indexed on
2010/06/15
4:32 UTC
Read the original article
Hit count: 156
ruby
|metaprogramming
I've got some code that looks like the following. First, there's a simple Parser
class for parsing command-line arguments with options.
class Parser
def initialize(&b); ...; end # Create new parser.
def parse(args = ARGV); ...; end # Consume command-line args.
def opt(...); ...; end # Declare supported option.
def die(...); ...; end # Validation handler.
end
Then I have my own Parsers
module which holds some metadata about parsers that I want to track.
module Parsers
ParserMap = {}
def self.make_parser(kind, desc, &b)
b ||= lambda {}
module_eval {
ParserMap[kind] = {:desc => "", :validation => lambda {} }
ParserMap[kind][:desc] = desc
# Create new parser identified by `<Kind>Parser`. Making a Parser is very
# expensive, so we defer its creation until it's actually needed later
# by wrapping it in a lambda and calling it when we actually need it.
const_set(name_for_parser(kind), lambda { Parser.new(&b) })
}
end
# ...
end
Now when you want to add a new parser, you can call make_parser
like so:
make_parser :db, "login to database" do
# Options that this parser knows how to parse.
opt :verbose, "be verbose with output messages"
opt :uid, "user id"
opt :pwd, "password"
end
Cool. But there's a problem. We want to optionally associate validation with each parser, so that we can write something like:
validation = lambda { |parser, opts|
parser.die unless opts[:uid] && opts[:pwd] # Must provide login.
}
The interface contract with Parser
says that we can't do any validation until after Parser#parse
has been called. So, we want to do the following:
- Associate an optional block with every
Parser
we make withmake_parser
. - We also want to be able to run this block, ideally as a new method called
Parser#validate
. But any on-demand method is equally suitable.
How do we do that?
© Stack Overflow or respective owner