Class: Inquirex::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/inquirex/node.rb

Overview

A single step in the flow. The verb determines the role of this node:

Collecting verbs (user provides input):

:ask     — typed question with one of the 11 data types
:confirm — yes/no boolean gate (shorthand for ask with type :boolean)

Display verbs (no input, auto-advance):

:say     — informational message
:header  — section heading or title card
:btw     — admonition, sidebar, or contextual note
:warning — important alert

Constant Summary collapse

VERBS =

Valid DSL verbs and which ones collect input from the user.

%i[ask say header btw warning confirm].freeze
COLLECTING_VERBS =
%i[ask confirm].freeze
DISPLAY_VERBS =
%i[say header btw warning].freeze
TYPES =

Valid data types for :ask steps.

%i[
  string text integer decimal currency boolean
  enum multi_enum date email phone
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, verb:, type: nil, question: nil, text: nil, options: nil, transitions: [], skip_if: nil, default: nil) ⇒ Node

Returns a new instance of Node.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/inquirex/node.rb', line 49

def initialize(id:,
  verb:,
  type: nil,
  question: nil,
  text: nil,
  options: nil,
  transitions: [],
  skip_if: nil,
  default: nil)
  @id = id.to_sym
  @verb = verb.to_sym
  @type = type&.to_sym
  @question = question
  @text = text
  @transitions = transitions.freeze
  @skip_if = skip_if
  @default = default
  extract_options(options)
  freeze
end

Instance Attribute Details

#defaultObject? (readonly)

default value (pre-fill, user can change)

Returns:

  • (Object, nil)

    the current value of default



26
27
28
# File 'lib/inquirex/node.rb', line 26

def default
  @default
end

#idSymbol (readonly)

unique step identifier

Returns:

  • (Symbol)

    the current value of id



26
27
28
# File 'lib/inquirex/node.rb', line 26

def id
  @id
end

#option_labelsHash? (readonly)

key => display label mapping

Returns:

  • (Hash, nil)

    the current value of option_labels



26
27
28
# File 'lib/inquirex/node.rb', line 26

def option_labels
  @option_labels
end

#optionsArray? (readonly)

option keys for :enum/:multi_enum steps

Returns:

  • (Array, nil)

    the current value of options



26
27
28
# File 'lib/inquirex/node.rb', line 26

def options
  @options
end

#questionString? (readonly)

prompt text for collecting steps

Returns:

  • (String, nil)

    the current value of question



26
27
28
# File 'lib/inquirex/node.rb', line 26

def question
  @question
end

#skip_ifRules::Base? (readonly)

rule to skip this step entirely

Returns:



26
27
28
# File 'lib/inquirex/node.rb', line 26

def skip_if
  @skip_if
end

#textString? (readonly)

display text for non-collecting steps

Returns:

  • (String, nil)

    the current value of text



26
27
28
# File 'lib/inquirex/node.rb', line 26

def text
  @text
end

#transitionsArray<Transition> (readonly)

ordered conditional next-step edges

Returns:

  • (Array<Transition>)

    the current value of transitions



26
27
28
# File 'lib/inquirex/node.rb', line 26

def transitions
  @transitions
end

#typeSymbol? (readonly)

input type for :ask/:confirm (nil for display verbs)

Returns:

  • (Symbol, nil)

    the current value of type



26
27
28
# File 'lib/inquirex/node.rb', line 26

def type
  @type
end

#verbSymbol (readonly)

DSL verb (:ask, :say, :header, :btw, :warning, :confirm)

Returns:

  • (Symbol)

    the current value of verb



26
27
28
# File 'lib/inquirex/node.rb', line 26

def verb
  @verb
end

Class Method Details

.from_h(id, hash) ⇒ Node

Deserializes a node from a plain Hash.

Parameters:

  • id (Symbol, String)

    step id

  • hash (Hash)

    node attributes

Returns:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/inquirex/node.rb', line 126

def self.from_h(id, hash)
  verb = hash["verb"] || hash[:verb]
  type = hash["type"] || hash[:type]
  question = hash["question"] || hash[:question]
  text = hash["text"] || hash[:text]
  raw_options = hash["options"] || hash[:options]
  transitions_data = hash["transitions"] || hash[:transitions] || []
  skip_if_data = hash["skip_if"] || hash[:skip_if]
  default = hash["default"] || hash[:default]

  transitions = transitions_data.map { |t| Transition.from_h(t) }
  skip_if = skip_if_data ? Rules::Base.from_h(skip_if_data) : nil
  options = deserialize_options(raw_options)

  new(
    id:,
    verb:,
    type:,
    question:,
    text:,
    options:,
    transitions:,
    skip_if:,
    default:
  )
end

Instance Method Details

#collecting?Boolean

Returns true if this step collects input from the user.

Returns:

  • (Boolean)

    true if this step collects input from the user



72
73
74
# File 'lib/inquirex/node.rb', line 72

def collecting?
  COLLECTING_VERBS.include?(@verb)
end

#display?Boolean

Returns true if this step only displays content (no input).

Returns:

  • (Boolean)

    true if this step only displays content (no input)



77
78
79
# File 'lib/inquirex/node.rb', line 77

def display?
  DISPLAY_VERBS.include?(@verb)
end

#next_step_id(answers) ⇒ Symbol?

Resolves the next step id from current answers by evaluating transitions in order.

Parameters:

  • answers (Hash)

    current answer state

Returns:

  • (Symbol, nil)

    id of the next step, or nil if no transition matches (flow end)



85
86
87
88
# File 'lib/inquirex/node.rb', line 85

def next_step_id(answers)
  match = @transitions.find { |t| t.applies?(answers) }
  match&.target
end

#skip?(answers) ⇒ Boolean

Whether this step should be skipped given current answers.

Parameters:

  • answers (Hash)

Returns:

  • (Boolean)


94
95
96
97
98
# File 'lib/inquirex/node.rb', line 94

def skip?(answers)
  return false if @skip_if.nil?

  @skip_if.evaluate(answers)
end

#to_hHash

Serializes the node to a plain Hash for JSON output. Lambda defaults/compute are stripped (server-side only).

Returns:

  • (Hash)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/inquirex/node.rb', line 104

def to_h
  hash = { "verb" => @verb.to_s }

  if collecting?
    hash["type"] = @type.to_s if @type
    hash["question"] = @question if @question
    hash["options"] = serialize_options if @options
    hash["skip_if"] = @skip_if.to_h if @skip_if
    hash["default"] = @default unless @default.nil? || @default.is_a?(Proc)
  elsif @text
    hash["text"] = @text
  end

  hash["transitions"] = @transitions.map(&:to_h) unless @transitions.empty?
  hash
end