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
157 changes: 102 additions & 55 deletions src/lib/ruby-generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,40 @@ export default function (Blockly) {
}
}
this.defineSprite(this.editingTarget);
this.defineVariables(this.editingTarget);
};

Blockly.Ruby.isString = function (s) {
return (typeof s === 'string' || s instanceof String);
};

Blockly.Ruby.scalarToCode = function (scalar) {
if (this.isString(scalar)) {
return this.quote_(scalar);
}
return scalar;
};

Blockly.Ruby.listToCode = function (list) {
const values = list.map(i => {
if (this.isString(i)) {
return this.quote_(i);
}
return i;
}).join(', ');
return `[${values}]`;
};

Blockly.Ruby.hashToCode = function (hash, separator = ': ', brace = true) {
const lines = [];
for (const key in hash) {
const value = hash[key];
lines.push(`${key}${separator}${value}`);
}
let code = lines.join(',\n');
if (brace) {
code = ['{', this.prefixLines(code, this.INDENT), '}'].join('\n');
}
return code;
};

Blockly.Ruby.defineSprite = function (renderedTarget) {
Expand All @@ -115,83 +148,97 @@ export default function (Blockly) {
const definitionsId = `sprite_${name}`;

if (!this.definitions_.hasOwnProperty(definitionsId)) {
const attributes = [''];
const attributes = {};

if (renderedTarget.x !== 0) {
attributes.push(`x: ${renderedTarget.x}`);
attributes.x = renderedTarget.x;
}
if (renderedTarget.y !== 0) {
attributes.push(`y: ${renderedTarget.y}`);
attributes.y = renderedTarget.y;
}
if (renderedTarget.direction !== 90) {
attributes.push(`direction: ${renderedTarget.direction}`);
attributes.direction = renderedTarget.direction;
}
if (!renderedTarget.visible) {
attributes.push(`visible: ${!!renderedTarget.visible}`);
attributes.visible = !!renderedTarget.visible;
}
if (renderedTarget.size !== 100) {
attributes.push(`size: ${renderedTarget.size}`);
attributes.size = renderedTarget.size;
}
if (renderedTarget.currentCostume > 1) {
attributes.push(`current_costume: ${renderedTarget.currentCostume - 1}`);
attributes.current_costume = renderedTarget.currentCostume - 1;
}
if (renderedTarget.sprite.costumes.length > 0) {
const costumesParams = ['costumes: ['];
costumesParams.push(
renderedTarget.sprite.costumes.map(costume => ` {
asset_id: ${this.quote_(costume.assetId)},
name: ${this.quote_(costume.name)},
bitmap_resolution: ${costume.bitmapResolution},
md5: ${this.quote_(costume.md5)},
data_format: ${this.quote_(costume.dataFormat)},
rotation_center_x: ${costume.rotationCenterX},
rotation_center_y: ${costume.rotationCenterY}
}`).join(',\n')
);
costumesParams.push(' ]');
attributes.push(costumesParams.join('\n'));
const costumes = renderedTarget.sprite.costumes;
if (costumes.length > 0) {
const s = costumes.map(i => {
const h = {
asset_id: this.quote_(i.assetId),
name: this.quote_(i.name),
bitmap_resolution: i.bitmapResolution,
md5: this.quote_(i.md5),
data_format: this.quote_(i.dataFormat),
rotation_center_x: i.rotationCenterX,
rotation_center_y: i.rotationCenterY
};
return this.hashToCode(h);
}).join(',\n');
attributes.costumes = `[\n${this.prefixLines(s, this.INDENT)}\n]`;
}
switch (renderedTarget.rotationStyle) {
case RenderedTarget.ROTATION_STYLE_LEFT_RIGHT:
attributes.push('rotation_style: :left_right');
attributes.rotation_style = ':left_right';
break;
case RenderedTarget.ROTATION_STYLE_NONE:
attributes.push('rotation_style: :none');
attributes.rotation_style = ':none';
break;
}

this.definitions_[definitionsId] =
`Sprite.new(${this.quote_(name)}${attributes.join(',\n ')})`;
}
return Blockly.Ruby.definitions_[definitionsId];
};

Blockly.Ruby.defineVariables = function (renderedTarget) {
if (!renderedTarget) {
return null;
}
const variables = [];
const lists = [];
for (const id in renderedTarget.variables) {
const v = renderedTarget.variables[id];
switch (v.type) {
case SCALAR_TYPE:
variables.push(v);
break;
case LIST_TYPE:
lists.push(v);
break;
}
}
if (variables.length > 0) {
const s = variables.map(i => {
const h = {
name: this.quote_(i.name)
};
if (i.value !== 0) {
h.value = this.scalarToCode(i.value);
}
return this.hashToCode(h);
}).join(',\n');
attributes.variables = `[\n${this.prefixLines(s, this.INDENT)}\n]`;
}
if (lists.length > 0) {
const s = lists.map(i => {
const h = {
name: this.quote_(i.name)
};
if (i.value.length > 0) {
h.value = this.listToCode(i.value);
}
return this.hashToCode(h);
}).join(',\n');
attributes.lists = `[\n${this.prefixLines(s, this.INDENT)}\n]`;
}

const variables = [];
const lists = [];
for (const varId in renderedTarget.variables) {
const currVar = renderedTarget.variables[varId];
switch (currVar.type) {
case SCALAR_TYPE:
variables.push(currVar);
break;
case LIST_TYPE:
lists.push(currVar);
break;
let code = this.hashToCode(attributes, ': ', false);
if (code.length > 0) {
code = `,\n${this.prefixLines(code, ' ')}`;
}
this.definitions_[definitionsId] =
`Sprite.new(${this.quote_(name)}${code})`;
}
variables.forEach(currVar => {
this.definitions_[`variable_${currVar.name}`] =
`${this.spriteName(renderedTarget)}.make_variable(${this.quote_(currVar.name)})`;
});
lists.forEach(currVar => {
this.definitions_[`list_${currVar.name}`] =
`${this.spriteName(renderedTarget)}.make_list(${this.quote_(currVar.name)})`;
});
return Blockly.Ruby.definitions_[definitionsId];
};

Blockly.Ruby.characterStack = function () {
Expand Down Expand Up @@ -301,7 +348,7 @@ export default function (Blockly) {

for (name in Blockly.Ruby.definitions_) {
const def = this.definitions_[name];
if (typeof def === 'string' || def instanceof String) {
if (this.isString(def)) {
if (name.match(/^require__/)) {
requires.push(def);
} else if (name.match(/^prepare__/)) {
Expand Down
118 changes: 65 additions & 53 deletions test/unit/lib/ruby-generator.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ describe('RubyGenerator', () => {
let Blockly;
let Ruby;

const SCALAR_TYPE = '';
const LIST_TYPE = 'list';

beforeEach(() => {
vm = new VM();
Blockly = VMScratchBlocks(vm);
Expand Down Expand Up @@ -55,9 +58,6 @@ describe('RubyGenerator', () => {
let renderedTarget;

beforeEach(() => {
const SCALAR_TYPE = '';
const LIST_TYPE = 'list';

renderedTarget = {
sprite: {
name: 'Sprite1'
Expand Down Expand Up @@ -176,7 +176,39 @@ describe('RubyGenerator', () => {
visible: false,
size: 44,
currentCostume: 2,
rotationStyle: 'left-right'
rotationStyle: 'left-right',
variables: {
id1: {
name: 'Variable1',
type: SCALAR_TYPE,
value: 10
},
id2: {
name: 'List1',
type: LIST_TYPE,
value: [1, 2, 3]
},
id3: {
name: 'Variable2',
type: SCALAR_TYPE,
value: 0
},
id4: {
name: 'List2',
type: LIST_TYPE,
value: []
},
id5: {
name: 'Variable3',
type: SCALAR_TYPE,
value: 'abc'
},
id6: {
name: 'List3',
type: LIST_TYPE,
value: ['a', 'b', 'c']
}
}
};
});

Expand Down Expand Up @@ -208,7 +240,33 @@ describe('RubyGenerator', () => {
rotation_center_y: 61
}
],
rotation_style: :left_right)`;
rotation_style: :left_right,
variables: [
{
name: "Variable1",
value: 10
},
{
name: "Variable2"
},
{
name: "Variable3",
value: "abc"
}
],
lists: [
{
name: "List1",
value: [1, 2, 3]
},
{
name: "List2"
},
{
name: "List3",
value: ["a", "b", "c"]
}
])`;
expect(Ruby.defineSprite(renderedTarget)).toEqual(expected);
});

Expand All @@ -225,58 +283,12 @@ describe('RubyGenerator', () => {
visible: true,
size: 100,
currentCostume: 1,
rotationStyle: 'all around'
rotationStyle: 'all around',
variables: {}
});
renderedTarget.sprite.costumes = [];
const expected = `Sprite.new(${Ruby.quote_(spriteName)})`;
expect(Ruby.defineSprite(renderedTarget)).toEqual(expected);
});
});

describe('defineVariables', () => {
let renderedTarget;

beforeEach(() => {
const SCALAR_TYPE = '';
const LIST_TYPE = 'list';

renderedTarget = {
sprite: {
name: 'Sprite1'
},
variables: {
id1: {
name: 'Variable1',
type: SCALAR_TYPE
},
id2: {
name: 'List1',
type: LIST_TYPE
},
id3: {
name: 'Variable2',
type: SCALAR_TYPE
},
id4: {
name: 'List2',
type: LIST_TYPE
}
}
};
});

test('add definitions_ the make_variable and make_list codes', () => {
Ruby.defineVariables(renderedTarget);
const spriteName = Ruby.spriteName(renderedTarget);
const expecteds = {
variable_Variable1: `${spriteName}.make_variable(${Ruby.quote_('Variable1')})`,
variable_Variable2: `${spriteName}.make_variable(${Ruby.quote_('Variable2')})`,
list_List1: `${spriteName}.make_list(${Ruby.quote_('List1')})`,
list_List2: `${spriteName}.make_list(${Ruby.quote_('List2')})`
};
for (const name in expecteds) {
expect(Ruby.definitions_[name]).toEqual(expecteds[name]);
}
});
});
});