Module: Inquirex

Defined in:
lib/inquirex.rb,
lib/inquirex/dsl.rb,
lib/inquirex/node.rb,
lib/inquirex/engine.rb,
lib/inquirex/errors.rb,
lib/inquirex/answers.rb,
lib/inquirex/version.rb,
lib/inquirex/template.rb,
lib/inquirex/evaluator.rb,
lib/inquirex/rules/all.rb,
lib/inquirex/rules/any.rb,
lib/inquirex/definition.rb,
lib/inquirex/rules/base.rb,
lib/inquirex/send_email.rb,
lib/inquirex/transcript.rb,
lib/inquirex/transition.rb,
lib/inquirex/accumulator.rb,
lib/inquirex/safe_source.rb,
lib/inquirex/widget_hint.rb,
lib/inquirex/rules/equals.rb,
lib/inquirex/rules/contains.rb,
lib/inquirex/rules/less_than.rb,
lib/inquirex/rules/not_empty.rb,
lib/inquirex/widget_registry.rb,
lib/inquirex/dsl/flow_builder.rb,
lib/inquirex/dsl/rule_helpers.rb,
lib/inquirex/dsl/step_builder.rb,
lib/inquirex/rules/greater_than.rb,
lib/inquirex/validation/adapter.rb,
lib/inquirex/completion_metadata.rb,
lib/inquirex/safe_source/call_spec.rb,
lib/inquirex/safe_source/validator.rb,
lib/inquirex/dsl/send_email_builder.rb,
lib/inquirex/graph/mermaid_exporter.rb,
lib/inquirex/safe_source/vocabulary.rb,
lib/inquirex/engine/state_serializer.rb,
lib/inquirex/validation/null_adapter.rb

Overview

Declarative, rules-driven questionnaire engine for building conditional intake forms, qualification wizards, and branching surveys.

Examples:

Define a flow

definition = Inquirex.define id: "tax-intake-2025" do
  meta title: "Tax Preparation Intake", subtitle: "Let's understand your situation"
  start :filing_status

  ask :filing_status do
    type :enum
    question "What is your filing status?"
    options single: "Single", married_jointly: "Married Filing Jointly"
    transition to: :dependents
  end

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

  say :done do
    text "Thank you!"
  end
end

engine = Inquirex::Engine.new(definition)
engine.answer("single")
engine.answer(2)
engine.advance              # past the :done say step
engine.finished?            # => true

JSON round-trip

json = definition.to_json
restored = Inquirex::Definition.from_json(json)

Defined Under Namespace

Modules: DSL, Errors, Graph, Rules, SafeSource, Template, Transcript, Validation, WidgetRegistry Classes: Accumulation, Accumulator, Answers, CompletionMetadata, Definition, Engine, Evaluator, Node, SendEmail, Transition, WidgetHint

Constant Summary collapse

VERSION =
"0.9.6"

Class Method Summary collapse

Class Method Details

.define(id: nil, version: "1.0.0") { ... } ⇒ Definition

Builds an immutable Definition from the declarative DSL block.

Parameters:

  • id (String, nil) (defaults to: nil)

    optional flow identifier

  • version (String) (defaults to: "1.0.0")

    semver (default: "1.0.0")

Yields:

  • context of DSL::FlowBuilder

Returns:



100
101
102
103
104
# File 'lib/inquirex.rb', line 100

def self.define(id: nil, version: "1.0.0", &)
  builder = DSL::FlowBuilder.new(id:, version:)
  builder.instance_eval(&)
  builder.build
end

.load_dsl(text, unsafe: false, max_bytes: SafeSource.max_source_bytes, max_depth: SafeSource.max_depth) ⇒ Definition

Evaluates a string of DSL code and returns the resulting definition. Intended for loading flow definitions from files or stored text.

This is an eval. Whenever the text comes from anywhere other than your own repository — a database column a customer edits, an upload, an LLM, a visual builder — evaluating it unguarded is arbitrary code execution in the loading process. Inquirex::SafeSource.validate! therefore runs before the eval unless you opt out; the ordering is the whole point.

unsafe: true is for source you control as code: a .rb file in your own repository, a fixture, the file a CLI was pointed at. It is named unsafe rather than safe: false so the dangerous call is the conspicuous one.

Examples:

Stored, customer-authored DSL (validated)

Inquirex.load_dsl(qualifier.flow_dsl)

Your own file (validation skipped)

Inquirex.load_dsl(File.read("flow.rb"), unsafe: true)

Parameters:

  • text (String)

    Ruby source containing Inquirex.define { ... }

  • unsafe (Boolean) (defaults to: false)

    skip validation — only for source you authored

  • max_bytes (Integer) (defaults to: SafeSource.max_source_bytes)

    source size ceiling for validation

  • max_depth (Integer) (defaults to: SafeSource.max_depth)

    AST nesting ceiling for validation

Returns:

Raises:



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

def self.load_dsl(text,
  unsafe: false,
  max_bytes: SafeSource.max_source_bytes,
  max_depth: SafeSource.max_depth)
  SafeSource.validate!(text, max_bytes:, max_depth:) unless unsafe

  begin
    # Deliberate eval: the flow DSL *is* Ruby, so there is nothing else to
    # evaluate it with. Reaching this line means either SafeSource accepted
    # the source against a default-deny allowlist (above), or the caller
    # asserted `unsafe: true` for source it authored itself.
    # rubocop:disable Security/Eval
    eval(text, TOPLEVEL_BINDING.dup, "(dsl)", 1)
    # rubocop:enable Security/Eval
  rescue SyntaxError => e
    raise Errors::DefinitionError, "DSL syntax error: #{e.message}"
  rescue StandardError => e
    raise Errors::DefinitionError, "DSL evaluation error: #{e.message}"
  end
end