Kernel#proc
proc { |params| block } -> Proc Proc · Added in v1.8.7 · Updated March 13, 2026 · Kernel Methods Kernel#proc creates a new Proc object by capturing the current block of code. Procs are closures — they retain access to variables from their defining scope even when called elsewhere. This makes them powerful for deferred execution, callbacks, and dynamic code organization.
Syntax
proc { |params| block }
Proc.new { |params| block }
The shorthand proc { } is equivalent to Proc.new { }. Both create a Proc object that can be stored in variables, passed to methods, or called later.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
block | block | — | The block of code to capture as a Proc object |
Examples
Basic usage
my_proc = proc { |x| x * 2 }
my_proc.call(5)
# => 10
my_proc.call(21)
# => 42
Storing a proc in a variable
greeting = proc { |name| "Hello, #{name}!" }
greeting.call("Alice")
# => "Hello, Alice!"
greeting.call("Bob")
# => "Hello, Bob!"
Passing a proc to a method
def apply_operation(array, operation)
array.map(&operation)
end
double = proc { |n| n * 2 }
apply_operation([1, 2, 3], double)
# => [2, 4, 6]
The & operator converts a Proc to a block. This is covered in more detail in the Common Patterns section.
Common Patterns
Converting between procs and blocks
Use & to convert a Proc to a block when passing to methods:
my_proc = proc { |x| x + 1 }
[1, 2, 3].map(&my_proc)
# => [2, 3, 4]
Use .to_proc on symbols for quick conversions:
[:upcase, :downcase, :reverse].map(&:to_s)
# => ["UPCASE", "downcase", "REVERSED"]
Proc vs Lambda
Procs and lambdas are both Proc objects, but they differ in argument handling:
my_proc = proc { |a, b| [a, b] }
my_lambda = lambda { |a, b| [a, b] }
my_proc.call(1, 2, 3)
# => [1, 2] - extra args ignored
my_lambda.call(1, 2, 3)
# => ArgumentError (lambda is strict)
Lambdas return from their own scope, while procs return from the calling method:
def test_proc
p = proc { return "returned from proc" }
p.call
"this won't print"
end
def test_lambda
l = lambda { return "returned from lambda" }
l.call
"this will print"
end
test_proc
# => "returned from proc"
test_lambda
# => "this will print"
Using procs for configuration
Procs are excellent for configurable behavior:
class Calculator
def initialize(&operation)
@operation = operation
end
def calculate(values)
values.map(&@operation)
end
end
add_one = Calculator.new { |x| x + 1 }
add_one.calculate([1, 2, 3])
# => [2, 3, 4]
square = Calculator.new { |x| x ** 2 }
square.calculate([1, 2, 3])
# => [1, 4, 9]
Memoization with procs
def expensive_computation
@cache ||= proc { heavy_calculation }
@cache.call
end
def heavy_calculation
puts "Computing..."
42
end
expensive_computation
# Computing...
# => 42
expensive_computation
# => 42 (cached, no recomputation)
Errors
ArgumentError
Lambdas raise ArgumentError when passed the wrong number of arguments. Procs are lenient and assign nil to missing parameters or ignore extras:
strict = lambda { |a, b| a + b }
strict.call(1)
# => ArgumentError: wrong number of arguments (given 1, expected 2)
lenient = proc { |a, b| a + b }
lenient.call(1)
# => 1 (b is nil)
See Also
- lambda — creates a lambda Proc with strict argument checking
- block_given? — checks if a block was passed to the current method