CTC 教育サービス
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes
6/26にRails4.0.6及び4.1.2がリリースされました(*1)。このリリースは4.1系では初めての、4.0系では4.0.4以来となるバグフィックスリリースです。3回のRelease Candidate版を経て、"Regression"をフィックスしているようですので是非使ってみてください。
尚、3.2系に対するバグフィックスリリースは既に終了しています(*2)。当該バージョンをお使いの方はRails4系にアップデートされることをお勧めいたします。
いまやWeb開発の必須スキルともいえるJavaScriptですが、その独特の仕様ゆえに評価が分かれる言語でもあります(*3)。そこでJQueryやUnderscore.jsなどのライブラリやJavaScriptへのコード変換が行えるCoffeeScriptやTypeScriptなどが脚光を浴びています。
そのような中今回は、100%のRubyの表記で記述できJavaScriptへのコード変換が行える「Opal(*4)」をご紹介いたします。
なお、動作環境は以下の通りです。(*5)
まずはプロジェクトを作成しましょう。「--javascript=opal」のオプションをつけることで、Opalの使用に必要な環境が自動的にインストール・定義されます。
> rails new OpalSample --javascript=opal
「/Gemfile」にはopal-railsを使用するように記述されています。
(略) # Use opal as the JavaScript library gem 'opal-rails' (略)
「/app/assets/javascripts/application.js」にはjquery、jquery_ujsの代わりにopal、opal_ujsを使用するように記述されています。
(略) //= require opal //= require opal_ujs //= require turbolinks //= require_tree .
次にOpalを実行する画面を作成します。ここではSampleController#indexをジェネレートしました(*6)。
> rails g controller sample index create app/controllers/sample_controller.rb route get 'sample/index' invoke erb create app/views/sample create app/views/sample/index.html.erb (略)
とりあえず適当な演算を行ってみましょう。「app/assets/javascripts/sample.js.opal」を作成し(*7)、以下のように編集します。
# 文字列の出力 puts "Hello Opal!" # 5の階乗(1) def factorial(n) n > 1 ? n * factorial(n-1) : n end puts factorial(5) # 5の階乗(2) puts 1.upto(5).inject(:*) # 5の階乗(3) class Fixnum def factorial self > 1 ? self * (self-1).factorial : self end end puts 5.factorial
編集後「http://localhost:3000/sample/index」にアクセスし、開発者ツールでコンソールを確認すると結果が表示されているかと思います(*8)。
お決まりの「Hello Opal」以外に階乗の計算を3パターンで行ってみましたが、どれも正常に出力されています。当たり前といえば当たり前ですが、オープンクラスにも対応しておりなかなか完成度が高そうです。
続いてDOM操作を行ってみましょう。OpalにはJQueryライクなOpal-JQueryというライブラリがついていますのでそちらを利用します。
ここでは特に凝ったことをせずに自動生成されるerbファイルをそのまま用いてみます。h1要素をクリックした際、末尾に赤字で「h1 was clicked!」と表示させてみましょう。
自動生成される「app/views/sample/index.html.erb」の中身は以下のようになっています。
<h1>Sample#index</h1> <p>Find me in app/views/sample/index.html.erb</p>
JQueryで記述すると以下のようなソースコードになるでしょう。
$(function(){ $("h1").on("click", function(){ var p_elem = $("<p>");
p_elem.text("h1 was clicked"); p_elem.css("color", "red");
$().append(p_elem);
}); });
「app/assets/javascripts/sample.js.opal」を以下のように編集します。
# Document.ready? do Element.find("h1").on(:click) do p_elem = Element.new("p") p_elem.text("h1 was clicked!") p_elem.css("color", "red") Element.find("body").append(p_elem) end end
多少記述の違いはありますが、JQueryライクにDOM操作が行えますね。下記の表に特筆すべき違いを示します。
JQuery | Opal | |
要素の参照 | $("selector") | Element.find("selector") |
要素の作成 | $("<element>") | Element.new("element") |
JQueryオブジェクトの取得 | $(object) | Element.parse(object) |
documentの取得 | $(document) | Document |
また、JQueryではキャメルケースでメソッド名やプロパティ名などが定義されていますが、OpalではRubyの文化に合わせてスネークケースで定義されているようです(*9)。
「`(アクサングラーブ)」を使うことで、NativeなJavaScriptのコードを実行することができます(*10)。
`window.open("http://example.com", "example")`
windowオブジェクトのほか、前回までに使用したWebSocketやEventSourceなどへアクセスする際にもこの構文を使うことになりますが、「`」の中はJavaScriptの文法になるためOpalを使うメリットが半減してしまいます。
そのようなケースのために、OpalではKernel#Nativeが用意されています。このメソッドを使うことでRubyライクにJavaScriptのオブジェクトを使用することができます。
win = Native(`window`) win.open("http://example.com", "example")
ここでは1行目でJavaScriptのコードを引数にNativeメソッドを呼び出し、変数winに代入しています(*11)。2行目ではRubyライクにopenメソッドを呼び出しています。
Opal-Parserというライブラリを用いることで、Rubyスクリプトを直接HTMLに埋め込むことができます。Rails上で動作させるには、「app/asset/javascripts/application.js」を以下のように編集します。
(略) //= require opal //= require opal_ujs //= require opal-parser // この行を追加 //= require turbolinks //= require_tree .
ここでは、前回のActionController::Liveによるチャット機能のクライアントサイドコードをOpalで書き換えてみたいと思います。
「app/views/chat/index.html.erb」を以下のように編集します。
<!-- チャット表示部分 --> <ul id="chat_area"> </ul> <!-- コメントフォーム --> <%# Ajaxリクエストで送信 %> <%= form_tag "/chat/message", :remote => true do %> <%= text_field_tag :comment %> <%= submit_tag "send" %> <% end %> <script type="text/ruby"> # SSEの接続 sse = Native(`new EventSource("/chat/stream")`) # メッセージ受信時の処理 sse.onmessage = lambda do |native_event| event = Native(`native_event`) message_li = Element.new("li") message_li.text(event.data) Element.find("#chat_area").append(message_li) end </script>
ポイントをいくつか説明します。
[Line12]
<script type="text/ruby">
OpalをHTMLに埋め込むためにはscriptタグのtype属性に「text/ruby」を指定します。ここではインラインで書いていますが、src属性を用いることで外部ファイルを読み込むこともできます。
[Line14]
sse = Native(`new EventSource("/chat/stream")`)
この行ではEventSourceオブジェクトを取得しています。本来は「NativeEventSource = Native(`EventSource`)」でEventSourceクラスを取得後、「sse = NativeEventSource.new("/chat/stream")」としたいところですがこのやり方ではエラーとなるため(*12)、オブジェクトの生成までをJavaScriptコードで行っています。
[Line18]
event = Native(`native_event`)
イベントハンドラのコールバック関数に引き渡されるMessageEventオブジェクトをRubyのオブジェクトに変換しています(*13)。
ここまで簡単ではありますが、Opalの紹介をしてまいりました。公式サイトにはより詳しく説明が掲載されていますので、一度ご覧ください。
使用感としては、ActionController::Liveにおけるクライアントサイドコードを見ていただいても分かる通り、まだ本番運用で使用するには難しいところもあるかなと思います。またエラー発生時のデバッグが難しいという問題も抱えています(*14)。
ですがRSpecによるテストも行えるようですし、何よりRubyの表現力は魅力的ですので今後に期待していきたいと思います。みなさんも是非試してみてください。
それでは、Enjoy Ruby!
*1 : http://weblog.rubyonrails.org/2014/6/26/Rails-4-1-2-and-4-0-6-has-been-released/
*2 : Rails3.2.14リリースの際にアナウンスされています(http://weblog.rubyonrails.org/2013/7/23/Rails-3-2-14-has-been-released/)。
*3 : ここら辺の話はこちらのスライド(http://goo.gl/ovgS7Z)が参考になります。
*4 : http://opalrb.org/
*5 : 今回はコンパイルなどの手間を省くためRails上で動作させていますが、Railsなしでも動作させることができます。
*6 : Opalファイルを作るためのジェネレータが存在しないため、ジェネレート中にエラーが発生します(https://github.com/opal/opal-rails/issues/26)。しかし手動で作成しても問題ないため、ここでは無視します。
*7 : 拡張子は「.rb」もしくは「.opal」である必要があります。ここでは「.opal」を選択してみました。
*8 : putsメソッドを使用するとコンソール上に出力を行います(console.log()と同じ)。
*9 : 例えば、JQueryで定義されているaddClassやremoveClassはOpalではadd_class、remove_classと定義されています。
*10 : 外部コマンドを実行するKernel#`(http://docs.ruby-lang.org/ja/2.1.0/class/Kernel.html#M_--60)と同様の形式です。
*11 : Opalのドキュメント(view-source:http://opalrb.org/docs/interacting_with_javascript/)では「window = Native(`window`)」と説明されていますが、この記述では変数windowに何も代入されず次行でエラーになります。これは左辺の変数windowの宣言が先に行われ、「`window`」ではそちらを参照しにいくためだと考えられます。この挙動が正しいのかどうかはよく分かりません。
*12 : 「Native(`EventSource`)」の戻り値はProcオブジェクトとなるため、クラスのように扱うことができません。これはJavaScriptがクラスレスなプログラミング言語であり、クラスに当たる部分は関数を用いて実現しているためだと考えられます。
*13 : コールバック関数に渡される引数はJavaScriptのオブジェクトになるようです。
*14 : デバッグ(というかOpalのバグ調査)については、こちらにまとめられています(http://qiita.com/yhara/items/2c8a668aeb7173321875)。
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes