Scala.js が sbt プロジェクト以外でも使えるようになっていた
Scala.js 0.5.0 では standalone 版が配布されるようになりました。
http://www.scala-js.org/news/2014/06/13/announcing-scalajs-0.5.0/
これで sbt プロジェクトでなくても Scala.js が使えるようになりました。 以下の URL で配布されています。
http://www.scala-js.org/downloads.html
このパッケージには 3 つコマンドが含まれています。
- scalajsc
- scalajsld
- scalajsp
scalajsc は Scala.js のコンパイラです。 scalac のラッパーになっていて、scalac を起動するときに Scala.js の jar もクラスパスに加えてくれるだけの単純なもの。
試して見ましょう。次のような Hello.scala を用意します。
package hello import scala.scalajs.js import js.Dynamic.{ global => g } import js.annotation.JSExport @JSExport object Hello { @JSExport def hello(): Unit = { g.alert("Hello") } }
$ scalajsc Hello.scala
すると、hello というディレクトリが生成されました。この中にクラスファイルが含まれています。
$ tree hello hello ├── Hello$.class ├── Hello$.sjsir └── Hello.class 0 directories, 3 files
sjsir ってなんだよって感じですね。これは Scala.js が生成する中間ファイルで、気にしないで良いですが、気になる人は scalajsp コマンドでのぞけるっぽいですよ。
$ scalajsp hello/Hello\$.sjsir module class Lhello_Hello$ extends O ancestors O { hello__V(): <notype> { <global>["alert"]("Hello".cast[dyn]) } $$js$exported$meth$hello__O(): any { this.hello__V(); undefined } "hello"(): any { this.$$js$exported$meth$hello__O() } export "Hello" hello__(): any { this.hello__V(); undefined } } ;
生成されたクラスファイルをリンクして js を生成するには scalajsld コマンドを使います。 scalajsld コマンドには引数としてクラスパス(つまりhelloディレクトリ)を渡し、 出力先の js ファイルを -o オプションとして渡します。
$ scalajsld -o hello.js hello Fast optimizing hello.js Inc. opt stats: reused: 0 -- invalidated: 2726 -- trees read: 219
scalajsld のヘルプを見ればわかりますが、optimize の仕方は fastOpt(-f), noOpt(-n), fullOpt(-u) から選ぶことができます。デフォルトは fastOpt です。
これで、hello.js というファイルが生成されてめでたく使えるようになりました。
<html> <head> <script type="text/javascript" src="hello.js"></script> <script type="text/javascript"> Hello().hello(); </script> </head> </html>
ちゃんと動いた。
sbt のプロジェクトどころか Scala のプロジェクトである必要もないですね。めでたしめでたし。
PHP の file_get_contents は get どころか post も put も delete も upload もできる
stream_context_create と組み合わせて使います。
手元でてきとーに動かしてた REST API とかで試してます。
get
普通ですね。
<?php $content = json_decode(file_get_contents("http://localhost:5000/api/note/161"));
post
<?php $context = stream_context_create( array( 'http' => array( 'method'=> 'POST', 'header'=> 'Content-type: application/json; charset=UTF-8', 'content' => json_encode( array( 'title' => 'file_get_contents で POST', 'raw' => "file_get_contents で POST\nPHP すごい...\n" ) ) ) ) ); file_get_contents('http://localhost:5000/api/note', false, $context);
なるほど〜。file_get_contents は file_post_contents だったのか〜。
put
<?php $context = stream_context_create( array( 'http' => array( 'method'=> 'PUT', 'header'=> 'Content-type: application/json; charset=UTF-8', 'content' => json_encode( array( 'id' => 162, 'title' => 'file_get_contents で PUT', 'raw' => "file_get_contents で PUT\nPHP すごい...\n" ) ) ) ) ); file_get_contents('http://localhost:5000/api/note/162', false, $context);
なるほど〜。file_get_contents は file_put_contents だったのか〜。
delete
<?php $context = stream_context_create( array( 'http' => array( 'method'=> 'DELETE' ) ) ); file_get_contents('http://localhost:5000/api/note/162', false, $context);
なるほど〜。file_get_contents は file_delete_contents だったのか〜。
upload
<?php $upload_content = file_get_contents('upfile.txt'); $context = stream_context_create( array( 'http' => array( 'method'=> 'POST', 'header'=> 'Content-Type: multipart/form-data; boundary=-PHP_FILE_GET_CONTENTS', 'content' => "---PHP_FILE_GET_CONTENTS Content-Disposition: form-data; name=\"upfile\"; filename=\"upfile.txt\" Content-Type: text/plain {$upload_content} ---PHP_FILE_GET_CONTENTS " ) ) ); file_get_contents("http://localhost:5001/test_upload.php", false, $context);
なるほど〜。file_get_contents は file_upload_contents だったのか〜。
ひとこと
無理すんなや。
Scala.js を情報商材風に説明する
天下一altJS武闘会 で Scala.js の紹介をしました。
Scala.js 楽しいよって言っても全く流行る気配ないので、 情報商材風のスライドを作ってみました。洗脳されちゃって下さい。
http://tototoshi.github.io/slides/tenka1altjs-scalajs/
fork元を明示したいところですが、 普通によくある怪しげな情報商材サイトなのでやめておきます。
Play 2.4 と Dependency Injection
Play 2.3 が出たばっかで 2.4 の話をします。
前置き: Scala での DI
Scala では DI についてのベストプラクティスと言える方法はなく、まだ意見が分かれている状態です。大きく割ると DI コンテナなどを使った動的な DI と、cake pattern, implicit parameter, macro, reader monad などを利用した静的な DI の 2 パターンです。
動的な DI と静的な DI にはそれぞれメリットとデメリットがあります。動的な DI のメリットは Java のわりと優秀な DI コンテナ (Guice とか) が使えて比較的取っ付きやすいこと、デメリットは型安全ではないところ。静的な DI のメリットは型安全、デメリットは trait だの macro だの implicit parameter だの、コンパイル時間が伸びる要因満載であることです。
- 実戦での Scala: Cake パターンを用いた Dependency Injection (DI) | eed3si9n
- Dependency injection in Scala with Play 2: it’s free | Julien Richard-Foy
- Scrap Your Cake Pattern Boilerplate: Dependency Injection Using the Reader Monad - Originate Developer Blog
- Careful Escapades: Using implicit parameters for Dependency Injection in Scala
また静的な DI を行うとコードが少し複雑になってしまう傾向もあります。私は良く cake pattern で DI をしていますが、いくつもの trait を組み合わせてオブジェクトを組み立てていくと実装がばらけてしまい、コードが追いづらくなるという批判は納得しています。オブジェクトの継承関係が複雑になると、初期化順でハマったりもします。implicit parameter や reader monad による DI はあまりしませんが、まあ多くの開発者はそんなフレンドリーとは受け取ってくれないでしょう。
型安全好きな Scala コミュニティとしては当然静的な DI が良いよねと言いたいんでしょうが、現状はいろいろ問題があるので、DI は定期的によく盛り上がる(燃え上がる)話題の一つです。
Play 2.4 の DI
Play には DI の機能は一部あるものの、まだ本気ではない感じです。 そんな中 play-framework dev(開発者 ML) に、James Roper さんから DI の話題が投下されました。
Play 2.4 - Dependency Injection
要旨をまとめると
- Play としては DI を動的に行うのか、静的に行うのか、どちらか一方の立場を取るつもりはない。ただしドキュメントに載せるなら動的な方法が良い気がする。
- Play 2.4、そして Play 3.0 では constructor injection を基本にしたい
- play.api.Play.current が状態を持たせるよりも constructor injection を基本にしたほうがテスタビリティは上がるだろう
constructor injection と言ってるのはまあこんな感じです。
class MyController(wsClient: WSClient) {
wsClient.url(...)
}
constructor で WSClient という依存性を渡しています。まあ普通っすね。普通っぽいですが、これができると Play ではかなりテストがしやすくなります。
現状では Play の各モジュールは play.api.Application というグローバルな状態を持つクラスにべったりと依存しています。ピンとこない人に説明すると、良く何も考えずに import しているあれです。
import play.api.Play.current // これが play.api.Application のインスタンス
設定などアプリケーションの情報はこのインスタンスがなんでもかんでも持っています。そのため、Play のテストではこの Play.api.Application の Fake を作ってあげる必要があります。サードバーティプラグインを使ったり、データベースの設定を変えたり、ちょっと凝ったことをやりたくなるとこれがなかなかめんどくさい。
// Play のドキュメントから class ExampleSpec extends PlaySpec with OneAppPerSuite { // Override app if you need a FakeApplication with other than // default parameters. implicit override lazy val app: FakeApplication = FakeApplication( additionalConfiguration = Map("ehcacheplugin" -> "disabled") ) "The OneAppPerSuite trait" must { "provide a FakeApplication" in { app.configuration.getString("ehcacheplugin") mustBe Some("disabled") } "start the FakeApplication" in { Play.maybeApplication mustBe Some(app) } } }
グローバルなオブジェクトに状態を持たせるのは、良くないなあと思いつつも、実際 Web アプリの場合はこういうグローバルなものがあったほうがやっぱり便利かなと思ってしまうこともあるのでよくわかりません。ただそういう設計ではやっぱりテストしづらいよね。もっとシンプルな Constructor Injection を基本にしたフレームワークにしてテストをもう少し楽に書けるようにしようね、というのが Play 2.4 そして Play 3.0 の方針だそうです。
実際どのような DI の方式が採用されるのか、どのくらいの規模の変更になるのかは知りませんが、Play 2.4、Play 3.0 のことを考えるならあまり play.api.Application(play.api.Play.current) に頼ったコードは書かないよう気をつけていたほうが移行が楽になるかもしれません。
いやあしかしすでにもう Play 3.0 の話題が出る時期なんですね。
middleman で簡単なドキュメントサイトを作る
play-flyway のドキュメントサイトを作るのに middleman を使った。そのメモ。
インストール
$ gem install middleman
最低限のコマンド
middleman init でひな形を作成。
$ middleman init website ... create website/.gitignore create website/config.rb create website/source/index.html.erb create website/source/layouts/layout.erb create website/source/stylesheets create website/source/stylesheets/all.css create website/source/stylesheets/normalize.css create website/source/javascripts create website/source/javascripts/all.js create website/source/images create website/source/images/background.png create website/source/images/middleman.png
source/ 以下のファイルを編集していくことになる。
開発用サーバの起動は middleman server で。
$ bundle exec middleman server
できあがったら middleman build でHTML にエキスポートできる。
$ bundle exec middleman build
Markdown を使えるようにする
redcarpet を Gemfile に加える。オプション次第で GFM っぽくなる。
# Gemfile gem "redcarpet"
# config.rb set :markdown_engine, :redcarpet set :markdown, :tables => true, :autolink => true, :gh_blockcode => true, :fenced_code_blocks => true
これでファイルの拡張子を .markdown にすると markdown で書けるようになる。
シンタックスハイライト
middleman-syntax を使う
# Gemfile gem "middleman-syntax"
# config.rb activate :syntax
感想
- reloadとか勝手にしてくれるし使いやすかった。
- middleman 流の asset の扱いがよくわかってない、というかまじめに調べてない。layout.erb で普通に script タグ書いたりしたけど、まあいっかという感じ。
play-flyway 1.1.0 をリリースしました
Play 2.3 用に play-flyway 1.1.0 をリリースしました。 pull-req 下さった皆様ありがとうございました。
変更点
- Play 2.3.0 対応
- Scala 2.10, 2.11 でのクロスビルド
- Flyway のアップデート (2.3 -> 3.0)
- Delay initialization by fernandoacorreia · Pull Request #17 · tototoshi/play-flyway
- Init with version number by aziegler · Pull Request #8 · tototoshi/play-flyway
Flyway 3.0 への更新は API 的にはさほど変化なく、package 名の変更くらいで済みました。
管理ページに bootstrap を当ててややかっこ良くしました。
Play 2.3 がリリースされたので変更点と試し方を説明します
http://www.playframework.com/documentation/2.3.x/Highlights23 https://groups.google.com/forum/#!msg/play-framework/bTvJbeR_zvU/J3reqk6Xo4AJ
変更点は以下の通り
- 新規プロジェクトを作るのに今までは play new コマンドを使っていたけれど Typesafe Activator を使うようになった。
- asset のコンパイルに sbt-web を利用するようになった(sbt-web については http://slides.pab-tech.net/sbt-web/ を見るとよい) 。
- Java8 サポート。Java 6,7 も引き続き使えます。
- Play-Java のパフォーマンス向上
- Scala 2.11 サポート (2.10 も引き続きサポート)
- Anorm の機能追加。SQL Interpolation 使えたりするようになった。
- WS の機能追加。
- ScalaTemplate の実装が twirl になった。
- WebSocket 用の Actor を追加 http://www.playframework.com/documentation/2.3.x/ScalaWebSockets
- HTTPS の SSLEngine がカスタマイズできるようになった。
- Asset のパフォーマンス向上。
- deprecated になっていた古い Result 系の型が削除された。
- いろいろバグ直した
以前からバリバリ使ってるよって人的には Result 型の整理がちょっとめんどいかもしれません。あとは WebSocket が Actor で少し楽に書けるようになったのが嬉しいかもしれませんね。Iteratee わけわからんって人も Actor ならまだなんとかなるんじゃないでしょうか。
ライブラリ・プラグイン作者にとってはまず sbt-web が大きくて、asset 系のプラグインを作りたいなら知っておく必要があります。あとは Scala 2.10, 2.11 のクロスビルドになってしまったので、まあ、ビルド頑張りましょう。
Play 初心者の人はプロジェクトの作成は play new ではなく、activator new を使うということだけ抑えておきましょう。古い情報を見て play new を探さないように。また activator のドキュメントを見ると activator ui というコマンドがありますが、activator ui は別に知らなくても良いただの余興みたいなものですのでとにかく気にせずに activator new しましょう。
activator は typesafe のサイトから手に入りますが、林檎教徒であれば homebrew でインストールできます。
$ brew install typesafe-activator
異教徒の方、こちらです。
$ wget http://downloads.typesafe.com/typesafe-activator/1.2.0/typesafe-activator-1.2.0-minimal.zip $ # いい感じでパスを通す
これで activator コマンドがインストールされるので activator new しましょう。
$ activator new
プロジェクトの名前を打ちます。今回は適当に try-play-23 にしました。
Enter an application name > try-play-23 Fetching the latest list of templates... The new application will be created in /Users/toshi/tmp/try-play-23 Browse the list of templates: http://typesafe.com/activator/templates Enter a template name, or hit tab to see a list
なんかサイト見ろって言ってますが、気にせず tab を押します。
> Display all 125 possibilities? (y or n) PlayStartApp activator-akka-cassandra activator-akka-scala-guice activator-akka-spray activator-akka-tracing activator-gilt-app ...
なんかテンプレートがいっぱい出てくるんですけど使用するのは play-scala です。
> play-scala OK, application "try-play-23" is being created using the "play-scala" template. To run "try-play-23" from the command-line, run: /Users/toshi/tmp/try-play-23/activator run To run the test for "try-play-23" from the command-line, run: /Users/toshi/tmp/try-play-23/activator test To run the Activator UI for "try-play-23" from the command-line, run: /Users/toshi/tmp/try-play-23/activator ui
これで try-play-23 プロジェクトができました。activator 使えってうるさいですね。どれどれ。
$ cd try-play-23 $ ls LICENSE conf README logs activator project activator-launch-1.1.0.jar public app target build.sbt test
プロジェクトの中に activator コマンドと起動用の jar が入っています。2.2 以前は play コマンドを使っていましたが、2.3 からはこの activator コマンドを使うのが流儀のようです。
$ ./activator run
実際 activator は sbt のラッパーなので、あまり必要性を感じない人は rm しちゃって sbt そのまま使えば良いでしょう。
$ rm activator* # 汚物は消毒だ! $ sbt run
これでもりもりとダウンロードやらコンパイルが始まるので待ちましょう。途中で OutOfMemory とか PermGen なんちゃらとか言われて落ちてもくじけない。
ふう、やっと起動した。
感想
- activator の存在意義は未だにわからない
- でも play で採用されることで activator の存在がいよいよ知れ渡ってしまったので一応知っておく必要はある
- sbt にプロジェクトテンプレート作成機能があればいい気がした
- play new したいがために Play のでかい zip を落としてくる必要がなくなったのは嬉しい