Skip to content

Commit af79e19

Browse files
committed
aliasing, repeat(times) { } as control_repeat.
1 parent 7c82b1a commit af79e19

File tree

3 files changed

+129
-4
lines changed

3 files changed

+129
-4
lines changed

src/lib/ruby-to-blocks-converter/control.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
/* global Opal */
22

3+
/* eslint-disable no-invalid-this */
4+
const createControlRepeatBlock = function (times, body) {
5+
const block = this._createBlock('control_repeat', 'statement');
6+
this._addNumberInput(block, 'TIMES', 'math_whole_number', times, 10);
7+
this._addSubstack(block, body);
8+
return block;
9+
};
10+
/* eslint-enable no-invalid-this */
11+
312
/**
413
* Control converter
514
*/
@@ -15,6 +24,12 @@ const ControlConverter = {
1524
this._addNumberInput(block, 'DURATION', 'math_positive_number', args[0], 1);
1625
}
1726
break;
27+
case 'repeat':
28+
if (args.length === 1 && this._isNumberOrBlock(args[0]) &&
29+
rubyBlockArgs && rubyBlockArgs.length === 0) {
30+
block = createControlRepeatBlock.call(this, args[0], rubyBlock);
31+
}
32+
break;
1833
}
1934
} else if (this._isNumberOrBlock(receiver)) {
2035
switch (name) {
@@ -24,9 +39,7 @@ const ControlConverter = {
2439
rubyBlock && rubyBlock.length >= 1) {
2540
const waitBlock = this._popWaitBlock(rubyBlock);
2641
if (waitBlock) {
27-
block = this._createBlock('control_repeat', 'statement');
28-
this._addNumberInput(block, 'TIMES', 'math_whole_number', receiver, 10);
29-
this._addSubstack(block, rubyBlock);
42+
block = createControlRepeatBlock.call(this, receiver, rubyBlock);
3043
}
3144
}
3245
break;

src/lib/ruby-to-blocks-converter/index.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,15 @@ class RubyToBlocksConverter {
581581
let prevBlock = null;
582582
const blocks = [];
583583
let terminated = false;
584+
let firstBlock;
584585
node.children.forEach(childNode => {
585586
const block = this._process(childNode);
586587
if (!block) {
587588
return;
588589
}
590+
if (!firstBlock) {
591+
firstBlock = block;
592+
}
589593
switch (this._getBlockType(block)) {
590594
case 'statement':
591595
if (prevBlock) {
@@ -616,6 +620,12 @@ class RubyToBlocksConverter {
616620
break;
617621
}
618622
});
623+
if (blocks.length === 0 && firstBlock) {
624+
if (/^value/.test(this._getBlockType(firstBlock))) {
625+
firstBlock.topLevel = false;
626+
}
627+
blocks.push(firstBlock);
628+
}
619629
return blocks;
620630
}
621631

@@ -628,7 +638,10 @@ class RubyToBlocksConverter {
628638
_onSend (node, rubyBlockArgsNode, rubyBlockNode) {
629639
const saved = this._saveContext();
630640

631-
const receiver = this._process(node.children[0]);
641+
let receiver = this._process(node.children[0]);
642+
if (_.isArray(receiver) && receiver.length === 1) {
643+
receiver = receiver[0];
644+
}
632645
const name = node.children[1].toString();
633646
const args = node.children.slice(2).map(childNode => this._process(childNode));
634647

test/unit/lib/ruby-to-blocks-converter/control.test.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,105 @@ describe('RubyToBlocksConverter/Control', () => {
182182
expect(res).toBeTruthy();
183183
});
184184
});
185+
186+
describe('repeat', () => {
187+
test('number', () => {
188+
code = 'repeat(10) { move(10) }';
189+
expected = [
190+
{
191+
opcode: 'control_repeat',
192+
inputs: [
193+
{
194+
name: 'TIMES',
195+
block: expectedInfo.makeNumber(10, 'math_whole_number')
196+
}
197+
],
198+
branches: [
199+
rubyToExpected(converter, target, 'move(10)')[0]
200+
]
201+
}
202+
];
203+
convertAndExpectToEqualBlocks(converter, target, code, expected);
204+
205+
code = 'repeat(10) { move(10); bounce_if_on_edge }';
206+
expected = [
207+
{
208+
opcode: 'control_repeat',
209+
inputs: [
210+
{
211+
name: 'TIMES',
212+
block: expectedInfo.makeNumber(10, 'math_whole_number')
213+
}
214+
],
215+
branches: [
216+
rubyToExpected(converter, target, 'move(10); bounce_if_on_edge')[0]
217+
]
218+
}
219+
];
220+
convertAndExpectToEqualBlocks(converter, target, code, expected);
221+
});
222+
223+
test('value block', () => {
224+
code = 'repeat(x) { move(10) }';
225+
expected = [
226+
{
227+
opcode: 'control_repeat',
228+
inputs: [
229+
{
230+
name: 'TIMES',
231+
block: rubyToExpected(converter, target, 'x')[0],
232+
shadow: expectedInfo.makeNumber(10, 'math_whole_number')
233+
}
234+
],
235+
branches: [
236+
rubyToExpected(converter, target, 'move(10)')[0]
237+
]
238+
}
239+
];
240+
convertAndExpectToEqualBlocks(converter, target, code, expected);
241+
});
242+
243+
test('boolean block', () => {
244+
code = 'repeat(touching?("_edge_")) { move(10) }';
245+
expected = [
246+
{
247+
opcode: 'control_repeat',
248+
inputs: [
249+
{
250+
name: 'TIMES',
251+
block: rubyToExpected(converter, target, 'touching?("_edge_")')[0],
252+
shadow: expectedInfo.makeNumber(10, 'math_whole_number')
253+
}
254+
],
255+
branches: [
256+
rubyToExpected(converter, target, 'move(10)')[0]
257+
]
258+
}
259+
];
260+
convertAndExpectToEqualBlocks(converter, target, code, expected);
261+
});
262+
263+
test('invalid', () => {
264+
[
265+
'repeat(10)',
266+
'repeat(10, 1)'
267+
].forEach(c => {
268+
convertAndExpectToEqualRubyStatement(converter, target, c, c);
269+
});
270+
271+
[
272+
'repeat(10) { |i| }',
273+
'repeat("10") { }'
274+
].forEach(c => {
275+
const res = converter.targetCodeToBlocks(target, c);
276+
expect(converter.errors).toHaveLength(0);
277+
const scriptIds = Object.keys(converter.blocks).filter(id => converter.blocks[id].topLevel);
278+
expect(scriptIds).toHaveLength(1);
279+
expect(converter.blocks[scriptIds[0]]).toHaveProperty('opcode', 'ruby_statement_with_block');
280+
expect(res).toBeTruthy();
281+
});
282+
});
283+
});
185284
});
186285

187286
test('control_forever', () => {

0 commit comments

Comments
 (0)