# A `Proc` object is an encapsulation of a block of code, which can be # stored in a local variable, passed to a method or another # [Proc](Proc), and can be called. # [Proc](Proc) is an essential concept in Ruby and a # core of its functional programming features. # # ```ruby # square = Proc.new {|x| x**2 } # # square.call(3) #=> 9 # # shorthands: # square.(3) #=> 9 # square[3] #=> 9 # ``` # # [Proc](Proc) objects are *closures* , meaning they # remember and can use the entire context in which they were created. # # ```ruby # def gen_times(factor) # Proc.new {|n| n*factor } # remembers the value of factor at the moment of creation # end # # times3 = gen_times(3) # times5 = gen_times(5) # # times3.call(12) #=> 36 # times5.call(5) #=> 25 # times3.call(times5.call(4)) #=> 60 # ``` # # # There are several methods to create a [Proc](Proc) # # - Use the [Proc](Proc) class constructor: # # ```ruby # proc1 = Proc.new {|x| x**2 } # ``` # # - Use the # [Kernel\#proc](https://ruby-doc.org/core-2.6.3/Kernel.html#method-i-proc) # method as a shorthand of # [::new](Proc#method-c-new): # # ```ruby # proc2 = proc {|x| x**2 } # ``` # # - Receiving a block of code into proc argument (note the `&` ): # # ```ruby # def make_proc(&block) # block # end # # proc3 = make_proc {|x| x**2 } # ``` # # - Construct a proc with lambda semantics using the # [Kernel\#lambda](https://ruby-doc.org/core-2.6.3/Kernel.html#method-i-lambda) # method (see below for explanations about lambdas): # # ```ruby # lambda1 = lambda {|x| x**2 } # ``` # # - Use the Lambda literal syntax (also constructs a proc with lambda # semantics): # # ```ruby # lambda2 = ->(x) { x**2 } # ``` # # # Procs are coming in two flavors: lambda and non-lambda (regular procs). # Differences are: # # - In lambdas, `return` means exit from this lambda; # # - In regular procs, `return` means exit from embracing method (and # will throw `LocalJumpError` if invoked outside the method); # # - In lambdas, arguments are treated in the same way as in methods: # strict, with `ArgumentError` for mismatching argument number, and no # additional argument processing; # # - Regular procs accept arguments more generously: missing arguments # are filled with `nil`, single # [Array](https://ruby-doc.org/core-2.6.3/Array.html) arguments are # deconstructed if the proc has multiple arguments, and there is no # error raised on extra arguments. # # Examples: # # ```ruby # p = proc {|x, y| "x=#{x}, y=#{y}" } # p.call(1, 2) #=> "x=1, y=2" # p.call([1, 2]) #=> "x=1, y=2", array deconstructed # p.call(1, 2, 8) #=> "x=1, y=2", extra argument discarded # p.call(1) #=> "x=1, y=", nil substituted instead of error # # l = lambda {|x, y| "x=#{x}, y=#{y}" } # l.call(1, 2) #=> "x=1, y=2" # l.call([1, 2]) # ArgumentError: wrong number of arguments (given 1, expected 2) # l.call(1, 2, 8) # ArgumentError: wrong number of arguments (given 3, expected 2) # l.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2) # # def test_return # -> { return 3 }.call # just returns from lambda into method body # proc { return 4 }.call # returns from method # return 5 # end # # test_return # => 4, return from proc # ``` # # Lambdas are useful as self-sufficient functions, in particular useful as # arguments to higher-order functions, behaving exactly like Ruby methods. # # Procs are useful for implementing iterators: # # ```ruby # def test # [[1, 2], [3, 4], [5, 6]].map {|a, b| return a if a + b > 10 } # # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # end # ``` # # Inside `map`, the block of code is treated as a regular (non-lambda) # proc, which means that the internal arrays will be deconstructed to # pairs of arguments, and `return` will exit from the method `test` . That # would not be possible with a stricter lambda. # # You can tell a lambda from a regular proc by using the # [lambda?](Proc#method-i-lambda-3F) instance method. # # Lambda semantics is typically preserved during the proc lifetime, # including `&` -deconstruction to a block of code: # # ```ruby # p = proc {|x, y| x } # l = lambda {|x, y| x } # [[1, 2], [3, 4]].map(&p) #=> [1, 2] # [[1, 2], [3, 4]].map(&l) # ArgumentError: wrong number of arguments (given 1, expected 2) # ``` # # The only exception is dynamic method definition: even if defined by # passing a non-lambda proc, methods still have normal semantics of # argument checking. # # ```ruby # class C # define_method(:e, &proc {}) # end # C.new.e(1,2) #=> ArgumentError # C.new.method(:e).to_proc.lambda? #=> true # ``` # # This exception ensures that methods never have unusual argument passing # conventions, and makes it easy to have wrappers defining methods that # behave as usual. # # ```ruby # class C # def self.def2(name, &body) # define_method(name, &body) # end # # def2(:f) {} # end # C.new.f(1,2) #=> ArgumentError # ``` # # The wrapper *def2* receives `body` as a non-lambda proc, yet defines a # method which has normal semantics. # # # Any object that implements the `to_proc` method can be converted into a # proc by the `&` operator, and therefore con be consumed by iterators. # # ```ruby # class Greater # def initialize(greating) # @greating = greating # end # # def to_proc # proc {|name| "#{@greating}, #{name}!" } # end # end # # hi = Greater.new("Hi") # hey = Greater.new("Hey") # ["Bob", "Jane"].map(&hi) #=> ["Hi, Bob!", "Hi, Jane!"] # ["Bob", "Jane"].map(&hey) #=> ["Hey, Bob!", "Hey, Jane!"] # ``` # # Of the Ruby core classes, this method is implemented by # [Symbol](https://ruby-doc.org/core-2.6.3/Symbol.html), # [Method](https://ruby-doc.org/core-2.6.3/Method.html), and # [Hash](https://ruby-doc.org/core-2.6.3/Hash.html). # # :to_s.to_proc.call(1) #=> "1" # [1, 2].map(&:to_s) #=> ["1", "2"] # # method(:puts).to_proc.call(1) # prints 1 # [1, 2].each(&method(:puts)) # prints 1, 2 # # {test: 1}.to_proc.call(:test) #=> 1 # %i[test many keys].map(&{test: 1}) #=> [1, nil, nil] class Proc < Object def clone: () -> self # Returns the number of mandatory arguments. If the block is declared to # take no arguments, returns 0. If the block is known to take exactly n # arguments, returns n. If the block has optional arguments, returns -n-1, # where n is the number of mandatory arguments, with the exception for # blocks that are not lambdas and have only a finite number of optional # arguments; in this latter case, returns n. Keyword arguments will be # considered as a single additional argument, that argument being # mandatory if any keyword argument is mandatory. A `proc` with no # argument declarations is the same as a block declaring `||` as its # arguments. # # proc {}.arity #=> 0 # proc { || }.arity #=> 0 # proc { |a| }.arity #=> 1 # proc { |a, b| }.arity #=> 2 # proc { |a, b, c| }.arity #=> 3 # proc { |*a| }.arity #=> -1 # proc { |a, *b| }.arity #=> -2 # proc { |a, *b, c| }.arity #=> -3 # proc { |x:, y:, z:0| }.arity #=> 1 # proc { |*a, x:, y:0| }.arity #=> -2 # # proc { |a=0| }.arity #=> 0 # lambda { |a=0| }.arity #=> -1 # proc { |a=0, b| }.arity #=> 1 # lambda { |a=0, b| }.arity #=> -2 # proc { |a=0, b=0| }.arity #=> 0 # lambda { |a=0, b=0| }.arity #=> -1 # proc { |a, b=0| }.arity #=> 1 # lambda { |a, b=0| }.arity #=> -2 # proc { |(a, b), c=0| }.arity #=> 1 # lambda { |(a, b), c=0| }.arity #=> -2 # proc { |a, x:0, y:0| }.arity #=> 1 # lambda { |a, x:0, y:0| }.arity #=> -2 def arity: () -> Integer # Returns the binding associated with *prc* . # # ```ruby # def fred(param) # proc {} # end # # b = fred(99) # eval("param", b.binding) #=> 99 # ``` def binding: () -> Binding def call: (*untyped arg0) -> untyped def []: (*untyped arg0) -> untyped def curry: (?_ToInt arity) -> Proc # Returns a hash value corresponding to proc body. # # See also Object\#hash. def hash: () -> Integer def initialize: () { (*untyped) -> untyped } -> void # Returns `true` for a [Proc](Proc.downloaded.ruby_doc) object for which # argument handling is rigid. Such procs are typically generated by # `lambda` . # # A [Proc](Proc.downloaded.ruby_doc) object generated by `proc` ignores # extra arguments. # # ```ruby # proc {|a,b| [a,b] }.call(1,2,3) #=> [1,2] # ``` # # It provides `nil` for missing arguments. # # ```ruby # proc {|a,b| [a,b] }.call(1) #=> [1,nil] # ``` # # It expands a single array argument. # # ```ruby # proc {|a,b| [a,b] }.call([1,2]) #=> [1,2] # ``` # # A [Proc](Proc.downloaded.ruby_doc) object generated by `lambda` doesn’t # have such tricks. # # ```ruby # lambda {|a,b| [a,b] }.call(1,2,3) #=> ArgumentError # lambda {|a,b| [a,b] }.call(1) #=> ArgumentError # lambda {|a,b| [a,b] }.call([1,2]) #=> ArgumentError # ``` # # [\#lambda?](Proc.downloaded.ruby_doc#method-i-lambda-3F) is a predicate # for the tricks. It returns `true` if no tricks apply. # # ```ruby # lambda {}.lambda? #=> true # proc {}.lambda? #=> false # ``` # # [::new](Proc.downloaded.ruby_doc#method-c-new) is the same as `proc` . # # ```ruby # Proc.new {}.lambda? #=> false # ``` # # `lambda`, `proc` and [::new](Proc.downloaded.ruby_doc#method-c-new) # preserve the tricks of a [Proc](Proc.downloaded.ruby_doc) object given # by `&` argument. # # ```ruby # lambda(&lambda {}).lambda? #=> true # proc(&lambda {}).lambda? #=> true # Proc.new(&lambda {}).lambda? #=> true # # lambda(&proc {}).lambda? #=> false # proc(&proc {}).lambda? #=> false # Proc.new(&proc {}).lambda? #=> false # ``` # # A [Proc](Proc.downloaded.ruby_doc) object generated by `&` argument has # the tricks # # ```ruby # def n(&b) b.lambda? end # n {} #=> false # ``` # # The `&` argument preserves the tricks if a # [Proc](Proc.downloaded.ruby_doc) object is given by `&` argument. # # ```ruby # n(&lambda {}) #=> true # n(&proc {}) #=> false # n(&Proc.new {}) #=> false # ``` # # A [Proc](Proc.downloaded.ruby_doc) object converted from a method has no # tricks. # # ```ruby # def m() end # method(:m).to_proc.lambda? #=> true # # n(&method(:m)) #=> true # n(&method(:m).to_proc) #=> true # ``` # # `define_method` is treated the same as method definition. The defined # method has no tricks. # # ```ruby # class C # define_method(:d) {} # end # C.new.d(1,2) #=> ArgumentError # C.new.method(:d).to_proc.lambda? #=> true # ``` # # `define_method` always defines a method without the tricks, even if a # non-lambda [Proc](Proc.downloaded.ruby_doc) object is given. This is the # only exception for which the tricks are not preserved. # # ```ruby # class C # define_method(:e, &proc {}) # end # C.new.e(1,2) #=> ArgumentError # C.new.method(:e).to_proc.lambda? #=> true # ``` # # This exception ensures that methods never have tricks and makes it easy # to have wrappers to define methods that behave as usual. # # ```ruby # class C # def self.def2(name, &body) # define_method(name, &body) # end # # def2(:f) {} # end # C.new.f(1,2) #=> ArgumentError # ``` # # The wrapper *def2* defines a method which has no tricks. def lambda?: () -> bool # Returns the parameter information of this proc. # # ```ruby # prc = lambda{|x, y=42, *other|} # prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]] # ``` def parameters: () -> ::Array[[ Symbol, Symbol ]] # Returns the Ruby source filename and line number containing this proc or # `nil` if this proc was not defined in Ruby (i.e. native). def source_location: () -> [ String, Integer ] # Part of the protocol for converting objects to `Proc` objects. Instances # of class `Proc` simply return themselves. def to_proc: () -> self # Returns the unique identifier for this proc, along with an indication of # where the proc was defined. # # # # Also aliased as: [inspect](Proc.downloaded.ruby_doc#method-i-inspect) def to_s: () -> String # Alias for: [to\_s](Proc.downloaded.ruby_doc#method-i-to_s) def inspect: () -> String end