Verbindungsprüfungen

Verbindungsprüfungen schränken ein, welche Verbindungen (und somit Blöcke) miteinander verbunden werden können.

Verbindungsprüfungen sind für Modellierungstypen hilfreich. Die folgenden drei Blöcke haben beispielsweise keine Verbindung zu einem Geschäft, da sie Code darstellen, der unterschiedliche Typen zurückgibt:

Ein leerer Listenblock, der mit einem Quadratwurzelblock und einem Großbuchstaben verbunden ist

Verbindungsprüfungen können verwendet werden, um zu verhindern, dass diese Blöcke eine Verbindung herstellen. So erhalten die Nutzer unmittelbares Feedback und vermeiden viele einfache Fehler.

Funktionsweise

Jede Verbindung kann einer „Verbindungsprüfung“ zugeordnet werden. Dabei handelt es sich um ein Array von Strings, für das Nullwerte zulässig sind.

In folgenden Fällen können zwei Verbindungen hergestellt werden:

  1. Es sind kompatible Typen (z.B. ein Ausgang, der mit einer Eingabe verbunden ist).
  2. Sie haben mindestens einen String in ihrer Verbindungsprüfung gemeinsam.

Die folgenden beiden Prüfungen könnten beispielsweise eine Verbindung herstellen, da sie den String 'apple' teilen:

['apple', 'ball', 'cat']
['apple', 'bear', 'caterpillar']

Diese beiden Prüfungen konnten jedoch keine Verbindung herstellen, da sie keine Strings gemeinsam haben:

['apple', 'ball', 'cat']
['ape', 'bear', 'caterpillar']

Es gibt noch einen Sonderfall. Wenn eines der Arrays null ist, können die beiden Verbindungen ebenfalls verbunden werden. So können Sie Verbindungen definieren, die sich mit beliebigen Verbindungen verbinden können.

null
['ape', 'bear', 'caterpillar]

Überprüfungen einrichten

Standardmäßig haben alle Verbindungen eine null-Verbindungsprüfung, d. h., sie können mit allen Verbindungen verbunden werden. Verbindungsprüfungen müssen manuell zugewiesen werden.

Wie Sie Verbindungen Verbindungsprüfungen zuweisen, hängt davon ab, ob Sie JSON-Blockdefinitionen oder JavaScript-Blockdefinitionen verwenden.

JSON

Bei Verbindungen auf oberster Ebene weisen Sie die Prüfung direkt der Property zu, die die Verbindung definiert. Der Wert, den Sie zuweisen, kann null, ein String (der einziger Eintrag in der Verbindungsprüfung wird) oder ein String-Array sein.

{
  'type': 'custom_block',

  'output': null,
  'nextStatement': 'a connection check entry',
  'previousStatement': ['four', 'connection', 'check', 'entries']
}

Bei Eingaben können Sie die Diagnose dem Attribut check der Eingabedefinition zuweisen. Fehlt die Property check, wird die Diagnose als null gewertet. Der Wert, den Sie zuweisen, kann eine Zeichenfolge oder ein String-Array sein.

{
  'type': 'custom_block',
  'message0': '%1 %2',

  'args0': [
    {
      'type': 'input_value',
      'check': 'a connection check entry'
    },
    {
      'type': 'input_statement',
      'check': ['four', 'connection', 'check', 'entries']
    }
  ]
}

JavaScript

Bei Verbindungen auf oberster Ebene können Sie die Prüfung direkt an die Methode übergeben, die die Verbindung definiert. Wenn kein Wert übergeben wird, wird die Prüfung als null ausgeführt. Der Wert, den Sie übergeben, kann ein String (der einzige Eintrag in der Verbindungsprüfung wird) oder ein String-Array sein.

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.setOutput(true); // null check
    this.setNextStatement(true, 'a connection check entry');
    this.setPreviousStatement(true, ['four', 'connection', 'check', 'entries']);
  }
}

Bei Eingaben können Sie die Prüfung an die Methode setCheck übergeben, nachdem Sie die Eingabe definiert haben. Wenn die Methode setCheck nicht aufgerufen wird, gilt die Prüfung als null. Der Wert, der übergeben wird, kann ein String oder ein String-Array sein.

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.appendValueInput('NAME')
        .setCheck('a connection check entry');
    this.appendStatementInput('NAME')
        .setCheck(['four', 'connection', 'check', 'entries']);
  }
}

