Проверка соединения

Проверки соединений ограничивают, какие соединения (и, следовательно, блоки) могут соединяться друг с другом.

Проверки соединений полезны для типов моделирования. Например, следующие три блока не имеют никакой связи между собой, поскольку они представляют собой код, возвращающий разные типы:

Пустой блок списка, соединенный с блоком квадратного корня, соединенным с блоком верхнего регистра.

Проверки соединений можно использовать для предотвращения соединения этих блоков. Это дает пользователям мгновенную обратную связь и предотвращает множество простых ошибок.

Как они работают

Каждое соединение может быть связано с «проверкой соединения», которая представляет собой массив строк, допускающий значение NULL.

Два соединения могут соединиться, если:

  1. Это совместимые типы (например, выход, соединяющийся со входом).
  2. У них есть хотя бы одна общая строка в проверке соединения.

Например, следующие две проверки могут быть связаны, поскольку они имеют общую строку 'apple' :

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

Но эти две проверки не удалось соединить, поскольку они не имеют общих строк:

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

Есть еще один особый случай. Если любой из массивов имеет значение null , то два соединения также могут соединяться. Это позволяет вам определять соединения, которые могут подключаться к чему угодно.

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

Установить проверки

По умолчанию все соединения имеют null проверку соединения, что означает, что они могут подключаться к чему угодно. Проверки подключения необходимо назначать вручную.

Способ назначения проверок соединений соединениям зависит от того, используете ли вы определения блоков JSON или определения блоков JavaScript.

JSON

Для соединений верхнего уровня вы назначаете проверку непосредственно свойству, определяющему соединение. Назначаемое вами значение может быть null , строкой (которая становится единственной записью при проверке соединения) или массивом строк.

