高尾宏治日記 on はてなブログ

プログラミング言語Rubyを中心とした技術情報を扱うブログです(Microsoft Surfaceはやめました)。

Google 製 Visual Programming Editor「Blockly」の調査

Blockly とは

smalruby-editor の視覚的なプログラムエディタ(Visual Programming Editor)の実装には Blockly を使うことを想定しています。 BlocklyGoogle 製の Visual Programming Editor です。Apache License, Version 2.0 にしたがって配布されているオープンソースソフトウェアです。また、いわゆるタダ乗りにも寛容なフリーソフトウェアの思想を感じます。

まずは デモサイト Code - Export a Blockly program into JavaScript, Python or XML. にアクセスして Blockly がどのようなものか確認するといいでしょう。

f:id:kouji0625:20140119011930p:plain

さて、ざっと Blockly がどのようなものかわかったところで smalruby-editor の実装に必要な次の情報を調査していきましょう。

  • デモサイトをローカルマシンで動作させる方法
  • Blockly を改良する方法
  • Rubyソースコードを出力する方法
  • 任意のブロックを作成する方法
  • ブロックをカテゴリ分けする方法
  • インタフェースをカスタマイズする方法
  • インタフェースを日本語にする方法

デモサイトをローカルマシンで動作させる方法

まずは git clone します。

git clone https://github.com/google/blockly

そして、 \path\to\blockly\apps\code\index.html をブラウザで開きます。

あらま、これだけで Blocklyデモサイト が手元でも動作します。

Blockly を改良する方法

Blocklyを改良するために必要なソフトウェアをインストールします。

これで準備が完了しました。

Blocklyをビルドします。

PS C:\Users\kouji\work\smalruby\blockly> python build.py
('Error running i18n/js_to_json.py: ', WindowsError(193, '%1 \x82\xcd\x97L\x8c\xf8\x82\xc8 Win32 \x83A\x83v\x83\x8a\x83P\x81[\x83V\x83\x87\x83\x93\x82\xc5\x82\xcd\x82\xa0\x82\xe8\x82\xdc\x82\xb9\x82\xf1\x81B'))
SUCCESS: blockly_uncompressed.js
SUCCESS: blockly_compressed.js
Size changed from 1814 KB to 439 KB (24%).
SUCCESS: blocks_compressed.js
Size changed from 91 KB to 53 KB (59%).
SUCCESS: javascript_compressed.js
Size changed from 76 KB to 44 KB (58%).
SUCCESS: python_compressed.js
Size changed from 62 KB to 29 KB (47%).

なんかエラーが出ていますね。失敗しているのは以下の箇所です。 i18n/js_to_json.py の実行に失敗していますが、Windows では shebang を指定してもスクリプトは実行できないのでどうにかする必要があります。

        subprocess.check_call([
            os.path.join('i18n', 'js_to_json.py'),
            '--input_file', 'msg/messages.js',
            '--output_dir', 'msg/json/',
            '--quiet'])

以下のように修正して回避します。

