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.
-
#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, 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.
-
#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, widget_hints: nil, accumulations: []) ⇒ Node
Returns a new instance of Node.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/inquirex/node.rb', line 54 def initialize(id:, verb:, type: nil, question: nil, text: nil, options: nil, transitions: [], skip_if: nil, default: nil, 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 @widget_hints = &.freeze @accumulations = accumulations.freeze () freeze end |
Instance Attribute Details
#accumulations ⇒ Object (readonly)
Returns the value of attribute accumulations.
41 42 43 |
# File 'lib/inquirex/node.rb', line 41 def accumulations @accumulations end |
#default ⇒ Object? (readonly)
default value (pre-fill, user can change)
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def default @default end |
#id ⇒ Symbol (readonly)
unique step identifier
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def id @id end |
#option_labels ⇒ Hash? (readonly)
key => display label mapping
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def option_labels @option_labels end |
#options ⇒ Array? (readonly)
option keys for :enum/:multi_enum steps
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def @options end |
#question ⇒ String? (readonly)
prompt text for collecting steps
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def question @question end |
#skip_if ⇒ Rules::Base? (readonly)
rule to skip this step entirely
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def skip_if @skip_if end |
#text ⇒ String? (readonly)
display text for non-collecting steps
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def text @text end |
#transitions ⇒ Array<Transition> (readonly)
ordered conditional next-step edges
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def transitions @transitions end |
#type ⇒ Symbol? (readonly)
input type for :ask/:confirm (nil for display verbs)
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def type @type end |
#verb ⇒ Symbol (readonly)
DSL verb (:ask, :say, :header, :btw, :warning, :confirm)
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def verb @verb end |
#widget_hints ⇒ Hash{Symbol => WidgetHint}? (readonly)
rendering hints per target
27 28 29 |
# File 'lib/inquirex/node.rb', line 27 def @widget_hints end |
Class Method Details
.from_h(id, hash) ⇒ Node
Deserializes a node from a plain Hash.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/inquirex/node.rb', line 163 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] = 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:, widget_hints:, accumulations: ) end |
Instance Method Details
#collecting? ⇒ Boolean
Returns true if this step collects input from the user.
80 81 82 |
# File 'lib/inquirex/node.rb', line 80 def collecting? COLLECTING_VERBS.include?(@verb) end |
#display? ⇒ Boolean
Returns true if this step only displays content (no input).
85 86 87 |
# File 'lib/inquirex/node.rb', line 85 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.
102 103 104 |
# File 'lib/inquirex/node.rb', line 102 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.
110 111 112 113 |
# File 'lib/inquirex/node.rb', line 110 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.
119 120 121 122 123 |
# File 'lib/inquirex/node.rb', line 119 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).
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/inquirex/node.rb', line 129 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) 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.
93 94 95 |
# File 'lib/inquirex/node.rb', line 93 def (target: :desktop) @widget_hints&.fetch(target.to_sym, nil) end |