Use when working with Ruby blocks, procs, lambdas, and functional programming patterns including closures and higher-order functions.
Provides Ruby blocks, procs, and lambdas support for functional programming patterns. Triggers when you write Ruby code using blocks, yield, -> syntax, or methods like map/select that accept closures.
/plugin marketplace add TheBushidoCollective/han/plugin install jutsu-react-native@hanThis skill is limited to using the following tools:
Master Ruby's functional programming features with blocks, procs, and lambdas. These are fundamental to Ruby's expressive and elegant style.
# Block with do...end (multi-line)
[1, 2, 3].each do |num|
puts num * 2
end
# Block with {...} (single line)
[1, 2, 3].each { |num| puts num * 2 }
def repeat(times)
times.times do
yield # Execute the block
end
end
repeat(3) { puts "Hello" }
# With block parameters
def greet
yield("World")
end
greet { |name| puts "Hello, #{name}!" }
def process_data(data)
result = yield(data)
puts "Result: #{result}"
end
process_data(10) { |x| x * 2 } # Result: 20
def optional_block
if block_given?
yield
else
puts "No block provided"
end
end
optional_block { puts "Block executed" }
optional_block
x = 10
[1, 2, 3].each do |num; local_var|
local_var = num * 2 # local_var only exists in block
puts local_var
end
puts x # 10 (unchanged)
# Using Proc.new
my_proc = Proc.new { |x| x * 2 }
puts my_proc.call(5) # 10
# Using proc method (deprecated in some versions)
my_proc = proc { |x| x * 2 }
# Using -> (stabby lambda syntax for Proc)
my_proc = ->(x) { x * 2 }
# Procs don't care about argument count
flexible_proc = Proc.new { |x, y| "x: #{x}, y: #{y}" }
puts flexible_proc.call(1) # x: 1, y:
puts flexible_proc.call(1, 2, 3) # x: 1, y: 2 (ignores extra)
# Procs return from the enclosing method
def proc_return
my_proc = Proc.new { return "from proc" }
my_proc.call
"after proc" # Never reached
end
puts proc_return # "from proc"
def execute_proc(my_proc)
my_proc.call
end
greeting = Proc.new { puts "Hello from proc!" }
execute_proc(greeting)
def method_with_proc(&block)
block.call
end
method_with_proc { puts "Block converted to proc" }
# Using lambda keyword
my_lambda = lambda { |x| x * 2 }
# Using -> (stabby lambda)
my_lambda = ->(x) { x * 2 }
# Multi-line stabby lambda
my_lambda = ->(x) do
result = x * 2
result + 1
end
puts my_lambda.call(5) # 11
# Lambdas enforce argument count
strict_lambda = ->(x, y) { x + y }
# strict_lambda.call(1) # ArgumentError
strict_lambda.call(1, 2) # Works
# Lambdas return to the caller
def lambda_return
my_lambda = -> { return "from lambda" }
my_lambda.call
"after lambda" # This IS reached
end
puts lambda_return # "after lambda"
add = ->(x, y) { x + y }
multiply = ->(x, y, z) { x * y * z }
puts add.call(3, 4) # 7
puts multiply.call(2, 3, 4) # 24
# Default arguments
greet = ->(name = "World") { "Hello, #{name}!" }
puts greet.call # "Hello, World!"
puts greet.call("Ruby") # "Hello, Ruby!"
# Argument handling
my_proc = Proc.new { |x, y| puts "x: #{x}, y: #{y}" }
my_lambda = ->(x, y) { puts "x: #{x}, y: #{y}" }
my_proc.call(1) # Works: x: 1, y:
# my_lambda.call(1) # ArgumentError
# Return behavior
def test_return
proc_test = Proc.new { return "proc return" }
lambda_test = -> { return "lambda return" }
proc_test.call # Returns from method
"end" # Never reached
end
def test_lambda
lambda_test = -> { return "lambda return" }
lambda_test.call # Returns from lambda
"end" # This IS reached
end
# Check if it's a lambda
my_proc = Proc.new { }
my_lambda = -> { }
puts my_proc.lambda? # false
puts my_lambda.lambda? # true
def multiplier(factor)
->(x) { x * factor }
end
times_two = multiplier(2)
times_three = multiplier(3)
puts times_two.call(5) # 10
puts times_three.call(5) # 15
# Closures capture variables
def counter
count = 0
increment = -> { count += 1 }
decrement = -> { count -= 1 }
value = -> { count }
[increment, decrement, value]
end
inc, dec, val = counter
inc.call
inc.call
puts val.call # 2
dec.call
puts val.call # 1
class Calculator
def add(x, y)
x + y
end
end
calc = Calculator.new
add_method = calc.method(:add)
puts add_method.call(3, 4) # 7
# Converting methods to procs
add_proc = calc.method(:add).to_proc
puts add_proc.call(5, 6) # 11
# & converts symbol to proc
numbers = [1, 2, 3, 4, 5]
# These are equivalent:
numbers.map { |n| n.to_s }
numbers.map(&:to_s)
# Works with any method
["hello", "world"].map(&:upcase) # ["HELLO", "WORLD"]
[1, 2, 3].select(&:even?) # [2]
def compose(f, g)
->(x) { f.call(g.call(x)) }
end
double = ->(x) { x * 2 }
square = ->(x) { x * x }
double_then_square = compose(square, double)
puts double_then_square.call(3) # 36 (3 * 2 = 6, 6 * 6 = 36)
# Manual currying
add = ->(x) { ->(y) { x + y } }
add_five = add.call(5)
puts add_five.call(3) # 8
# Built-in currying
multiply = ->(x, y, z) { x * y * z }
curried = multiply.curry
times_two = curried.call(2)
times_two_three = times_two.call(3)
puts times_two_three.call(4) # 24
# Partial application
puts curried.call(2, 3).call(4) # 24
def lazy_value
puts "Computing expensive value..."
42
end
# Wrap in lambda for lazy evaluation
lazy = -> { lazy_value }
puts "Before call"
result = lazy.call # Only computed here
puts result
class Button
def initialize
@on_click = []
end
def on_click(&block)
@on_click << block
end
def click
@on_click.each(&:call)
end
end
button = Button.new
button.on_click { puts "Button clicked!" }
button.on_click { puts "Another handler" }
button.click
class Sorter
def initialize(strategy)
@strategy = strategy
end
def sort(array)
@strategy.call(array)
end
end
ascending = ->(arr) { arr.sort }
descending = ->(arr) { arr.sort.reverse }
sorter = Sorter.new(ascending)
puts sorter.sort([3, 1, 2]) # [1, 2, 3]
sorter = Sorter.new(descending)
puts sorter.sort([3, 1, 2]) # [3, 2, 1]
def memoize(&block)
cache = {}
->(arg) do
cache[arg] ||= block.call(arg)
end
end
expensive_operation = memoize do |n|
puts "Computing for #{n}..."
n * n
end
puts expensive_operation.call(5) # Computing for 5... 25
puts expensive_operation.call(5) # 25 (cached)
❌ Don't use Proc.new for strict behavior - use lambda instead ❌ Don't ignore return behavior - understand proc vs lambda differences ❌ Don't overuse closures - can lead to memory leaks if not careful ❌ Don't create deeply nested lambdas - hard to read and debug ❌ Don't forget to handle missing blocks - check with block_given?
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.