Integrierte Prüfstrings

Die integrierten Blöcke haben Verbindungsprüfungen mit den Werten 'Array', 'Boolean', 'Colour', 'Number' und 'String'. Wenn Sie möchten, dass Ihre Blöcke mit den integrierten Blöcken zusammenarbeiten, können Sie diese Werte verwenden, um sie kompatibel zu machen.

Beispiele für Werte

Wenn Sie Verbindungsprüfungen für Ein- und Ausgaben definieren, sollten Sie sich die Prüfungen in der Regel als Typen darstellen.

Die Überprüfungen von Eingaben sollten jeden akzeptierten "Typ" enthalten, und die Prüfungen von Ausgaben sollten exakt das enthalten, was sie "zurückgeben".

Einzelnen Typ akzeptieren

Im einfachsten Fall, in dem Sie einen Block erstellen möchten, der einen Typ "akzeptiert" oder "zurückgibt", müssen Sie diesen Typ in die Verbindungsprüfung der Verbindung aufnehmen.

Wertblock, der einen einzelnen Typ akzeptiert

Mehrere Typen akzeptieren

Um einen Block zu erstellen, der mehrere Typen "akzeptiert", müssen Sie jeden akzeptierten Typ in die Verbindungsprüfung der Eingabe aufnehmen.

Wertblock, der mehrere Typen akzeptiert

Wenn eine Ausgabe manchmal in mehreren Situationen akzeptiert werden kann (z.B. wenn Sie die Verwendung von Zahlen als Strings zulassen), sollte die Ausgabe Konventionsgemäß restriktiver sein und die Eingabe(n) großzügiger sein. Diese Konvention sorgt dafür, dass Ausgaben nicht an Stellen verbunden werden, an denen sie nicht unterstützt werden.

Alle Typen akzeptieren

Zum Erstellen eines Blocks, der jeden Typ "akzeptiert", müssen Sie die Verbindungsprüfung der Eingabe auf null setzen.

Wertblock, der jeden Typ von

Rückgabeuntertypen

Um einen Block zu erstellen, der einen Untertyp "zurückgibt", müssen Sie sowohl den Typ als auch den Supertyp in die Verbindungsprüfung der Ausgabe aufnehmen.

Einen Wertblock, der seinen Typ und seinen Supertyp zurückgibt

Bei Untertypen ist es in Ordnung, mehrere Prüfungen in einer Ausgabeprüfung zu haben, da der Block immer beide Typen "zurückgibt".

Parameterisierte Typen zurückgeben

Um einen Block zu erstellen, der einen parametrisierten Typ "zurückgibt", müssen Sie sowohl die parametrisierte Version als auch die nicht parametrierte Version in die Verbindungsprüfung der Ausgabe aufnehmen.

Je nachdem, wie streng die Blocksprache sein soll, können Sie auch die Varianz(en) des Typs einbeziehen.

Ein Wertblock, der seinen parametrisierten und seinen nicht parametrierten Typ zurückgibt

Wie bei Subtypen ist es in diesem Fall in Ordnung, mehrere Prüfungen in einer Ausgabeprüfung zu haben, da der Block immer beide Typen "zurückgibt".

Beispiele für Stacks oder Anweisungen

Es gibt einige gängige Methoden, mit denen Entwickler Prüfungen für vorherige und nächste Verbindungen definieren. Normalerweise beschränken Sie damit die Reihenfolge der Blöcke.

Nächste Verbindungen sollten angeben, welche Blöcke dem aktuellen Block folgen sollen. Vorherige Verbindungen geben an, was der aktuelle Block ist.

Blöcke in der richtigen Reihenfolge halten

Wenn Sie eine Gruppe von Blöcken erstellen möchten, die in einer definierten Reihenfolge verbunden werden, müssen Sie angeben, welche Blöcke in der nächsten Verbindungsprüfung auf den aktuellen Block folgen sollen und was der aktuelle Block in der vorherigen Verbindungsprüfung „ist“.

Anweisungsblöcke mit einer erzwungenen Reihenfolge

Viele mittlere Blöcke zulassen

