はじめに
世の中には数多のプログラミング言語がありますが、テキストではなくブロックなどのオブジェクトを組みたててプログラミングをする、ビジュアルプログラミング言語というジャンルがあります。
ビジュアルプログラミング言語には、データフローやビジネスプロセスモデリング1に特化したものもありますが、教育目的で利用されるScratchという言語の名前を聞いたことがある人もいらっしゃると思います。または、Hour of Code2という、コンピューターサイエンスが身近で楽しいことを伝える世界的な活動をご存知かもしれません。
Scratchライクなビジュアルプログラミング・エディタが簡単に作れるBlocklyを使うと、ビジュアルプログラミング環境をかんたんに作ったりカスタマイズすることができます。Hour of Codeの教材のcode.orgも、Blocklyを利用しています。
Blocklyの日本語記事がほとんどなかったので、導入からカスタマイズのやりかたまでを書いてみます。3
※ Google for Education > Blocklyより
セットアップ
Get StartedにBlocklyのライブラリのリンクがあります。
基本的には、公式ドキュメントを読み進めて行けばBlocklyをカスタマイズしていくところまでできます。
とはいえ、環境準備なども含めると手間になるので、テンプレートとなるリポジトリを作りました。
予めnode.jsをインストールしておいてください。
$ git clone -b getting_started git@github.com:taise/blockly_custom.git && cd blockly_custom
$ npm install yarn -g
$ yarn
ここまで終わったら、以下のコマンドを実行するとBlocklyの画面が表示されます。
$ npm run http-server
ブロックを設置する
環境準備が終わったので早速ブロックを配置していきましょう。
左側のグレーのエリアはtoolbox
といい、プログラミングで使えるブロックを配置します。
今回はcontrols_repeat
,text
,text_print
のブロックをおいてみます。ブロックを追加するには、id="toolbox"
の属性を持つxml
タグに利用したいブロックを定義していきます。
<xml id="toolbox" style="display: none">
<block type="controls_repeat"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>
すると、すると以下のようにブロックが表示されます。
ブロックを右側のworkspace
エリアにドラッグ & ドロップすることで、プログラミングをしていきます。
たくさんのブロックがカスタマイズなく利用できます。全てのブロックは紹介しきれないので、他のブロックも見てみたい場合は
こちらのリンク先のデモが参考になると思います。
ブロックのカテゴライズ
ブロックが増えてきた場合は、ブロックのカテゴライズができます。
toolbox
のxml
にloop系のブロックを足してカテゴリーを作ります。
<xml id="toolbox" style="display: none">
<category name="くりかえし">
<block type="controls_repeat_ext"></block>
<block type="controls_repeat"></block>
<block type="controls_whileUntil"></block>
<block type="controls_for"></block>
<block type="controls_forEach"></block>
<block type="controls_flow_statements"></block>
</category>
<category name="文字と出力">
<block type="text"></block>
<block type="text_print"></block>
</category>
</xml>
カテゴリーは、複数階層作ることもできます。
なお、ここで追加したloop系のブロックは、blockly/blocks/loops.jsのものを羅列しています。
Blocklyの設定
カテゴリーを作ると右下にゴミ箱(trashcan
)が出てきましたが、これをいつでも表示させたいなど、Blockly全体に関わる設定はBlockly.inject
をする際に行います。
Configurationのところに設定項目のリストがあります。
試しに色々設定してみます。
- 最大ブロック数: 3
- グリッドを表示
- ゴミ箱を表示
- ズームのコントロールパーツ表示
Blockly.inject(
'blocklyDiv',
{
toolbox: document.getElementById('toolbox'),
maxBlocks: 3,
grid: {
spacing: 18,
length: 3,
colour: '#ccc',
snap: true,
},
trashcan: true,
zoom: {
controls: true,
wheel: true,
startScale: 1.0,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.2,
},
},
);
実行可能なJavaScriptを出力する
Blocklyはブロックで作ったプログラムをJavaScriptに変換して実行することができます。まずはJavaScriptに変換して表示してみます。
index.html
にjavascript/compressed.js
の読み込ませ、JavaScript
表示用のボタンと表示エリアを作ります。
<button id="showCode">JavaScriptを表示する</button>
<pre id='jsCode'></pre>
<script src="lib/google-blockly/blockly_compressed.js"></script>
<script src="lib/google-blockly/blocks_compressed.js"></script>
<script src="lib/google-blockly/javascript_compressed.js"></script>
Blockly.JavaScript.workspaceToCode(workspace)
のように実行すると、workspace
に置かれたブロックをJavaScriptに変換できます。
const workspace = Blockly.inject(
'blocklyDiv',
{
toolbox: document.getElementById('toolbox'),
trashcan: true,
},
);
function showCode() {
Blockly.JavaScript.INFINITE_LOOP_TRAP = null;
const pre = document.getElementById('jsCode');
pre.innerHTML = Blockly.JavaScript.workspaceToCode(workspace);
}
document.getElementById('showCode').addEventListener('click', showCode, false);
なお、出力できる言語はJavaScript
だけではなく、python, php, lua, dartにも対応しています。4
ブロックをJavaScriptとして実行する
JavaScriptの文字列が取得できたので、eval()
を使えばブラウザ上で実行することができます。ただし、htmlに埋め込むために&
などが実体参照に変換されていたり、人間の目で追えない速度で実行されてしまったり、セキュリティのリスクがあるなど、そのまま使うにはいくつか課題もあります。
そのため、公式ドキュメントでも紹介されているとおり、JS Interpreter projectを使うのが良さそうです。
まずは、index.html
に実行用のボタンとインタープリタのスクリプトを読み込ませましょう。
<button id="showCode">JavaScriptを表示する</button>
<button id="runCode">JavaScriptを実行する</button>
<pre id='jsCode'></pre>
<script src="lib/js-interpreter/acorn_interpreter.js"></script>
<script src="lib/google-blockly/blockly_compressed.js"></script>
<script src="lib/google-blockly/blocks_compressed.js"></script>
つづいてindex.js
にインタープリタの設定を書いていきます。alert
が実装されていないため、createNativeFunction
で追加する必要があります。
function runCode() {
let maxSteps = 10000;
const code = Blockly.JavaScript.workspaceToCode(workspace);
function initialize(interpreter, scope) {
function alertWrapper(text) {
const msg = text ? text.toString() : '';
return interpreter.createPrimitive(window.alert(msg));
}
interpreter.setProperty(scope, 'alert', interpreter.createNativeFunction(alertWrapper));
}
const jsInterpreter = new Interpreter(code, initialize);
while (jsInterpreter.step() && maxSteps) {
maxSteps -= 1;
}
if (!maxSteps) {
throw EvalError('Infinite loop.');
}
jsInterpreter.run();
}
document.getElementById('showCode').addEventListener('click', showCode, false);
document.getElementById('runCode').addEventListener('click', runCode, false);
これだけでブロックが実際に実行できるようになりました。
ブロックをカスタマイズする
Blocklyは、ブロックの定義を追加することができます。
今回は文字列をシャッフルするブロックを作ってみます。
これだけだと取っ掛かりがなさすぎるので、Githubのblockly/blocks/text.jsを見てみましょう。すると中身がJSONで定義されていることがわかります。
JSONのなかで参照されているBlockly.Msg
は、表示用の文字列で、別ファイルで読み込まれています。Blocklyはi18n対応されており、msg/js/ja.js
を読み込んでいるため日本語表示されています。
表示される日本語に違和感を感じた方や、漢字が多くて小学校低学年向けには厳しいという方は、このファイルを書き換えてあげるとよいでしょう。
すこし話がそれてしまいましたが、カスタムブロック用のjsファイルを作ります。
今回のブロックは、シャッフルしたい文字だけなのでmessage
とargs
が1つずつです。
Blockly.Blocks.text_shuffle = {
/**
* Block for shuffle characters.
* @this Blockly.Block
*/
init() {
this.jsonInit({
message0: '%1をシャッフルする',
args0: [
{
type: 'input_value',
name: 'TEXT',
check: 'String',
},
],
output: 'String',
inputsInline: true,
colour: 160,
tooltip: '文字の順番をランダムでいれかえる',
});
},
};
Blockly.Blocks
を参照したいのと、Blockly.inject
で環境が初期化される前に読み込みたいので、scriptファイルの読み込み順に気をつけてください。
<script src="lib/google-blockly/msg/js/ja.js"></script>
<script src="custom_block.js"></script>
<script src="index.js"></script>
これで再度読み込んでみると...でました!
しかし、「JavaScriptを表示/実行する」は、ボタンを押しても反応がありません。
コンソールを開くとエラーが出ています。実装していないので当然ですね。実装しましょう。
Blockly.JavaScript
に対象ブロックのJavaScriptを生成するメソッドを生やします。
見ていただくとわかりますが、そうです、ただの文字列連結です。
当たり前なんですがこうしてみると、改めてプログラミング言語って文字列なんだなと思わされますね。
Blockly.JavaScript.text_shuffle = function(block) {
const args0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\'';
const OPERATOR = ".split('').sort(function(){return 0.5-Math.random()}).join('')";
return [args0 + OPERATOR, Blockly.JavaScript.ORDER_MEMBER];
};
では、これで実行してみます。
カスタムブロックのJavaScriptを実行できました
おわりに
これで自由にBlocklyをカスタムしながら、コンテンツを作る準備が整いました。
さらっとできる感じで書いてますが、なんだかんだ詰まりつつここまでまとめています。
基本的には公式ドキュメントに記載している範囲の内容ですので、もっと詳しく知りたくなった方はBlocklyのドキュメントをご覧ください。
-
例えば、BPELなどがあります。BPELは、XMLベースのビジュアルプログラミング言語で、SOAが流行していた時期にサービス間のオーケストレーションを目的に使われていましたね。 ↩
-
私が所属するリブセンスもCSR活動としてHour of Codeのワークショップを開催しました。 ↩
-
BlocklyにはWeb / Android / iOS向けのライブラリがありますが、Web版のみです。
なお、この記事は職業プログラマ向けのレベルで書かれています。 ↩ -
多言語への切り替えはgenerating codeを参照ください。 ↩
-
Livesense - 学 Advent Calendar 2017の記事として書かれたものです。 ↩