Sha256: bc07f71089f65b758d2baf611cb2f9abedc7a08eabcba4792ce8d19e697082f7
Contents?: true
Size: 1.59 KB
Versions: 26
Compression:
Stored size: 1.59 KB
Contents
require 'backports/tools/alias_method_chain' module Backports # Metaprogramming utility to make block optional. # Tests first if block is already optional when given options def self.make_block_optional(mod, *methods) mod = class << mod; self; end unless mod.is_a? Module options = methods.last.is_a?(Hash) ? methods.pop : {} methods.each do |selector| unless mod.method_defined? selector warn "#{mod}##{selector} is not defined, so block can't be made optional" next end unless options[:force] # Check if needed test_on = options.fetch(:test_on) result = begin test_on.send(selector, *options.fetch(:arg, [])) rescue LocalJumpError false end next if result.class.name =~ /Enumerator/ end require 'enumerator' arity = mod.instance_method(selector).arity last_arg = [] if arity < 0 last_arg = ["*rest"] arity = -1-arity end arg_sequence = ((0...arity).map{|i| "arg_#{i}"} + last_arg + ["&block"]).join(", ") alias_method_chain(mod, selector, :optional_block) do |aliased_target, punctuation| mod.module_eval <<-end_eval, __FILE__, __LINE__ + 1 def #{aliased_target}_with_optional_block#{punctuation}(#{arg_sequence}) return to_enum(:#{aliased_target}_without_optional_block#{punctuation}, #{arg_sequence}) unless block_given? #{aliased_target}_without_optional_block#{punctuation}(#{arg_sequence}) end end_eval end end end end
Version data entries
26 entries across 26 versions & 3 rubygems