Skip to content

recipient_variable is nil in solve block (Regression in 3.5.4) #333

@anfinil

Description

@anfinil

Description

When using Dentaku::Calculator#solve with a block to handle errors, the recipient_variable attribute on the exception object is intermittently nil for unbound variables in versions 3.5.4 through 3.5.7. This worked correctly in version 3.5.3.

Root Cause

The regression was introduced in version 3.5.4 during the refactoring of BulkExpressionSolver to use Evaluator classes. In PermissiveEvaluator#evaluate, the block passed during evaluation is ignored:

# lib/dentaku/bulk_expression_solver.rb

class PermissiveEvaluator
  def initialize(calculator, block)
    @calculator = calculator
    @block = block || ->(*) { :undefined }
  end

  def evaluate(*args)
    @calculator.evaluate(*args) { |expr, ex|
      @block.call(ex) # <--- This uses the @block from initialization, 
                      #      ignoring any block passed to #evaluate
    }
  end
end

However, BulkExpressionSolver#load_results attempts to pass a block that sets the recipient_variable:

# lib/dentaku/bulk_expression_solver.rb

variables_in_resolve_order.each_with_object({}) do |var_name, results|
  # ...
  with_rescues(var_name, results, block) do
    results[var_name] = evaluated_facts[var_name] || evaluator.evaluate(
      expressions[var_name],
      context.merge(results),
      &expression_with_exception_handler(var_name, &block) # <--- This block is ignored
    )
  end
end

Reproduction Script

require 'dentaku'

calculator = Dentaku::Calculator.new
to_compute = { result: 'unknown_variable * 2' }
errors = {}

calculator.solve(to_compute) do |e|
  errors[e.recipient_variable] = e.class.name
end

puts "Errors: #{errors.inspect}"
# Expected (3.5.3): {"result"=>"Dentaku::UnboundVariableError"}
# Actual (3.5.4+): {nil=>"Dentaku::UnboundVariableError"}

Suggested Fix

Modify PermissiveEvaluator#evaluate to accept and prefer the passed block:

def evaluate(*args, &block)
  @calculator.evaluate(*args, &(block || @block))
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions