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

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.