Class: Inquirex::DSL::StepBuilder

Inherits:
Object
  • Object
show all
Includes:
RuleHelpers
Defined in:
lib/inquirex/dsl/step_builder.rb

Overview

Builds a single Node from a step DSL block. Used by FlowBuilder for each verb (ask, say, header, btw, warning, confirm). Includes RuleHelpers for transition conditions and skip_if expressions.

Instance Method Summary collapse

Methods included from RuleHelpers

#all, #any, #contains, #equals, #greater_than, #less_than, #not_empty

Constructor Details

#initialize(verb) ⇒ StepBuilder

Returns a new instance of StepBuilder.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/inquirex/dsl/step_builder.rb', line 11

def initialize(verb)
  @verb = verb
  @type = nil
  @question = nil
  @text = nil
  @options = nil
  @transitions = []
  @skip_if = nil
  @default = nil
  @required = true
  @compute = nil
  @widget_hints = {}
  @accumulations = []
end

Instance Method Details

#accumulate(target, lookup: nil, per_selection: nil, per_unit: nil, flat: nil) ⇒ Object

Declares how this step's answer contributes to a named accumulator. Exactly one shape key should be provided:

lookup:        Hash of answer_value => amount (for :enum)
per_selection: Hash of option_value => amount (for :multi_enum)
per_unit:      Numeric rate (multiplied by the numeric answer)
flat:          Numeric (added when the step has any answer)

Examples:

accumulate :price, lookup: { single: 200, mfj: 400 }
accumulate :price, per_unit: 25
accumulate :price, per_selection: { c: 150, e: 75 }
accumulate :complexity, flat: 1


38
39
40
41
# File 'lib/inquirex/dsl/step_builder.rb', line 38

def accumulate(target, lookup: nil, per_selection: nil, per_unit: nil, flat: nil)
  shape, payload = pick_accumulator_shape(lookup:, per_selection:, per_unit:, flat:)
  @accumulations << Accumulation.new(target:, shape:, payload:)
end

#build(id) ⇒ Node

Builds the Node for the given step id.

Parameters:

  • id (Symbol)

Returns:



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/inquirex/dsl/step_builder.rb', line 157

def build(id)
  Node.new(
    id:,
    verb:          @verb,
    type:          resolve_type,
    question:      @question,
    text:          @text,
    options:       @options,
    transitions:   @transitions,
    skip_if:       @skip_if,
    default:       @default,
    required:      @required,
    widget_hints:  resolve_widget_hints,
    accumulations: @accumulations
  )
end

#compute {|Answers| ... } ⇒ Object

Registers a compute block: auto-calculates a value from answers, not shown to user. The computed value is stored server-side only and stripped from JSON serialization.

Yields:

  • (Answers)

    block receiving answers, must return the computed value



149
150
151
# File 'lib/inquirex/dsl/step_builder.rb', line 149

def compute(&block)
  @compute = block
end

#default(value = nil, &block) ⇒ Object

Sets a default value for this step (shown pre-filled; user can change it). Can be a static value or a proc receiving collected answers so far. On a required false step the default is also what Engine#skip records into the answers when the user skips the question.

Parameters:

  • value (Object, Proc) (defaults to: nil)


122
123
124
# File 'lib/inquirex/dsl/step_builder.rb', line 122

def default(value = nil, &block)
  @default = block || value
end

#options(list) ⇒ Object

Sets the list of options for :enum or :multi_enum steps. Accepts an Array (option keys) or a Hash (key => label).

Parameters:

  • list (Array, Hash)


80
81
82
# File 'lib/inquirex/dsl/step_builder.rb', line 80

def options(list)
  @options = list
end

#price(**kwargs) ⇒ Object

Sugar for the common :price accumulator. Accepts either a shape keyword (lookup:, per_selection:, per_unit:, flat:) or — when given plain option=>amount keys — treats it as a lookup. So both work:

price single: 200, mfj: 400           # => lookup
price per_unit: 25                    # => per_unit
price lookup: { single: 200, ... }    # => lookup (explicit)


50
51
52
53
54
55
56
57
# File 'lib/inquirex/dsl/step_builder.rb', line 50

def price(**kwargs)
  shape_keys = %i[lookup per_selection per_unit flat]
  if kwargs.keys.intersect?(shape_keys)
    accumulate(:price, **kwargs.slice(*shape_keys))
  else
    accumulate(:price, lookup: kwargs)
  end
end

#question(text) ⇒ Object

Sets the prompt/question text for collecting steps.

Parameters:

  • text (String)


67
68
69
# File 'lib/inquirex/dsl/step_builder.rb', line 67

def question(text)
  @question = text
end

#required(value = true) ⇒ Object

Declares whether the user must answer this step (true by default). required false marks the question as optional: renderers show a small Skip control, and Engine#skip records the step's default (when one is declared) into the answers while marking the step as skipped.

Examples:

An optional question with a skip default

ask :dependents do
  type :integer
  question "How many dependents?"
  required false
  default 0
  transition to: :done
end

Parameters:

  • value (Boolean) (defaults to: true)

    false to make the step skippable



141
142
143
# File 'lib/inquirex/dsl/step_builder.rb', line 141

def required(value = true)
  @required = value
end

#skip_if(rule) ⇒ Object

Sets a rule that skips this step entirely when true. The step is omitted from the user's path and no answer is recorded.

Parameters:



112
113
114
# File 'lib/inquirex/dsl/step_builder.rb', line 112

def skip_if(rule)
  @skip_if = rule
end

#text(content) ⇒ Object

Sets the display text for non-collecting steps (say/header/btw/warning).

Parameters:

  • content (String)


73
74
75
# File 'lib/inquirex/dsl/step_builder.rb', line 73

def text(content)
  @text = content
end

#transition(to:, if_rule: nil, requires_server: false) ⇒ Object

Adds a conditional transition. First matching transition wins.

Parameters:

  • to (Symbol)

    target step id

  • if_rule (Rules::Base, nil) (defaults to: nil)

    condition (nil = unconditional)

  • requires_server (Boolean) (defaults to: false)

    whether this transition needs server round-trip



104
105
106
# File 'lib/inquirex/dsl/step_builder.rb', line 104

def transition(to:, if_rule: nil, requires_server: false)
  @transitions << Transition.new(target: to, rule: if_rule, requires_server:)
end

#type(value) ⇒ Object

Sets the input data type for :ask steps.

Parameters:

  • value (Symbol)

    one of Node::TYPES



61
62
63
# File 'lib/inquirex/dsl/step_builder.rb', line 61

def type(value)
  @type = value
end

#widget(type:, target: :desktop, **opts) ⇒ Object

Sets a rendering hint for the given target context. Recognized targets: :desktop, :mobile, :tty (and any future targets).

Examples:

widget target: :desktop, type: :radio_group, columns: 2
widget target: :mobile,  type: :dropdown
widget target: :tty,     type: :select

Parameters:

  • type (Symbol)

    widget type (e.g. :radio_group, :dropdown)

  • target (Symbol) (defaults to: :desktop)

    rendering context (default: :desktop)

  • opts (Hash)

    widget-specific options (e.g. columns: 2)



95
96
97
# File 'lib/inquirex/dsl/step_builder.rb', line 95

def widget(type:, target: :desktop, **opts)
  @widget_hints[target.to_sym] = WidgetHint.new(type:, options: opts)
end