Hatena::ブログ(Diary)

Ehrenの日記 このページをアンテナに追加

2012-02-07

Play2.0でmoreStylesとmoreScriptsの書き方をいろいろ考えてたら、テンプレートの使い方がいろいろわかってきた

id:kiris60 さんの別解的な書き方があるので一応紹介。

でも書くなら kirisさん方式が個人的には一番好きだな。

http://kiris.hatenablog.com/entry/2012/01/26/172446

参考

https://github.com/playframework/Play20/wiki/ScalaTemplates

http://playscalaja.appspot.com/documentation/0.9.1/templates Play1+Scalaとあまり変わってない

気づき点(仕様?)

  • {}の仕様

テンプレートからテンプレート引数を渡すときに、

中括弧({})で囲むと暗黙的に"play.api.templates.Html"に変換されるっぽい。

"@"をつけてScalaの処理を加えて、明示的に変数化してもplay.api.templates.Htmlになります。

@main("ここは任意の型が使えるが、"){
  <!-- ここはplay.api.templates.Html型になる  -->
}

f:id:Ehren:20120201161330j:image


こんなかんじ(例1 )

@(title: String)(content: Html)(moreStyles: Html)(moreScripts: Html)

<!DOCTYPE html>

<html>
    <head>
        <title>@title</title>
        
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">

	    @moreStyles
        <script src="/assets/javascripts/jquery-1.7.1.min.js" type="text/javascript"></script>
	    @moreScripts
    </head>
  ...

@(message: String)

@import tags._

@main("Welcome to Play 2.0") {
    
    @play20.welcome(message)
    
}{
    @styleSheets(
      List(
        ("screen", "stylesheets/main.css")
      )
    )
}{

    @javaScripts(
      List(
        "javascripts/underscore.js",
        "javascripts/underscore.string.js"
      )
    )
}

こんな書き方も可能

カリー化っぽく書くこともできます。


@(title: String)(moreStyles: Seq[(String, String)]=Nil)(moreScripts: Seq[String]=Nil)(content: Html)

@import tags._

<!DOCTYPE html>

<html>
    <head>
        <title>@title</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">

        
        @styleSheets(moreStyles)
        <script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
@javaScripts(moreScripts)

    </head>
    <body>
        @content
    </body>
</html>
@(message: String)

@import tags._

@main("Welcome to Play 2.0")()(
          List(
        "javascripts/underscore.js",
        "javascripts/underscore.string.js"
        )
    ){
    
    @play20.welcome(message)
    
}

実験用ソース

https://github.com/masahitojp/Play20_customtag_example

まとめ

Play2系ではビルダがsbtになったお陰でテンプレートコンパイル時のビルド時間が早くなってくれて嬉しい。*1

Play+Scalaで開発するときのサクサク感が1系よりもあがった気がします。

*1:1+Scalaテンプレートで一文字変更しただけでも結構ビルドに時間がかかる

2012-01-31

Play20でEclipseプロジェクトを作る

これはPlay!framework 2.0 RC1-SNAPSHOTのお話です。betaでは動かないかも。

Play20ではsbteclipseがsbtのDependencyに登録されています。


https://github.com/playframework/Play20/blob/master/framework/project/Build.scala#L83

基本的にコマンド実行でOKです。コマンドはPlay!framework 1系と同じです。*1

$ play eclipsify

*1: netbeansify,idealizeは現状ありません。

2012-01-29

Play20でIntelliJを使う

Play20で IntelliJをのプロジェクト化する方法をまとめておきます。

前にMLIntelliJに取り込む方法が紹介されてたけどこちらの方が簡単なので紹介します。*1

参考


やりかた

  • Play RC1-snapshotをビルド
  • "play new hoge"で新規プロジェクトを作成
  • "hoge/project/plugin.sbt" を以下のように変更
resolvers ++= Seq(
    DefaultMavenRepository,
    Resolver.url("Play", url("http://download.playframework.org/ivy-releases/"))(Resolver.ivyStylePatterns),
    "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
)

addSbtPlugin("play" % "sbt-plugin" % "2.0-RC1-SNAPSHOT")

resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/"

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.0.0")
  • プロジェクト内で play コマンドを実行
  • sbt コンソールで "update"コマンド実行.
  • sbt-ideaがきちんと登録されたら、"gen-idea"コマンド実行
  • IntelliJを開いて、"File"メニューから,"Open Project"でPlay プロジェクトのフォルダを選択
  • できました.-)

f:id:Ehren:20120129233950p:image


まとめ

Play2.0はsbtベースになってくれたお陰でsbtの拡張がそのまま使えるのが便利ですね。

Play2.0 finalまでにコマンドが取り込まれる予定らしいのでそれまではsbtの拡張を探して使うのが良さそうですね。

なお、eclipse版もあるので、後日試してみたいところです。

先人に感謝。

typesafehub/sbteclipse - GitHub

*1: 実はPlay!flamework AdventCalendar 2週目以降用のネタだったのですが、現状に合わせて大幅に変更して今更公開します。

2012-01-23

unittest2でテストスキップする

テストを特定の条件の場合のみ実行できるようにしたい。

unittest2(python2.7,python3.2以降だとunittest)だとunittest2.skipという機能が追加されました。

http://www.voidspace.org.uk/python/articles/unittest2.shtml

こんな感じ


