Created
December 27, 2010 04:35
-
-
Save roman/755865 to your computer and use it in GitHub Desktop.
curry.rb
This file contains hidden or 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 | |
alias_method :old_call, :call | |
public | |
def curried? | |
!!@curried | |
end | |
def curry(level = nil) | |
CurriedProcHelper.new(self).curry(level) | |
end | |
def call(*args) | |
if self.curried? | |
args.inject(self) do |last_proc, a| | |
last_proc = last_proc.old_call(a) | |
last_proc | |
end | |
else | |
old_call(*args) | |
end | |
end | |
private | |
def currify! | |
@curried = true | |
self | |
end | |
class CurriedProcHelper | |
def initialize(block) | |
@proc = block | |
end | |
def curry(level = nil) | |
level ||= number_of_proc_parameters | |
return @proc unless it_has_parameters_to_curry? | |
@proc.instance_eval(append_proc_tail(append_proc_call(build_proc_head(level)), level)) | |
end | |
private | |
def build_proc_head(level) | |
proc_body = "" | |
l = 'a' | |
number_of_proc_parameters.times do |index| | |
if level < index + 1 | |
proc_body << "proc { |#{parameter_name_list(l)}| " | |
break | |
else | |
proc_body << "proc { |#{l}| " | |
end | |
l.next! | |
end | |
proc_body | |
end | |
def append_proc_call(proc_body) | |
proc_body << "self.call(#{parameter_name_list})" | |
proc_body | |
end | |
def append_proc_tail(proc_body, level) | |
number_of_proc_parameters.times do |index| | |
break if level < index | |
proc_body << " }" | |
proc_body << ".send(:currify!)" unless index == 0 | |
end | |
proc_body | |
end | |
def parameter_name_list(from = 'a') | |
(from ... last_parameter_letter).to_a.join(', ') | |
end | |
def last_parameter_letter | |
l = 'a' | |
@_curry_last_paremeter_letter ||= (number_of_proc_parameters.times { l.next! } && l) | |
end | |
def it_has_parameters_to_curry? | |
@proc.arity < -1 || @proc.arity > 0 | |
end | |
def number_of_proc_parameters | |
@proc.arity < -1 ? @proc.arity.abs - 1 : @proc.arity | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment