Play で Scala.js を使う

Play meetup では Play や Scalaフレームワークの歴史みたいな話をしていましたが、本当はこのネタで LT をするつもりでした。諸事情によりってやつです。

さて Play で Scala.js をサポートしようぜって話は少し前からありますが、今のところまだ進展はないようです。

Add buildin ScalaJs support · Issue #2321 · playframework/playframework

ただ、もちろん sbt をいじれば一緒に使うことが可能です。

単純に optimizeJS して出力された js を Play の public/javascripts フォルダにコピーするとか。

lazy val copyJS = Command.command("copyJS") { (state) =>
  scala.sys.process.Process(List("cp", "js/target/scala-2.10/scala-js-slide-js-opt.js", "server/public/javascripts/")).!
  state
}

ちょっとやっつけ感ありますが問題なく使えます。

でもまあもうちょっとまともな方法はが公式サイトからリンク貼られてました。 これを clone するか設定パクればOKです。

git clone git@github.com:vmunier/play-with-scalajs-example.git

このプロジェクトでは Scala.js のプロジェクトが scalajs というサブプロジェクト、Play アプリが scalajvm というサブプロジェクト、さらにその両方で共有されるコードが shared というサブプロジェクトになっています。

├── README.md
├── project
│   ├── Build.scala
│   ├── build.properties
│   ├── plugins.sbt
│   ├── project
│   └── target
├── scala
│   ├── shared
│   └── target
├── scalajs
│   ├── src
│   └── target
└── scalajvm
    ├── app
    ├── conf
    ├── logs
    ├── public
    ├── target
    └── test

このやり方については pab_tech さんも書いてるのでそちらを見てください。

Scala.jsとJVMの両対応コードとScala.jsのテストの書き方 | PABlog

で、Play と使うための build.sbt 設定の中心は以下の部分です。 Scala.js の出力先を Play の public/javascripts にしています。さらに dependsOn を使って Play のアプリをコンパイルしたときに Scala.js のプロジェクトのコンパイルを走らせるようにしています。dist コマンドを使ったときには optimize も行うようになっています。

lazy val scalajvmSettings =
    play.Project.playScalaSettings ++ Seq(
      scalajsOutputDir     := (crossTarget in Compile).value / "classes" / "public" / "javascripts",
      compile in Compile <<= (compile in Compile) dependsOn (preoptimizeJS in (scalajs, Compile)),
      dist <<= dist dependsOn (optimizeJS in (scalajs, Compile)),
    ) ++ (
      // ask scalajs project to put its outputs in scalajsOutputDir
      Seq(packageExternalDepsJS, packageInternalDepsJS, packageExportedProductsJS, preoptimizeJS, optimizeJS) map { packageJSKey =>
        crossTarget in (scalajs, Compile, packageJSKey) := scalajsOutputDir.value
      }
    )

これで、Play でも Scala.js が使えるようになります。やったー!コンパイル時間がさらに伸びますね!

f:id:tototoshi:20140525232911p:plain

Play 2 meetup を開催しました & スライドまとめ

ドワンゴさんを会場としてお借りして Play meetup を行いました。ありがとうございました!

f:id:tototoshi:20140525010622p:plain

http://connpass.com/event/6020/

発表資料をTLから拾ってまとめましたのでどうぞ。

Play と Scala のこれまでとこれから/@tototoshi

(開会挨拶的なもので特に面白くはないですが一応貼っておきます)

やさしい Iteratee 入門 / @kawachi

play2のjsonと型クラス @xuwei_k

f:id:tototoshi:20140525010334p:plain

http://xuwei-k.github.io/slides/play2typeclasses/

DSLからのコードジェネレーションで楽々Play開発 @takezoux2

ActionBuilder の罠(仮) @gakuzzzz

f:id:tototoshi:20140525010338p:plain

https://docs.google.com/presentation/d/1jzdBxSz-gSUxOG16WDguJlu1i4y8CE_-vbCaqgZjWkY/present#slide=id.p

