Ruby Logo

Numbered Block Parameters

Master concise block syntax with _1, _2 numbered parameters for functional programming patterns.

Home Ruby Numbered Block Parameters

Numbered Parameters

Master Ruby's numbered parameters (_1, _2, etc.) for concise block syntax, reducing verbosity in simple transformations and iterations.

Understanding Numbered Parameters

Numbered parameters, introduced in Ruby 2.7, provide a shorthand syntax for simple blocks. Instead of explicitly naming block parameters, you can use _1, _2, etc. to refer to the first, second, and subsequent block arguments. This feature reduces verbosity for simple transformations and makes code more concise.

When to Use Numbered Parameters:

  • Simple transformations: Basic data manipulation
  • Short blocks: One-liner operations
  • Mathematical operations: Arithmetic on block arguments
  • Accessor patterns: Simple property access

When NOT to Use:

  • Complex logic: Multi-line blocks with complex operations
  • Multiple parameters: When you need many block arguments
  • Unclear context: When named parameters improve readability
  • Nested blocks: Can become confusing with multiple levels

Basic Syntax and Usage

Single Parameter Blocks

class NumberedParametersBasics
  def self.demonstrate_single_parameter
    puts "=== Single Parameter Examples ==="

    numbers = [1, 2, 3, 4, 5]

    # Traditional syntax vs numbered parameters
    puts "Traditional map: #{numbers.map { |n| n * 2 }}"
    puts "Numbered param:  #{numbers.map { _1 * 2 }}"

    puts "Traditional select: #{numbers.select { |n| n.even? }}"
    puts "Numbered param:     #{numbers.select { _1.even? }}"

    puts "Traditional find: #{numbers.find { |n| n > 3 }}"
    puts "Numbered param:   #{numbers.find { _1 > 3 }}"

    # String operations
    words = ["hello", "world", "ruby", "programming"]

    puts "\nString operations:"
    puts "Traditional upcase: #{words.map { |word| word.upcase }}"
    puts "Numbered param:     #{words.map { _1.upcase }}"

    puts "Traditional length: #{words.map { |word| word.length }}"
    puts "Numbered param:     #{words.map { _1.length }}"

    puts "Traditional filter: #{words.select { |word| word.length > 4 }}"
    puts "Numbered param:     #{words.select { _1.length > 4 }}"
  end

  def self.demonstrate_method_chaining
    puts "\n=== Method Chaining Examples ==="

    data = ["  apple  ", "  BANANA  ", "  Cherry  "]

    # Complex transformations with numbered parameters
    result1 = data.map { |item| item.strip.downcase.capitalize }
    result2 = data.map { _1.strip.downcase.capitalize }

    puts "Traditional chaining: #{result1}"
    puts "Numbered param:       #{result2}"

    # Hash operations
    users = [
      { name: "Alice", age: 30 },
      { name: "Bob", age: 25 },
      { name: "Carol", age: 35 }
    ]

    names_traditional = users.map { |user| user[:name] }
    names_numbered = users.map { _1[:name] }

    puts "\nHash access:"
    puts "Traditional: #{names_traditional}"
    puts "Numbered:    #{names_numbered}"

    adults_traditional = users.select { |user| user[:age] >= 30 }
    adults_numbered = users.select { _1[:age] >= 30 }

    puts "\nFiltering adults:"
    puts "Traditional: #{adults_traditional.map { |u| u[:name] }}"
    puts "Numbered:    #{adults_numbered.map { _1[:name] }}"
  end

  def self.demonstrate_mathematical_operations
    puts "\n=== Mathematical Operations ==="

    numbers = [1, 2, 3, 4, 5]

    operations = [
      ["Square", { |n| n ** 2 }, { _1 ** 2 }],
      ["Cube", { |n| n ** 3 }, { _1 ** 3 }],
      ["Double + 1", { |n| n * 2 + 1 }, { _1 * 2 + 1 }],
      ["Factorial", { |n| (1..n).reduce(:*) }, { (1.._1).reduce(:*) }]
    ]

    operations.each do |name, traditional, numbered|
      result1 = numbers.map(&traditional)
      result2 = numbers.map(&numbered)

      puts "#{name}:"
      puts "  Traditional: #{result1}"
      puts "  Numbered:    #{result2}"
      puts "  Same result: #{result1 == result2}"
    end
  end
