Skip to content

Commit 8964db7

Browse files
authored
Merge pull request #216 from smalruby/pen_block_to_ruby
Pen block to ruby
2 parents 2d4a6aa + 790975e commit 8964db7

File tree

3 files changed

+137
-21
lines changed

3 files changed

+137
-21
lines changed

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

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,28 @@ import SensingConverter from './sensing';
1717
import OperatorsConverter from './operators';
1818
import VariablesConverter from './variables';
1919
import MyBlocksConverter from './my-blocks';
20-
import MicroBitConverter from './microbit';
2120
import MusicConverter from './music';
21+
import PenConverter from './pen';
22+
import MicroBitConverter from './microbit';
2223
import EV3Converter from './ev3';
2324
import Wedo2Converter from './wedo2';
2425

26+
/* eslint-disable no-invalid-this */
27+
const ColorRegexp = /^#[0-9a-fA-F]{6}$/;
28+
2529
/**
2630
* Class for a block converter that translates ruby code into the blocks.
2731
*/
2832
class RubyToBlocksConverter {
2933
constructor (vm) {
3034
this.vm = vm;
3135
this._converters = [
36+
MusicConverter,
37+
PenConverter,
38+
MicroBitConverter,
39+
EV3Converter,
40+
Wedo2Converter,
41+
3242
MotionConverter,
3343
LooksConverter,
3444
SoundConverter,
@@ -37,11 +47,7 @@ class RubyToBlocksConverter {
3747
SensingConverter,
3848
OperatorsConverter,
3949
VariablesConverter,
40-
MyBlocksConverter,
41-
MicroBitConverter,
42-
MusicConverter,
43-
EV3Converter,
44-
Wedo2Converter
50+
MyBlocksConverter
4551
];
4652
this.reset();
4753
}
@@ -346,6 +352,10 @@ class RubyToBlocksConverter {
346352
return this._isNumber(block) || this._isString(block) || this._isValueBlock(block);
347353
}
348354

355+
_isColorOrBlock (colorOrBlock) {
356+
return this._isBlock(colorOrBlock) || (this._isString(colorOrBlock) && ColorRegexp.test(colorOrBlock));
357+
}
358+
349359
_isFalseOrBooleanBlock (block) {
350360
if (this._isFalse(block)) {
351361
return true;
@@ -371,6 +381,30 @@ class RubyToBlocksConverter {
371381
return /_variable$/.test(this._getBlockType(block));
372382
}
373383

384+
_isRubyExpression (block) {
385+
return this._isBlock(block) && block.opcode === 'ruby_expression';
386+
}
387+
388+
_getRubyExpression (block) {
389+
if (this._isRubyExpression(block)) {
390+
const textBlock = this._context.blocks[block.inputs.EXPRESSION.block];
391+
return textBlock.fields.TEXT.value;
392+
}
393+
return null;
394+
}
395+
396+
_isRubyStatement (block) {
397+
return this._isBlock(block) && block.opcode === 'ruby_statement';
398+
}
399+
400+
_getRubyStatement (block) {
401+
if (this._isRubyStatement(block)) {
402+
const textBlock = this._context.blocks[block.inputs.STATEMENT.block];
403+
return textBlock.fields.TEXT.value;
404+
}
405+
return null;
406+
}
407+
374408
_createBlock (opcode, type, attributes = {}) {
375409
const block = Object.assign({
376410
id: Blockly.utils.genUid(),
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* global Opal */
2+
import _ from 'lodash';
3+
4+
/**
5+
* Pen converter
6+
*/
7+
const PenConverter = {
8+
onSend: function (receiver, name, args, rubyBlockArgs, rubyBlock) {
9+
let block;
10+
if ((this._isSelf(receiver) || receiver === Opal.nil) && !rubyBlock) {
11+
switch (name) {
12+
case 'pen_clear':
13+
if (args.length === 0) {
14+
block = this._createBlock('pen_clear', 'statement');
15+
}
16+
break;
17+
case 'pen_stamp':
18+
if (args.length === 0) {
19+
block = this._createBlock('pen_stamp', 'statement');
20+
}
21+
break;
22+
case 'pen_down':
23+
if (args.length === 0) {
24+
block = this._createBlock('pen_penDown', 'statement');
25+
}
26+
break;
27+
case 'pen_up':
28+
if (args.length === 0) {
29+
block = this._createBlock('pen_penUp', 'statement');
30+
}
31+
break;
32+
case 'pen_color=':
33+
if (args.length === 1 && this._isColorOrBlock(args[0])) {
34+
block = this._createBlock('pen_setPenColorToColor', 'statement');
35+
this._addFieldInput(block, 'COLOR', 'colour_picker', 'COLOUR', args[0], '#43066f');
36+
}
37+
break;
38+
case 'color=':
39+
case 'saturation=':
40+
case 'brightness=':
41+
case 'transparency=':
42+
if (args.length === 1 && this._isNumberOrBlock(args[0])) {
43+
block = this._createBlock('pen_setPenColorParamTo', 'statement');
44+
this._addFieldInput(
45+
block, 'COLOR_PARAM', 'pen_menu_colorParam', 'colorParam',
46+
name.replace('=', ''), 'color'
47+
);
48+
this._addNumberInput(block, 'VALUE', 'math_number', args[0], 50);
49+
}
50+
break;
51+
case 'pen_size=':
52+
if (args.length === 1 && this._isNumberOrBlock(args[0])) {
53+
block = this._createBlock('pen_setPenSizeTo', 'statement');
54+
this._addNumberInput(block, 'SIZE', 'math_number', args[0], 1);
55+
}
56+
break;
57+
}
58+
}
59+
return block;
60+
},
61+
62+
// eslint-disable-next-line no-unused-vars
63+
onOpAsgn: function (lh, operator, rh) {
64+
let block;
65+
if (this._isRubyStatement(lh) && operator === '+' && this._isNumberOrBlock(rh)) {
66+
const code = this._getRubyStatement(lh);
67+
switch (code) {
68+
case 'self.pen_size':
69+
block = this._changeBlock(lh, 'pen_changePenSizeBy', 'statement');
70+
this._addNumberInput(block, 'SIZE', 'math_number', rh, 1);
71+
break;
72+
case 'self.color':
73+
case 'self.saturation':
74+
case 'self.brightness':
75+
case 'self.transparency':
76+
block = this._changeBlock(lh, 'pen_changePenColorParamBy', 'statement');
77+
this._addFieldInput(
78+
block, 'COLOR_PARAM', 'pen_menu_colorParam', 'colorParam',
79+
code.replace('self.', ''), 'color'
80+
);
81+
this._addNumberInput(block, 'VALUE', 'math_number', rh, 10);
82+
break;
83+
}
84+
}
85+
return block;
86+
}
87+
};
88+
89+
export default PenConverter;

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

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
import _ from 'lodash';
33
import {KeyOptions} from './constants';
44

5-
/* eslint-disable no-invalid-this */
6-
const ColorRegexp = /^#[0-9a-fA-F]{6}$/;
7-
85
const DragMode = [
96
'draggable',
107
'not draggable'
@@ -17,12 +14,11 @@ const spriteCall = function (name) {
1714
return `sprite("${name.toString()}")`;
1815
};
1916
const SpriteCallRe = /^sprite\("(.*)"\)$/;
20-
const getSpriteName = function (block) {
21-
if (!this._isBlock(block) || block.opcode !== 'ruby_expression') {
22-
return null;
17+
const getSpriteName = function (code) {
18+
if (code !== null) {
19+
return SpriteCallRe.exec(code)[1];
2320
}
24-
const textBlock = this._context.blocks[block.inputs.EXPRESSION.block];
25-
return SpriteCallRe.exec(textBlock.fields.TEXT.value)[1];
21+
return null;
2622
};
2723

2824
const Stage = 'stage';
@@ -47,16 +43,13 @@ const SensingConverter = {
4743
}
4844
break;
4945
case 'touching_color?':
50-
if (args.length === 1 &&
51-
(this._isBlock(args[0]) || (this._isString(args[0]) && ColorRegexp.test(args[0].toString())))) {
46+
if (args.length === 1 && this._isColorOrBlock(args[0])) {
5247
block = this._createBlock('sensing_touchingcolor', 'value_boolean');
5348
this._addFieldInput(block, 'COLOR', 'colour_picker', 'COLOUR', args[0], '#43066f');
5449
}
5550
break;
5651
case 'color_is_touching_color?':
57-
if (args.length === 2 &&
58-
(this._isBlock(args[0]) || (this._isString(args[0]) && ColorRegexp.test(args[0].toString()))) &&
59-
(this._isBlock(args[1]) || (this._isString(args[1]) && ColorRegexp.test(args[1].toString())))) {
52+
if (args.length === 2 && this._isColorOrBlock(args[0]) && this._isColorOrBlock(args[1])) {
6053
block = this._createBlock('sensing_coloristouchingcolor', 'value_boolean');
6154
this._addFieldInput(block, 'COLOR', 'colour_picker', 'COLOUR', args[0], '#aad315');
6255
this._addFieldInput(block, 'COLOR2', 'colour_picker', 'COLOUR', args[1], '#fca3bf');
@@ -248,7 +241,7 @@ const SensingConverter = {
248241
break;
249242
}
250243
if (property) {
251-
const spriteName = getSpriteName.call(this, receiver);
244+
const spriteName = getSpriteName(this._getRubyExpression(receiver));
252245

253246
block = this._changeBlock(receiver, 'sensing_of', 'value');
254247
delete this._context.blocks[receiver.inputs.EXPRESSION.block];
@@ -258,7 +251,7 @@ const SensingConverter = {
258251
this._addFieldInput(block, 'OBJECT', 'sensing_of_object_menu', 'OBJECT', spriteName);
259252
}
260253
} else if (args.length === 1 && name === 'variable' && this._isString(args[0])) {
261-
const spriteName = getSpriteName.call(this, receiver);
254+
const spriteName = getSpriteName(this._getRubyExpression(receiver));
262255

263256
block = this._changeBlock(receiver, 'sensing_of', 'value');
264257
delete this._context.blocks[receiver.inputs.EXPRESSION.block];

0 commit comments

Comments
 (0)