Prohlížeč zdrojového kódu

docs/specs/examples-runner.md

Náhled Zdrojový kód

Spec: Examples Runner

  • Status: active
  • Created: 2026-03-05
  • Related code: app/services/scenario_runner.rb, app/controllers/examples_controller.rb, app/views/examples/

Overview

Visitors can interactively run code examples from the detail page. Each example may define one or more scenarios, each with a set of dropdown inputs. The user selects parameter values and submits; the example code executes server-side and the result appears inline without a full page reload.

Behaviour

Scenarios and inputs

  • An example may define zero or more named scenarios.
  • Each scenario has a name, an optional description, and zero or more inputs.
  • Each input has a label and a fixed list of allowed options; only dropdown selection is possible — no free-text entry. The input's variable name is shown alongside the label so visitors can see which local variable the selected value is bound to.
  • Each scenario is displayed as a separate card on the example detail page, with its own form and result area.

Submitting a scenario

  • The user selects a value for each input from the dropdown and clicks "Spustit".
  • The form submits via Turbo Frame; only the result area for that scenario updates — the rest of the page is unchanged.
  • The server validates that the selected value for each input is one of the allowed options. Any invalid or missing value results in a 422 Unprocessable Entity response.

Boilerplate code display

  • Each scenario card shows its boilerplate_file content as a syntax-highlighted, read-only code block above the input form.

Execution

  • If the example has a source_file, it is loaded into an anonymous module first; the scenario's boilerplate_file snippet is then evaluated inside the same module context.
  • If there is no source_file, the boilerplate snippet is evaluated in a fresh anonymous module — it must be fully self-contained.
  • Input values are pre-bound as local variables matching each input's name field before the boilerplate snippet is evaluated.
  • Output is captured by overriding puts within the execution context; the snippet uses puts like ordinary Ruby. Captured output becomes the displayed result string.
  • Execution is capped at a 5-second timeout. If exceeded, a Czech error message is shown.
  • Any Ruby exception during execution is caught; a Czech-language error string including the exception class and message is shown.
  • On success, the captured output and execution duration (in seconds, 4 decimal places) are displayed.

Result display

  • Success: output text in a styled box, followed by a completion time.
  • Failure (timeout or exception): error message in a styled error box.

Implementation Notes

  • ScenarioRunner loads source_file into an anonymous Module via module_eval, so example classes do not leak into the global namespace.
  • Input locals are prepended to the snippet as literal assignment statements (name = "Alice"\n...) before module_eval, keeping the snippet source readable without metaprogramming.
  • $stdout is replaced with a StringIO instance during snippet evaluation and restored in an ensure block; puts in the snippet writes to the captured buffer naturally.
  • Execution uses Timeout.timeout(5); Timeout::Error and all other exceptions are rescued separately.
  • ScenarioRunner.run takes source_file: (may be nil), boilerplate_file:, and inputs: — no entry_class or entry_method. When source_file is nil, the module_eval of the source file is skipped.
  • The Turbo Frame tag for each scenario result is scenario_result_<index>; the form targets the same frame so only that area re-renders.
  • Input validation in the controller checks both presence and membership in input.options before calling ScenarioRunner.

Tests

  • spec/services/scenario_runner_spec.rb — puts output capture, local variable binding, exception handling, timeout, module isolation

See Also

  • Examples System — defines the example structure, metadata, and registry the runner operates on.
  • Rich Example Content — scenario forms are embedded via placeholder tags in the example's Markdown content.
  • Styling and CSS.result-box styles the execution output area; .code-block styles inline code display.

Change Log

  • 2026-03-05: Initial retrospective spec.
  • 2026-03-09: Prospective update — boilerplate snippet model; removed entry_class/entry_method; added boilerplate_file per scenario, local-variable input binding, puts-capture output.
  • 2026-03-23: Prospective update — source_file is optional; runner skips source loading when nil.