end

NumberedParametersBasics.demonstrate_single_parameter
NumberedParametersBasics.demonstrate_method_chaining
NumberedParametersBasics.demonstrate_mathematical_operations

Multiple Parameter Blocks

class MultipleParameterExamples
  def self.demonstrate_two_parameters
    puts "=== Two Parameter Examples ==="

    # Hash iteration
    scores = { "Alice" => 95, "Bob" => 87, "Carol" => 92 }

    puts "Hash iteration:"
    scores.each { |name, score| puts "Traditional: #{name}: #{score}" }
    scores.each { puts "Numbered: #{_1}: #{_2}" }

    # Transform hash to array
    pairs_traditional = scores.map { |name, score| [name, score] }
    pairs_numbered = scores.map { [_1, _2] }

    puts "\nHash to array conversion:"
    puts "Traditional: #{pairs_traditional}"
    puts "Numbered:    #{pairs_numbered}"

    # Array operations with index
    fruits = ["apple", "banana", "cherry"]

    puts "\nArray with index:"
    fruits.each_with_index { |fruit, index| puts "Traditional: #{index}: #{fruit}" }
    fruits.each_with_index { puts "Numbered: #{_2}: #{_1}" }

    # Filter with condition on both parameters
    high_scorers_traditional = scores.select { |name, score| score > 90 }
    high_scorers_numbered = scores.select { _2 > 90 }

    puts "\nHigh scorers (score > 90):"
    puts "Traditional: #{high_scorers_traditional}"
    puts "Numbered:    #{high_scorers_numbered}"
  end

  def self.demonstrate_array_operations
    puts "\n=== Array Operations with Multiple Parameters ==="

    # Array combination operations
    arr1 = [1, 2, 3]
    arr2 = [4, 5, 6]

    zipped_traditional = arr1.zip(arr2).map { |a, b| a + b }
    zipped_numbered = arr1.zip(arr2).map { _1 + _2 }

    puts "Array addition:"
    puts "Traditional: #{zipped_traditional}"
    puts "Numbered:    #{zipped_numbered}"

    # More complex operations
    multiplication_traditional = arr1.zip(arr2).map { |a, b| a * b }
    multiplication_numbered = arr1.zip(arr2).map { _1 * _2 }

    puts "\nArray multiplication:"
    puts "Traditional: #{multiplication_traditional}"
    puts "Numbered:    #{multiplication_numbered}"

    # Conditional operations
    max_values_traditional = arr1.zip(arr2).map { |a, b| [a, b].max }
    max_values_numbered = arr1.zip(arr2).map { [_1, _2].max }

    puts "\nMax values:"
    puts "Traditional: #{max_values_traditional}"
    puts "Numbered:    #{max_values_numbered}"
  end

  def self.demonstrate_reduce_operations
    puts "\n=== Reduce Operations ==="

    numbers = [1, 2, 3, 4, 5]

    # Sum with reduce
    sum_traditional = numbers.reduce { |acc, n| acc + n }
    sum_numbered = numbers.reduce { _1 + _2 }

    puts "Sum:"
    puts "Traditional: #{sum_traditional}"
    puts "Numbered:    #{sum_numbered}"

    # Product
    product_traditional = numbers.reduce { |acc, n| acc * n }
    product_numbered = numbers.reduce { _1 * _2 }

    puts "\nProduct:"
    puts "Traditional: #{product_traditional}"
    puts "Numbered:    #{product_numbered}"

    # String concatenation
    words = ["Ruby", "is", "awesome"]
    sentence_traditional = words.reduce { |acc, word| acc + " " + word }
    sentence_numbered = words.reduce { _1 + " " + _2 }

    puts "\nString concatenation:"
    puts "Traditional: #{sentence_traditional}"
    puts "Numbered:    #{sentence_numbered}"

    # Complex reduce operation
    data = [
      { name: "Alice", score: 95 },
      { name: "Bob", score: 87 },
      { name: "Carol", score: 92 }
    ]

    # Find highest scorer
    highest_traditional = data.reduce { |acc, person| acc[:score] > person[:score] ? acc : person }
    highest_numbered = data.reduce { _1[:score] > _2[:score] ? _1 : _2 }

    puts "\nHighest scorer:"
    puts "Traditional: #{highest_traditional[:name]} (#{highest_traditional[:score]})"
    puts "Numbered:    #{highest_numbered[:name]} (#{highest_numbered[:score]})"
  end