sbt-webを使ったプラグインの作り方(仮) @pab_tech

f:id:tototoshi:20140525010336p:plain

http://slides.pab-tech.net/sbt-web/

フロントエンドとバックエンドのビルド構成について @kara_d

一番簡単なWebSocketの試し方 @shunjikonishi

Play2 WS 再入門 @magnet88jp

f:id:tototoshi:20140525010339p:plain

https://docs.google.com/presentation/d/1H8PhVmMqDHf8bRhsuw03KW0jd98SWKRoEnwt1UecRtc/htmlpresent

MyFleetGirls @ponkotuy

https://gist.github.com/ponkotuy/02c091b00a9317bd8ee3

なんでこがいに並外れた Typesafe ができたんか言うたら...

「よくシリコンバレーのスタートアップが作ってるようなうさんくさいビデオ」を Typesafe も作っていました。

Typesafe activator ダウンロードするか、めんどくさい...とサイトに行ったらいきなりビデオ見せられました。なかなかのユーザー体験をしました。

何か Typesafe Activator がすごい革新的っぽいことが伝わってきます。

他にもいろいろあります。

去年 Scala Conference に来てくれた Jamie さん

すごそう。

知らない人

すごそう。

Heiko さん

すごそう。

小田好先生

すごい(確信)

まとめ

  • Typesafe すごそう
  • 広島弁バージョンの登場が待たれる

composer で依存関係から特定のライブラリを除外する

Maven でのこれ

<dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>sample.ProjectB</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>

composer にはこの依存関係から特定のライブラリを除外する機能はない。まだ実装していないのではなく方針として入れるつもりはなさそう。composer 開発者はこの機能を不要と思っているっぽい。

Exclude packages · Issue #1549 · composer/composer

理想をいうと微妙なところだけど、実際こういう問題はよく起きるからカバーするべきじゃないかな。composer 開発者はそういう経験ないのだろうか。PHPフルスタックでそれのみで完結するようなフレームワークが多く、依存関係のツリーが深くならないから dependency hell が起きづらいと勝手に理解しておく。

一応、問題自体は除外したいモジュールを provide に指定すれば解決する。すでに提供されているのだから composer で持ってくる必要はないよね、ということ。

{
    "require": {
        "foo": "1.0.0"
    },
    "provide": {
        "bar": "*"
    }
}

ただし、これだと問題は解決するものの意味としては全く違うから気持ち悪い。設定が json だからコメントも書けない。

まとめ

  • composer で exclude したいときは provide を使う
  • json で設定ファイルはきびしい

Python で Github Flavored Markdown をレンダリングする

前回の補足的な内容

python の Markdown ライブラリ自体は Github Flavored Markdown(GFM) をサポートしていない。

>>> import markdown
>>> markdown.markdown("```python\ndef hello():\n    print('hello')\n```")
u"<p><code>python\ndef hello():\n    print('hello')</code></p>"

python の Markdown ライブラリは拡張可能になっている。Markdown ライブラリの拡張ライブラリとして py-gfm を使うと gfm も扱えるようになる。

>>> import markdown
>>> markdown.markdown("```python\ndef hello():\n    print('hello')\n```", extensions=['gfm'])
u'<pre class="highlight"><code class="language-python">def hello():\n    print(\'hello\')</code></pre>'

さて、これで python であることを認識してくれたわけではあるけれど、シンタックスハイライトが効いていない。しかし、前回のエントリで MoinMoin に Markdown + py-gfm を組み込んだときはシンタックスハイライトがついていた。なんで?

これが気になっていろいろソース読んだりしたのだけど、答えは MoinMoin が pygments に依存しているから。pygments をインストールする前後で Markdown ライブラリは動きが変わる。

