Class: Inquirex::Node
- Inherits:
-
Object
- Object
- Inquirex::Node
- 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 =
Verbs that collect input from the user.
%i[ask confirm].freeze
- DISPLAY_VERBS =
Verbs that only display content and auto-advance.
%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
-
#accumulations ⇒ Object
readonly
Returns the value of attribute accumulations.
-
#default ⇒ Object?
readonly
default value (pre-fill, user can change).
-
#id ⇒ Symbol
readonly
unique step identifier.
-
#option_labels ⇒ Hash?
readonly
key => display label mapping.
-
#options ⇒ Array?
readonly
option keys for :enum/:multi_enum steps.
-
#question ⇒ String?
readonly
prompt text for collecting steps.
-
#required ⇒ Boolean
readonly
whether the user must answer (true by default);
required falsesteps render a Skip control and accept Engine#skip. -
#skip_if ⇒ Rules::Base?
readonly
rule to skip this step entirely.
-
#text ⇒ String?
readonly
display text for non-collecting steps.
-
#transitions ⇒ Array<Transition>
readonly
ordered conditional next-step edges.
-
#type ⇒ Symbol?
readonly
input type for :ask/:confirm (nil for display verbs).
-
#verb ⇒ Symbol
readonly
DSL verb (:ask, :say, :header, :btw, :warning, :confirm).
-
#widget_hints ⇒ Hash{Symbol => WidgetHint}?
readonly
rendering hints per target.
Class Method Summary collapse
-
.from_h(id, hash) ⇒ Node
Deserializes a node from a plain Hash.
Instance Method Summary collapse
-
#collecting? ⇒ Boolean
True if this step collects input from the user.
-
#display? ⇒ Boolean
True if this step only displays content (no input).
-
#effective_widget_hint_for(target: :desktop) ⇒ WidgetHint?
Returns the explicit hint for the target, falling back to the registry default for this node's type when no explicit hint is set.
-
#initialize(id:, verb:, type: nil, question: nil, text: nil, options: nil, transitions: [], skip_if: nil, default: nil, required: true, widget_hints: nil, accumulations: []) ⇒ Node
constructor
A new instance of Node.
-
#next_step_id(answers) ⇒ Symbol?
Resolves the next step id from current answers by evaluating transitions in order.
-
#required? ⇒ Boolean
Whether the user must answer this step.
-
#skip?(answers) ⇒ Boolean
Whether this step should be skipped given current answers.
-
#to_h ⇒ Hash
Serializes the node to a plain Hash for JSON output.
-
#widget_hint_for(target: :desktop) ⇒ WidgetHint?
Returns the explicit widget hint for the given target, or nil.
Constructor Details
#initialize(id:, verb:, type: nil, question: nil, text: nil, options: nil, transitions: [], skip_if: nil, default: nil, required: true, widget_hints: nil, accumulations: []) ⇒ Node
Returns a new instance of Node.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/inquirex/node.rb', line 57 def initialize(id:, verb:, type: nil, question: nil, text: nil, options: nil, transitions: [], skip_if: nil, default: nil, required: true, widget_hints: nil, accumulations: []) @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 @required = required ? true : false @widget_hints = &.freeze @accumulations = accumulations.freeze () freeze end |
Instance Attribute Details
#accumulations ⇒ Object (readonly)
Returns the value of attribute accumulations.
43 44 45 |
# File 'lib/inquirex/node.rb', line 43 def accumulations @accumulations end |
#default ⇒ Object? (readonly)
default value (pre-fill, user can change)
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def default @default end |
#id ⇒ Symbol (readonly)
unique step identifier
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def id @id end |
#option_labels ⇒ Hash? (readonly)
key => display label mapping
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def option_labels @option_labels end |
#options ⇒ Array? (readonly)
option keys for :enum/:multi_enum steps
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def @options end |
#question ⇒ String? (readonly)
prompt text for collecting steps
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def question @question end |
#required ⇒ Boolean (readonly)
whether the user must answer (true by default);
required false steps render a Skip control and accept Engine#skip
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def required @required end |
#skip_if ⇒ Rules::Base? (readonly)
rule to skip this step entirely
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def skip_if @skip_if end |
#text ⇒ String? (readonly)
display text for non-collecting steps
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def text @text end |
#transitions ⇒ Array<Transition> (readonly)
ordered conditional next-step edges
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def transitions @transitions end |
#type ⇒ Symbol? (readonly)
input type for :ask/:confirm (nil for display verbs)
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def type @type end |
#verb ⇒ Symbol (readonly)
DSL verb (:ask, :say, :header, :btw, :warning, :confirm)
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def verb @verb end |
#widget_hints ⇒ Hash{Symbol => WidgetHint}? (readonly)
rendering hints per target
29 30 31 |
# File 'lib/inquirex/node.rb', line 29 def @widget_hints end |
Class Method Details
.from_h(id, hash) ⇒ Node
Deserializes a node from a plain Hash.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/inquirex/node.rb', line 178 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] = hash["options"] || hash[:options] transitions_data = hash["transitions"] || hash[:transitions] || [] skip_if_data = hash["skip_if"] || hash[:skip_if] default = hash["default"] || hash[:default] # Fetch chain (not ||) so an explicit false survives; absent key means required. required = hash.fetch("required") { hash.fetch(:required, true) } = hash["widget"] || hash[:widget] accumulate_data = hash["accumulate"] || hash[:accumulate] transitions = transitions_data.map { |t| Transition.from_h(t) } skip_if = skip_if_data ? Rules::Base.from_h(skip_if_data) : nil = () = () accumulations = deserialize_accumulations(accumulate_data) new( id:, verb:, type:, question:, text:, options:, transitions:, skip_if:, default:, required:, widget_hints:, accumulations: ) end |
Instance Method Details
#collecting? ⇒ Boolean
Returns true if this step collects input from the user.
85 86 87 |
# File 'lib/inquirex/node.rb', line 85 def collecting? COLLECTING_VERBS.include?(@verb) end |
#display? ⇒ Boolean
Returns true if this step only displays content (no input).
90 91 92 |
# File 'lib/inquirex/node.rb', line 90 def display? DISPLAY_VERBS.include?(@verb) end |
#effective_widget_hint_for(target: :desktop) ⇒ WidgetHint?
Returns the explicit hint for the target, falling back to the registry default for this node's type when no explicit hint is set.
116 117 118 |
# File 'lib/inquirex/node.rb', line 116 def (target: :desktop) (target:) || WidgetRegistry.default_hint_for(@type, context: target) end |
#next_step_id(answers) ⇒ Symbol?
Resolves the next step id from current answers by evaluating transitions in order.
124 125 126 127 |
# File 'lib/inquirex/node.rb', line 124 def next_step_id(answers) match = @transitions.find { |t| t.applies?(answers) } match&.target end |
#required? ⇒ Boolean
Whether the user must answer this step. True by default; steps declared
with required false render a Skip control and accept Engine#skip.
Only meaningful for collecting steps.
99 100 101 |
# File 'lib/inquirex/node.rb', line 99 def required? @required end |
#skip?(answers) ⇒ Boolean
Whether this step should be skipped given current answers.
133 134 135 136 137 |
# File 'lib/inquirex/node.rb', line 133 def skip?(answers) return false if @skip_if.nil? @skip_if.evaluate(answers) end |
#to_h ⇒ Hash
Serializes the node to a plain Hash for JSON output. Lambda defaults/compute are stripped (server-side only).
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/inquirex/node.rb', line 143 def to_h hash = { "verb" => @verb.to_s } if collecting? hash["type"] = @type.to_s if @type hash["question"] = @question if @question hash["options"] = if @options hash["skip_if"] = @skip_if.to_h if @skip_if hash["default"] = @default unless @default.nil? || @default.is_a?(Proc) hash["required"] = false unless @required elsif @text hash["text"] = @text end hash["transitions"] = @transitions.map(&:to_h) unless @transitions.empty? if @widget_hints && !@widget_hints.empty? hash["widget"] = @widget_hints.transform_keys(&:to_s) .transform_values(&:to_h) end unless @accumulations.empty? hash["accumulate"] = @accumulations.to_h do |acc| [acc.target.to_s, acc.to_h] end end hash end |
#widget_hint_for(target: :desktop) ⇒ WidgetHint?
Returns the explicit widget hint for the given target, or nil.
107 108 109 |
# File 'lib/inquirex/node.rb', line 107 def (target: :desktop) @widget_hints&.fetch(target.to_sym, nil) end |