end

MultipleParameterExamples.demonstrate_two_parameters
MultipleParameterExamples.demonstrate_array_operations
MultipleParameterExamples.demonstrate_reduce_operations

Advanced Usage Patterns

Conditional Logic and Comparisons

class AdvancedNumberedParameters
  def self.demonstrate_conditional_logic
    puts "=== Conditional Logic with Numbered Parameters ==="

    numbers = [-5, -2, 0, 3, 7, 12]

    # Ternary operators
    abs_values_traditional = numbers.map { |n| n < 0 ? -n : n }
    abs_values_numbered = numbers.map { _1 < 0 ? -_1 : _1 }

    puts "Absolute values:"
    puts "Traditional: #{abs_values_traditional}"
    puts "Numbered:    #{abs_values_numbered}"

    # Complex conditions
    categories_traditional = numbers.map do |n|
      if n < 0
        "negative"
      elsif n == 0
        "zero"
      elsif n < 10
        "small positive"
      else
        "large positive"
      end
    end

    categories_numbered = numbers.map do
      if _1 < 0
        "negative"
      elsif _1 == 0
        "zero"
      elsif _1 < 10
        "small positive"
      else
        "large positive"
      end
    end

    puts "\nNumber categories:"
    puts "Traditional: #{categories_traditional}"
    puts "Numbered:    #{categories_numbered}"

    # Case statements
    grades = [95, 87, 76, 65, 45]

    letter_grades_traditional = grades.map do |grade|
      case grade
      when 90..100 then "A"
      when 80..89  then "B"
      when 70..79  then "C"
      when 60..69  then "D"
      else              "F"
      end
    end

    letter_grades_numbered = grades.map do
      case _1
      when 90..100 then "A"
      when 80..89  then "B"
      when 70..79  then "C"
      when 60..69  then "D"
      else              "F"
      end
    end

    puts "\nLetter grades:"
    puts "Traditional: #{letter_grades_traditional}"
    puts "Numbered:    #{letter_grades_numbered}"
  end

  def self.demonstrate_string_processing
    puts "\n=== String Processing ==="

    texts = ["hello world", "RUBY programming", "Mixed Case Text"]

    # String transformations
    title_case_traditional = texts.map { |text| text.split.map(&:capitalize).join(" ") }
    title_case_numbered = texts.map { _1.split.map(&:capitalize).join(" ") }

    puts "Title case:"
    puts "Traditional: #{title_case_traditional}"
    puts "Numbered:    #{title_case_numbered}"

    # Regular expression operations
    emails = ["user@domain.com", "invalid-email", "another@test.org", "not-valid"]

    valid_emails_traditional = emails.select { |email| email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) }
    valid_emails_numbered = emails.select { _1.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) }

    puts "\nValid emails:"
    puts "Traditional: #{valid_emails_traditional}"
    puts "Numbered:    #{valid_emails_numbered}"

    # String length filtering and transformation
    words = ["a", "hello", "world", "x", "programming", "ruby"]

    long_words_traditional = words.select { |word| word.length > 3 }.map { |word| word.upcase }
    long_words_numbered = words.select { _1.length > 3 }.map { _1.upcase }

    puts "\nLong words (uppercase):"
    puts "Traditional: #{long_words_traditional}"
    puts "Numbered:    #{long_words_numbered}"
  end

  def self.demonstrate_data_structures
    puts "\n=== Complex Data Structure Operations ==="

    products = [
      { name: "Laptop", price: 999.99, category: "Electronics" },
      { name: "Book", price: 19.99, category: "Education" },
      { name: "Phone", price: 699.99, category: "Electronics" },
      { name: "Desk", price: 299.99, category: "Furniture" }
    ]

    # Price calculations
    prices_traditional = products.map { |product| product[:price] }
    prices_numbered = products.map { _1[:price] }

    puts "All prices:"
    puts "Traditional: #{prices_traditional}"
    puts "Numbered:    #{prices_numbered}"

    # Filtering and transformation
    expensive_electronics_traditional = products
      .select { |product| product[:category] == "Electronics" }
      .select { |product| product[:price] > 500 }
      .map { |product| product[:name] }

    expensive_electronics_numbered = products
      .select { _1[:category] == "Electronics" }
      .select { _1[:price] > 500 }
      .map { _1[:name] }

    puts "\nExpensive electronics:"
    puts "Traditional: #{expensive_electronics_traditional}"
    puts "Numbered:    #{expensive_electronics_numbered}"

    # Grouping operations
    by_category_traditional = products.group_by { |product| product[:category] }
    by_category_numbered = products.group_by { _1[:category] }

    puts "\nProducts by category:"
    puts "Traditional keys: #{by_category_traditional.keys}"
    puts "Numbered keys:    #{by_category_numbered.keys}"

    # Nested operations
    category_stats_traditional = by_category_traditional.transform_values do |products|
      {
        count: products.length,
        avg_price: products.map { |p| p[:price] }.sum / products.length
      }
    end

    category_stats_numbered = by_category_numbered.transform_values do
      {
        count: _1.length,
        avg_price: _1.map { _1[:price] }.sum / _1.length
      }
    end

    puts "\nCategory statistics:"
    category_stats_traditional.each { |cat, stats| puts "Traditional #{cat}: #{stats}" }
    category_stats_numbered.each { puts "Numbered #{_1}: #{_2}" }
  end