$ pip install pygments
>>> import markdown
>>> markdown.markdown("```python\ndef hello():\n    print('hello')\n```", extensions=['gfm'])
u'<div class="highlight"><pre><span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>\n    <span class="k">print</span><span class="p">(</span><span class="s">&#39;hello&#39;</span><span class="p">)</span>\n</pre></div>'
>

pygments をインストールしたらシンタックスハイライトがついた。

実は Markdown のほうにこんなコードがあった。

try:
    from pygments import highlight
    from pygments.lexers import get_lexer_by_name, guess_lexer, TextLexer
    from pygments.formatters import HtmlFormatter
    pygments = True
except ImportError:
    pygments = False

https://github.com/waylan/Python-Markdown/blob/2.4-final/markdown/extensions/codehilite.py#L26-L32

わかりにくい挙動だと思う。markdown 関数の第二引数で extensions=['pygment'] みたいに渡すようにすればいいのに。せっかく拡張を作れるにしたのになぜこういう結合をさせるのか理解に苦しむ。

まあともあれ、Markdown + py-gfm + pygments で良い感じに GFM がレンダリングできるので使うと良いと思います。

MoinMoin で Markdown (Github Flavored Markdown) を使う

Markdown のメモ帳として kobito を使っていたんだけど Qiita に新規投稿ができないし、過去の投稿は編集できるけど取得はできない(つまり書いた記事がいつのまにか巻き戻されている)という状態に頻繁になるので使うのをやめました。なんなんだ、嫌がらせか。

いい加減あきれたので Qiita で書いていたもののうち、非公開にしているものを自分で管理している MoinMoin Wiki に記事を移行することにしました。公開しているものはこのブログに持ってくることにします。

さて、Qiita は Markdown で、MoinMoin は独自記法なので単純に考えると変換を書ける必要がある、と思いきや実はそんな必要はない。MoinMoin の parser はプラガブルになっていて自分で追加ができるので自分で Markdown パーサーを書いてやれば OK。 MoinMoin の公式の Wiki には Python の Markdown ライブラリを用いた方法が紹介されています。

しかし使ってみたら Qiita は Github Flavored Markdown (の亜種?)なのでコードブロックなどが Markdown ライブラリだとうまくレンダリングできませんでした。Github Flavored Markdown を扱えるライブラリを探していたら dart-lang の人たちがなぜか python で実装している py-gfm というのを教えてもらいました。

というわけでまず py-gfm をインストールします。

$ git clone https://github.com/dart-lang/py-gfm.git
$ cd py-gfm
$ python setup.py install

これで Markdown ライブラリで GFM 拡張が使えるようになるので、これを使って GFM プラグインを書きます。

# coding: utf-8
from markdown import markdown
import json

Dependencies = ['user']

class Parser:

    def __init__(self, raw, request, **kw):
        self.raw = raw
        self.request = request

    def format(self, formatter):
        output_html = markdown(self.raw, extensions=['gfm'])
        try:
            self.request.write(formatter.rawHTML(output_html))
        except:
            self.request.write(formatter.escapedText(output_html))

すごくテキトーですが、これで GFM プラグインの完成です。簡単ですね。 text_markdown.py という名前で MoinMoin の plugin/parser ディレクトリに入れてあげましょう。

2015/02/10 追記

原因は追ってないけど最近 py-gfm が動作しなくなったので Markdown の extension を組み合わせてほぼ GFM っぽい感じにしてます。これだけで十分かも。なにか互換性壊れたのかなー。

# coding: utf-8
from markdown import markdown
import json

Dependencies = ['user']

class Parser:

    def __init__(self, raw, request, **kw):
        self.raw = raw
        self.request = request

    def format(self, formatter):
        output_html = markdown(
            self.raw,
            extensions=[
                'markdown.extensions.fenced_code',
                'markdown.extensions.toc',
                'markdown.extensions.codehilite',
                'markdown.extensions.wikilinks',
                'markdown.extensions.tables',
                'markdown.extensions.def_list',
                'markdown.extensions.nl2br',
                'markdown.extensions.headerid',
                ])
        try:
            self.request.write(formatter.rawHTML(output_html))
        except:
            self.request.write(formatter.escapedText(output_html))

