Class: BetterService::Workflows::BranchGroup

Inherits:
Object
  • Object
show all
Defined in:
lib/better_service/workflows/branch_group.rb

Overview

Represents a group of conditional branches in a workflow

A BranchGroup is created by the ‘branch do…end` DSL block and contains:

  • Multiple conditional branches (from on blocks)

  • An optional default branch (from otherwise block)

When executed, it evaluates conditions in order and executes the first matching branch. If no branch matches and there’s no default, it raises an error.

Examples:

branch_group = BranchGroup.new(name: :payment_routing)
branch_group.add_branch(condition: ->(ctx) { ctx.type == 'card' }) do
  # steps...
end
branch_group.set_default do
  # default steps...
end

result = branch_group.call(context, user, params)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name: nil) ⇒ BranchGroup

Creates a new BranchGroup

Parameters:

  • name (Symbol, nil) (defaults to: nil)

    Optional name for the branch group



30
31
32
33
34
# File 'lib/better_service/workflows/branch_group.rb', line 30

def initialize(name: nil)
  @branches = []
  @default_branch = nil
  @name = name
end

Instance Attribute Details

#branchesObject (readonly)

Returns the value of attribute branches.



25
26
27
# File 'lib/better_service/workflows/branch_group.rb', line 25

def branches
  @branches
end

#default_branchObject (readonly)

Returns the value of attribute default_branch.



25
26
27
# File 'lib/better_service/workflows/branch_group.rb', line 25

def default_branch
  @default_branch
end

#nameObject (readonly)

Returns the value of attribute name.



25
26
27
# File 'lib/better_service/workflows/branch_group.rb', line 25

def name
  @name
end

Instance Method Details

#add_branch(condition:, name: nil) ⇒ Branch

Adds a conditional branch to this group

Parameters:

  • condition (Proc)

    The condition to evaluate

  • name (Symbol, nil) (defaults to: nil)

    Optional name for the branch

Returns:

  • (Branch)

    The created branch



41
42
43
44
45
# File 'lib/better_service/workflows/branch_group.rb', line 41

def add_branch(condition:, name: nil)
  branch = Branch.new(condition: condition, name: name)
  @branches << branch
  branch
end

#branch_countInteger

Returns the total number of branches (including default)

Returns:

  • (Integer)


116
117
118
119
120
# File 'lib/better_service/workflows/branch_group.rb', line 116

def branch_count
  count = @branches.count
  count += 1 if @default_branch
  count
end

#call(context, user, params, parent_decisions = nil) ⇒ Hash

Executes the appropriate branch based on context

This is called during workflow execution. It:

  1. Selects the matching branch

  2. Executes all steps in that branch

  3. Returns metadata about the execution

Parameters:

  • context (Workflowable::Context)

    The workflow context

  • user (Object)

    The current user

  • params (Hash)

    The workflow parameters

  • parent_decisions (Array, nil) (defaults to: nil)

    Parent branch decisions for nested tracking

Returns:

  • (Hash)

    Execution result with :executed_steps, :branch_taken, :branch_decisions, :skipped

Raises:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/better_service/workflows/branch_group.rb', line 82

def call(context, user, params, parent_decisions = nil)
  selected_branch = select_branch(context)

  if selected_branch.nil?
    raise Errors::Configuration::InvalidConfigurationError.new(
      "No matching branch found and no default branch defined",
      code: ErrorCodes::CONFIGURATION_ERROR,
      context: {
        branch_group: @name,
        branches_count: @branches.count,
        has_default: !@default_branch.nil?
      }
    )
  end

  # Track this branch decision
  branch_decision = "#{@name}:#{selected_branch.name}"
  branch_decisions = [ branch_decision ]

  # Execute the selected branch
  executed_steps = selected_branch.execute(context, user, params, branch_decisions)

  # Return execution metadata
  {
    executed_steps: executed_steps,
    branch_taken: selected_branch,
    branch_decisions: branch_decisions,
    skipped: false
  }
end

#has_default?Boolean

Returns whether this group has a default branch

Returns:

  • (Boolean)


125
126
127
# File 'lib/better_service/workflows/branch_group.rb', line 125

def has_default?
  !@default_branch.nil?
end

#inspectString

Returns a string representation of this branch group

Returns:

  • (String)


132
133
134
135
136
# File 'lib/better_service/workflows/branch_group.rb', line 132

def inspect
  "#<BetterService::Workflows::BranchGroup name=#{@name.inspect} " \
    "branches=#{@branches.count} " \
    "has_default=#{has_default?}>"
end

#select_branch(context) ⇒ Branch?

Selects the first branch that matches the context

Parameters:

Returns:

  • (Branch, nil)

    The matching branch or nil if none match



59
60
61
62
63
64
65
66
67
# File 'lib/better_service/workflows/branch_group.rb', line 59

def select_branch(context)
  # Try conditional branches first (in order)
  @branches.each do |branch|
    return branch if branch.matches?(context)
  end

  # Fall back to default branch if present
  @default_branch
end

#set_default(name: nil) ⇒ Branch

Sets the default branch (otherwise)

Parameters:

  • name (Symbol, nil) (defaults to: nil)

    Optional name for the default branch

Returns:

  • (Branch)

    The created default branch



51
52
53
# File 'lib/better_service/workflows/branch_group.rb', line 51

def set_default(name: nil)
  @default_branch = Branch.new(condition: nil, name: name || :otherwise)
end