この記事は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を便利に扱えるライブラリを作ってみましょう。