{
  'type': 'custom_block',

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

Для входных данных вы можете назначить проверку свойству check определения входных данных. Если свойство check не существует, проверка считается null . Назначаемое вами значение может быть строкой или массивом строк.

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

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

JavaScript

Для соединений верхнего уровня вы можете передать проверку непосредственно методу, определяющему соединение. Если вы не передадите значение, проверка считается null . Передаваемое вами значение может быть строкой (которая становится единственной записью при проверке соединения) или массивом строк.

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

Для входных данных вы можете передать проверку методу setCheck после того, как вы определили входные данные. Если метод setCheck не вызывается, проверка считается null . Значение, которое вы передаете, может быть строкой или массивом строк.

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

Встроенные проверочные строки

Встроенные блоки имеют проверки соединения со значениями 'Array' , 'Boolean' , 'Colour' , 'Number' и 'String' . Если вы хотите, чтобы ваши блоки взаимодействовали со встроенными блоками, вы можете использовать эти значения, чтобы сделать их совместимыми.

Примеры значений

Когда вы определяете проверки соединений для входов и выходов, обычно вам следует думать о проверках как о представлении типов.

Проверки входов должны включать каждый «тип», который они принимают, а проверки выходов должны включать именно то, что они «возвращают».

Принять один тип

В самом простом случае, когда вы хотите создать блок, который «принимает» или «возвращает» один тип, вам необходимо включить этот тип в проверку соединения соединения.

блок значений, который принимает один тип

Принять несколько типов

Чтобы создать блок, который «принимает» несколько типов, вам необходимо включить каждый принятый тип во входную проверку соединения.

блок значений, который принимает несколько типов

По соглашению, если выходные данные иногда могут быть приняты в нескольких ситуациях (например, если вы разрешаете иногда использовать числа в качестве строк), выходные данные должны быть более ограничительными, а входные данные должны быть более разрешающими. Это соглашение гарантирует, что выходы не подключаются там, где они не поддерживаются.

Примите любой тип

Чтобы создать блок, который «принимает» любой тип, вам нужно установить проверку соединения входа на null .

блок значений, который принимает любой тип

Подтипы возврата

Чтобы создать блок, который «возвращает» подтип, вам необходимо включить и тип, и супертип в проверку соединения вывода.

блок значений, который возвращает его тип и супертип

В случае с подтипами можно иметь несколько проверок при проверке вывода, поскольку блок всегда «возвращает» оба типа.

Возвращать параметризованные типы

Чтобы создать блок, который «возвращает» параметризованный тип, вам необходимо включить как параметризованную, так и непараметризованную версию в проверку выходного соединения.

В зависимости от того, насколько строгим вы хотите, чтобы ваш язык блоков был, вы также можете включить дисперсию(и) типа.

блок значений, который возвращает его параметризованный тип и его непараметризованный тип

Как и в случае с подтипами, в этом случае можно иметь несколько проверок при проверке вывода, потому что блок всегда «возвращает» оба типа.

Примеры стека или операторов

Существует несколько распространенных способов, которыми разработчики определяют проверки предыдущих и следующих соединений. Обычно вы думаете об этом как об ограничении порядка блоков.

Следующие соединения должны включать информацию о том, какие блоки должны следовать за текущим, а предыдущие соединения должны включать информацию о том, что представляет собой текущий блок.

Держите блоки в порядке

Чтобы создать набор блоков, которые соединяются в определенном порядке, вам необходимо указать, какие блоки должны следовать за текущим при следующей проверке соединения и что представляет собой текущий блок при предыдущей проверке соединения.

блоки операторов с принудительным порядком

Разрешить много средних блоков

Чтобы создать набор упорядоченных блоков, допускающий множество средних блоков, вам необходимо включить хотя бы одну запись из предыдущей проверки соединения среднего блока в следующую проверку соединения среднего блока. Это позволяет за блоком следовать самому себе.

блоки операторов, допускающие множество средних блоков

Не разрешать средние блоки

Чтобы создать набор упорядоченных блоков, в котором средние блоки являются необязательными, вам необходимо включить по крайней мере одну запись как из предыдущей проверки соединения среднего блока, так и из предыдущей проверки соединения последнего блока в следующую проверку соединения первого блока. Это позволяет после первого блока следовать либо среднему блоку, либо последнему блоку.

блоки операторов, которые не допускают средних блоков

Либо-или складывается

Чтобы создать блок, за которым могут следовать только блоки из одной группы или блоки из другой (а не оба), вам нужно сделать две вещи:

  1. Вам необходимо включить хотя бы одну запись из обеих групп предыдущих проверок соединения в следующую проверку соединения первого блока.

  2. Вам необходимо определить следующие проверки соединения групп, чтобы они включали только те значения, которые были в их предыдущих проверках соединения (чтобы за ними могли следовать только блоки той же группы).

блоки операторов, за которыми может следовать несколько блоков одного типа или несколько блоков другого типа, но не оба сразу

Ограничения

Эта система довольно надежна и может решить множество вариантов использования, но у нее есть несколько ограничений.

Ограничить более широкий контекст

Эта система сама по себе не поддерживает ограничение «большого контекста», в котором разрешено соединение. Например, вы не можете сказать, что блоку break разрешено существовать только внутри блока loop . Система проверки соединения учитывает только два подключенных соединения.

Вы можете поддержать это, используя систему событий , чтобы прослушивать события перемещения блока и проверять, не расположен ли блок неправильно.

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

Общие типы

Эта система сама по себе не поддерживает определение универсальных типов. Например, вы не можете создать блок «Идентификация», который «возвращает» любые входные данные.

Вы можете в некоторой степени поддержать это, активно изменяя проверку соединения на выходе блока, чтобы она соответствовала его входу. Что вы можете сделать, используя систему событий для прослушивания событий перемещения блока.

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

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

Но если подключенный блок также является универсальным, это работает неправильно. В этом случае нет хорошего решения.

Проверка соединений

Если эта система не подходит для вашего варианта использования, вы также можете изменить способ сравнения проверок соединений, создав собственную программу проверки соединений .

Например, если вы хотите создать более продвинутую систему, которая учитывает некоторые ограничения этой системы, вы можете создать собственную программу проверки соединений.