Blockly: Finalize API for developer variables

Created on 11 Jan 2018  路  4Comments  路  Source: google/blockly

After #1531 the developer can specify hidden variables on their blocks, called developer variables. Finalize the API for these.

variables

Most helpful comment

As a reminder, Python needs those variables to be declared global each time a user uses a Function block.

All 4 comments

The current use case is in the generator tests.

The unit test blocks all assume that the variable unittestResults exists and can be written to. To indicate this, the block definition includes the function getDeveloperVars, which returns an array of strings. Each string is a variable name.

Here's the block definition for the unittest_fail block:

Blockly.Blocks['unittest_fail'] = {
  // Always assert an error.
  init: function() {
    this.setColour(65);
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.appendDummyInput()
        .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE')
        .appendField('fail');
    this.setTooltip('Records an error.');
  },
  getDeveloperVars: function() {
    return ['unittestResults'];
  }
};

To use the variable in the generator, call getName on the variableDB_ with type Blockly.Names.DEVELOPER_VARIABLE_TYPE. Here's the unittest_fail generator for python:

Blockly.Python['unittest_fail'] = function(block) {
  // Always assert an error.
  var resultsVar = Blockly.Python.variableDB_.getName('unittestResults',
      Blockly.Names.DEVELOPER_VARIABLE_TYPE);
  var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE'));
  var functionName = Blockly.Python.provideFunction_(
      'fail',
      ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(message):',
       '  # Always assert an error.',
       '  if ' + resultsVar + ' == None:',
       '    raise Exception("Orphaned assert equals: " + message)',
       '  ' + resultsVar + '.append((False, "Fail.", message))']);
  return functionName + '(' + message + ')\n';
};

And the equivalent generator for JavaScript:

Blockly.JavaScript['unittest_fail'] = function(block) {
  // Always assert an error.
  var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults',
      Blockly.Names.DEVELOPER_VARIABLE_TYPE);
  var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE'));
  var functionName = Blockly.JavaScript.provideFunction_(
      'unittest_fail',
      [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ +
          '(message) {',
        '  // Always assert an error.',
        '  if (!' + resultsVar + ') {',
        '    throw "Orphaned assert fail: " + message;',
        '  }',
        '  ' + resultsVar + '.push([false, "Fail.", message]);',
        '}']);
  return functionName + '(' + message + ');\n';
};

Using Blockly.Names.DEVELOPER_VARIABLE_TYPE lets you avoid name conflicts (e.g. if the user declared a variable named unittestResults).

As a reminder, Python needs those variables to be declared global each time a user uses a Function block.

Currently if a user has a variable foo and a developer has a variable foo, the user variable keeps the name foo and the developer variable becomes foo2. That is, user variable names have priority.

Do we want developer names to have priority? We could accomplish that by swapping the order in which they are first declared in the generators: https://github.com/google/blockly/blob/develop/generators/python.js#L173

After discussion with @picklesrus I'm going to move the developer names to have priority. Our reasoning: if a user's variable gets renamed from foo to foo2 they may be confused, but if a developer is relying on the existence of foo and it turns out to be foo2, it could break all of the generated code in a way that the user cannot debug.

To avoid this whole set of problems, developers should choose variable names that are unlikely to have conflicts with user names.

I'll make this change in a separate PR from #1543. It shouldn't change anything if the developer variable names are unique.

Was this page helpful?
0 / 5 - 0 ratings