Verificações de conexão

As verificações de conexão restringem quais conexões (e, portanto, blocos) podem se conectar entre si.

As verificações de conexão são úteis para tipos de modelagem. Por exemplo, os três blocos a seguir não têm empresas conectadas, porque representam códigos que retornam tipos diferentes:

Um bloco de lista vazia, conectado a um bloco raiz quadrada, conectado a um
bloco de letras maiúsculas.

As verificações de conexão podem ser usadas para impedir a conexão desses blocos. Isso dá aos usuários feedback instantâneo e evita muitos erros simples.

Como funcionam

Toda conexão pode ser associada a uma "verificação de conexão", que é uma matriz de strings anuláveis.

Duas conexões podem se conectar se:

  1. Eles são tipos compatíveis (por exemplo, uma saída que se conecta a uma entrada).
  2. Elas têm pelo menos uma string em comum na verificação de conexão.

Por exemplo, as duas verificações a seguir podem se conectar porque compartilham a string 'apple':

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

No entanto, não foi possível conectar essas duas verificações porque elas não compartilham nenhuma string:

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

Há outro caso especial. Se uma das matrizes for null, as duas conexões também poderão se conectar. Isso permite definir conexões que podem se conectar a qualquer coisa.

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

Definir verificações

Por padrão, todas as conexões têm uma verificação de conexão null, o que significa que elas podem se conectar a qualquer coisa. As verificações de conexão precisam ser atribuídas manualmente.

A maneira como você atribui verificações de conexão às conexões varia caso você esteja usando definições de bloco JSON ou JavaScript.

JSON

Para conexões de nível superior, você atribui a verificação diretamente à propriedade que define a conexão. O valor atribuído pode ser null, uma string (que se torna a única entrada na verificação de conexão) ou uma matriz de strings.

{
  'type': 'custom_block',

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

Para entradas, é possível atribuir a verificação a uma propriedade check da definição de entrada. Se a propriedade check não existir, a verificação será considerada null. O valor atribuído pode ser uma string ou uma matriz de strings.

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

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

JavaScript

Para conexões de nível superior, você pode passar a verificação diretamente para o método que define a conexão. Se você não transmitir um valor, a verificação será considerada null. O valor transmitido pode ser uma string (que se torna a única entrada na verificação de conexão) ou uma matriz de strings.

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']);
  }
}

Para entradas, é possível passar a verificação para o método setCheck, depois de ter definido a entrada. Se o método setCheck não for chamado, a verificação será considerada null. O valor transmitido pode ser uma string ou uma matriz de strings.

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

Strings de verificação integradas

Os blocos integrados têm verificações de conexão com os valores 'Array', 'Boolean', 'Colour', 'Number' e 'String'. Se você quiser que os blocos interoperem com os integrados, use esses valores para torná-los compatíveis.

Exemplos de valor

Ao definir verificações de conexão para entradas e saídas, considere as verificações como tipos.

As verificações de entradas precisam incluir todos os "tipos" que elas aceitam, e as verificações das saídas precisam incluir exatamente o que elas "retornam".

Aceitar um único tipo

No caso mais básico em que você quer criar um bloco que "aceita" ou "retorna" um tipo, é necessário incluir esse tipo na verificação de conexão da conexão.

um bloco de valor que aceita um único tipo

Aceitar vários tipos

Para criar um bloco que "aceite" vários tipos, você precisa incluir todos os tipos aceitos na verificação de conexão da entrada.

um bloco de valor que aceita vários tipos

Por convenção, se uma saída às vezes puder ser aceita em diversas situações (por exemplo, se você permitir que números às vezes sejam usados como strings), a saída precisará ser mais restritiva, e as entradas precisarão ser mais permissivas. Essa convenção garante que as saídas não se conectem em locais incompatíveis.

Aceitar qualquer tipo

Para criar um bloco que "aceite" qualquer tipo, é necessário definir a verificação de conexão da entrada como null.

um bloco de valor que aceita qualquer tipo

Retornar subtipos

Para criar um bloco que "retorna" um subtipo, é necessário incluir o tipo e o supertipo na verificação de conexão da saída.

um bloco de valor que retorna seu tipo e seu supertipo