platform = 'linux' if sys.platform.startswith('linux') else sys.platform

@skip("skip this test")
def test_method(self):
    ...

@skipIf(platform == "win32", "win32ではテストしない")
def test_method(self):
    ...

@skipUnless(platform == "win32", "win32のみテスト")
def test_method(self):
    ...

# classにも使える
@skipIf(platform == "win32", "win32ではテストしない")
class TestSequenceFunctions(unittest2.TestCase):
    def setUp(self):
        self.seq = range(10)
    def test_shuffle(self):
        ...

でも同じメッセージを出す場合、毎回同じメッセージ書くのはだるいですよね。

メッセージを変数に格納するにしても毎回設定するのもめんどいです。

そこで

wrapしちゃえ!

こんな感じ

# decorator for class
def platform_skip(platform_list):
    def _inner(obj):
        return obj
    if platform in platform_list:
        return unittest2.skip("Test disabled in the current platform")
    return _inner

@platform_skip(["win32", "darwin"])
class TestSequenceFunctions(unittest2.TestCase):
        ...

まとめ

実はやってみるまでデコレーターのwrapができるとは思ってなかったのですが、割と何とかなるものですね。

Python書くのは楽しいです!

2012-01-19

Pythonでのテストツールtox入門

libuvPython実装であるpyuvのPython3対応しているときに、Python2.6/2.7/3.0/3.1/3.2で個別にテストする必要がありました。

各バージョンのPythonを入れるのも割と大変だし、各バージョンごとに確認するのも非常に手間です。

lazyな私にはこんなのやってられません。がおー。めんどくせー。

というわけでいろいろテストツールをいろいろ探していたら、79.pyで @ さんにtoxを教えていただきました。

早速使ってみたので、軽くメモを残しておきます。


ドキュメント

↓を読めば大体わかるはず。

Welcome to the tox automation project — tox 1.4.dev3 documentation


ざっくり説明すると

Pythonライブラリを複数バージョンでテストするツールです。

CI(Jenkinsなど)で使うことも想定しているようです。(Jenkinsでの使い方はここを参照)

mock, greenlet ,pylibなどで使われています。

私はやったことないですが、きちんと設定すれば、Sphinxのdoctestを実行することも可能です。(General tips and tricks — tox 1.4.dev3 documentation)

動作の仕組み

PATHからバージョン付きのpythonコマンド(例: python2.6)を探し、バージョンごとにvirtualenvで環境を作って

各バージョンごとにテストしてくれます。つまり、もとの環境は汚れません。

なお、各バージョンのPATHは設定ファイルで、設定することができます。(ここを参照)


インストール

以下のコマンドのどちらかを使いましょう。ここでは easy_install or pipの説明はしません。

$ easy_install tox
$ pip install tox

実行方法

tox.iniを作る

設定ファイルを作ります。おなじみのini形式です。

toxのexampleでは py.testですが、ここでは私が使い慣れているnoseで記述しています。

他のテストランナー(unit2コマンドなど)を使うこともできます。

# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py31, py32
[testenv]
deps=nose           # テストで使うライブラリ
commands=nosetests  # テスト時に実行するコマンド

コマンド実行

以下のコマンドをたたけば実行できます。

$ tox
$ tox -e py32 # py32だけのテストをしたい場合

ちょっと進んだ使い方

Python2.6 /3.0では unittest2 を使いたい場合の設定を紹介します。

[tox]
envlist = py26, py27, py30, py31, py32

[testenv]
deps = nose
commands = nosetests -v -w tests []

[testenv:py26]
deps = 
  unittest2
  nose
commands = nosetests -v -w tests []

[testenv:py30]
deps =
  unittest2py3k
  nose
commands = nosetests -v -w tests []

Python2,3両方に対応する場合

今回は幸いなことに対象となるライブラリで"2to3"コマンドを使わずにすみました。*1

そうでない場合は、わりと大変だと思います。

commands で"2to3" or "3to2" を追加する必要があるのですが、ドキュメントには書かれていません。

実際に処理を行っているtoxを探してみるといいと思います。

3to2コマンドを使ってる例を紹介しておきます。

ここで使われているライブラリはPython3.2向けに書かれていて2系は3to2して使うという先進的なものです。

https://github.com/EnigmaCurry/blogofile/blob/plugins/tox.ini


使い方の想定

toxコマンド実行の度にライブラリのパッケージング&テストがはしります。

ですので、まず1バージョンのテストをすませた後で、最後にtoxテストを実行できるようにするといいと思いました。

ライブラリの対応バージョンが少なく,CIでのテストを考えない, Windows/Unix両方で動かすことを考えない場合は別に使わなくてもいいかもしれません。

今回の私の仕様用途にはばっちりあっていたので使っていて非常に楽でした。

むしろ、もとのテストがvirtualenvを考えない作りで書かれていたので、動くように書き直す方が大変でしたOTZ


まとめ

複数バージョンでのテストが楽になるので、toxはライブラリ作者には非常に福音となるツールになると思います。

テストはきちんと書きましょうね :-)


その他

というわけで、pyuvの作者にtox化したテストをPull/Requestしたところ取り込んでもらえました。

これで今年2勝目だ!作者さんに喜んでもらえたみたいですげー嬉しい。

https://github.com/saghul/pyuv/pull/6

*1: 2.6以降しか対応してない and テスト以外はCAPIのみ