Edited at
OpalDay 9

OpalでJavaScriptのAPIを呼びだしてみよう

More than 1 year has passed since last update.

この記事はOpal Advent Calendar 2016の9日目の投稿として書いています。

またしても日付を超えてしまいましたが、今日はOpalからJavaScriptのAPIを呼びだしてみようと思います。

OpalはRubyからJavaScriptへソースコードを変換するコンパイラです。なので基本的にはRubyでプログラムを書くことになります。

Opalのエコシステムが充実してきているとはいえ、やはりそれだけでは足りないこともあります。

JavaScriptを直接実行することができれば、プラットフォームやライブラリで提供されるAPIを呼びだすことができます。

もっとも簡単な方法は、`で囲まれた中にJavaScriptのコードを書くことです。

例えば、

`alert('hello world')`

のように書きます。

複数行あるような場合は%x記法でも書けます。

%x(

var str = 'hello world';
alert(str);
)

アラートだけではつまらないのでもうすこし実用的なプログラムにしましょう。

Web Audioを使って音を鳴らすなんでどうでしょう。Qiitaで検索すると適当なサンプルがありますね。

http://qiita.com/ykob/items/462b558192ab09500bf3

昨日紹介したsilicaで作ったプロジェクトに埋めこんでみましょう。

app/application.rbを以下のように書きかえます。

app/application.rb

require 'hyalite'

#require 'menilite'

class AppView
include Hyalite::Component

def play
%x(
var context = new AudioContext();
var buffer = null;
var source = context.createBufferSource();

var request = new XMLHttpRequest();
request.open('GET', 'assets/sounds/sample.mp3', true);
request.responseType = 'arraybuffer';
request.send();

request.onload = function () {
var res = request.response;
context.decodeAudioData(res, function (buf) {
source.buffer = buf;
});
};
source.connect(context.destination);
source.start(0);
)
end

def render
div(nil,
button({onClick: self.method(:play)}, 'Play')
)
end
end
Hyalite.render(Hyalite.create_element(AppView), $document['.content'])

mp3ファイルをassets/soundsというディレクトリを作ったその下にsample.mp3という名前で置いてください。

mp3ファイルはご自身でご用意くださいね。

Playボタンを押してみてください。サウンドが鳴りましたでしょうか?

さて、これでいつでもJavaScriptを実行できるので、Opalの上でなんでもできることになります。

しかし、せっかくRubyで書けるのに埋め込みのJavaScriptで埋めつくされるのも残念な感じです。JavaScriptからまたRubyに戻ってくる必要がありますね。

そこでOpalにはNativeという機能が用意されています。

require 'native'して、AudioContextを以下のように作成します。

  context = Native(`new AudioContext()`)

先ほどの説明のとおり、`に囲まれたところはJavaScriptのコードになります。

Native()Native::Object.new()と同じ意味でNativeオブジェクトを作ることになります。

NativeオブジェクトはRubyのメソッド呼び出しとしてJavaScriptのメソッドを呼びだすことができます。

  source = context.createBufferSource

このように、JavaScriptで作られたオブジェクトをNativeオブジェクトでRuby側で自由にあつかうことができるようになります。

playメソッドはつぎのように書きかえることができます。

  def play

context = Native(`new AudioContext()`)
source = context.createBufferSource

request = Native(`new XMLHttpRequest()`)
request.open('GET', 'assets/sounds/sound.mp3', true)
request.responseType = 'arraybuffer'
request.send

request.onload = Proc.new do
res = request.response
context.decodeAudioData(res) do |buf|
source.buffer = buf
end
end
source.connect(context.destination)
source.start(0)
end

JavaScriptのfunctionはRubyのProcオブジェクトやブロックで置きかえることができます。

どうでしょうかサウンドは鳴りましたか?

このようにNativeを使えばJavaScriptのオブジェクトをラップすることができます。明日は(というってももう日付が変ってしまいましたが)Web Audioを便利に扱えるライブラリを作ってみましょう。