end

AdvancedNumberedParameters.demonstrate_conditional_logic
AdvancedNumberedParameters.demonstrate_string_processing
AdvancedNumberedParameters.demonstrate_data_structures

Performance and Functional Programming

class FunctionalProgramming
  def self.demonstrate_functional_patterns
    puts "=== Functional Programming Patterns ==="

    # Function composition
    numbers = [1, 2, 3, 4, 5]

    # Traditional function composition
    result_traditional = numbers
      .map { |n| n * 2 }
      .select { |n| n > 5 }
      .map { |n| n.to_s }

    # Numbered parameters version
    result_numbered = numbers
      .map { _1 * 2 }
      .select { _1 > 5 }
      .map { _1.to_s }

    puts "Function composition:"
    puts "Traditional: #{result_traditional}"
    puts "Numbered:    #{result_numbered}"

    # Currying-like behavior
    add_ten = proc { |x| x + 10 }
    multiply_by_two = proc { |x| x * 2 }

    # Traditional composition
    composed_traditional = numbers.map { |n| multiply_by_two.call(add_ten.call(n)) }

    # Numbered parameters
    composed_numbered = numbers.map { multiply_by_two.call(add_ten.call(_1)) }

    puts "\nFunction composition with procs:"
    puts "Traditional: #{composed_traditional}"
    puts "Numbered:    #{composed_numbered}"
  end

  def self.demonstrate_lazy_evaluation
    puts "\n=== Lazy Evaluation ==="

    # Large range for demonstration
    large_range = (1..1_000_000)

    # Find first 5 numbers that satisfy complex condition
    start_time = Time.now

    result_traditional = large_range
      .lazy
      .select { |n| n % 7 == 0 }
      .map { |n| n ** 2 }
      .select { |n| n.to_s.include?("9") }
      .first(5)

    traditional_time = Time.now - start_time

    start_time = Time.now

    result_numbered = large_range
      .lazy
      .select { _1 % 7 == 0 }
      .map { _1 ** 2 }
      .select { _1.to_s.include?("9") }
      .first(5)

    numbered_time = Time.now - start_time

    puts "Lazy evaluation results:"
    puts "Traditional: #{result_traditional}"
    puts "Numbered:    #{result_numbered}"
    puts "Traditional time: #{traditional_time.round(4)}s"
    puts "Numbered time:    #{numbered_time.round(4)}s"
  end

  def self.benchmark_performance
    puts "\n=== Performance Comparison ==="

    require 'benchmark'

    data = (1..100_000).to_a

    Benchmark.bm(20) do |x|
      x.report("Traditional syntax") do
        data.map { |n| n * 2 }.select { |n| n > 50_000 }.first(100)
      end

      x.report("Numbered parameters") do
        data.map { _1 * 2 }.select { _1 > 50_000 }.first(100)
      end

      x.report("Traditional complex") do
        data.map { |n| n * 2 + 1 }.select { |n| n.even? }.map { |n| n.to_s }
      end

      x.report("Numbered complex") do
        data.map { _1 * 2 + 1 }.select { _1.even? }.map { _1.to_s }
      end
    end
  end

  def self.demonstrate_higher_order_functions
    puts "\n=== Higher-Order Functions ==="

    # Functions that return functions
    def self.create_multiplier(factor)
      proc { _1 * factor }
    end

    def self.create_filter(condition)
      proc { condition.call(_1) }
    end

    numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    # Using higher-order functions with numbered parameters
    double = create_multiplier(2)
    triple = create_multiplier(3)
    is_even = create_filter(proc { _1.even? })
    is_greater_than_5 = create_filter(proc { _1 > 5 })

    puts "Original: #{numbers}"
    puts "Doubled: #{numbers.map(&double)}"
    puts "Tripled: #{numbers.map(&triple)}"
    puts "Even numbers: #{numbers.select(&is_even)}"
    puts "Greater than 5: #{numbers.select(&is_greater_than_5)}"

    # Combining higher-order functions
    result = numbers
      .map(&double)
      .select(&is_greater_than_5)
      .map { _1.to_s }

    puts "Combined operations: #{result}"
  end