Markdown で Wiki エントリを追加する

markdown で Wiki にエントリを追加したいときは、書き出しを

#format text_markdown
(空行)

にすれば Markdown として解釈してくれるようになります。

これでレンダリングが崩れることはなくなりましたが、CSS が当たっていません。 CSS はどこに追加するのが流儀なんでしょうか。よくわからないので本体の common.csshttps://github.com/johnmdonahue/git_marked から拝借したのを突っ込んでしまいました。

.c{color:#998;font-style:italic;}
.err{color:#a61717;background-color:#e3d2d2;}
.k{font-weight:bold;}
.o{font-weight:bold;}
.cm{color:#998;font-style:italic;}
.cp{color:#999;font-weight:bold;}
.c1{color:#998;font-style:italic;}
.cs{color:#999;font-weight:bold;font-style:italic;}
.gd{color:#000;background-color:#fdd;}
.gd .x{color:#000;background-color:#faa;}
.ge{font-style:italic;}
.gr{color:#a00;}
.gh{color:#999;}
.gi{color:#000;background-color:#dfd;}
.gi .x{color:#000;background-color:#afa;}
.go{color:#888;}
.gp{color:#555;}
.gs{font-weight:bold;}
.gu{color:#800080;font-weight:bold;}
.gt{color:#a00;}
.kc{font-weight:bold;}
.kd{font-weight:bold;}
.kn{font-weight:bold;}
.kp{font-weight:bold;}
.kr{font-weight:bold;}
.kt{color:#458;font-weight:bold;}
.m{color:#099;}
.s{color:#d14;}
.na{color:#008080;}
.nb{color:#0086B3;}
.nc{color:#458;font-weight:bold;}
.no{color:#008080;}
.ni{color:#800080;}
.ne{color:#900;font-weight:bold;}
.nf{color:#900;font-weight:bold;}
.nn{color:#555;}
.nt{color:#000080;}
.nv{color:#008080;}
.ow{font-weight:bold;}
.w{color:#bbb;}
.mf{color:#099;}
.mh{color:#099;}
.mi{color:#099;}
.mo{color:#099;}
.sb{color:#d14;}
.sc{color:#d14;}
.sd{color:#d14;}
.s2{color:#d14;}
.se{color:#d14;}
.sh{color:#d14;}
.si{color:#d14;}
.sx{color:#d14;}
.sr{color:#009926;}
.s1{color:#d14;}
.ss{color:#990073;}
.bp{color:#999;}
.vc{color:#008080;}
.vg{color:#008080;}
.vi{color:#008080;}
.il{color:#099;}

やっつけ感すごいですが、とりあえずこれで MoinMoin で Github Flavored Markdown が使えるようになりました。めでたし。

f:id:tototoshi:20140514022146p:plain

Scala.js について

Sendagaya.js(仮)Scala.js について LT しました。

資料はこちら

http://tototoshi.github.io/slides/sendagaya-js-scala-js/

スライドは Scala.js を使って作ってみました。 ソースコードはこちら。

tototoshi/scala-js-slide

Scala.js は以前から知っていましたが、今回初めてさわりました。意外にサクサク書けました。ふむふむ、なんだちゃんと動くじゃないか、という感じ。

特にハマりどころはなかったし、ScalaJavaScript に変換されるということだけで十分面白いです。Scala 好きな方は一度試して見ると良いと思います。Scala の学習コストを考えたら Scala.js の学習コストはかなり低いです。そして何より心をざわつかせる何かがあります。

仕事で使うのはファイルサイズの都合上まだ無理ですが、バージョンが上がるごとに劇的な改善があるので、もしかしたら...という感じです。まあしばらくは良いおもちゃという感じで情報を追っておこうと思います。