mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
3fc7dd1858
`lambda {|a, b=nil|}.curry(3)` used to silently return a curried Proc;
CRuby raises `ArgumentError` because the lambda accepts at most 2 args.
Use `self.parameters` to compute the upper bound (count `:req`/`:opt`
entries, unbounded if `:rest`/`:keyrest` is present) and add the
corresponding range check alongside the existing minimum check.
close #2855
Co-authored-by: Claude <noreply@anthropic.com>
144 lines
3.7 KiB
Ruby
144 lines
3.7 KiB
Ruby
class Proc
|
|
|
|
#
|
|
# call-seq:
|
|
# prc === obj -> result_of_proc
|
|
#
|
|
# Invokes the block with obj as the parameter like Proc#call.
|
|
# This allows a proc object to be the target of a when clause
|
|
# in a case statement.
|
|
#
|
|
# def the_answer
|
|
# 42
|
|
# end
|
|
#
|
|
# case the_answer
|
|
# when proc { |x| x > 40 }
|
|
# "correct"
|
|
# else
|
|
# "incorrect"
|
|
# end
|
|
# #=> "correct"
|
|
#
|
|
def ===(*args)
|
|
call(*args)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# prc.yield(params,...) -> obj
|
|
#
|
|
# Invokes the block with the given arguments. This method is provided
|
|
# for compatibility and is equivalent to Proc#call.
|
|
#
|
|
# prc = proc { |x| x * 2 }
|
|
# prc.yield(5) #=> 10
|
|
#
|
|
def yield(*args)
|
|
call(*args)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# prc.to_proc -> prc
|
|
#
|
|
# Part of the protocol for converting objects to Proc objects.
|
|
# Instances of class Proc simply return themselves.
|
|
#
|
|
# prc = proc { "hello" }
|
|
# prc.to_proc #=> #<Proc:0x401b3d30@(irb):3>
|
|
#
|
|
def to_proc
|
|
self
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# prc.curry -> curried_proc
|
|
# prc.curry(arity) -> curried_proc
|
|
#
|
|
# Returns a curried proc. If the optional arity argument is given, it
|
|
# determines the number of arguments. A curried proc receives some
|
|
# arguments. If a sufficient number of arguments are supplied, it passes
|
|
# the supplied arguments to the original proc and returns the result.
|
|
# Otherwise, returns another curried proc that takes the rest of arguments.
|
|
#
|
|
# b = proc {|x, y, z| (x||0) + (y||0) + (z||0) }
|
|
# p b.curry[1][2][3] #=> 6
|
|
# p b.curry[1, 2][3, 4] #=> 6
|
|
# p b.curry(5)[1][2][3][4][5] #=> 6
|
|
#
|
|
def curry(arity=self.arity)
|
|
type = :proc
|
|
abs = lambda {|a| a < 0 ? -a - 1 : a}
|
|
arity = abs[arity]
|
|
if lambda?
|
|
type = :lambda
|
|
self_arity = self.arity
|
|
min_req = abs[self_arity]
|
|
if self_arity < 0
|
|
max_arity = 0
|
|
has_rest = false
|
|
self.parameters.each do |p|
|
|
case p[0]
|
|
when :rest, :keyrest then has_rest = true
|
|
when :req, :opt then max_arity += 1
|
|
end
|
|
end
|
|
if arity < min_req || (!has_rest && arity > max_arity)
|
|
expected = (!has_rest && max_arity != min_req) ? "#{min_req}..#{max_arity}" : min_req.to_s
|
|
raise ArgumentError, "wrong number of arguments (given #{arity}, expected #{expected})"
|
|
end
|
|
elsif arity != self_arity
|
|
raise ArgumentError, "wrong number of arguments (given #{arity}, expected #{self_arity})"
|
|
end
|
|
end
|
|
|
|
pproc = self
|
|
make_curry = proc do |given_args=[]|
|
|
__send__(type) do |*args|
|
|
new_args = given_args + args
|
|
if new_args.size >= arity
|
|
pproc[*new_args]
|
|
else
|
|
make_curry[new_args]
|
|
end
|
|
end
|
|
end
|
|
make_curry.call
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# prc << other_proc -> new_proc
|
|
#
|
|
# Returns a new Proc which is the composition of this proc and the given
|
|
# other_proc. The returned proc takes a variable number of arguments, calls
|
|
# other_proc with them then calls this proc with the result.
|
|
#
|
|
# f = proc {|x| x * x }
|
|
# g = proc {|x| x + x }
|
|
# p (f << g).call(2) #=> 16
|
|
#
|
|
def <<(other)
|
|
->(*args, **opts, &block) { call(other.call(*args, **opts, &block)) }
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# prc >> other_proc -> new_proc
|
|
#
|
|
# Returns a new Proc which is the composition of this proc and the given
|
|
# other_proc. The returned proc takes a variable number of arguments, calls
|
|
# this proc with them then calls other_proc with the result.
|
|
#
|
|
# f = proc {|x| x * x }
|
|
# g = proc {|x| x + x }
|
|
# p (f >> g).call(2) #=> 8
|
|
#
|
|
def >>(other)
|
|
->(*args, **opts, &block) { other.call(call(*args, **opts, &block)) }
|
|
end
|
|
|
|
end
|