end

FunctionalProgramming.demonstrate_functional_patterns
FunctionalProgramming.demonstrate_lazy_evaluation
# FunctionalProgramming.benchmark_performance  # Uncomment to run benchmark
FunctionalProgramming.demonstrate_higher_order_functions

Real-World Applications

Data Processing and Analysis

class RealWorldApplications
  def self.demonstrate_log_analysis
    puts "=== Log File Analysis ==="

    # Simulated log entries
    log_entries = [
      "2023-01-01 10:00:00 INFO User login: alice@example.com",
      "2023-01-01 10:01:15 ERROR Database connection failed",
      "2023-01-01 10:02:30 INFO User login: bob@example.com",
      "2023-01-01 10:03:45 WARN High memory usage: 85%",
      "2023-01-01 10:05:00 ERROR Authentication failed for user: charlie@example.com",
      "2023-01-01 10:06:15 INFO User logout: alice@example.com"
    ]

    # Extract error messages
    errors_traditional = log_entries
      .select { |entry| entry.include?("ERROR") }
      .map { |entry| entry.split(" ", 4)[3] }

    errors_numbered = log_entries
      .select { _1.include?("ERROR") }
      .map { _1.split(" ", 4)[3] }

    puts "Error messages:"
    puts "Traditional: #{errors_traditional}"
    puts "Numbered:    #{errors_numbered}"

    # Count log levels
    log_levels_traditional = log_entries
      .map { |entry| entry.split(" ")[2] }
      .tally

    log_levels_numbered = log_entries
      .map { _1.split(" ")[2] }
      .tally

    puts "\nLog level counts:"
    puts "Traditional: #{log_levels_traditional}"
    puts "Numbered:    #{log_levels_numbered}"

    # Extract user activities
    user_activities_traditional = log_entries
      .select { |entry| entry.include?("User") }
      .map { |entry| entry.match(/User (\w+): (.+)/)[1..2] }
      .group_by { |activity, user| activity }

    user_activities_numbered = log_entries
      .select { _1.include?("User") }
      .map { _1.match(/User (\w+): (.+)/)[1..2] }
      .group_by { _1[0] }

    puts "\nUser activities:"
    user_activities_traditional.each { |activity, users| puts "Traditional #{activity}: #{users.map(&:last)}" }
  end

  def self.demonstrate_sales_data_processing
    puts "\n=== Sales Data Processing ==="

    sales_data = [
      { date: "2023-01-01", product: "Laptop", amount: 1200, quantity: 1, salesperson: "Alice" },
      { date: "2023-01-02", product: "Mouse", amount: 25, quantity: 5, salesperson: "Bob" },
      { date: "2023-01-02", product: "Laptop", amount: 1200, quantity: 1, salesperson: "Alice" },
      { date: "2023-01-03", product: "Keyboard", amount: 75, quantity: 3, salesperson: "Charlie" },
      { date: "2023-01-03", product: "Monitor", amount: 300, quantity: 2, salesperson: "Alice" }
    ]

    # Calculate total sales by salesperson
    sales_by_person_traditional = sales_data
      .group_by { |sale| sale[:salesperson] }
      .transform_values { |sales| sales.sum { |sale| sale[:amount] } }

    sales_by_person_numbered = sales_data
      .group_by { _1[:salesperson] }
      .transform_values { _1.sum { _1[:amount] } }

    puts "Sales by salesperson:"
    puts "Traditional: #{sales_by_person_traditional}"
    puts "Numbered:    #{sales_by_person_numbered}"

    # Find high-value sales (> $500)
    high_value_sales_traditional = sales_data
      .select { |sale| sale[:amount] > 500 }
      .map { |sale| "#{sale[:product]} ($#{sale[:amount]}) by #{sale[:salesperson]}" }

    high_value_sales_numbered = sales_data
      .select { _1[:amount] > 500 }
      .map { "#{_1[:product]} ($#{_1[:amount]}) by #{_1[:salesperson]}" }

    puts "\nHigh-value sales:"
    high_value_sales_traditional.each { |sale| puts "Traditional: #{sale}" }
    high_value_sales_numbered.each { puts "Numbered: #{_1}" }

    # Calculate average order value by product
    avg_by_product_traditional = sales_data
      .group_by { |sale| sale[:product] }
      .transform_values { |sales| sales.sum { |sale| sale[:amount] } / sales.length }

    avg_by_product_numbered = sales_data
      .group_by { _1[:product] }
      .transform_values { _1.sum { _1[:amount] } / _1.length }

    puts "\nAverage order value by product:"
    puts "Traditional: #{avg_by_product_traditional}"
    puts "Numbered:    #{avg_by_product_numbered}"
  end

  def self.demonstrate_api_response_processing
    puts "\n=== API Response Processing ==="

    # Simulated API responses
    api_responses = [
      { status: 200, data: { user_id: 1, name: "Alice" }, timestamp: "2023-01-01T10:00:00Z" },
      { status: 404, error: "User not found", timestamp: "2023-01-01T10:01:00Z" },
      { status: 200, data: { user_id: 2, name: "Bob" }, timestamp: "2023-01-01T10:02:00Z" },
      { status: 500, error: "Internal server error", timestamp: "2023-01-01T10:03:00Z" },
      { status: 200, data: { user_id: 3, name: "Charlie" }, timestamp: "2023-01-01T10:04:00Z" }
    ]

    # Extract successful responses
    successful_responses_traditional = api_responses
      .select { |response| response[:status] == 200 }
      .map { |response| response[:data] }

    successful_responses_numbered = api_responses
      .select { _1[:status] == 200 }
      .map { _1[:data] }

    puts "Successful responses:"
    puts "Traditional: #{successful_responses_traditional}"
    puts "Numbered:    #{successful_responses_numbered}"

    # Error summary
    errors_traditional = api_responses
      .select { |response| response[:status] != 200 }
      .map { |response| { status: response[:status], error: response[:error] } }

    errors_numbered = api_responses
      .select { _1[:status] != 200 }
      .map { { status: _1[:status], error: _1[:error] } }

    puts "\nError summary:"
    puts "Traditional: #{errors_traditional}"
    puts "Numbered:    #{errors_numbered}"

    # Response time analysis (simulated)
    response_times = api_responses.map.with_index { |response, index| [response, rand(100..500)] }

    slow_responses_traditional = response_times
      .select { |response, time| time > 300 }
      .map { |response, time| { status: response[:status], time: time } }

    slow_responses_numbered = response_times
      .select { _2 > 300 }
      .map { { status: _1[:status], time: _2 } }

    puts "\nSlow responses (> 300ms):"
    puts "Traditional: #{slow_responses_traditional}"
    puts "Numbered:    #{slow_responses_numbered}"
  end

  def self.demonstrate_configuration_processing
    puts "\n=== Configuration Processing ==="

    # Environment configuration
    raw_config = {
      "DATABASE_URL" => "postgresql://localhost:5432/myapp",
      "REDIS_URL" => "redis://localhost:6379",
      "LOG_LEVEL" => "info",
      "MAX_THREADS" => "5",
      "FEATURE_FLAG_NEW_UI" => "true",
      "FEATURE_FLAG_ANALYTICS" => "false"
    }

    # Extract feature flags
    feature_flags_traditional = raw_config
      .select { |key, value| key.start_with?("FEATURE_FLAG_") }
      .transform_keys { |key| key.sub("FEATURE_FLAG_", "").downcase }
      .transform_values { |value| value == "true" }

    feature_flags_numbered = raw_config
      .select { _1.start_with?("FEATURE_FLAG_") }
      .transform_keys { _1.sub("FEATURE_FLAG_", "").downcase }
      .transform_values { _1 == "true" }

    puts "Feature flags:"
    puts "Traditional: #{feature_flags_traditional}"
    puts "Numbered:    #{feature_flags_numbered}"

    # Parse numeric configurations
    numeric_configs_traditional = raw_config
      .select { |key, value| value.match?(/^\d+$/) }
      .transform_values { |value| value.to_i }

    numeric_configs_numbered = raw_config
      .select { _2.match?(/^\d+$/) }
      .transform_values { _1.to_i }

    puts "\nNumeric configurations:"
    puts "Traditional: #{numeric_configs_traditional}"
    puts "Numbered:    #{numeric_configs_numbered}"

    # URL configurations
    url_configs_traditional = raw_config
      .select { |key, value| value.start_with?("http://", "https://", "redis://", "postgresql://") }
      .transform_values { |url| URI.parse(url) rescue nil }
      .compact

    url_configs_numbered = raw_config
      .select { _2.start_with?("http://", "https://", "redis://", "postgresql://") }
      .transform_values { URI.parse(_1) rescue nil }
      .compact

    puts "\nURL configurations:"
    url_configs_traditional.each { |key, uri| puts "Traditional #{key}: #{uri.scheme}://#{uri.host}:#{uri.port}" }
    url_configs_numbered.each { puts "Numbered #{_1}: #{_2.scheme}://#{_2.host}:#{_2.port}" }
  end