Wenn Sie einen Satz geordneter Blöcke erstellen möchten, der viele mittlere Blöcke zulässt, müssen Sie mindestens einen Eintrag aus der vorherigen Verbindungsprüfung des mittleren Blocks in die nächste Verbindungsprüfung des mittleren Blocks aufnehmen. So kann dem Block mehr von sich selbst folgen.

Anweisungsblöcke, die viele mittlere Blöcke ermöglichen

Keine mittleren Blöcke zulassen

Zum Erstellen einer Reihe geordneter Blöcke, bei denen die mittleren Blöcke optional sind, müssen Sie mindestens einen Eintrag aus der vorherigen Verbindungsprüfung des mittleren Blocks und der vorherigen Verbindungsprüfung des letzten Blocks in die nächste Verbindungsprüfung des ersten Blocks aufnehmen. Auf diese Weise kann auf den ersten Block entweder ein mittlerer oder ein letzter Block folgen.

Anweisungsblöcke, die keine mittleren Blöcke zulassen

Entweder-oder-Stacks

Um einen Block zu erstellen, dem nur Blöcke aus einer Gruppe oder Blöcke aus einer anderen Gruppe folgen können (nicht beides), müssen Sie zwei Schritte ausführen:

  1. Sie müssen in die nächste Verbindungsprüfung des ersten Blocks mindestens einen Eintrag aus den beiden vorherigen Verbindungsprüfungen der Gruppen aufnehmen.

  2. Sie müssen die nächsten Verbindungsprüfungen der Gruppen so definieren, dass nur Werte einbezogen werden, die in ihren vorherigen Verbindungsprüfungen enthalten sind (damit können nur Blöcke derselben Gruppe gefolgt werden).

Anweisungsblöcke, denen mehrere eines Blocktyps oder mehrfache
Blöcke eines anderen Blocktyps folgen können, jedoch nicht beides

Beschränkungen

Dieses System ist ziemlich robust und kann viele Anwendungsfälle lösen, hat jedoch einige Einschränkungen.

Den größeren Kontext einschränken

Dieses System selbst unterstützt nicht das Einschränken des „größeren Kontexts“, in dem eine Verbindung eine Verbindung herstellen darf. Sie können beispielsweise nicht festlegen, dass ein break-Block nur innerhalb eines loop-Blocks vorhanden sein darf. Das System zur Verbindungsprüfung berücksichtigt nur die unmittelbar verbundenen Verbindungen.

Sie können dies unterstützen, indem Sie das Ereignissystem verwenden, um auf Blockverschiebungsereignisse zu warten und zu prüfen, ob der Block falsch positioniert ist.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (this.workspace.isDragging()) return;
    if (e.type !== Blockly.Events.BlockMove) return;
    if (!this.getSurroundLoop()) this.outputConnection.disconnect();
  }

  loopTypes: new Set(); // Your valid *block types* (not connection checks).

  getSurroundLoop: function () {
    let block = this.getSurroundParent();
    do {
      if (loopTypes.has(block.type)) return block;
      block = block.getSurroundParent();
    } while (block);
    return null;
  },
}

Allgemeine Typen

Dieses System selbst unterstützt nicht die Definition generischer Typen. Sie können beispielsweise keinen Block „Identity“ erstellen, der die Eingabe „zurückgibt“.

Sie können dies etwas unterstützen, indem Sie die Verbindungsprüfung in der Ausgabe des Blocks aktiv an die Eingabe anpassen. Sie können das Ereignissystem verwenden, um Verschiebungsereignisse zu überwachen.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (e.type !== Blockly.Events.BlockMove) return;
    this.setOutput(
        true, this.getInputTargetBlock()?.outputConnection.getCheck());
  }
}

Wenn der verbundene Block jedoch auch generisch ist, funktioniert dies nicht richtig. Für diesen Fall gibt es keine geeignete Lösung.

Verbindungsprüfungen

Wenn dieses System für Ihren Anwendungsfall nicht funktioniert, können Sie auch eine benutzerdefinierte Verbindungsprüfung erstellen, um zu ändern, wie die Verbindungsprüfungen verglichen werden.

Wenn Sie beispielsweise ein komplexeres System erstellen möchten, das einige der Einschränkungen dieses Systems handhabt, können Sie eine benutzerdefinierte Verbindungsprüfung erstellen.