diff --git a/build.py b/build.py
index 4dbbf89..92f917b 100755
--- a/build.py
+++ b/build.py
@@ -334,6 +334,7 @@ class Gen_langfiles(threading.Thread):
                       ['en.json', 'qqq.json', 'synonyms.json']]):
       try:
         subprocess.check_call([
+            'python',
             os.path.join('i18n', 'js_to_json.py'),
             '--input_file', 'msg/messages.js',
             '--output_dir', 'msg/json/',
@@ -350,6 +351,7 @@ class Gen_langfiles(threading.Thread):
     try:
       # Use create_messages.py to create .js files from .json files.
       cmd = [
+          'python',
           os.path.join('i18n', 'create_messages.py'),
           '--source_lang_file', os.path.join('msg', 'json', 'en.json'),
           '--source_synonym_file', os.path.join('msg', 'json', 'synonyms.json'),

これでBlocklyをビルドできるようになりました。

PS C:\Users\kouji\work\smalruby\blockly> python build.py
WARNING: definition of LOGIC_NEGATE_TOOLTIP in msg\json\th.json contained a newline character.
SUCCESS: msg\js\ar.js
SUCCESS: msg\js\az.js
(省略)
Size changed from 91 KB to 53 KB (59%).
SUCCESS: javascript_compressed.js
Size changed from 76 KB to 44 KB (58%).
SUCCESS: python_compressed.js
Size changed from 62 KB to 29 KB (47%).

Blockly が正しく動作しているかどうかは、 https://code.google.com/p/blockly/wiki/UnitTesting に従って操作することで確認できます。なお、Windows 8.1/Internet Explorer 11 では確認用の HTML が正しく動作しません。Firefox or Chromeで試しましょう。

ついでにちょっと修正してみます。意味は特にないのですが文字列のダブルクォーテーションを2つにしてみます。

以下の修正を行って、ビルドして、demos/fixed/index.html をブラウザで開くと修正内容が反映されていることが確認できます。

diff --git a/blocks/text.js b/blocks/text.js
index 3bdd714..9797353 100644
--- a/blocks/text.js
+++ b/blocks/text.js
@@ -36,6 +36,8 @@ Blockly.Blocks['text'] = {
     this.appendDummyInput()
         .appendField(new Blockly.FieldImage(Blockly.pathToBlockly +
         'media/quote0.png', 12, 12))
+        .appendField(new Blockly.FieldImage(Blockly.pathToBlockly +
+        'media/quote0.png', 12, 12))
         .appendField(new Blockly.FieldTextInput(''), 'TEXT')
         .appendField(new Blockly.FieldImage(Blockly.pathToBlockly +
         'media/quote1.png', 12, 12));

Rubyソースコードを出力する方法

Blocklyは、JavaScriptPythonソースコードを生成できます。しかしながら、Rubyには対応していません。 でもね、 https://github.com/velniukas/blockly.cascading.jrubyRubyソースコード生成に対応したものが公開されています。 とっても参考になります。

レポジトリをリモートに追加しておきます。

cd path/to/blockly
git remote add velniukas git@github.com:velniukas/blockly.cascading.jruby.git

また、 https://code.google.com/p/blockly/wiki/CustomBlocks から参照できる以下の文書も参考になります。

まとめると、BlocklyRubyソースコードを生成できるようにするには、

といったことをすればいいようですね。

任意のブロックを作成する方法

チュートリアルに従ってタートルグラフィックス用のブロックを作ってみました。ブロックのカスタマイズを GUI で行える ことには驚きました。よくできています。

ただし、WindowsPowerShell だと最後のコマンドの --srcs オプションの引数を以下のように " で括ってやる必要がありました。

PS C:\Users\kouji\work\smalruby\blockly\apps\turtle> java -jar ../_soy/SoyToJsSrcCompiler.jar --outputPathFormat generated/en.js --srcs "../common.soy,template.soy"

ブロックを作るときに使うAPIのリファレンス もあります。

ブロックをカテゴリ分けする方法

Blockly ではブロックを選択するところを Toolbox と呼びます。このサンプルのように Toolbox にずら~とブロックを並べたり、タートルグラフィックス用のブロック のようにカテゴリ分けしてブロックを配置することができます。

そのやり方は https://code.google.com/p/blockly/wiki/Toolbox に記述されています。この文書の最後のサンプルには、あらかじめいくつかのブロックを組み合わせたものを Toolbox に配置する方法が説明されていますね。

インタフェースをカスタマイズする方法

Blockly のインタフェースのうち、ブロックやブロックを配置するためのキャンバスは SVG で表現されているようですので、それをカスタマイズするのは簡単ではなさそうです。 しかしながら、Toolbox は HTML で表現されていますので、CSS で簡単に見た目を変えることができそうです。

smalruby-editor では、できればScratchのように選択中のカテゴリのブロックを常に表示させたいのですが、そのためには core/toolbox.js を編集するか、それを継承した独自の Toolbox を作成する必要がありそうですね。

インタフェースを日本語にする方法

Blockly で利用している Soy というテンプレートエンジンがメッセージの翻訳に対応しているようです。 前述した「任意のブロックを作成する方法」で使ったコマンド java -jar ../_soy/SoyToJsSrcCompiler.jar --outputPathFormat generated/en.js --srcs "../common.soy,template.soy" のようにして、テンプレートから翻訳対象の文字列を抽出して、 JavaScript のメッセージカタログを出力できます。

実際には、SoyMsgExtractor.jar/xliff_to_json.py というコマンドを使って翻訳対象のメッセージをJSON形式で抽出して、ja.json などの各国語に翻訳したものを作成後、 json_to_js.pyJSON から JavaScript のメッセージカタログを出力するようです。

ここまでの準備ができたら、以下のJavaScriptの処理によってメッセージカタログを読み込みます。これでインタフェースを日本語にできます。

document.write('<script type="text/javascript" src="generated/' +
               BlocklyApps.LANG + '.js"></script>\n');

詳細は TranslationForDevelopersApplications and Tutorials に書いてあります。