end

RealWorldApplications.demonstrate_log_analysis
RealWorldApplications.demonstrate_sales_data_processing
RealWorldApplications.demonstrate_api_response_processing
RealWorldApplications.demonstrate_configuration_processing

Best Practices and Limitations

✅ Best Practices

  • Use for simple transformations: Mathematical operations, data access
  • Prefer for one-liners: Keep blocks short and focused
  • Chain operations: Works well with functional programming
  • Consistent usage: Use throughout a method for consistency
  • Document when unclear: Add comments for complex logic
  • Consider readability: Don't sacrifice clarity for brevity

❌ Limitations & Pitfalls

  • No mixing: Can't mix numbered and named parameters
  • Limited to _9: Only _1 through _9 are available
  • Nested blocks: Can become confusing with multiple levels
  • Complex logic: Reduces readability in complex operations
  • Team adoption: May confuse developers unfamiliar with syntax
  • Debugging: Can be harder to debug without named variables

When to Use vs. Avoid

class BestPracticesDemo
  def self.good_uses
    puts "=== Good Uses of Numbered Parameters ==="

    data = [1, 2, 3, 4, 5]

    # ✅ Simple mathematical operations
    squares = data.map { _1 ** 2 }
    puts "Squares: #{squares}"

    # ✅ Property access
    users = [{ name: "Alice" }, { name: "Bob" }]
    names = users.map { _1[:name] }
    puts "Names: #{names}"

    # ✅ Simple filtering
    evens = data.select { _1.even? }
    puts "Evens: #{evens}"

    # ✅ Chaining operations
    result = data.map { _1 * 2 }.select { _1 > 5 }.map { _1.to_s }
    puts "Chained: #{result}"
  end

  def self.problematic_uses
    puts "\n=== Avoid These Patterns ==="

    data = [1, 2, 3, 4, 5]

    # ❌ Complex logic (better with named parameters)
    def self.complex_bad_example
      data.map do
        if _1 < 3
          result = _1 * 2
          result += 1 if _1.odd?
          result.to_s.ljust(5, "0")
        else
          (_1 ** 2 + _1).to_s.reverse
        end
      end
    end

    # ✅ Better version with named parameter
    def self.complex_good_example
      data.map do |num|
        if num < 3
          result = num * 2
          result += 1 if num.odd?
          result.to_s.ljust(5, "0")
        else
          (num ** 2 + num).to_s.reverse
        end
      end
    end

    puts "Complex logic results:"
    puts "Bad (numbered):  #{complex_bad_example}"
    puts "Good (named):    #{complex_good_example}"

    # ❌ Multiple nested levels
    nested_data = [[1, 2], [3, 4], [5, 6]]

    # This becomes hard to read
    flattened_bad = nested_data.map { _1.map { _1 * 2 } }.flatten
    puts "\nNested numbered: #{flattened_bad}"

    # Better with named parameters
    flattened_good = nested_data.map { |pair| pair.map { |num| num * 2 } }.flatten
    puts "Nested named: #{flattened_good}"
  end

  def self.migration_example
    puts "\n=== Migration Strategy ==="

    # Start with traditional syntax
    data = ["hello", "world", "ruby"]

    # Step 1: Identify simple transformations
    traditional = data.map { |word| word.upcase }

    # Step 2: Convert to numbered parameters
    numbered = data.map { _1.upcase }

    # Step 3: Verify behavior is identical
    puts "Traditional: #{traditional}"
    puts "Numbered:    #{numbered}"
    puts "Same result: #{traditional == numbered}"

    # Step 4: Consider readability
    # For teams new to numbered parameters, document the change
    # and ensure everyone understands the syntax
  end

  def self.performance_considerations
    puts "\n=== Performance Considerations ==="

    require 'benchmark'

    large_array = (1..100_000).to_a

    # Performance is generally equivalent
    Benchmark.bm(20) do |x|
      x.report("Named parameter") do
        large_array.map { |n| n * 2 }.first(1000)
      end

      x.report("Numbered parameter") do
        large_array.map { _1 * 2 }.first(1000)
      end
    end

    puts "\nPerformance is typically equivalent."
    puts "Choose based on readability, not performance."
  end
end

BestPracticesDemo.good_uses
BestPracticesDemo.problematic_uses
BestPracticesDemo.migration_example
# BestPracticesDemo.performance_considerations  # Uncomment to run benchmark

🎯 Key Takeaways

  • Concise Syntax: Reduces verbosity for simple block operations using _1, _2, etc.
  • Perfect for Simple Cases: Mathematical operations, property access, and basic filtering
  • Functional Programming: Works excellently with method chaining and transformations
  • Limited Parameters: Only supports _1 through _9, no mixing with named parameters
  • Readability First: Use only when it improves or maintains code clarity
  • Team Consideration: Ensure team familiarity before widespread adoption
  • Avoid Complexity: Not suitable for multi-line blocks or complex logic

Quick Navigation

Related Topics

Video Tutorial

Watch and learn numbered block parameters

Pro Tip: After reading through the content above, watch this video to reinforce your understanding and see the concepts in action!