Skip to content

Commit 6b6711a

Browse files
committed
feat: video sensing extension block
1 parent 99eccbe commit 6b6711a

File tree

5 files changed

+138
-38
lines changed

5 files changed

+138
-38
lines changed

src/lib/ruby-generator/video.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
export default function (Generator) {
77
Generator.videoSensing_whenMotionGreaterThan = function (block) {
88
block.isStatement = true;
9-
const rh = Generator.valueToCode(block, 'REFERENCE', Generator.ORDER_NONE) || 0;
10-
return `${Generator.spriteName()}.when(:video_motion_greater_than, ${rh}) do\n`;
9+
const reference = Generator.valueToCode(block, 'REFERENCE', Generator.ORDER_NONE) || 0;
10+
return `video_sensing.when_video_motion_greater_than(${reference}) do\n`;
1111
};
1212

1313
Generator.videoSensing_videoToggle = function (block) {
1414
const videoState = Generator.valueToCode(block, 'VIDEO_STATE', Generator.ORDER_NONE);
15-
return `video_turn(${videoState})\n`;
15+
return `video_sensing.video_turn(${videoState})\n`;
1616
};
1717

1818
Generator.videoSensing_menu_VIDEO_STATE = function (block) {
@@ -22,28 +22,23 @@ export default function (Generator) {
2222

2323
Generator.videoSensing_setVideoTransparency = function (block) {
2424
const transparency = Generator.valueToCode(block, 'TRANSPARENCY', Generator.ORDER_NONE) || 0;
25-
return `self.video_transparency = ${transparency}\n`;
25+
return `video_sensing.video_transparency = ${transparency}\n`;
2626
};
2727

2828
Generator.videoSensing_videoOn = function (block) {
2929
const attribute = Generator.valueToCode(block, 'ATTRIBUTE', Generator.ORDER_NONE);
3030
const subject = Generator.valueToCode(block, 'SUBJECT', Generator.ORDER_NONE);
31-
return [`${subject}video_${attribute}`, Generator.ORDER_ATOMIC];
31+
return [`video_sensing.video_on(${attribute}, ${subject})`, Generator.ORDER_ATOMIC];
3232
};
3333

3434
Generator.videoSensing_menu_ATTRIBUTE = function (block) {
35-
const attribute = Generator.getFieldValue(block, 'ATTRIBUTE') || 'motion';
35+
const attribute = Generator.quote_(Generator.getFieldValue(block, 'ATTRIBUTE') || 'motion');
3636
return [attribute, Generator.ORDER_ATOMIC];
3737
};
3838

3939
Generator.videoSensing_menu_SUBJECT = function (block) {
40-
const subject = Generator.getFieldValue(block, 'SUBJECT') || 'this sprite';
41-
if (subject === 'Stage') {
42-
return ['stage.', Generator.ORDER_ATOMIC];
43-
} else if (subject === 'this sprite') {
44-
return ['', Generator.ORDER_ATOMIC];
45-
}
46-
return [`${subject}.`, Generator.ORDER_ATOMIC];
40+
const subject = Generator.quote_(Generator.getFieldValue(block, 'SUBJECT') || 'this sprite');
41+
return [subject, Generator.ORDER_ATOMIC];
4742
};
4843

4944
return Generator;

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import SmalrubotS1Converter from './smalrubot_s1';
3030
import BoostConverter from './boost';
3131
import TranslateConverter from './translate';
3232
import MakeyMakeyConverter from './makeymakey';
33+
import VideoConverter from './video';
3334

3435
const messages = defineMessages({
3536
couldNotConvertPremitive: {
@@ -91,6 +92,7 @@ class RubyToBlocksConverter {
9192
SmalrubotS1Converter,
9293
BoostConverter,
9394
TranslateConverter,
95+
MakeyMakeyConverter,
9496

9597
MotionConverter,
9698
LooksConverter,
@@ -99,16 +101,16 @@ class RubyToBlocksConverter {
99101
SensingConverter,
100102
OperatorsConverter,
101103
VariablesConverter,
102-
MyBlocksConverter,
103-
MakeyMakeyConverter
104+
MyBlocksConverter
104105
];
105106
this._receiverToMethods = {};
106107
this.reset();
107108

108109
[
109110
EventConverter,
110111
ControlConverter,
111-
MicroBitConverter
112+
MicroBitConverter,
113+
VideoConverter
112114
].forEach(x => x.register(this));
113115
}
114116

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ const MicroBitConverter = {
2929
register: function (converter) {
3030
const createMicrobitBlock = node => converter.createRubyExpressionBlock(MicroBit, node);
3131

32-
converter.registerCallMethod('self', 'microbit', 0, params => {
32+
converter.registerCallMethod('self', MicroBit, 0, params => {
3333
const {node} = params;
3434

3535
return createMicrobitBlock(node);
3636
});
3737

38-
converter.registerCallMethodWithBlock('microbit', 'when_button_pressed', 1, 0, params => {
38+
converter.registerCallMethodWithBlock(MicroBit, 'when_button_pressed', 1, 0, params => {
3939
const {receiver, args, rubyBlock} = params;
4040

4141
if (!converter.isStringOrBlock(args[0])) return null;
@@ -47,7 +47,7 @@ const MicroBitConverter = {
4747
return block;
4848
});
4949

50-
converter.registerCallMethod('microbit', 'button_pressed?', 1, params => {
50+
converter.registerCallMethod(MicroBit, 'button_pressed?', 1, params => {
5151
const {receiver, args} = params;
5252

5353
if (!converter.isStringOrBlock(args[0])) return null;
@@ -58,7 +58,7 @@ const MicroBitConverter = {
5858
return block;
5959
});
6060

61-
converter.registerCallMethodWithBlock('microbit', 'when', 1, 0, params => {
61+
converter.registerCallMethodWithBlock(MicroBit, 'when', 1, 0, params => {
6262
const {receiver, args, rubyBlock} = params;
6363

6464
if (!converter.isStringOrBlock(args[0])) return null;
@@ -70,7 +70,7 @@ const MicroBitConverter = {
7070
return block;
7171
});
7272

73-
converter.registerCallMethod('microbit', 'display', 5, params => {
73+
converter.registerCallMethod(MicroBit, 'display', 5, params => {
7474
const {receiver, args} = params;
7575

7676
if (!args.every(x => converter.isString(x))) return null;
@@ -86,7 +86,7 @@ const MicroBitConverter = {
8686
return block;
8787
});
8888

89-
converter.registerCallMethod('microbit', 'display_text', 1, params => {
89+
converter.registerCallMethod(MicroBit, 'display_text', 1, params => {
9090
const {receiver, args} = params;
9191

9292
if (!converter.isStringOrBlock(args[0])) return null;
@@ -96,13 +96,13 @@ const MicroBitConverter = {
9696
return block;
9797
});
9898

99-
converter.registerCallMethod('microbit', 'clear_display', 0, params => {
99+
converter.registerCallMethod(MicroBit, 'clear_display', 0, params => {
100100
const {receiver} = params;
101101

102102
return converter.changeRubyExpressionBlock(receiver, 'microbit_displayClear', 'statement');
103103
});
104104

105-
converter.registerCallMethodWithBlock('microbit', 'when_tilted', 1, 0, params => {
105+
converter.registerCallMethodWithBlock(MicroBit, 'when_tilted', 1, 0, params => {
106106
const {receiver, args, rubyBlock} = params;
107107

108108
if (!converter.isStringOrBlock(args[0])) return null;
@@ -116,7 +116,7 @@ const MicroBitConverter = {
116116
return block;
117117
});
118118

119-
converter.registerCallMethod('microbit', 'tilted?', 1, params => {
119+
converter.registerCallMethod(MicroBit, 'tilted?', 1, params => {
120120
const {receiver, args} = params;
121121

122122
if (!converter.isStringOrBlock(args[0])) return null;
@@ -129,7 +129,7 @@ const MicroBitConverter = {
129129
return block;
130130
});
131131

132-
converter.registerCallMethod('microbit', 'tilt_angle', 1, params => {
132+
converter.registerCallMethod(MicroBit, 'tilt_angle', 1, params => {
133133
const {receiver, args} = params;
134134

135135
if (!converter.isStringOrBlock(args[0])) return null;
@@ -142,7 +142,7 @@ const MicroBitConverter = {
142142
return block;
143143
});
144144

145-
converter.registerCallMethodWithBlock('microbit', 'when_pin_connected', 1, 0, params => {
145+
converter.registerCallMethodWithBlock(MicroBit, 'when_pin_connected', 1, 0, params => {
146146
const {receiver, args, rubyBlock} = params;
147147

148148
if (!converter.isNumberOrBlock(args[0])) return null;
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import Primitive from './primitive';
2+
3+
const VideoSensing = 'video_sensing';
4+
5+
const SensingAttributeMenu = [
6+
'motion',
7+
'direction'
8+
];
9+
10+
const SensingSubjectMenu = [
11+
'Stage',
12+
'this sprite'
13+
];
14+
const SensingSubjectMenuLower = SensingSubjectMenu.map(x => x.toLowerCase());
15+
16+
const VideoStateMenu = [
17+
'off',
18+
'on',
19+
'on-flipped'
20+
];
21+
22+
/**
23+
* Video converter
24+
*/
25+
const VideoConverter = {
26+
register: function (converter) {
27+
converter.registerCallMethod('self', 'video_sensing', 0, params => {
28+
const {node} = params;
29+
30+
return converter.createRubyExpressionBlock(VideoSensing, node);
31+
});
32+
33+
converter.registerCallMethodWithBlock(VideoSensing, 'when_video_motion_greater_than', 1, 0, params => {
34+
const {receiver, args, rubyBlock} = params;
35+
36+
if (!converter.isNumberOrBlock(args[0])) return null;
37+
38+
const block = converter.changeRubyExpressionBlock(receiver, 'videoSensing_whenMotionGreaterThan', 'hat');
39+
converter.addNumberInput(block, 'REFERENCE', 'math_number', args[0], 10);
40+
converter.setParent(rubyBlock, block);
41+
return block;
42+
});
43+
44+
converter.registerCallMethod(VideoSensing, 'video_on', 2, params => {
45+
const {receiver, args} = params;
46+
47+
if (!converter.isStringOrBlock(args[0])) return null;
48+
if (converter.isString(args[0])) {
49+
const index = SensingAttributeMenu.indexOf(args[0].toString().toLowerCase());
50+
if (index < 0) return null;
51+
52+
args[0] = new Primitive('str', SensingAttributeMenu[index], args[0].node);
53+
}
54+
if (!converter.isStringOrBlock(args[1])) return null;
55+
if (converter.isString(args[1])) {
56+
const index = SensingSubjectMenuLower.indexOf(args[1].toString().toLowerCase());
57+
if (index < 0) return null;
58+
59+
args[1] = new Primitive('str', SensingSubjectMenu[index], args[1].node);
60+
}
61+
62+
const block = converter.changeRubyExpressionBlock(receiver, 'videoSensing_videoOn', 'value');
63+
converter.addFieldInput(
64+
block, 'ATTRIBUTE', 'videoSensing_menu_ATTRIBUTE', 'ATTRIBUTE', args[0], 'motion'
65+
);
66+
converter.addFieldInput(
67+
block, 'SUBJECT', 'videoSensing_menu_SUBJECT', 'SUBJECT', args[1], 'this sprite'
68+
);
69+
return block;
70+
});
71+
72+
converter.registerCallMethod(VideoSensing, 'video_turn', 1, params => {
73+
const {receiver, args} = params;
74+
75+
if (!converter.isStringOrBlock(args[0])) return null;
76+
if (converter.isString(args[0])) {
77+
const index = VideoStateMenu.indexOf(args[0].toString().toLowerCase());
78+
if (index < 0) return null;
79+
80+
args[0] = new Primitive('str', VideoStateMenu[index], args[0].node);
81+
}
82+
83+
const block = converter.changeRubyExpressionBlock(receiver, 'videoSensing_videoToggle', 'statement');
84+
converter.addFieldInput(
85+
block, 'VIDEO_STATE', 'videoSensing_menu_VIDEO_STATE', 'VIDEO_STATE', args[0], 'on'
86+
);
87+
return block;
88+
});
89+
90+
converter.registerCallMethod(VideoSensing, 'video_transparency=', 1, params => {
91+
const {receiver, args} = params;
92+
93+
if (!converter.isNumberOrBlock(args[0])) return null;
94+
95+
const block =
96+
converter.changeRubyExpressionBlock(receiver, 'videoSensing_setVideoTransparency', 'statement');
97+
converter.addNumberInput(block, 'TRANSPARENCY', 'math_number', args[0], 50);
98+
return block;
99+
});
100+
}
101+
};
102+
103+
export default VideoConverter;

test/integration/ruby-tab/extension_video_sensing.test.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,26 @@ describe('Ruby Tab: Video Sensing extension blocks', () => {
2525
await driver.quit();
2626
});
2727

28-
// not implemented Ruby to Code yet
29-
test.skip('Ruby -> Code -> Ruby', async () => {
28+
test('Ruby -> Code -> Ruby', async () => {
3029
await loadUri(urlFor('/'));
3130

3231
const code = dedent`
33-
self.when(:video_motion_greater_than, 10) do
32+
video_sensing.when_video_motion_greater_than(10) do
3433
end
3534
36-
video_motion
35+
video_sensing.when_video_motion_greater_than(x) do
36+
end
3737
38-
video_turn("on")
39-
video_turn("off")
40-
video_turn("on-flipped")
41-
self.video_transparency = 50
38+
video_sensing.video_on("motion", "this sprite")
4239
43-
video_direction
40+
video_sensing.video_on("direction", "this sprite")
4441
45-
stage.video_motion
42+
video_sensing.video_on("direction", "Stage")
4643
47-
stage.video_direction
44+
video_sensing.video_turn("on")
45+
video_sensing.video_turn("off")
46+
video_sensing.video_turn("on-flipped")
47+
video_sensing.video_transparency = 50
4848
`;
4949
await expectInterconvertBetweenCodeAndRuby(code);
5050
});

0 commit comments

Comments
 (0)