Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/lib/ruby-generator/looks.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ export default function (Generator) {
};

Generator.looks_gotofrontback = function (block) {
const frontBack = Generator.getFieldValue(block, 'FRONT_BACK') || 'front';
return `go_to_layer(:${frontBack})\n`;
const frontBack = Generator.quote_(Generator.getFieldValue(block, 'FRONT_BACK') || 'front');
return `go_to_layer(${frontBack})\n`;
};

Generator.looks_goforwardbackwardlayers = function (block) {
const layer = Generator.valueToCode(block, 'NUM', Generator.ORDER_NONE) || 0;
const forwardBackward = Generator.getFieldValue(block, 'FORWARD_BACKWARD') || 'forward';
return `go_layers(${layer}, :${forwardBackward})\n`;
const forwardBackward = Generator.quote_(Generator.getFieldValue(block, 'FORWARD_BACKWARD') || 'forward');
return `go_layers(${layer}, ${forwardBackward})\n`;
};

Generator.looks_costumenumbername = function (block) {
Expand All @@ -115,7 +115,7 @@ export default function (Generator) {

Generator.looks_switchbackdroptoandwait = function (block) {
const backdrop = Generator.valueToCode(block, 'BACKDROP', Generator.ORDER_NONE) || null;
return `switch_backdrop_to_and_wait(${backdrop})\n`;
return `switch_backdrop_and_wait(${backdrop})\n`;
};

return Generator;
Expand Down
12 changes: 7 additions & 5 deletions src/lib/ruby-to-blocks-converter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1330,7 +1330,8 @@ class RubyToBlocksConverter {
_onOpAsgn (node) {
this._checkNumChildren(node, 3);

const savedBlockIds = Object.keys(this._context.blocks);
const saved = this._saveContext();

const lh = this._process(node.children[0]);
const operator = node.children[1].toString();
const rh = this._process(node.children[2]);
Expand Down Expand Up @@ -1373,12 +1374,13 @@ class RubyToBlocksConverter {
}
}
}
if (!block) {
block = this._callConvertersHandler('onOpAsgn', lh, operator, rh);
}

if (!block) {
Object.keys(this._context.blocks).filter(i => savedBlockIds.indexOf(i) < 0)
.forEach(blockId => {
delete this._context.blocks[blockId];
});
this._restoreContext(saved);

block = this._createRubyStatementBlock(this._getSource(node));
}
return block;
Expand Down
153 changes: 149 additions & 4 deletions src/lib/ruby-to-blocks-converter/looks.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,169 @@
/* global Opal */
import _ from 'lodash';

/* eslint-disable no-invalid-this */
const createBlockWithMessage = function (opcode, message, defaultMessage) {
const block = this._createBlock(opcode, 'statement');
this._addTextInput(block, 'MESSAGE', _.isNumber(message) ? message.toString() : message, defaultMessage);
return block;
};

const Effects = [
'COLOR',
'FISHEYE',
'WHIRL',
'PIXELATE',
'MOSAIC',
'BRIGHTNESS',
'GHOST'
];

const FrontBack = [
'front',
'back'
];

const ForwardBackward = [
'forward',
'backward'
];
/* eslint-enable no-invalid-this */

/**
* Looks converter
*/
const LooksConverter = {
// eslint-disable-next-line no-unused-vars
onSend: function (receiver, name, args, rubyBlockArgs, rubyBlock) {
let block;
if (this._isSelf(receiver) || receiver === Opal.nil) {
if ((this._isSelf(receiver) || receiver === Opal.nil) && !rubyBlock) {
switch (name) {
case 'say':
if (args.length === 1 && this._isNumberOrStringOrBlock(args[0])) {
block = this._createBlock('looks_say', 'statement');
this._addTextInput(block, 'MESSAGE', _.isNumber(args[0]) ? args[0].toString() : args[0], 'Hello!');
case 'think':
if ((args.length === 1 && this._isNumberOrStringOrBlock(args[0])) ||
(args.length === 2 &&
this._isNumberOrStringOrBlock(args[0]) &&
this._isNumberOrBlock(args[1]))) {
let opcode;
let defaultMessage;
if (name === 'say') {
opcode = 'looks_say';
defaultMessage = 'Hello!';
} else {
opcode = 'looks_think';
defaultMessage = 'Hmm...';
}
block = createBlockWithMessage.call(this, opcode, args[0], defaultMessage);
if (args.length === 2) {
block.opcode += 'forsecs';
this._addNumberInput(block, 'SECS', 'math_number', args[1], 2);
}
}
break;
case 'switch_costume':
if (args.length === 1 && _.isString(args[0])) {
block = this._createBlock('looks_switchcostumeto', 'statement');
this._addInput(block, 'COSTUME', this._createFieldBlock('looks_costume', 'COSTUME', args[0]));
}
break;
case 'switch_backdrop':
if (args.length === 1 && _.isString(args[0])) {
block = this._createBlock('looks_switchbackdropto', 'statement');
this._addInput(block, 'BACKDROP', this._createFieldBlock('looks_backdrops', 'BACKDROP', args[0]));
}
break;
case 'switch_backdrop_and_wait':
if (args.length === 1 && _.isString(args[0])) {
block = this._createBlock('looks_switchbackdroptoandwait', 'statement');
this._addInput(block, 'BACKDROP', this._createFieldBlock('looks_backdrops', 'BACKDROP', args[0]));
}
break;
case 'size=':
if (args.length === 1 && this._isNumberOrBlock(args[0])) {
block = this._createBlock('looks_setsizeto', 'statement');
this._addNumberInput(block, 'SIZE', 'math_number', args[0], 100);
}
break;
case 'change_effect_by':
case 'set_effect':
if (args.length === 2 && _.isString(args[0]) && Effects.indexOf(args[0]) >= 0 &&
this._isNumberOrBlock(args[1])) {
let opcode;
let inputName;
if (name === 'change_effect_by') {
opcode = 'looks_changeeffectby';
inputName = 'CHANGE';
} else {
opcode = 'looks_seteffectto';
inputName = 'VALUE';
}
block = this._createBlock(opcode, 'statement');
this._addField(block, 'EFFECT', args[0]);
this._addNumberInput(block, inputName, 'math_number', args[1], 25);
}
break;
case 'go_to_layer':
if (args.length === 1 && _.isString(args[0]) && FrontBack.indexOf(args[0]) >= 0) {
block = this._createBlock('looks_gotofrontback', 'statement');
this._addField(block, 'FRONT_BACK', args[0]);
}
break;
case 'go_layers':
if (args.length === 2 && this._isNumberOrBlock(args[0]) && ForwardBackward.indexOf(args[1]) >= 0) {
block = this._createBlock('looks_goforwardbackwardlayers', 'statement');
this._addNumberInput(block, 'NUM', 'math_integer', args[0], 1);
this._addField(block, 'FORWARD_BACKWARD', args[1]);
}
break;
case 'costume_number':
case 'costume_name':
case 'backdrop_number':
case 'backdrop_name':
if (args.length === 0) {
const a = name.split('_');
block = this._createBlock(`looks_${a[0]}numbername`, 'value');
this._addField(block, 'NUMBER_NAME', a[1]);
}
break;
}
if (!block && args.length === 0) {
let opcode;
switch (name) {
case 'next_costume':
opcode = 'looks_nextcostume';
break;
case 'next_backdrop':
opcode = 'looks_nextbackdrop';
break;
case 'clear_graphic_effects':
opcode = 'looks_cleargraphiceffects';
break;
case 'show':
opcode = 'looks_show';
break;
case 'hide':
opcode = 'looks_hide';
break;
case 'size':
opcode = 'looks_size';
break;
}
if (opcode) {
block = this._createBlock(opcode, 'statement');
}
}
}
return block;
},

// eslint-disable-next-line no-unused-vars
onOpAsgn: function (lh, operator, rh) {
let block;
if (this._isBlock(lh) && lh.opcode === 'looks_size' && operator === '+' && this._isNumberOrBlock(rh)) {
block = this._changeBlock(lh, 'looks_changesizeby', 'statement');
this._addNumberInput(block, 'CHANGE', 'math_number', rh, 10);
}
return block;
}
};

Expand Down
50 changes: 49 additions & 1 deletion test/helpers/expect-to-equal-blocks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Blocks from 'scratch-vm/src/engine/blocks';
import Variable from 'scratch-vm/src/engine/variable';
import RubyToBlocksConverter from '../../src/lib/ruby-to-blocks-converter';

// for debug
const toJson = function (o) {
Expand Down Expand Up @@ -404,12 +405,59 @@ const expectedInfo = {
})
};

const expectNoArgsMethod = function (opcode, methodName) {
let converter;
let target;
let code;
let expected;

beforeEach(() => {
converter = new RubyToBlocksConverter(null);
target = null;
code = null;
expected = null;
});

describe(opcode, () => {
test('normal', () => {
code = methodName;
expected = [
{
opcode: opcode
}
];
convertAndExpectToEqualBlocks(converter, target, code, expected);

code = `${methodName}()`;
expected = [
{
opcode: opcode
}
];
convertAndExpectToEqualBlocks(converter, target, code, expected);
});

test('invalid', () => {
[
`${methodName}(false)`,
`${methodName}(true)`,
`${methodName}(1)`,
`${methodName}("backdrop2")`,
`${methodName}(x)`
].forEach(c => {
convertAndExpectToEqualRubyStatement(converter, target, c, c);
});
});
});
};

export {
toJson,
expectToEqualBlocks,
convertAndExpectToEqualBlocks,
expectToEqualRubyStatement,
convertAndExpectToEqualRubyStatement,
rubyToExpected,
expectedInfo
expectedInfo,
expectNoArgsMethod
};
Loading