No caso de subtipos, não há problema em ter várias verificações em uma verificação de saída, porque o bloco sempre "retorna" os dois tipos.

Tipos parametrizados de retorno

Para criar um bloco que "retorna" um tipo parametrizado, é preciso incluir a versão parametrizada e a não parametrizada na verificação de conexão da saída.

Dependendo do quanto você quer que o idioma do bloco seja rigoroso, também é possível incluir as variações do tipo.

um bloco de valor que retorna os tipos parametrizados e não parametrizados

Assim como com os subtipos, não há problema em ter várias verificações em uma verificação de saída nesse caso, porque o bloco sempre "retorna" os dois tipos.

Exemplos de pilha ou instrução

Há algumas maneiras comuns de os desenvolvedores definirem verificações para conexões anteriores e próximas. Normalmente, você avalia isso como uma restrição na ordem dos blocos.

As próximas conexões precisam incluir os blocos que devem seguir o atual, e as conexões anteriores incluem o que o bloco atual "é".

Manter os blocos em ordem

Para criar um conjunto de blocos que se conectam em uma ordem definida, você precisa incluir quais blocos precisam seguir o atual na próxima verificação de conexão e qual é o bloco atual "é" na verificação de conexão anterior.

blocos de instrução que têm uma ordem forçada

Permitir muitos bloqueios no meio

Para criar um conjunto de blocos ordenados que permitem muitos blocos do meio, você precisa incluir pelo menos uma entrada da verificação de conexão anterior do bloco do meio na próxima verificação de conexão do bloco do meio. Isso permite que o bloco seja seguido por mais de si mesmo.

de instrução que permitem vários blocos no meio

Não permitir bloqueios no meio

Para criar um conjunto de blocos ordenados em que os blocos do meio são opcionais, é necessário incluir pelo menos uma entrada da verificação de conexão anterior do bloco do meio e da verificação de conexão anterior do último bloco na próxima verificação de conexão do primeiro bloco. Isso permite que o primeiro bloco seja seguido por um bloco do meio ou um último bloco.

blocos de instrução que não permitem blocos no meio

Uma ou pilhas

Para criar um bloco que só pode ser seguido por bloqueios de um grupo ou bloqueios de outro (e não ambos), você precisa fazer duas coisas:

  1. É necessário incluir pelo menos uma entrada de ambas as verificações de conexão anteriores do grupo na próxima verificação de conexão do primeiro bloco.

  2. É necessário definir as próximas verificações de conexão dos grupos para incluir apenas os valores que estão nas verificações de conexão anteriores (para que eles só possam ser seguidos por blocos do mesmo grupo).

blocos de instrução que podem ser seguidos por vários de um tipo de bloco ou
vários de outro, mas não por ambos

Limitações

Esse sistema é bastante robusto e pode resolver muitos casos de uso, mas tem algumas limitações.

Restringir o contexto maior

Esse sistema, por si só, não oferece suporte à restrição de "maior contexto" em que uma conexão pode se conectar. Por exemplo, não é possível dizer que um bloco break só pode existir dentro de um bloco loop. O sistema de verificação de conexão considera apenas as duas conexões imediatas.

É possível oferecer suporte a isso usando o sistema de eventos para detectar eventos de movimento do bloco e verificar se o bloco está posicionado incorretamente.

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;
  },
}

Tipos genéricos

Esse sistema, por si só, não oferece suporte à definição de tipos genéricos. Por exemplo, não é possível criar um bloco "Identidade", que "retorna" qualquer que seja a entrada.

Você pode oferecer suporte de certa forma mudando ativamente a verificação de conexão na saída do bloco para corresponder à entrada. Isso pode ser feito usando o sistema de eventos para detectar eventos de movimentação.

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

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

No entanto, se o bloco conectado também for genérico, isso não vai funcionar corretamente. Não há uma solução alternativa para esse caso.

Verificadores de conexão

Se esse sistema não funcionar para seu caso de uso, também será possível alterar como as verificações de conexão são comparadas criando um verificador de conexão personalizado.

Por exemplo, se você quiser criar um sistema mais avançado que gerencie algumas limitações dessa atual, crie um verificador de conexão personalizado.