Class: Teek::UI::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/teek/ui/validator.rb

Overview

Note:

"Mixed pack+grid geometry in one container" (the classic Tk-hangs hazard) isn't checked here because, within the pure DSL layout path, it can't happen: Realizer#arrange_children picks exactly one arrangement strategy per container, from that container's own node type, and every container realizes into its own dedicated Tk master

  • a guarantee locked down by a realizer test (test_realizer.rb) asserting no master ever receives calls from more than one manager, so a future refactor that shares/flattens frames fails a test instead of shipping the hazard silently.

That guarantee only covers what the DSL itself can construct, though - it says nothing about the escape hatch. ui.raw, session.app.command, and a live handle's own app.command calls are opaque Procs the tree-walking validator can't see inside, so a raw +pack+/+grid+ call from one of those can still target a master the DSL already manages - that's the one real, unguardable vector, not "direct Node/Document manipulation" (which is what the narrower checks in GridValidator/TabValidator/PaneValidator actually guard against). If it happens, Tk itself is a synchronous backstop: it refuses a second geometry manager on an already-managed master with an immediate, clear Teek::TclError ("cannot use geometry manager X inside Y") rather than the classic silent hang - but the DSL has no way to stop the mistake up front, so avoid mixing raw geometry calls onto a DSL-managed master (see the README's escape hatch section).

Walks a Document before realize and collects ALL problems, so a broken build can be fixed in one pass instead of a cycle of "run, hit the next cryptic Tcl error, fix, repeat." Headless - no interpreter needed, since it only ever inspects the tree.

Two severities: problems that are "definitely broken" raise (folded into one ValidationError listing every one found); problems that are "probably a mistake" warn via Kernel#warn by default, or raise too under strict: true.

This class runs the checks that span the whole tree or relate arbitrary nodes to each other (dangling event targets, orphans). A specific widget/container's own contract (a grid's children all need cells, a tab's parent must be a ui.tabs, ...) lives in its own WidgetValidators-registered validator instead (see GridValidator/TabValidator/PaneValidator/OverlayValidator), dispatched by node type the same way CommandInterceptors dispatches by widget type. One depth-first walk covers both the document-level checks below and every registered widget validator.

A WidgetType descriptor's own validator: (see WidgetTypes) needs no separate handling here at all - WidgetTypes.register forwards it into WidgetValidators directly, so it's dispatched through the exact same WidgetValidators.for_type call every other validator already goes through.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document, strict: false) ⇒ Validator

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Validator.



73
74
75
76
77
78
79
# File 'lib/teek/ui/validator.rb', line 73

def initialize(document, strict: false)
  @document = document
  @strict = strict
  @errors = []
  @warnings = []
  @reachable = {}
end

Class Method Details

.validate!(document, strict: false) ⇒ Object

Parameters:

  • document (Document)
  • strict (Boolean) (defaults to: false)

    promote warn-level problems (currently just orphans) to raise-level too

Raises:



68
69
70
# File 'lib/teek/ui/validator.rb', line 68

def self.validate!(document, strict: false)
  new(document, strict: strict).validate!
end

Instance Method Details

#validate!void

This method returns an undefined value.

Raises:



82
83
84
85
86
87
88
# File 'lib/teek/ui/validator.rb', line 82

def validate!
  walk(@document.root, nil)
  check_orphans

  @warnings.each { |message| warn "teek-ui: #{message}" }
  raise ValidationError, @errors.join("\n") if @errors.any?
end